zipper.pp 29 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042
  1. {
  2. $Id: header,v 1.1 2000/07/13 06:33:45 michael Exp $
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {$mode objfpc}
  12. {$h+}
  13. unit zipper;
  14. Interface
  15. Uses
  16. SysUtils,Classes, ZStream;
  17. Const
  18. LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
  19. Type
  20. Local_File_Header_Type = Packed Record
  21. Signature : LongInt;
  22. Extract_Version_Reqd : Word;
  23. Bit_Flag : Word;
  24. Compress_Method : Word;
  25. Last_Mod_Time : Word;
  26. Last_Mod_Date : Word;
  27. Crc32 : LongInt;
  28. Compressed_Size : LongInt;
  29. Uncompressed_Size : LongInt;
  30. Filename_Length : Word;
  31. Extra_Field_Length : Word;
  32. end;
  33. { Define the Central Directory record types }
  34. Const
  35. CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
  36. Type
  37. Central_File_Header_Type = Packed Record
  38. Signature : LongInt;
  39. MadeBy_Version : Word;
  40. Extract_Version_Reqd : Word;
  41. Bit_Flag : Word;
  42. Compress_Method : Word;
  43. Last_Mod_Time : Word;
  44. Last_Mod_Date : Word;
  45. Crc32 : LongInt;
  46. Compressed_Size : LongInt;
  47. Uncompressed_Size : LongInt;
  48. Filename_Length : Word;
  49. Extra_Field_Length : Word;
  50. File_Comment_Length : Word;
  51. Starting_Disk_Num : Word;
  52. Internal_Attributes : Word;
  53. External_Attributes : LongInt;
  54. Local_Header_Offset : LongInt;
  55. End;
  56. Const
  57. END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
  58. Type
  59. End_of_Central_Dir_Type = Packed Record
  60. Signature : LongInt;
  61. Disk_Number : Word;
  62. Central_Dir_Start_Disk : Word;
  63. Entries_This_Disk : Word;
  64. Total_Entries : Word;
  65. Central_Dir_Size : LongInt;
  66. Start_Disk_Offset : LongInt;
  67. ZipFile_Comment_Length : Word;
  68. end;
  69. Const
  70. Crc_32_Tab : Array[0..255] of LongInt = (
  71. $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
  72. $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
  73. $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
  74. $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
  75. $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
  76. $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
  77. $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
  78. $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
  79. $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
  80. $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
  81. $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
  82. $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
  83. $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
  84. $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
  85. $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
  86. $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
  87. $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
  88. $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
  89. $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
  90. $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
  91. $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
  92. $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
  93. $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
  94. $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
  95. $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
  96. $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
  97. $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
  98. $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
  99. $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
  100. $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
  101. $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
  102. $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d
  103. );
  104. Type
  105. TZipItem = Class(TObject)
  106. Path : String;
  107. Name : String;
  108. Size : LongInt;
  109. DateTime : TDateTime;
  110. end;
  111. TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
  112. TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
  113. TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
  114. Type
  115. { TCompressor }
  116. TCompressor = Class(TObject)
  117. Protected
  118. FInFile : TStream; { I/O file variables }
  119. FOutFile : TStream;
  120. FCrc32Val : LongInt; { CRC calculation variable }
  121. FBufferSize : Cardinal;
  122. FOnPercent : Integer;
  123. FOnProgress : TProgressEvent;
  124. Procedure UpdC32(Octet: Byte);
  125. Public
  126. Constructor Create(AInFile, AOutFile : TStream; ABufSize : Cardinal); virtual;
  127. Procedure Compress; Virtual; Abstract;
  128. Class Function ZipID : Word; virtual; Abstract;
  129. Property BufferSize : Cardinal read FBufferSize;
  130. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  131. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  132. Property Crc32Val : Longint Read FCrc32Val Write FCrc32Val;
  133. end;
  134. { TShrinker }
  135. Const
  136. TABLESIZE = 8191;
  137. FIRSTENTRY = 257;
  138. Type
  139. CodeRec = Packed Record
  140. Child : Smallint;
  141. Sibling : Smallint;
  142. Suffix : Byte;
  143. end;
  144. CodeArray = Array[0..TABLESIZE] of CodeRec;
  145. TablePtr = ^CodeArray;
  146. FreeListPtr = ^FreeListArray;
  147. FreeListArray = Array[FIRSTENTRY..TABLESIZE] of Word;
  148. BufPtr = PByte;
  149. TShrinker = Class(TCompressor)
  150. Private
  151. FBufSize : Cardinal;
  152. MaxInBufIdx : Cardinal; { Count of valid chars in input buffer }
  153. InputEof : Boolean; { End of file indicator }
  154. CodeTable : TablePtr; { Points to code table for LZW compression }
  155. FreeList : FreeListPtr; { Table of free code table entries }
  156. NextFree : Word; { Index into free list table }
  157. ClearList : Array[0..1023] of Byte; { Bit mapped structure used in }
  158. { during adaptive resets }
  159. CodeSize : Byte; { Size of codes (in bits) currently being written }
  160. MaxCode : Word; { Largest code that can be written in CodeSize bits }
  161. InBufIdx, { Points to next char in buffer to be read }
  162. OutBufIdx : Cardinal; { Points to next free space in output buffer }
  163. InBuf, { I/O buffers }
  164. OutBuf : BufPtr;
  165. FirstCh : Boolean; { Flag indicating the START of a shrink operation }
  166. TableFull : Boolean; { Flag indicating a full symbol table }
  167. SaveByte : Byte; { Output code buffer }
  168. BitsUsed : Byte; { Index into output code buffer }
  169. BytesIn : LongInt; { Count of input file bytes processed }
  170. BytesOut : LongInt; { Count of output bytes }
  171. FOnBytes : Longint;
  172. Procedure FillInputBuffer;
  173. Procedure WriteOutputBuffer;
  174. Procedure FlushOutput;
  175. Procedure PutChar(B : Byte);
  176. procedure PutCode(Code : Smallint);
  177. Procedure InitializeCodeTable;
  178. Procedure Prune(Parent : Word);
  179. Procedure Clear_Table;
  180. Procedure Table_Add(Prefix : Word; Suffix : Byte);
  181. function Table_Lookup(TargetPrefix : Smallint;
  182. TargetSuffix : Byte;
  183. Var FoundAt : Smallint) : Boolean;
  184. Procedure Shrink(Suffix : Smallint);
  185. Procedure ProcessLine(Const Source : String);
  186. Procedure DoOnProgress(Const Pct : Double); Virtual;
  187. Public
  188. Constructor Create(AInFile, AOutFile : TStream; ABufSize : Cardinal); override;
  189. Destructor Destroy; override;
  190. Procedure Compress; override;
  191. Class Function ZipID : Word; override;
  192. end;
  193. { TDeflater }
  194. TDeflater = Class(TCompressor)
  195. private
  196. FCompressionLevel: TCompressionlevel;
  197. Public
  198. Constructor Create(AInFile, AOutFile : TStream; ABufSize : Cardinal);override;
  199. Procedure Compress; override;
  200. Class Function ZipID : Word; override;
  201. Property CompressionLevel : TCompressionlevel Read FCompressionLevel Write FCompressionLevel;
  202. end;
  203. { TZipper }
  204. TZipper = Class(TObject)
  205. Private
  206. FZipping : Boolean;
  207. FBufSize : Cardinal;
  208. FFileName : String; { Name of resulting Zip file }
  209. FFiles : TStrings;
  210. FInMemSize : Integer;
  211. FOutFile : TFileStream;
  212. FInFile : TFileStream; { I/O file variables }
  213. LocalHdr : Local_File_Header_Type;
  214. CentralHdr : Central_File_Header_Type;
  215. EndHdr : End_of_Central_Dir_Type;
  216. FOnPercent : LongInt;
  217. FOnProgress : TProgressEvent;
  218. FOnEndOfFile : TOnEndOfFileEvent;
  219. FOnStartFile : TOnStartFileEvent;
  220. Protected
  221. Procedure OpenOutput;
  222. Procedure CloseOutput;
  223. Procedure CloseInput;
  224. Procedure StartZipFile(Item : TZipItem);
  225. Function UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : Integer;AMethod : Word) : Boolean;
  226. Procedure BuildZipDirectory;
  227. Procedure DoEndOfFile;
  228. Procedure ZipOneFile(Item : TZipItem); virtual;
  229. Function OpenInput(InFileName : String) : Boolean;
  230. Procedure GetFileInfo;
  231. Procedure SetBufSize(Value : Cardinal);
  232. Procedure SetFileName(Value : String);
  233. Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
  234. Public
  235. Constructor Create;
  236. Destructor Destroy;
  237. Procedure ZipAllFiles; virtual;
  238. Procedure ZipFiles(AFileName : String; FileList : TStrings);
  239. Procedure Clear;
  240. Public
  241. Property BufferSize : Cardinal Read FBufSize Write SetBufSize;
  242. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  243. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  244. Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
  245. Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
  246. Property FileName : String Read FFileName Write SetFileName;
  247. Property Files : TStrings Read FFiles;
  248. Property InMemSize : Integer Read FInMemSize Write FInMemSize;
  249. end;
  250. EZipError = Class(Exception);
  251. Implementation
  252. ResourceString
  253. SErrBufsizeChange = 'Changing buffer size is not allowed while zipping';
  254. SErrOutputFileChange = 'Changing output file name is not allowed while zipping';
  255. { ---------------------------------------------------------------------
  256. Auxiliary
  257. ---------------------------------------------------------------------}
  258. Procedure DateTimeToZipDateTime(DT : TDateTime; Var ZD,ZT : Word);
  259. Var
  260. Y,M,D,H,N,S,MS : Word;
  261. begin
  262. DecodeDate(DT,Y,M,D);
  263. DecodeTime(DT,H,N,S,MS);
  264. Y:=Y-1980;
  265. ZD:=d+(32*M)+(512*Y);
  266. ZT:=(S div 2)+(32*N)+(2048*h);
  267. end;
  268. { ---------------------------------------------------------------------
  269. TCompressor
  270. ---------------------------------------------------------------------}
  271. Procedure TCompressor.UpdC32(Octet: Byte);
  272. Begin
  273. FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
  274. end;
  275. constructor TCompressor.Create(AInFile, AOutFile: TStream; ABufSize: Cardinal);
  276. begin
  277. FinFile:=AInFile;
  278. FoutFile:=AOutFile;
  279. FBufferSize:=ABufSize;
  280. CRC32Val:=$FFFFFFFF;
  281. end;
  282. { ---------------------------------------------------------------------
  283. TDeflater
  284. ---------------------------------------------------------------------}
  285. constructor TDeflater.Create(AInFile, AOutFile: TStream; ABufSize: Cardinal);
  286. begin
  287. Inherited;
  288. FCompressionLevel:=clDefault;
  289. end;
  290. procedure TDeflater.Compress;
  291. Var
  292. Buf : PByte;
  293. I,Count,NewCount : Integer;
  294. C : TCompressionStream;
  295. begin
  296. CRC32Val:=$FFFFFFFF;
  297. Buf:=GetMem(FBufferSize);
  298. Try
  299. C:=TCompressionStream.Create(FCompressionLevel,FOutFile,True);
  300. Try
  301. Repeat
  302. Count:=FInFile.Read(Buf^,FBufferSize);
  303. For I:=0 to Count-1 do
  304. UpdC32(Buf[i]);
  305. NewCount:=Count;
  306. While (NewCount>0) do
  307. NewCount:=NewCount-C.Write(Buf^,NewCount);
  308. Until (Count=0);
  309. Finally
  310. C.Free;
  311. end;
  312. Finally
  313. FreeMem(Buf);
  314. end;
  315. Crc32Val:=NOT Crc32Val;
  316. end;
  317. class function TDeflater.ZipID: Word;
  318. begin
  319. Result:=8;
  320. end;
  321. { ---------------------------------------------------------------------
  322. TShrinker
  323. ---------------------------------------------------------------------}
  324. Const
  325. DefaultInMemSize = 256*1024; { Files larger than 256k are processed on disk }
  326. DefaultBufSize = 16384; { Use 16K file buffers }
  327. MINBITS = 9; { Starting code size of 9 bits }
  328. MAXBITS = 13; { Maximum code size of 13 bits }
  329. SPECIAL = 256; { Special function code }
  330. INCSIZE = 1; { Code indicating a jump in code size }
  331. CLEARCODE = 2; { Code indicating code table has been cleared }
  332. STDATTR = $23; { Standard file attribute for DOS Find First/Next }
  333. constructor TShrinker.Create(AInFile, AOutFile : TStream; ABufSize : Cardinal);
  334. begin
  335. Inherited;
  336. FBufSize:=ABufSize;
  337. InBuf:=GetMem(FBUFSIZE);
  338. OutBuf:=GetMem(FBUFSIZE);
  339. CodeTable:=GetMem(SizeOf(CodeTable^));
  340. FreeList:=GetMem(SizeOf(FreeList^));
  341. end;
  342. destructor TShrinker.Destroy;
  343. begin
  344. FreeMem(CodeTable);
  345. FreeMem(FreeList);
  346. FreeMem(InBuf);
  347. FreeMem(OutBuf);
  348. inherited Destroy;
  349. end;
  350. Procedure TShrinker.Compress;
  351. Var
  352. OneString : String;
  353. Remaining : Word;
  354. begin
  355. BytesIn := 1;
  356. BytesOut := 1;
  357. InitializeCodeTable;
  358. FillInputBuffer;
  359. FirstCh:= TRUE;
  360. Crc32Val:=$FFFFFFFF;
  361. FOnBytes:=Round((FInFile.Size * FOnPercent) / 100);
  362. While NOT InputEof do
  363. begin
  364. Remaining:=Succ(MaxInBufIdx - InBufIdx);
  365. If Remaining>255 then
  366. Remaining:=255;
  367. If Remaining=0 then
  368. FillInputBuffer
  369. else
  370. begin
  371. SetLength(OneString,Remaining);
  372. Move(InBuf[InBufIdx], OneString[1], Remaining);
  373. Inc(InBufIdx, Remaining);
  374. ProcessLine(OneString);
  375. end;
  376. end;
  377. Crc32Val := NOT Crc32Val;
  378. ProcessLine('');
  379. end;
  380. class function TShrinker.ZipID: Word;
  381. begin
  382. Result:=1;
  383. end;
  384. Procedure TShrinker.FillInputBuffer;
  385. Begin
  386. MaxInbufIDx:=FInfile.Read(InBuf[0], FBufSize);
  387. If MaxInbufIDx=0 then
  388. InputEof := TRUE
  389. else
  390. InputEOF := FALSE;
  391. InBufIdx := 0;
  392. end;
  393. Procedure TShrinker.WriteOutputBuffer;
  394. Begin
  395. FOutFile.WriteBuffer(OutBuf[0], OutBufIdx);
  396. OutBufIdx := 0;
  397. end;
  398. Procedure TShrinker.PutChar(B : Byte);
  399. Begin
  400. OutBuf[OutBufIdx] := B;
  401. Inc(OutBufIdx);
  402. If OutBufIdx>=FBufSize then
  403. WriteOutputBuffer;
  404. Inc(BytesOut);
  405. end;
  406. Procedure TShrinker.FlushOutput;
  407. Begin
  408. If OutBufIdx>0 then
  409. WriteOutputBuffer;
  410. End;
  411. procedure TShrinker.PutCode(Code : Smallint);
  412. var
  413. ACode : LongInt;
  414. XSize : Smallint;
  415. begin
  416. if (Code=-1) then
  417. begin
  418. if BitsUsed>0 then
  419. PutChar(SaveByte);
  420. end
  421. else
  422. begin
  423. ACode := Longint(Code);
  424. XSize := CodeSize+BitsUsed;
  425. ACode := (ACode shl BitsUsed) or SaveByte;
  426. while (XSize div 8) > 0 do
  427. begin
  428. PutChar(Lo(ACode));
  429. ACode := ACode shr 8;
  430. Dec(XSize,8);
  431. end;
  432. BitsUsed := XSize;
  433. SaveByte := Lo(ACode);
  434. end;
  435. end;
  436. Procedure TShrinker.InitializeCodeTable;
  437. Var
  438. I : Word;
  439. Begin
  440. For I := 0 to TableSize do
  441. begin
  442. With CodeTable^[I] do
  443. begin
  444. Child := -1;
  445. Sibling := -1;
  446. If (I<=255) then
  447. Suffix := I;
  448. end;
  449. If (I>=257) then
  450. FreeList^[I] := I;
  451. end;
  452. NextFree := FIRSTENTRY;
  453. TableFull := FALSE;
  454. end;
  455. Procedure TShrinker.Prune(Parent : Word);
  456. Var
  457. CurrChild : Smallint;
  458. NextSibling : Smallint;
  459. Begin
  460. CurrChild := CodeTable^[Parent].Child;
  461. { Find first Child that has descendants .. clear any that don't }
  462. While (CurrChild <> -1) AND (CodeTable^[CurrChild].Child = -1) do
  463. begin
  464. CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
  465. CodeTable^[CurrChild].Sibling := -1;
  466. { Turn on ClearList bit to indicate a cleared entry }
  467. ClearList[CurrChild DIV 8] := (ClearList[CurrChild DIV 8] OR (1 SHL (CurrChild MOD 8)));
  468. CurrChild := CodeTable^[Parent].Child;
  469. end;
  470. If CurrChild <> -1 then
  471. begin { If there are any children left ...}
  472. Prune(CurrChild);
  473. NextSibling := CodeTable^[CurrChild].Sibling;
  474. While NextSibling <> -1 do
  475. begin
  476. If CodeTable^[NextSibling].Child = -1 then
  477. begin
  478. CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
  479. CodeTable^[NextSibling].Sibling := -1;
  480. { Turn on ClearList bit to indicate a cleared entry }
  481. ClearList[NextSibling DIV 8] := (ClearList[NextSibling DIV 8] OR (1 SHL (NextSibling MOD 8)));
  482. NextSibling := CodeTable^[CurrChild].Sibling;
  483. end
  484. else
  485. begin
  486. CurrChild := NextSibling;
  487. Prune(CurrChild);
  488. NextSibling := CodeTable^[CurrChild].Sibling;
  489. end;
  490. end;
  491. end;
  492. end;
  493. Procedure TShrinker.Clear_Table;
  494. Var
  495. Node : Word;
  496. Begin
  497. FillChar(ClearList, SizeOf(ClearList), $00);
  498. For Node := 0 to 255 do
  499. Prune(Node);
  500. NextFree := Succ(TABLESIZE);
  501. For Node := TABLESIZE downto FIRSTENTRY do
  502. begin
  503. If (ClearList[Node DIV 8] AND (1 SHL (Node MOD 8))) <> 0 then
  504. begin
  505. Dec(NextFree);
  506. FreeList^[NextFree] := Node;
  507. end;
  508. end;
  509. If NextFree <= TABLESIZE then
  510. TableFull := FALSE;
  511. end;
  512. Procedure TShrinker.Table_Add(Prefix : Word; Suffix : Byte);
  513. Var
  514. FreeNode : Word;
  515. Begin
  516. If NextFree <= TABLESIZE then
  517. begin
  518. FreeNode := FreeList^[NextFree];
  519. Inc(NextFree);
  520. CodeTable^[FreeNode].Child := -1;
  521. CodeTable^[FreeNode].Sibling := -1;
  522. CodeTable^[FreeNode].Suffix := Suffix;
  523. If CodeTable^[Prefix].Child = -1 then
  524. CodeTable^[Prefix].Child := FreeNode
  525. else
  526. begin
  527. Prefix := CodeTable^[Prefix].Child;
  528. While CodeTable^[Prefix].Sibling <> -1 do
  529. Prefix := CodeTable^[Prefix].Sibling;
  530. CodeTable^[Prefix].Sibling := FreeNode;
  531. end;
  532. end;
  533. if NextFree > TABLESIZE then
  534. TableFull := TRUE;
  535. end;
  536. function TShrinker.Table_Lookup( TargetPrefix : Smallint;
  537. TargetSuffix : Byte;
  538. Var FoundAt : Smallint ) : Boolean;
  539. var TempPrefix : Smallint;
  540. begin
  541. TempPrefix := TargetPrefix;
  542. Table_lookup := False;
  543. if CodeTable^[TempPrefix].Child <> -1 then
  544. begin
  545. TempPrefix := CodeTable^[TempPrefix].Child;
  546. repeat
  547. if CodeTable^[TempPrefix].Suffix = TargetSuffix then
  548. begin
  549. Table_lookup := True;
  550. break;
  551. end;
  552. if CodeTable^[TempPrefix].Sibling = -1 then
  553. break;
  554. TempPrefix := CodeTable^[TempPrefix].Sibling;
  555. until False;
  556. end;
  557. if Table_Lookup then
  558. FoundAt := TempPrefix
  559. else
  560. FoundAt := -1;
  561. end;
  562. Procedure TShrinker.Shrink(Suffix : Smallint);
  563. Const
  564. LastCode : Smallint = 0;
  565. Var
  566. WhereFound : Smallint;
  567. Begin
  568. If FirstCh then
  569. begin
  570. SaveByte := $00;
  571. BitsUsed := 0;
  572. CodeSize := MINBITS;
  573. MaxCode := (1 SHL CodeSize) - 1;
  574. LastCode := Suffix;
  575. FirstCh := FALSE;
  576. end
  577. else
  578. begin
  579. If Suffix <> -1 then
  580. begin
  581. If TableFull then
  582. begin
  583. Putcode(LastCode);
  584. PutCode(SPECIAL);
  585. Putcode(CLEARCODE);
  586. Clear_Table;
  587. Table_Add(LastCode, Suffix);
  588. LastCode := Suffix;
  589. end
  590. else
  591. begin
  592. If Table_Lookup(LastCode, Suffix, WhereFound) then
  593. begin
  594. LastCode := WhereFound;
  595. end
  596. else
  597. begin
  598. PutCode(LastCode);
  599. Table_Add(LastCode, Suffix);
  600. LastCode := Suffix;
  601. If (FreeList^[NextFree] > MaxCode) and (CodeSize < MaxBits) then
  602. begin
  603. PutCode(SPECIAL);
  604. PutCode(INCSIZE);
  605. Inc(CodeSize);
  606. MaxCode := (1 SHL CodeSize) -1;
  607. end;
  608. end;
  609. end;
  610. end
  611. else
  612. begin
  613. PutCode(LastCode);
  614. PutCode(-1);
  615. FlushOutput;
  616. end;
  617. end;
  618. end;
  619. Procedure TShrinker.ProcessLine(Const Source : String);
  620. Var
  621. I : Word;
  622. Begin
  623. If Source = '' then
  624. Shrink(-1)
  625. else
  626. For I := 1 to Length(Source) do
  627. begin
  628. Inc(BytesIn);
  629. If (Pred(BytesIn) MOD FOnBytes) = 0 then
  630. DoOnProgress(100 * ( BytesIn / FInFile.Size));
  631. UpdC32(Ord(Source[I]));
  632. Shrink(Ord(Source[I]));
  633. end;
  634. end;
  635. { ---------------------------------------------------------------------
  636. TZipper
  637. ---------------------------------------------------------------------}
  638. Procedure TZipper.GetFileInfo;
  639. Var
  640. Info : TSearchRec;
  641. I : Word;
  642. NewNode : TZipItem;
  643. Begin
  644. For I := 0 to FFiles.Count-1 do
  645. If FindFirst(FFiles[I], STDATTR, Info)=0 then
  646. try
  647. NewNode:=TZipItem.Create;
  648. NewNode.Path := ExtractFilePath(FFiles[i]);
  649. NewNode.Name := Info.Name;
  650. NewNode.Size := Info.Size;
  651. NewNode.DateTime:=FileDateToDateTime(Info.Time);
  652. FFiles.Objects[i]:=NewNode;
  653. finally
  654. FindClose(Info);
  655. end;
  656. end;
  657. Procedure TZipper.OpenOutput;
  658. Begin
  659. FOutFile:=TFileStream.Create(FFileName,fmCreate);
  660. End;
  661. Function TZipper.OpenInput(InFileName : String) : Boolean;
  662. Begin
  663. FInFile:=TFileStream.Create(InFileName,fmOpenRead);
  664. Result:=True;
  665. If Assigned(FOnStartFile) then
  666. FOnStartFile(Self,InFileName);
  667. End;
  668. Procedure TZipper.CloseOutput;
  669. Begin
  670. FreeAndNil(FOutFile);
  671. end;
  672. Procedure TZipper.CloseInput;
  673. Begin
  674. FreeAndNil(FInFile);
  675. end;
  676. Procedure TZipper.StartZipFile(Item : TZipItem);
  677. Begin
  678. FillChar(LocalHdr,SizeOf(LocalHdr),0);
  679. With LocalHdr do
  680. begin
  681. Signature := LOCAL_FILE_HEADER_SIGNATURE;
  682. Extract_Version_Reqd := 10;
  683. Bit_Flag := 0;
  684. Compress_Method := 1;
  685. DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
  686. Crc32 := 0;
  687. Compressed_Size := 0;
  688. Uncompressed_Size := Item.Size;
  689. FileName_Length := Length(Item.Name);
  690. Extra_Field_Length := 0;
  691. end ;
  692. End;
  693. Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : Integer; AMethod : Word) : Boolean;
  694. Begin
  695. With LocalHdr do
  696. begin
  697. Compressed_Size := FZip.Size;
  698. Crc32 := ACRC;
  699. Compress_method:=AMethod;
  700. Result:=Not (Compressed_Size >= Uncompressed_Size);
  701. If Not Result then
  702. begin { No... }
  703. Compress_Method := 0; { ...change stowage type }
  704. Compressed_Size := Uncompressed_Size; { ...update compressed size }
  705. end;
  706. end;
  707. FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
  708. FOutFile.WriteBuffer(Item.Name[1],Length(Item.Name));
  709. End;
  710. Procedure TZipper.BuildZipDirectory;
  711. Var
  712. SavePos : LongInt;
  713. HdrPos : LongInt;
  714. CenDirPos : LongInt;
  715. Entries : Word;
  716. ZFileName : ShortString;
  717. Begin
  718. Entries := 0;
  719. CenDirPos := FOutFile.Position;
  720. FOutFile.Seek(0,soFrombeginning); { Rewind output file }
  721. HdrPos := FOutFile.Position;
  722. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  723. Repeat
  724. SetLength(ZFileName,LocalHdr.FileName_Length);
  725. FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
  726. SavePos := FOutFile.Position;
  727. FillChar(CentralHdr,SizeOf(CentralHdr),0);
  728. With CentralHdr do
  729. begin
  730. Signature := CENTRAL_FILE_HEADER_SIGNATURE;
  731. MadeBy_Version := LocalHdr.Extract_Version_Reqd;
  732. Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
  733. Last_Mod_Time:=localHdr.Last_Mod_Time;
  734. Last_Mod_Date:=localHdr.Last_Mod_Date;
  735. File_Comment_Length := 0;
  736. Starting_Disk_Num := 0;
  737. Internal_Attributes := 0;
  738. External_Attributes := faARCHIVE;
  739. Local_Header_Offset := HdrPos;
  740. end;
  741. FOutFile.Seek(0,soFromEnd);
  742. FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
  743. FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
  744. Inc(Entries);
  745. FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
  746. HdrPos:=FOutFile.Position;
  747. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  748. Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
  749. FOutFile.Seek(0,soFromEnd);
  750. FillChar(EndHdr,SizeOf(EndHdr),0);
  751. With EndHdr do
  752. begin
  753. Signature := END_OF_CENTRAL_DIR_SIGNATURE;
  754. Disk_Number := 0;
  755. Central_Dir_Start_Disk := 0;
  756. Entries_This_Disk := Entries;
  757. Total_Entries := Entries;
  758. Central_Dir_Size := FOutFile.Size-CenDirPos;
  759. Start_Disk_Offset := CenDirPos;
  760. ZipFile_Comment_Length := 0;
  761. FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
  762. end;
  763. end;
  764. Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
  765. begin
  766. Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
  767. end;
  768. Procedure TZipper.ZipOneFile(Item : TZipItem);
  769. Var
  770. CRC : Integer;
  771. ZMethod : Word;
  772. ZipStream : TStream;
  773. TmpFileName : String;
  774. Begin
  775. OpenInput(Item.Path+Item.Name);
  776. Try
  777. StartZipFile(Item);
  778. If (FInfile.Size<=FInMemSize) then
  779. ZipStream:=TMemoryStream.Create
  780. else
  781. begin
  782. TmpFileName:=ChangeFileExt(FFileName,'.tmp');
  783. ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
  784. end;
  785. Try
  786. With CreateCompressor(Item, FinFile,ZipStream) do
  787. Try
  788. OnProgress:=Self.OnProgress;
  789. OnPercent:=Self.OnPercent;
  790. Compress;
  791. CRC:=Crc32Val;
  792. ZMethod:=ZipID;
  793. Finally
  794. Free;
  795. end;
  796. If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
  797. // Compressed file smaller than original file.
  798. FOutFile.CopyFrom(ZipStream,0)
  799. else
  800. begin
  801. // Original file smaller than compressed file.
  802. FInfile.Seek(0,soFromBeginning);
  803. FOutFile.CopyFrom(FInFile,0);
  804. end;
  805. finally
  806. ZipStream.Free;
  807. If (TmpFileName<>'') then
  808. DeleteFile(TmpFileName);
  809. end;
  810. Finally
  811. CloseInput;
  812. end;
  813. end;
  814. Procedure TShrinker.DoOnProgress(Const Pct: Double);
  815. begin
  816. If Assigned(FOnProgress) then
  817. FOnProgress(Self,Pct);
  818. end;
  819. Procedure TZipper.ZipAllFiles;
  820. Var
  821. Item : TZipItem;
  822. I : Integer;
  823. Begin
  824. FZipping:=True;
  825. Try
  826. GetFileInfo;
  827. OpenOutput;
  828. Try
  829. For I:=0 to FFiles.Count-1 do
  830. begin
  831. Item:=FFiles.Objects[i] as TZipItem;
  832. ZipOneFile(Item);
  833. end;
  834. BuildZipDirectory;
  835. Finally
  836. CloseOutput;
  837. end;
  838. finally
  839. FZipping:=False;
  840. end;
  841. end;
  842. Procedure TZipper.SetBufSize(Value : Cardinal);
  843. begin
  844. If FZipping then
  845. Raise EZipError.Create(SErrBufsizeChange);
  846. If Value>=DefaultBufSize then
  847. FBufSize:=Value;
  848. end;
  849. Procedure TZipper.SetFileName(Value : String);
  850. begin
  851. If FZipping then
  852. Raise EZipError.Create(SErrOutputFileChange);
  853. FFileName:=Value;
  854. end;
  855. Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
  856. begin
  857. FFiles.Assign(FileList);
  858. FFileName:=AFileName;
  859. ZipAllFiles;
  860. end;
  861. Procedure TZipper.DoEndOfFile;
  862. Var
  863. ComprPct : Double;
  864. begin
  865. If (LocalHdr.Uncompressed_Size>0) then
  866. ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
  867. else
  868. ComprPct := 0;
  869. If Assigned(FOnEndOfFile) then
  870. FOnEndOfFile(Self,ComprPct);
  871. end;
  872. Constructor TZipper.Create;
  873. begin
  874. FBufSize:=DefaultBufSize;
  875. FInMemSize:=DefaultInMemSize;
  876. FFiles:=TStringList.Create;
  877. TStringlist(FFiles).Sorted:=True;
  878. FOnPercent:=1;
  879. end;
  880. Procedure TZipper.Clear;
  881. Var
  882. I : Integer;
  883. begin
  884. For I:=0 to FFiles.Count-1 do
  885. FFiles.Objects[i].Free;
  886. FFiles.Clear;
  887. end;
  888. Destructor TZipper.Destroy;
  889. begin
  890. Clear;
  891. FreeAndNil(FFiles);
  892. Inherited;
  893. end;
  894. End.