diff options
Diffstat (limited to 'src/samples/Dtf/DDiff')
| -rw-r--r-- | src/samples/Dtf/DDiff/CabDiffEngine.cs | 131 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/DDiff.cs | 72 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/DDiff.csproj | 39 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/DirectoryDiffEngine.cs | 154 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/FileDiffEngine.cs | 83 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/IDiffEngine.cs | 68 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/MsiDiffEngine.cs | 276 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/MspDiffEngine.cs | 127 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/TextFileDiffEngine.cs | 83 | ||||
| -rw-r--r-- | src/samples/Dtf/DDiff/VersionedFileDiffEngine.cs | 90 |
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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Collections; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using WixToolset.Dtf.Compression.Cab; | ||
| 8 | |||
| 9 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Text; | ||
| 6 | |||
| 7 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Collections; | ||
| 6 | |||
| 7 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | |||
| 6 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Collections; | ||
| 6 | |||
| 7 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Collections; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using WixToolset.Dtf.WindowsInstaller; | ||
| 8 | using WixToolset.Dtf.WindowsInstaller.Package; | ||
| 9 | |||
| 10 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using WixToolset.Dtf.WindowsInstaller; | ||
| 6 | using WixToolset.Dtf.WindowsInstaller.Package; | ||
| 7 | |||
| 8 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using System.Diagnostics; | ||
| 6 | |||
| 7 | namespace 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 | |||
| 3 | using System; | ||
| 4 | using System.IO; | ||
| 5 | using WixToolset.Dtf.WindowsInstaller; | ||
| 6 | |||
| 7 | namespace 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 | } | ||
