| 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.Tools.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 | } |