aboutsummaryrefslogtreecommitdiff
path: root/src/tools/Dtf/DDiff/MspDiffEngine.cs
blob: a32ab24ac25d3354b84ed011dc87a84b6e9e2d9d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.

using System;
using System.IO;
using WixToolset.Dtf.WindowsInstaller;
using WixToolset.Dtf.WindowsInstaller.Package;

namespace WixToolset.Dtf.Tools.DDiff
{
	public class MspDiffEngine : MsiDiffEngine
	{
		public MspDiffEngine()
		{
		}

		private string GetPatchTargetOption(string[] options)
		{
			for(int i = 0; i < options.Length - 1; i++)
			{
				switch(options[i].ToLower())
				{
					case "/p": goto case "-patchtarget";
					case "-p": goto case "-patchtarget";
					case "/patchtarget": goto case "-patchtarget";
					case "-patchtarget": return options[i+1];
				}
			}
			return null;
		}

		public override float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
		{
			if(diffInput1 != null && File.Exists(diffInput1) &&
				diffInput2 != null && File.Exists(diffInput2) &&
				GetPatchTargetOption(options) != null &&
				(IsMspPatch(diffInput1) && IsMspPatch(diffInput2)))
			{
				return .80f;
			}
			else if(diffInput1 != null && File.Exists(diffInput1) &&
				diffInput2 != null && File.Exists(diffInput2) &&
				GetPatchTargetOption(options) == null &&
				(IsMspPatch(diffInput1) && IsMsiDatabase(diffInput2)) ||
				(IsMsiDatabase(diffInput1) && IsMspPatch(diffInput2)))
			{
				return .75f;
			}
			else
			{
				return 0;
			}
		}

		public override bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
		{
			bool difference = false;

			InstallPackage db1, db2;
			if(IsMspPatch(diffInput1))
			{
				string patchTargetDbFile = GetPatchTargetOption(options);
				if(patchTargetDbFile == null) patchTargetDbFile = diffInput2;
				string tempPatchedDbFile = Path.GetTempFileName();
				File.Copy(patchTargetDbFile, tempPatchedDbFile, true);
				File.SetAttributes(tempPatchedDbFile, File.GetAttributes(tempPatchedDbFile) & ~System.IO.FileAttributes.ReadOnly);
				db1 = new InstallPackage(tempPatchedDbFile, DatabaseOpenMode.Direct);
				db1.ApplyPatch(new PatchPackage(diffInput1), null);
				db1.Commit();
			}
			else
			{
				db1 = new InstallPackage(diffInput1, DatabaseOpenMode.ReadOnly);
			}
			if(IsMspPatch(diffInput2))
			{
				string patchTargetDbFile = GetPatchTargetOption(options);
				if(patchTargetDbFile == null) patchTargetDbFile = diffInput1;
				string tempPatchedDbFile = Path.GetTempFileName();
				File.Copy(patchTargetDbFile, tempPatchedDbFile, true);
				File.SetAttributes(tempPatchedDbFile, File.GetAttributes(tempPatchedDbFile) & ~System.IO.FileAttributes.ReadOnly);
				db2 = new InstallPackage(tempPatchedDbFile, DatabaseOpenMode.Direct);
				db2.ApplyPatch(new PatchPackage(diffInput2), null);
				db2.Commit();
			}
			else
			{
				db2 = new InstallPackage(diffInput2, DatabaseOpenMode.ReadOnly);
			}

			if(GetSummaryInfoDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
			if(GetDatabaseDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
			if(GetStreamsDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;

			db1.Close();
			db2.Close();

			try
			{
				if(IsMspPatch(diffInput1)) File.Delete(db1.FilePath);
				if(IsMspPatch(diffInput1)) File.Delete(db2.FilePath);
			}
			catch(IOException)
			{
				#if DEBUG
				Console.WriteLine("Could not delete temporary files {0} and {1}", db1.FilePath, db2.FilePath);
				#endif
			}

			if(IsMspPatch(diffInput1) && IsMspPatch(diffInput2))
			{
				Database dbp1 = new Database(diffInput1, DatabaseOpenMode.ReadOnly);
				Database dbp2 = new Database(diffInput2, DatabaseOpenMode.ReadOnly);

				if(GetStreamsDiff(dbp1, dbp2, options, diffOutput, linePrefix, diffFactory)) difference = true;
				dbp1.Close();
				dbp2.Close();
			}

			return difference;
		}

		public override IDiffEngine Clone()
		{
			return new MspDiffEngine();
		}
	}
}