aboutsummaryrefslogtreecommitdiff
path: root/src/samples/Dtf/DDiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/samples/Dtf/DDiff')
-rw-r--r--src/samples/Dtf/DDiff/CabDiffEngine.cs131
-rw-r--r--src/samples/Dtf/DDiff/DDiff.cs72
-rw-r--r--src/samples/Dtf/DDiff/DDiff.csproj39
-rw-r--r--src/samples/Dtf/DDiff/DirectoryDiffEngine.cs154
-rw-r--r--src/samples/Dtf/DDiff/FileDiffEngine.cs83
-rw-r--r--src/samples/Dtf/DDiff/IDiffEngine.cs68
-rw-r--r--src/samples/Dtf/DDiff/MsiDiffEngine.cs276
-rw-r--r--src/samples/Dtf/DDiff/MspDiffEngine.cs127
-rw-r--r--src/samples/Dtf/DDiff/TextFileDiffEngine.cs83
-rw-r--r--src/samples/Dtf/DDiff/VersionedFileDiffEngine.cs90
10 files changed, 1123 insertions, 0 deletions
diff --git a/src/samples/Dtf/DDiff/CabDiffEngine.cs b/src/samples/Dtf/DDiff/CabDiffEngine.cs
new file mode 100644
index 00000000..6100ced8
--- /dev/null
+++ b/src/samples/Dtf/DDiff/CabDiffEngine.cs
@@ -0,0 +1,131 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Collections;
6using System.Collections.Generic;
7using WixToolset.Dtf.Compression.Cab;
8
9namespace WixToolset.Dtf.Samples.DDiff
10{
11 public class CabDiffEngine : IDiffEngine
12 {
13 public CabDiffEngine()
14 {
15 }
16
17 private bool IsCabinetFile(string file)
18 {
19 using(FileStream fileStream = File.OpenRead(file))
20 {
21 return new CabEngine().IsArchive(fileStream);
22 }
23 }
24
25 public virtual float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
26 {
27 if(diffInput1 != null && File.Exists(diffInput1) &&
28 diffInput2 != null && File.Exists(diffInput2) &&
29 (IsCabinetFile(diffInput1) || IsCabinetFile(diffInput2)))
30 {
31 return .80f;
32 }
33 else
34 {
35 return 0;
36 }
37 }
38
39 public bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
40 {
41 bool difference = false;
42 IComparer caseInsComp = CaseInsensitiveComparer.Default;
43
44 // TODO: Make this faster by extracting the whole cab at once.
45 // TODO: Optimize for the match case by first comparing the whole cab files.
46
47 CabInfo cab1 = new CabInfo(diffInput1);
48 CabInfo cab2 = new CabInfo(diffInput2);
49 IList<CabFileInfo> cabFilesList1 = cab1.GetFiles();
50 IList<CabFileInfo> cabFilesList2 = cab2.GetFiles();
51 CabFileInfo[] cabFiles1 = new CabFileInfo[cabFilesList1.Count];
52 CabFileInfo[] cabFiles2 = new CabFileInfo[cabFilesList2.Count];
53 cabFilesList1.CopyTo(cabFiles1, 0);
54 cabFilesList2.CopyTo(cabFiles2, 0);
55 string[] files1 = new string[cabFiles1.Length];
56 string[] files2 = new string[cabFiles2.Length];
57 for(int i1 = 0; i1 < cabFiles1.Length; i1++) files1[i1] = cabFiles1[i1].Name;
58 for(int i2 = 0; i2 < cabFiles2.Length; i2++) files2[i2] = cabFiles2[i2].Name;
59 Array.Sort(files1, cabFiles1, caseInsComp);
60 Array.Sort(files2, cabFiles2, caseInsComp);
61
62
63 for(int i1 = 0, i2 = 0; i1 < files1.Length || i2 < files2.Length; )
64 {
65 int comp;
66 if(i1 == files1.Length)
67 {
68 comp = 1;
69 }
70 else if(i2 == files2.Length)
71 {
72 comp = -1;
73 }
74 else
75 {
76 comp = caseInsComp.Compare(files1[i1], files2[i2]);
77 }
78 if(comp < 0)
79 {
80 diffOutput.WriteLine("{0}< {1}", linePrefix, files1[i1]);
81 i1++;
82 difference = true;
83 }
84 else if(comp > 0)
85 {
86 diffOutput.WriteLine("{0}> {1}", linePrefix, files2[i2]);
87 i2++;
88 difference = true;
89 }
90 else
91 {
92 string tempFile1 = Path.GetTempFileName();
93 string tempFile2 = Path.GetTempFileName();
94 cabFiles1[i1].CopyTo(tempFile1, true);
95 cabFiles2[i2].CopyTo(tempFile2, true);
96 IDiffEngine diffEngine = diffFactory.GetDiffEngine(tempFile1, tempFile2, options);
97 StringWriter sw = new StringWriter();
98 if(diffEngine.GetDiff(tempFile1, tempFile2, options, sw, linePrefix + " ", diffFactory))
99 {
100 diffOutput.WriteLine("{0}{1}", linePrefix, files1[i1]);
101 diffOutput.Write(sw.ToString());
102 difference = true;
103 }
104
105 File.SetAttributes(tempFile1, File.GetAttributes(tempFile1) & ~FileAttributes.ReadOnly);
106 File.SetAttributes(tempFile2, File.GetAttributes(tempFile2) & ~FileAttributes.ReadOnly);
107 try
108 {
109 File.Delete(tempFile1);
110 File.Delete(tempFile2);
111 }
112 catch(IOException)
113 {
114#if DEBUG
115 Console.WriteLine("Could not delete temporary files {0} and {1}", tempFile1, tempFile2);
116#endif
117 }
118 i1++;
119 i2++;
120 }
121 }
122
123 return difference;
124 }
125
126 public virtual IDiffEngine Clone()
127 {
128 return new CabDiffEngine();
129 }
130 }
131}
diff --git a/src/samples/Dtf/DDiff/DDiff.cs b/src/samples/Dtf/DDiff/DDiff.cs
new file mode 100644
index 00000000..27a5a782
--- /dev/null
+++ b/src/samples/Dtf/DDiff/DDiff.cs
@@ -0,0 +1,72 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Text;
6
7namespace WixToolset.Dtf.Samples.DDiff
8{
9 public class DDiff
10 {
11 public static void Usage(TextWriter w)
12 {
13 w.WriteLine("Usage: DDiff target1 target2 [options]");
14 w.WriteLine("Example: DDiff d:\\dir1 d:\\dir2");
15 w.WriteLine("Example: DDiff patch1.msp patch2.msp /patchtarget target.msi");
16 w.WriteLine();
17 w.WriteLine("Options:");
18 w.WriteLine(" /o [filename] Output results to text file (UTF8)");
19 w.WriteLine(" /p [package.msi] Diff patches relative to target MSI");
20 }
21
22 public static int Main(string[] args)
23 {
24 if(args.Length < 2)
25 {
26 Usage(Console.Out);
27 return -1;
28 }
29
30 string input1 = args[0];
31 string input2 = args[1];
32 string[] options = new string[args.Length - 2];
33 for(int i = 0; i < options.Length; i++) options[i] = args[i+2];
34
35 TextWriter output = Console.Out;
36
37 for(int i = 0; i < options.Length - 1; i++)
38 {
39 switch(options[i].ToLower())
40 {
41 case "/o": goto case "-output";
42 case "-o": goto case "-output";
43 case "/output": goto case "-output";
44 case "-output": output = new StreamWriter(options[i+1], false, Encoding.UTF8); break;
45 }
46 }
47
48 IDiffEngineFactory diffFactory = new BestQualityDiffEngineFactory(new IDiffEngine[]
49 {
50 new DirectoryDiffEngine(),
51 new FileDiffEngine(),
52 new VersionedFileDiffEngine(),
53 new TextFileDiffEngine(),
54 new MsiDiffEngine(),
55 new CabDiffEngine(),
56 new MspDiffEngine(),
57 });
58
59 IDiffEngine diffEngine = diffFactory.GetDiffEngine(input1, input2, options);
60 if(diffEngine != null)
61 {
62 bool different = diffEngine.GetDiff(input1, input2, options, output, "", diffFactory);
63 return different ? 1 : 0;
64 }
65 else
66 {
67 Console.Error.WriteLine("Dont know how to diff those inputs.");
68 return -1;
69 }
70 }
71 }
72}
diff --git a/src/samples/Dtf/DDiff/DDiff.csproj b/src/samples/Dtf/DDiff/DDiff.csproj
new file mode 100644
index 00000000..332ad4d0
--- /dev/null
+++ b/src/samples/Dtf/DDiff/DDiff.csproj
@@ -0,0 +1,39 @@
1
2<!-- 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. -->
3
4
5<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
6 <PropertyGroup>
7 <ProjectGuid>{1CDF4242-4C00-4744-BBCD-085128978FF3}</ProjectGuid>
8 <OutputType>Exe</OutputType>
9 <RootNamespace>WixToolset.Dtf.Samples.DDiff</RootNamespace>
10 <AssemblyName>DDiff</AssemblyName>
11 <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
12 <RunPostBuildEvent>OnOutputUpdated</RunPostBuildEvent>
13 </PropertyGroup>
14
15 <ItemGroup>
16 <Compile Include="CabDiffEngine.cs" />
17 <Compile Include="DDiff.cs" />
18 <Compile Include="DirectoryDiffEngine.cs" />
19 <Compile Include="FileDiffEngine.cs" />
20 <Compile Include="IDiffEngine.cs" />
21 <Compile Include="MsiDiffEngine.cs" />
22 <Compile Include="MspDiffEngine.cs" />
23 <Compile Include="TextFileDiffEngine.cs" />
24 <Compile Include="VersionedFileDiffEngine.cs" />
25 </ItemGroup>
26
27 <ItemGroup>
28 <Reference Include="System" />
29 <Reference Include="System.Data" />
30 <Reference Include="System.Xml" />
31 <ProjectReference Include="..\..\Libraries\Compression.Cab\Compression.Cab.csproj" />
32 <ProjectReference Include="..\..\Libraries\Compression.Zip\Compression.Zip.csproj" />
33 <ProjectReference Include="..\..\Libraries\Compression\Compression.csproj" />
34 <ProjectReference Include="..\..\Libraries\WindowsInstaller.Package\WindowsInstaller.Package.csproj" />
35 <ProjectReference Include="..\..\Libraries\WindowsInstaller\WindowsInstaller.csproj" />
36 </ItemGroup>
37
38 <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildProjectDirectory), wix.proj))\tools\WixBuild.targets" />
39</Project>
diff --git a/src/samples/Dtf/DDiff/DirectoryDiffEngine.cs b/src/samples/Dtf/DDiff/DirectoryDiffEngine.cs
new file mode 100644
index 00000000..89e8b47e
--- /dev/null
+++ b/src/samples/Dtf/DDiff/DirectoryDiffEngine.cs
@@ -0,0 +1,154 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Collections;
6
7namespace WixToolset.Dtf.Samples.DDiff
8{
9 public class DirectoryDiffEngine : IDiffEngine
10 {
11 public DirectoryDiffEngine()
12 {
13 }
14
15 public virtual float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
16 {
17 if(diffInput1 != null && Directory.Exists(diffInput1) &&
18 diffInput2 != null && Directory.Exists(diffInput2))
19 {
20 return .70f;
21 }
22 else
23 {
24 return 0;
25 }
26 }
27
28 public bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
29 {
30 bool difference = false;
31 IComparer caseInsComp = CaseInsensitiveComparer.Default;
32
33 string[] files1 = Directory.GetFiles(diffInput1);
34 string[] files2 = Directory.GetFiles(diffInput2);
35 for(int i1 = 0; i1 < files1.Length; i1++)
36 {
37 files1[i1] = Path.GetFileName(files1[i1]);
38 }
39 for(int i2 = 0; i2 < files2.Length; i2++)
40 {
41 files2[i2] = Path.GetFileName(files2[i2]);
42 }
43 Array.Sort(files1, caseInsComp);
44 Array.Sort(files2, caseInsComp);
45
46 for(int i1 = 0, i2 = 0; i1 < files1.Length || i2 < files2.Length; )
47 {
48 int comp;
49 if(i1 == files1.Length)
50 {
51 comp = 1;
52 }
53 else if(i2 == files2.Length)
54 {
55 comp = -1;
56 }
57 else
58 {
59 comp = caseInsComp.Compare(files1[i1], files2[i2]);
60 }
61 if(comp < 0)
62 {
63 diffOutput.WriteLine("{0}< {1}", linePrefix, files1[i1]);
64 i1++;
65 difference = true;
66 }
67 else if(comp > 0)
68 {
69 diffOutput.WriteLine("{0}> {1}", linePrefix, files2[i2]);
70 i2++;
71 difference = true;
72 }
73 else
74 {
75 string file1 = Path.Combine(diffInput1, files1[i1]);
76 string file2 = Path.Combine(diffInput2, files2[i2]);
77 IDiffEngine diffEngine = diffFactory.GetDiffEngine(file1, file2, options);
78 StringWriter sw = new StringWriter();
79 if(diffEngine.GetDiff(file1, file2, options, sw, linePrefix + " ", diffFactory))
80 {
81 diffOutput.WriteLine("{0}{1}", linePrefix, files1[i1]);
82 diffOutput.Write(sw.ToString());
83 difference = true;
84 }
85 i1++;
86 i2++;
87 }
88 }
89
90 string[] dirs1 = Directory.GetDirectories(diffInput1);
91 string[] dirs2 = Directory.GetDirectories(diffInput2);
92 for(int i1 = 0; i1 < dirs1.Length; i1++)
93 {
94 dirs1[i1] = Path.GetFileName(dirs1[i1]);
95 }
96 for(int i2 = 0; i2 < dirs2.Length; i2++)
97 {
98 dirs2[i2] = Path.GetFileName(dirs2[i2]);
99 }
100 Array.Sort(dirs1, caseInsComp);
101 Array.Sort(dirs2, caseInsComp);
102
103 for(int i1 = 0, i2 = 0; i1 < dirs1.Length || i2 < dirs2.Length; )
104 {
105 int comp;
106 if(i1 == dirs1.Length)
107 {
108 comp = 1;
109 }
110 else if(i2 == dirs2.Length)
111 {
112 comp = -1;
113 }
114 else
115 {
116 comp = caseInsComp.Compare(dirs1[i1], dirs2[i2]);
117 }
118 if(comp < 0)
119 {
120 diffOutput.WriteLine("{0}< {1}", linePrefix, dirs1[i1]);
121 i1++;
122 difference = true;
123 }
124 else if(comp > 0)
125 {
126 diffOutput.WriteLine("{0}> {1}", linePrefix, dirs2[i2]);
127 i2++;
128 difference = true;
129 }
130 else
131 {
132 string dir1 = Path.Combine(diffInput1, dirs1[i1]);
133 string dir2 = Path.Combine(diffInput2, dirs2[i2]);
134 IDiffEngine diffEngine = diffFactory.GetDiffEngine(dir1, dir2, options);
135 StringWriter sw = new StringWriter();
136 if(diffEngine.GetDiff(dir1, dir2, options, sw, linePrefix + " ", diffFactory))
137 {
138 diffOutput.WriteLine("{0}{1}\\", linePrefix, dirs1[i1]);
139 diffOutput.Write(sw.ToString());
140 difference = true;
141 }
142 i1++;
143 i2++;
144 }
145 }
146 return difference;
147 }
148
149 public virtual IDiffEngine Clone()
150 {
151 return new DirectoryDiffEngine();
152 }
153 }
154}
diff --git a/src/samples/Dtf/DDiff/FileDiffEngine.cs b/src/samples/Dtf/DDiff/FileDiffEngine.cs
new file mode 100644
index 00000000..20ecd857
--- /dev/null
+++ b/src/samples/Dtf/DDiff/FileDiffEngine.cs
@@ -0,0 +1,83 @@
1// 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.
2
3using System;
4using System.IO;
5
6namespace WixToolset.Dtf.Samples.DDiff
7{
8 public class FileDiffEngine : IDiffEngine
9 {
10 public FileDiffEngine()
11 {
12 }
13
14 public virtual float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
15 {
16 if(diffInput1 != null && File.Exists(diffInput1) &&
17 diffInput2 != null && File.Exists(diffInput2))
18 {
19 return .10f;
20 }
21 else
22 {
23 return 0;
24 }
25 }
26
27 public bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
28 {
29 bool difference = false;
30
31 FileInfo file1 = new FileInfo(diffInput1);
32 FileInfo file2 = new FileInfo(diffInput2);
33
34 if(file1.Length != file2.Length)
35 {
36 diffOutput.WriteLine("{0}File size: {1} -> {2}", linePrefix, file1.Length, file2.Length);
37 difference = true;
38 }
39 else
40 {
41 FileStream stream1 = file1.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
42 FileStream stream2 = file2.Open(FileMode.Open, FileAccess.Read, FileShare.Read);
43
44 byte[] buf1 = new byte[512];
45 byte[] buf2 = new byte[512];
46
47 while(!difference)
48 {
49 int count1 = stream1.Read(buf1, 0, buf1.Length);
50 int count2 = stream2.Read(buf2, 0, buf2.Length);
51
52 for(int i = 0; i < count1; i++)
53 {
54 if(i == count2 || buf1[i] != buf2[i])
55 {
56 difference = true;
57 break;
58 }
59 }
60 if(count1 < buf1.Length) // EOF
61 {
62 break;
63 }
64 }
65
66 stream1.Close();
67 stream2.Close();
68
69 if(difference)
70 {
71 diffOutput.WriteLine("{0}Files differ.", linePrefix);
72 }
73 }
74
75 return difference;
76 }
77
78 public virtual IDiffEngine Clone()
79 {
80 return new FileDiffEngine();
81 }
82 }
83}
diff --git a/src/samples/Dtf/DDiff/IDiffEngine.cs b/src/samples/Dtf/DDiff/IDiffEngine.cs
new file mode 100644
index 00000000..9895d6ff
--- /dev/null
+++ b/src/samples/Dtf/DDiff/IDiffEngine.cs
@@ -0,0 +1,68 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Collections;
6
7namespace WixToolset.Dtf.Samples.DDiff
8{
9 public interface IDiffEngine
10 {
11 float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory);
12
13 bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory);
14
15 IDiffEngine Clone();
16 }
17
18 public interface IDiffEngineFactory
19 {
20 IDiffEngine GetDiffEngine(string diffInput1, string diffInput2, string[] options);
21 }
22
23 public class BestQualityDiffEngineFactory : IDiffEngineFactory
24 {
25 public virtual IDiffEngine GetDiffEngine(string diffInput1, string diffInput2, string[] options)
26 {
27 float bestDiffQuality = 0;
28 IDiffEngine bestDiffEngine = null;
29
30 foreach(IDiffEngine diffEngine in diffEngines)
31 {
32 float diffQuality = diffEngine.GetDiffQuality(diffInput1, diffInput2, options, this);
33 if(diffQuality > bestDiffQuality)
34 {
35 bestDiffQuality = diffQuality;
36 bestDiffEngine = diffEngine;
37 }
38 }
39 return (bestDiffEngine != null ? bestDiffEngine.Clone() : null);
40 }
41
42 public BestQualityDiffEngineFactory() : this(null) { }
43 public BestQualityDiffEngineFactory(IDiffEngine[] diffEngines)
44 {
45 this.diffEngines = (diffEngines != null ? new ArrayList(diffEngines) : new ArrayList());
46 }
47
48 protected IList diffEngines;
49
50 public virtual void Add(IDiffEngine diffEngine)
51 {
52 diffEngines.Add(diffEngine);
53 }
54
55 public virtual void Remove(IDiffEngine diffEngine)
56 {
57 diffEngines.Remove(diffEngine);
58 }
59
60 public IList DiffEngines
61 {
62 get
63 {
64 return ArrayList.ReadOnly(diffEngines);
65 }
66 }
67 }
68}
diff --git a/src/samples/Dtf/DDiff/MsiDiffEngine.cs b/src/samples/Dtf/DDiff/MsiDiffEngine.cs
new file mode 100644
index 00000000..91bc2969
--- /dev/null
+++ b/src/samples/Dtf/DDiff/MsiDiffEngine.cs
@@ -0,0 +1,276 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Collections;
6using System.Collections.Generic;
7using WixToolset.Dtf.WindowsInstaller;
8using WixToolset.Dtf.WindowsInstaller.Package;
9
10namespace WixToolset.Dtf.Samples.DDiff
11{
12 public class MsiDiffEngine : IDiffEngine
13 {
14 public MsiDiffEngine()
15 {
16 }
17
18 protected bool IsMsiDatabase(string file)
19 {
20 // TODO: use something smarter?
21 switch(Path.GetExtension(file).ToLower())
22 {
23 case ".msi": return true;
24 case ".msm": return true;
25 case ".pcp": return true;
26 default : return false;
27 }
28 }
29
30 protected bool IsMspPatch(string file)
31 {
32 // TODO: use something smarter?
33 switch(Path.GetExtension(file).ToLower())
34 {
35 case ".msp": return true;
36 default : return false;
37 }
38 }
39
40 public virtual float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
41 {
42 if(diffInput1 != null && File.Exists(diffInput1) &&
43 diffInput2 != null && File.Exists(diffInput2) &&
44 (IsMsiDatabase(diffInput1) || IsMsiDatabase(diffInput2)))
45 {
46 return .70f;
47 }
48 else if(diffInput1 != null && File.Exists(diffInput1) &&
49 diffInput2 != null && File.Exists(diffInput2) &&
50 (IsMspPatch(diffInput1) || IsMspPatch(diffInput2)))
51 {
52 return .60f;
53 }
54 else
55 {
56 return 0;
57 }
58 }
59
60 public virtual bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
61 {
62 bool difference = false;
63 Database db1 = new Database(diffInput1, DatabaseOpenMode.ReadOnly);
64 Database db2 = new Database(diffInput2, DatabaseOpenMode.ReadOnly);
65
66 if(GetSummaryInfoDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
67 if(GetDatabaseDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
68 if(GetStreamsDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
69
70 db1.Close();
71 db2.Close();
72 return difference;
73 }
74
75 protected bool GetSummaryInfoDiff(Database db1, Database db2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
76 {
77 bool difference = false;
78
79 SummaryInfo summInfo1 = db1.SummaryInfo;
80 SummaryInfo summInfo2 = db2.SummaryInfo;
81 if(summInfo1.Title != summInfo2.Title ) { diffOutput.WriteLine("{0}SummaryInformation.Title {{{1}}}->{{{2}}}", linePrefix, summInfo1.Title, summInfo2.Title); difference = true; }
82 if(summInfo1.Subject != summInfo2.Subject ) { diffOutput.WriteLine("{0}SummaryInformation.Subject {{{1}}}->{{{2}}}", linePrefix, summInfo1.Subject, summInfo2.Subject); difference = true; }
83 if(summInfo1.Author != summInfo2.Author ) { diffOutput.WriteLine("{0}SummaryInformation.Author {{{1}}}->{{{2}}}", linePrefix, summInfo1.Author, summInfo2.Author); difference = true; }
84 if(summInfo1.Keywords != summInfo2.Keywords ) { diffOutput.WriteLine("{0}SummaryInformation.Keywords {{{1}}}->{{{2}}}", linePrefix, summInfo1.Keywords, summInfo2.Keywords); difference = true; }
85 if(summInfo1.Comments != summInfo2.Comments ) { diffOutput.WriteLine("{0}SummaryInformation.Comments {{{1}}}->{{{2}}}", linePrefix, summInfo1.Comments, summInfo2.Comments); difference = true; }
86 if(summInfo1.Template != summInfo2.Template ) { diffOutput.WriteLine("{0}SummaryInformation.Template {{{1}}}->{{{2}}}", linePrefix, summInfo1.Template, summInfo2.Template); difference = true; }
87 if(summInfo1.LastSavedBy != summInfo2.LastSavedBy ) { diffOutput.WriteLine("{0}SummaryInformation.LastSavedBy {{{1}}}->{{{2}}}", linePrefix, summInfo1.LastSavedBy, summInfo2.LastSavedBy); difference = true; }
88 if(summInfo1.RevisionNumber != summInfo2.RevisionNumber) { diffOutput.WriteLine("{0}SummaryInformation.RevisionNumber {{{1}}}->{{{2}}}", linePrefix, summInfo1.RevisionNumber, summInfo2.RevisionNumber); difference = true; }
89 if(summInfo1.CreatingApp != summInfo2.CreatingApp ) { diffOutput.WriteLine("{0}SummaryInformation.CreatingApp {{{1}}}->{{{2}}}", linePrefix, summInfo1.CreatingApp, summInfo2.CreatingApp); difference = true; }
90 if(summInfo1.LastPrintTime != summInfo2.LastPrintTime ) { diffOutput.WriteLine("{0}SummaryInformation.LastPrintTime {{{1}}}->{{{2}}}", linePrefix, summInfo1.LastPrintTime, summInfo2.LastPrintTime); difference = true; }
91 if(summInfo1.CreateTime != summInfo2.CreateTime ) { diffOutput.WriteLine("{0}SummaryInformation.CreateTime {{{1}}}->{{{2}}}", linePrefix, summInfo1.CreateTime, summInfo2.CreateTime); difference = true; }
92 if(summInfo1.LastSaveTime != summInfo2.LastSaveTime ) { diffOutput.WriteLine("{0}SummaryInformation.LastSaveTime {{{1}}}->{{{2}}}", linePrefix, summInfo1.LastSaveTime, summInfo2.LastSaveTime); difference = true; }
93 if(summInfo1.CodePage != summInfo2.CodePage ) { diffOutput.WriteLine("{0}SummaryInformation.Codepage {{{1}}}->{{{2}}}", linePrefix, summInfo1.CodePage, summInfo2.CodePage); difference = true; }
94 if(summInfo1.PageCount != summInfo2.PageCount ) { diffOutput.WriteLine("{0}SummaryInformation.PageCount {{{1}}}->{{{2}}}", linePrefix, summInfo1.PageCount, summInfo2.PageCount); difference = true; }
95 if(summInfo1.WordCount != summInfo2.WordCount ) { diffOutput.WriteLine("{0}SummaryInformation.WordCount {{{1}}}->{{{2}}}", linePrefix, summInfo1.WordCount, summInfo2.WordCount); difference = true; }
96 if(summInfo1.CharacterCount != summInfo2.CharacterCount) { diffOutput.WriteLine("{0}SummaryInformation.CharacterCount {{{1}}}->{{{2}}}", linePrefix, summInfo1.CharacterCount, summInfo2.CharacterCount); difference = true; }
97 if(summInfo1.Security != summInfo2.Security ) { diffOutput.WriteLine("{0}SummaryInformation.Security {{{1}}}->{{{2}}}", linePrefix, summInfo1.Security, summInfo2.Security); difference = true; }
98 summInfo1.Close();
99 summInfo2.Close();
100
101 return difference;
102 }
103
104 protected bool GetDatabaseDiff(Database db1, Database db2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
105 {
106 bool difference = false;
107
108 string tempFile = Path.GetTempFileName();
109 if(db2.GenerateTransform(db1, tempFile))
110 {
111 difference = true;
112
113 Database db = db1;
114 db.ViewTransform(tempFile);
115
116 string row, column, change;
117 using (View view = db.OpenView("SELECT `Table`, `Column`, `Row`, `Data`, `Current` " +
118 "FROM `_TransformView` ORDER BY `Table`, `Row`"))
119 {
120 view.Execute();
121
122 foreach (Record rec in view) using (rec)
123 {
124 column = String.Format("{0} {1}", rec[1], rec[2]);
125 change = "";
126 if (rec.IsNull(3))
127 {
128 row = "<DDL>";
129 if (!rec.IsNull(4))
130 {
131 change = "[" + rec[5] + "]: " + DecodeColDef(rec.GetInteger(4));
132 }
133 }
134 else
135 {
136 row = "[" + String.Join(",", rec.GetString(3).Split('\t')) + "]";
137 if (rec.GetString(2) != "INSERT" && rec.GetString(2) != "DELETE")
138 {
139 column = String.Format("{0}.{1}", rec[1], rec[2]);
140 change = "{" + rec[5] + "}->{" + rec[4] + "}";
141 }
142 }
143
144 diffOutput.WriteLine("{0}{1,-25} {2} {3}", linePrefix, column, row, change);
145 }
146 }
147 }
148 File.Delete(tempFile);
149
150 return difference;
151 }
152
153 private string DecodeColDef(int colDef)
154 {
155 const int icdLong = 0x0000;
156 const int icdShort = 0x0400;
157 const int icdObject = 0x0800;
158 const int icdString = 0x0C00;
159 const int icdTypeMask = 0x0F00;
160 const int icdNullable = 0x1000;
161 const int icdPrimaryKey = 0x2000;
162
163 string def = "";
164 switch(colDef & (icdTypeMask))
165 {
166 case icdLong : def = "LONG"; break;
167 case icdShort : def = "SHORT"; break;
168 case icdObject: def = "OBJECT"; break;
169 case icdString: def = "CHAR[" + (colDef & 0xFF) + "]"; break;
170 }
171 if((colDef & icdNullable) != 0)
172 {
173 def = def + " NOT NULL";
174 }
175 if((colDef & icdPrimaryKey) != 0)
176 {
177 def = def + " PRIMARY KEY";
178 }
179 return def;
180 }
181
182 protected bool GetStreamsDiff(Database db1, Database db2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
183 {
184 bool difference = false;
185
186 IList<string> streams1List = db1.ExecuteStringQuery("SELECT `Name` FROM `_Streams`");
187 IList<string> streams2List = db2.ExecuteStringQuery("SELECT `Name` FROM `_Streams`");
188 string[] streams1 = new string[streams1List.Count];
189 string[] streams2 = new string[streams2List.Count];
190 streams1List.CopyTo(streams1, 0);
191 streams2List.CopyTo(streams2, 0);
192
193 IComparer caseInsComp = CaseInsensitiveComparer.Default;
194 Array.Sort(streams1, caseInsComp);
195 Array.Sort(streams2, caseInsComp);
196
197 for (int i1 = 0, i2 = 0; i1 < streams1.Length || i2 < streams2.Length; )
198 {
199 int comp;
200 if (i1 == streams1.Length)
201 {
202 comp = 1;
203 }
204 else if (i2 == streams2.Length)
205 {
206 comp = -1;
207 }
208 else
209 {
210 comp = caseInsComp.Compare(streams1[i1], streams2[i2]);
211 }
212 if(comp < 0)
213 {
214 diffOutput.WriteLine("{0}< {1}", linePrefix, streams1[i1]);
215 i1++;
216 difference = true;
217 }
218 else if(comp > 0)
219 {
220 diffOutput.WriteLine("{0}> {1}", linePrefix, streams2[i2]);
221 i2++;
222 difference = true;
223 }
224 else
225 {
226 if(streams1[i1] != ("" + ((char)5) + "SummaryInformation"))
227 {
228 string tempFile1 = Path.GetTempFileName();
229 string tempFile2 = Path.GetTempFileName();
230
231 using (View view = db1.OpenView(String.Format("SELECT `Data` FROM `_Streams` WHERE `Name` = '{0}'", streams1[i1])))
232 {
233 view.Execute();
234
235 using (Record rec = view.Fetch())
236 {
237 rec.GetStream(1, tempFile1);
238 }
239 }
240
241 using (View view = db2.OpenView(String.Format("SELECT `Data` FROM `_Streams` WHERE `Name` = '{0}'", streams2[i2])))
242 {
243 view.Execute();
244
245 using (Record rec = view.Fetch())
246 {
247 rec.GetStream(1, tempFile2);
248 }
249 }
250
251 IDiffEngine diffEngine = diffFactory.GetDiffEngine(tempFile1, tempFile2, options);
252 StringWriter sw = new StringWriter();
253 if(diffEngine.GetDiff(tempFile1, tempFile2, options, sw, linePrefix + " ", diffFactory))
254 {
255 diffOutput.WriteLine("{0}{1}", linePrefix, streams1[i1]);
256 diffOutput.Write(sw.ToString());
257 difference = true;
258 }
259
260 File.Delete(tempFile1);
261 File.Delete(tempFile2);
262 }
263 i1++;
264 i2++;
265 }
266 }
267
268 return difference;
269 }
270
271 public virtual IDiffEngine Clone()
272 {
273 return new MsiDiffEngine();
274 }
275 }
276}
diff --git a/src/samples/Dtf/DDiff/MspDiffEngine.cs b/src/samples/Dtf/DDiff/MspDiffEngine.cs
new file mode 100644
index 00000000..285bc83d
--- /dev/null
+++ b/src/samples/Dtf/DDiff/MspDiffEngine.cs
@@ -0,0 +1,127 @@
1// 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.
2
3using System;
4using System.IO;
5using WixToolset.Dtf.WindowsInstaller;
6using WixToolset.Dtf.WindowsInstaller.Package;
7
8namespace WixToolset.Dtf.Samples.DDiff
9{
10 public class MspDiffEngine : MsiDiffEngine
11 {
12 public MspDiffEngine()
13 {
14 }
15
16 private string GetPatchTargetOption(string[] options)
17 {
18 for(int i = 0; i < options.Length - 1; i++)
19 {
20 switch(options[i].ToLower())
21 {
22 case "/p": goto case "-patchtarget";
23 case "-p": goto case "-patchtarget";
24 case "/patchtarget": goto case "-patchtarget";
25 case "-patchtarget": return options[i+1];
26 }
27 }
28 return null;
29 }
30
31 public override float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
32 {
33 if(diffInput1 != null && File.Exists(diffInput1) &&
34 diffInput2 != null && File.Exists(diffInput2) &&
35 GetPatchTargetOption(options) != null &&
36 (IsMspPatch(diffInput1) && IsMspPatch(diffInput2)))
37 {
38 return .80f;
39 }
40 else if(diffInput1 != null && File.Exists(diffInput1) &&
41 diffInput2 != null && File.Exists(diffInput2) &&
42 GetPatchTargetOption(options) == null &&
43 (IsMspPatch(diffInput1) && IsMsiDatabase(diffInput2)) ||
44 (IsMsiDatabase(diffInput1) && IsMspPatch(diffInput2)))
45 {
46 return .75f;
47 }
48 else
49 {
50 return 0;
51 }
52 }
53
54 public override bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
55 {
56 bool difference = false;
57
58 InstallPackage db1, db2;
59 if(IsMspPatch(diffInput1))
60 {
61 string patchTargetDbFile = GetPatchTargetOption(options);
62 if(patchTargetDbFile == null) patchTargetDbFile = diffInput2;
63 string tempPatchedDbFile = Path.GetTempFileName();
64 File.Copy(patchTargetDbFile, tempPatchedDbFile, true);
65 File.SetAttributes(tempPatchedDbFile, File.GetAttributes(tempPatchedDbFile) & ~System.IO.FileAttributes.ReadOnly);
66 db1 = new InstallPackage(tempPatchedDbFile, DatabaseOpenMode.Direct);
67 db1.ApplyPatch(new PatchPackage(diffInput1), null);
68 db1.Commit();
69 }
70 else
71 {
72 db1 = new InstallPackage(diffInput1, DatabaseOpenMode.ReadOnly);
73 }
74 if(IsMspPatch(diffInput2))
75 {
76 string patchTargetDbFile = GetPatchTargetOption(options);
77 if(patchTargetDbFile == null) patchTargetDbFile = diffInput1;
78 string tempPatchedDbFile = Path.GetTempFileName();
79 File.Copy(patchTargetDbFile, tempPatchedDbFile, true);
80 File.SetAttributes(tempPatchedDbFile, File.GetAttributes(tempPatchedDbFile) & ~System.IO.FileAttributes.ReadOnly);
81 db2 = new InstallPackage(tempPatchedDbFile, DatabaseOpenMode.Direct);
82 db2.ApplyPatch(new PatchPackage(diffInput2), null);
83 db2.Commit();
84 }
85 else
86 {
87 db2 = new InstallPackage(diffInput2, DatabaseOpenMode.ReadOnly);
88 }
89
90 if(GetSummaryInfoDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
91 if(GetDatabaseDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
92 if(GetStreamsDiff(db1, db2, options, diffOutput, linePrefix, diffFactory)) difference = true;
93
94 db1.Close();
95 db2.Close();
96
97 try
98 {
99 if(IsMspPatch(diffInput1)) File.Delete(db1.FilePath);
100 if(IsMspPatch(diffInput1)) File.Delete(db2.FilePath);
101 }
102 catch(IOException)
103 {
104 #if DEBUG
105 Console.WriteLine("Could not delete temporary files {0} and {1}", db1.FilePath, db2.FilePath);
106 #endif
107 }
108
109 if(IsMspPatch(diffInput1) && IsMspPatch(diffInput2))
110 {
111 Database dbp1 = new Database(diffInput1, DatabaseOpenMode.ReadOnly);
112 Database dbp2 = new Database(diffInput2, DatabaseOpenMode.ReadOnly);
113
114 if(GetStreamsDiff(dbp1, dbp2, options, diffOutput, linePrefix, diffFactory)) difference = true;
115 dbp1.Close();
116 dbp2.Close();
117 }
118
119 return difference;
120 }
121
122 public override IDiffEngine Clone()
123 {
124 return new MspDiffEngine();
125 }
126 }
127}
diff --git a/src/samples/Dtf/DDiff/TextFileDiffEngine.cs b/src/samples/Dtf/DDiff/TextFileDiffEngine.cs
new file mode 100644
index 00000000..22567023
--- /dev/null
+++ b/src/samples/Dtf/DDiff/TextFileDiffEngine.cs
@@ -0,0 +1,83 @@
1// 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.
2
3using System;
4using System.IO;
5using System.Diagnostics;
6
7namespace WixToolset.Dtf.Samples.DDiff
8{
9 public class TextFileDiffEngine : IDiffEngine
10 {
11 public TextFileDiffEngine()
12 {
13 }
14
15 private bool IsTextFile(string file)
16 {
17 // Guess whether this is a text file by reading the first few bytes and checking for non-ascii chars.
18
19 bool isText = true;
20 FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read);
21 byte[] buf = new byte[256];
22 int count = stream.Read(buf, 0, buf.Length);
23 for(int i = 0; i < count; i++)
24 {
25 if((buf[i] & 0x80) != 0)
26 {
27 isText = false;
28 break;
29 }
30 }
31 stream.Close();
32 return isText;
33 }
34
35 public float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
36 {
37 if(diffInput1 != null && File.Exists(diffInput1) &&
38 diffInput2 != null && File.Exists(diffInput2) &&
39 (IsTextFile(diffInput1) && IsTextFile(diffInput2)))
40 {
41 return .70f;
42 }
43 else
44 {
45 return 0;
46 }
47 }
48
49 public bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
50 {
51 try
52 {
53 bool difference = false;
54 ProcessStartInfo psi = new ProcessStartInfo("diff.exe");
55 psi.Arguments = String.Format("\"{0}\" \"{1}\"", diffInput1, diffInput2);
56 psi.WorkingDirectory = null;
57 psi.UseShellExecute = false;
58 psi.WindowStyle = ProcessWindowStyle.Hidden;
59 psi.RedirectStandardOutput = true;
60 Process proc = Process.Start(psi);
61
62 string line;
63 while((line = proc.StandardOutput.ReadLine()) != null)
64 {
65 diffOutput.WriteLine("{0}{1}", linePrefix, line);
66 difference = true;
67 }
68
69 proc.WaitForExit();
70 return difference;
71 }
72 catch(System.ComponentModel.Win32Exception) // If diff.exe is not found, just compare the bytes
73 {
74 return new FileDiffEngine().GetDiff(diffInput1, diffInput2, options, diffOutput, linePrefix, diffFactory);
75 }
76 }
77
78 public IDiffEngine Clone()
79 {
80 return new TextFileDiffEngine();
81 }
82 }
83}
diff --git a/src/samples/Dtf/DDiff/VersionedFileDiffEngine.cs b/src/samples/Dtf/DDiff/VersionedFileDiffEngine.cs
new file mode 100644
index 00000000..ad4014f3
--- /dev/null
+++ b/src/samples/Dtf/DDiff/VersionedFileDiffEngine.cs
@@ -0,0 +1,90 @@
1// 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.
2
3using System;
4using System.IO;
5using WixToolset.Dtf.WindowsInstaller;
6
7namespace WixToolset.Dtf.Samples.DDiff
8{
9 public class VersionedFileDiffEngine : IDiffEngine
10 {
11 public VersionedFileDiffEngine()
12 {
13 }
14
15 private bool IsVersionedFile(string file)
16 {
17 return Installer.GetFileVersion(file) != "";
18 }
19
20 public float GetDiffQuality(string diffInput1, string diffInput2, string[] options, IDiffEngineFactory diffFactory)
21 {
22 if(diffInput1 != null && File.Exists(diffInput1) &&
23 diffInput2 != null && File.Exists(diffInput2) &&
24 (IsVersionedFile(diffInput1) || IsVersionedFile(diffInput2)))
25 {
26 return .20f;
27 }
28 else
29 {
30 return 0;
31 }
32 }
33
34 public bool GetDiff(string diffInput1, string diffInput2, string[] options, TextWriter diffOutput, string linePrefix, IDiffEngineFactory diffFactory)
35 {
36 bool difference = false;
37
38 string ver1 = Installer.GetFileVersion(diffInput1);
39 string ver2 = Installer.GetFileVersion(diffInput2);
40
41 if(ver1 != ver2)
42 {
43 diffOutput.WriteLine("{0}File version: {1} -> {2}", linePrefix, ver1, ver2);
44 difference = true;
45 }
46 else
47 {
48 FileStream stream1 = new FileStream(diffInput1, FileMode.Open, FileAccess.Read, FileShare.Read);
49 FileStream stream2 = new FileStream(diffInput2, FileMode.Open, FileAccess.Read, FileShare.Read);
50
51 byte[] buf1 = new byte[512];
52 byte[] buf2 = new byte[512];
53
54 while(!difference)
55 {
56 int count1 = stream1.Read(buf1, 0, buf1.Length);
57 int count2 = stream2.Read(buf2, 0, buf2.Length);
58
59 for(int i = 0; i < count1; i++)
60 {
61 if(i == count2 || buf1[i] != buf2[i])
62 {
63 difference = true;
64 break;
65 }
66 }
67 if(count1 < buf1.Length) // EOF
68 {
69 break;
70 }
71 }
72
73 stream1.Close();
74 stream2.Close();
75
76 if(difference)
77 {
78 diffOutput.WriteLine("{0}File versions match but bits differ.", linePrefix);
79 }
80 }
81
82 return difference;
83 }
84
85 public IDiffEngine Clone()
86 {
87 return new VersionedFileDiffEngine();
88 }
89 }
90}