filecomparer.pas 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. unit filecomparer;
  2. {$mode objfpc}
  3. interface
  4. uses Classes;
  5. type
  6. TFileComparer = class(TObject)
  7. private
  8. protected
  9. function LoadFromFile(const aFilename: String): TMemoryStream;
  10. function Compare(const aFileName1, aFilename2: String; var aMsg: String): boolean;
  11. public
  12. procedure CompareFiles(aNoSourcefileExt, aNoDestfileExt, aSilent: boolean; const aSourceMask, aDestPath, aDestFileExtention: String);
  13. end;
  14. implementation
  15. uses SysUtils;
  16. { TFileComparer }
  17. function TFileComparer.Compare(const aFileName1,
  18. aFilename2: String; var aMsg: String): boolean;
  19. var
  20. MStream1: TMemoryStream;
  21. MStream2: TMemoryStream;
  22. begin
  23. result := false;
  24. aMsg := '';
  25. if not(FileExists(aFileName1)) then
  26. begin
  27. aMsg := format('file "%s" not found', [aFileName1]);
  28. end
  29. else if not(FileExists(aFileName1)) then
  30. begin
  31. aMsg := format('file "%s" not found', [aFileName2]);
  32. end
  33. else
  34. begin
  35. MStream1 := LoadFromFile(aFilename1);
  36. try
  37. MStream1.Position := 0;
  38. MStream2 := LoadFromFile(aFilename2);
  39. try
  40. MStream2.Position := 0;
  41. if MStream1.Size < 1 then aMsg := format('file "%s": start or endmarker not found', [aFilename1])
  42. else if MStream2.Size < 1 then aMsg := format('file "%s": start or endmarker not found', [aFilename2])
  43. else
  44. begin
  45. if MStream1.Size <> MStream2.Size then aMsg := format('diff: file: "%s" size: %d - file: "%s" size: %d',
  46. [aFilename1, MStream1.Size,
  47. aFilename2, MStream2.Size])
  48. else
  49. begin
  50. if CompareMem(MStream1.Memory, MStream2.Memory, MStream1.Size) then result := true
  51. else aMsg := format('diff: file: "%s" <> file: "%s"', [aFileName1, aFileName2]);
  52. end;
  53. end;
  54. finally
  55. FreeAndNil(MStream2);
  56. end;
  57. finally
  58. FreeAndNil(MStream1);
  59. end;
  60. end;
  61. end;
  62. procedure TFileComparer.CompareFiles(aNoSourcefileExt, aNoDestfileExt, aSilent: boolean; const aSourceMask, aDestPath, aDestFileExtention: String);
  63. var
  64. i: integer;
  65. sl: TStringList;
  66. sr: TSearchRec;
  67. Path: String;
  68. FileName: String;
  69. SourceFileName: String;
  70. DestFileName: String;
  71. DestFileExtention: String;
  72. Msg: String;
  73. begin
  74. Path := IncludeTrailingBackslash(ExtractFilePath(aSourceMask));
  75. DestFileExtention := aDestFileExtention;
  76. if (DestFileExtention <> '') and
  77. (copy(DestFileExtention, 1, 1) <> '.') then
  78. begin
  79. DestFileExtention := '.' + DestFileExtention;
  80. end;
  81. sl := TStringList.Create;
  82. try
  83. if FindFirst(aSourceMask, faAnyFile - faDirectory - faVolumeID , sr) = 0 then
  84. repeat
  85. if not((aNoSourcefileExt) and (ExtractFileExt(sr.Name) <> '')) then sl.Add(sr.Name);
  86. until FindNext(sr) <> 0;
  87. FindClose(sr);
  88. for i := 0 to sl.Count - 1 do
  89. begin
  90. sl.Sort;
  91. if aDestFileExtention <> '' then
  92. begin
  93. FileName := copy(sl[i], 1, length(sl[i]) - length(ExtractFileExt(sl[i])));
  94. if FileName = '' then FileName := sl[i];
  95. end
  96. else
  97. begin
  98. if aNoDestfileExt then
  99. begin
  100. if ExtractFileExt(sl[i]) = '' then Filename := sl[i]
  101. else
  102. begin
  103. FileName := copy(sl[i], 1, length(sl[i]) - length(ExtractFileExt(sl[i])));
  104. end;
  105. end
  106. else Filename := sl[i];
  107. end;
  108. SourceFileName := Path + sl[i];
  109. DestFileName := IncludeTrailingBackslash(aDestpath) + FileName + DestFileExtention;
  110. if FileExists(SourceFileName) then
  111. begin
  112. if FileExists(DestFileName) then
  113. begin
  114. if Compare(SourceFileName, DestFileName, Msg) then
  115. begin
  116. if not(aSilent) then writeln(format('compare = equal (source: "%s" destination: "%s")', [SourceFileName, DestFileName]));
  117. end
  118. else if Msg <> '' then writeln(ErrOutPut, Msg);
  119. end
  120. else writeln(ErrOutPut, format('Comparefile "%s" not found', [DestFileName]));
  121. end
  122. else writeln(ErrOutPut, format('Sourcefile "%s" not found', [SourceFileName]));
  123. end;
  124. finally
  125. FreeAndNil(sl);
  126. end;
  127. end;
  128. function TFileComparer.LoadFromFile(
  129. const aFilename: String): TMemoryStream;
  130. var
  131. MStream : TMemoryStream;
  132. StartPos : integer;
  133. EndPos : integer;
  134. function FindPos(aStream: TStream; aStartPos: integer; aEndPos: boolean): integer;
  135. var
  136. NopCount : integer;
  137. ch : byte;
  138. begin
  139. result := -1;
  140. if assigned(aStream) then
  141. begin
  142. aStream.Position := aStartPos;
  143. NopCount := 0;
  144. while MStream.Position < MStream.Size do
  145. begin
  146. MStream.Read(ch, 1);
  147. if ch = 144 then
  148. begin
  149. inc(NopCount);
  150. end
  151. else
  152. begin
  153. if NopCount >= 10 then
  154. begin
  155. if not(aEndPos) then result := MStream.Position
  156. else result := MStream.Position - NopCount - 1;
  157. break;
  158. end
  159. else NopCount := 0;
  160. end;
  161. end;
  162. end;
  163. end;
  164. begin
  165. result := TMemoryStream.Create;
  166. if FileExists(aFileName) then
  167. begin
  168. MStream := TMemoryStream.Create;
  169. try
  170. MStream.LoadFromFile(aFileName);
  171. StartPos := FindPos(MStream, 0, false);
  172. if StartPos >= 0 then
  173. begin
  174. if MStream.Size > StartPos + 16384 then
  175. begin
  176. EndPos := FindPos(MStream, MStream.Size - 16384, true);
  177. if EndPos < 0 then EndPos := FindPos(MStream, StartPos, true);
  178. end
  179. else EndPos := FindPos(MStream, StartPos, true);
  180. end;
  181. if (StartPos < 0) OR
  182. (EndPos < 0) then exit;
  183. MStream.Position := StartPos - 1;
  184. result.CopyFrom(MStream, EndPos - StartPos + 1);
  185. finally
  186. FreeAndNil(MStream);
  187. end;
  188. end;
  189. end;
  190. end.