zipper.pp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455
  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,Contnrs,ZStream;
  17. Const
  18. { Signatures }
  19. {$ifdef FPC_BIG_ENDIAN}
  20. END_OF_CENTRAL_DIR_SIGNATURE = $504B0506;
  21. LOCAL_FILE_HEADER_SIGNATURE = $504B0304;
  22. CENTRAL_FILE_HEADER_SIGNATURE = $504B0102;
  23. {$else FPC_BIG_ENDIAN}
  24. END_OF_CENTRAL_DIR_SIGNATURE = $06054B50;
  25. LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
  26. CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
  27. {$endif FPC_BIG_ENDIAN}
  28. Type
  29. Local_File_Header_Type = Packed Record
  30. Signature : LongInt;
  31. Extract_Version_Reqd : Word;
  32. Bit_Flag : Word;
  33. Compress_Method : Word;
  34. Last_Mod_Time : Word;
  35. Last_Mod_Date : Word;
  36. Crc32 : LongWord;
  37. Compressed_Size : LongInt;
  38. Uncompressed_Size : LongInt;
  39. Filename_Length : Word;
  40. Extra_Field_Length : Word;
  41. end;
  42. { Define the Central Directory record types }
  43. Central_File_Header_Type = Packed Record
  44. Signature : LongInt;
  45. MadeBy_Version : Word;
  46. Extract_Version_Reqd : Word;
  47. Bit_Flag : Word;
  48. Compress_Method : Word;
  49. Last_Mod_Time : Word;
  50. Last_Mod_Date : Word;
  51. Crc32 : LongWord;
  52. Compressed_Size : LongInt;
  53. Uncompressed_Size : LongInt;
  54. Filename_Length : Word;
  55. Extra_Field_Length : Word;
  56. File_Comment_Length : Word;
  57. Starting_Disk_Num : Word;
  58. Internal_Attributes : Word;
  59. External_Attributes : LongInt;
  60. Local_Header_Offset : LongInt;
  61. End;
  62. End_of_Central_Dir_Type = Packed Record
  63. Signature : LongInt;
  64. Disk_Number : Word;
  65. Central_Dir_Start_Disk : Word;
  66. Entries_This_Disk : Word;
  67. Total_Entries : Word;
  68. Central_Dir_Size : LongInt;
  69. Start_Disk_Offset : LongInt;
  70. ZipFile_Comment_Length : Word;
  71. end;
  72. Const
  73. Crc_32_Tab : Array[0..255] of LongWord = (
  74. $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3,
  75. $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91,
  76. $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7,
  77. $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5,
  78. $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
  79. $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59,
  80. $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f,
  81. $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d,
  82. $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433,
  83. $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
  84. $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457,
  85. $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65,
  86. $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb,
  87. $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9,
  88. $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
  89. $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad,
  90. $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683,
  91. $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1,
  92. $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7,
  93. $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
  94. $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b,
  95. $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79,
  96. $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f,
  97. $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d,
  98. $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
  99. $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21,
  100. $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777,
  101. $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45,
  102. $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db,
  103. $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
  104. $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf,
  105. $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d
  106. );
  107. Type
  108. TZipItem = Class(TObject)
  109. Path : String;
  110. Name : String;
  111. Size : LongInt;
  112. DateTime : TDateTime;
  113. HdrPos : Longint;
  114. end;
  115. TProgressEvent = Procedure(Sender : TObject; Const Pct : Double) of object;
  116. TOnEndOfFileEvent = Procedure(Sender : TObject; Const Ratio : Double) of object;
  117. TOnStartFileEvent = Procedure(Sender : TObject; Const AFileName : String) of object;
  118. Type
  119. { TCompressor }
  120. TCompressor = Class(TObject)
  121. Protected
  122. FInFile : TStream; { I/O file variables }
  123. FOutFile : TStream;
  124. FCrc32Val : LongWord; { CRC calculation variable }
  125. FBufferSize : LongWord;
  126. FOnPercent : Integer;
  127. FOnProgress : TProgressEvent;
  128. Procedure UpdC32(Octet: Byte);
  129. Public
  130. Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
  131. Procedure Compress; Virtual; Abstract;
  132. Class Function ZipID : Word; virtual; Abstract;
  133. Property BufferSize : LongWord read FBufferSize;
  134. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  135. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  136. Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
  137. end;
  138. { TDeCompressor }
  139. TDeCompressor = Class(TObject)
  140. Protected
  141. FInFile : TStream; { I/O file variables }
  142. FOutFile : TStream;
  143. FCrc32Val : LongWord; { CRC calculation variable }
  144. FBufferSize : LongWord;
  145. FOnPercent : Integer;
  146. FOnProgress : TProgressEvent;
  147. Procedure UpdC32(Octet: Byte);
  148. Public
  149. Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); virtual;
  150. Procedure DeCompress; Virtual; Abstract;
  151. Class Function ZipID : Word; virtual; Abstract;
  152. Property BufferSize : LongWord read FBufferSize;
  153. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  154. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  155. Property Crc32Val : LongWord Read FCrc32Val Write FCrc32Val;
  156. end;
  157. { TShrinker }
  158. Const
  159. TABLESIZE = 8191;
  160. FIRSTENTRY = 257;
  161. Type
  162. CodeRec = Packed Record
  163. Child : Smallint;
  164. Sibling : Smallint;
  165. Suffix : Byte;
  166. end;
  167. CodeArray = Array[0..TABLESIZE] of CodeRec;
  168. TablePtr = ^CodeArray;
  169. FreeListPtr = ^FreeListArray;
  170. FreeListArray = Array[FIRSTENTRY..TABLESIZE] of Word;
  171. BufPtr = PByte;
  172. TShrinker = Class(TCompressor)
  173. Private
  174. FBufSize : LongWord;
  175. MaxInBufIdx : LongWord; { Count of valid chars in input buffer }
  176. InputEof : Boolean; { End of file indicator }
  177. CodeTable : TablePtr; { Points to code table for LZW compression }
  178. FreeList : FreeListPtr; { Table of free code table entries }
  179. NextFree : Word; { Index into free list table }
  180. ClearList : Array[0..1023] of Byte; { Bit mapped structure used in }
  181. { during adaptive resets }
  182. CodeSize : Byte; { Size of codes (in bits) currently being written }
  183. MaxCode : Word; { Largest code that can be written in CodeSize bits }
  184. InBufIdx, { Points to next char in buffer to be read }
  185. OutBufIdx : LongWord; { Points to next free space in output buffer }
  186. InBuf, { I/O buffers }
  187. OutBuf : BufPtr;
  188. FirstCh : Boolean; { Flag indicating the START of a shrink operation }
  189. TableFull : Boolean; { Flag indicating a full symbol table }
  190. SaveByte : Byte; { Output code buffer }
  191. BitsUsed : Byte; { Index into output code buffer }
  192. BytesIn : LongInt; { Count of input file bytes processed }
  193. BytesOut : LongInt; { Count of output bytes }
  194. FOnBytes : Longint;
  195. Procedure FillInputBuffer;
  196. Procedure WriteOutputBuffer;
  197. Procedure FlushOutput;
  198. Procedure PutChar(B : Byte);
  199. procedure PutCode(Code : Smallint);
  200. Procedure InitializeCodeTable;
  201. Procedure Prune(Parent : Word);
  202. Procedure Clear_Table;
  203. Procedure Table_Add(Prefix : Word; Suffix : Byte);
  204. function Table_Lookup(TargetPrefix : Smallint;
  205. TargetSuffix : Byte;
  206. Out FoundAt : Smallint) : Boolean;
  207. Procedure Shrink(Suffix : Smallint);
  208. Procedure ProcessLine(Const Source : String);
  209. Procedure DoOnProgress(Const Pct : Double); Virtual;
  210. Public
  211. Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord); override;
  212. Destructor Destroy; override;
  213. Procedure Compress; override;
  214. Class Function ZipID : Word; override;
  215. end;
  216. { TDeflater }
  217. TDeflater = Class(TCompressor)
  218. private
  219. FCompressionLevel: TCompressionlevel;
  220. Public
  221. Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
  222. Procedure Compress; override;
  223. Class Function ZipID : Word; override;
  224. Property CompressionLevel : TCompressionlevel Read FCompressionLevel Write FCompressionLevel;
  225. end;
  226. { TInflater }
  227. TInflater = Class(TDeCompressor)
  228. Public
  229. Constructor Create(AInFile, AOutFile : TStream; ABufSize : LongWord);override;
  230. Procedure DeCompress; override;
  231. Class Function ZipID : Word; override;
  232. end;
  233. { TZipper }
  234. TZipper = Class(TObject)
  235. Private
  236. FZipping : Boolean;
  237. FBufSize : LongWord;
  238. FFileName : String; { Name of resulting Zip file }
  239. FFiles : TStrings;
  240. FInMemSize : Integer;
  241. FOutFile : TFileStream;
  242. FInFile : TFileStream; { I/O file variables }
  243. LocalHdr : Local_File_Header_Type;
  244. CentralHdr : Central_File_Header_Type;
  245. EndHdr : End_of_Central_Dir_Type;
  246. FOnPercent : LongInt;
  247. FOnProgress : TProgressEvent;
  248. FOnEndOfFile : TOnEndOfFileEvent;
  249. FOnStartFile : TOnStartFileEvent;
  250. Protected
  251. Procedure OpenOutput;
  252. Procedure CloseOutput;
  253. Procedure CloseInput;
  254. Procedure StartZipFile(Item : TZipItem);
  255. Function UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord;AMethod : Word) : Boolean;
  256. Procedure BuildZipDirectory;
  257. Procedure DoEndOfFile;
  258. Procedure ZipOneFile(Item : TZipItem); virtual;
  259. Function OpenInput(InFileName : String) : Boolean;
  260. Procedure GetFileInfo;
  261. Procedure SetBufSize(Value : LongWord);
  262. Procedure SetFileName(Value : String);
  263. Function CreateCompressor(Item : TZipItem; AinFile,AZipStream : TStream) : TCompressor; virtual;
  264. Public
  265. Constructor Create;
  266. Destructor Destroy;override;
  267. Procedure ZipAllFiles; virtual;
  268. Procedure ZipFiles(AFileName : String; FileList : TStrings);
  269. Procedure Clear;
  270. Public
  271. Property BufferSize : LongWord Read FBufSize Write SetBufSize;
  272. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  273. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  274. Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
  275. Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
  276. Property FileName : String Read FFileName Write SetFileName;
  277. Property Files : TStrings Read FFiles;
  278. Property InMemSize : Integer Read FInMemSize Write FInMemSize;
  279. end;
  280. { TYbZipper }
  281. { TUnZipper }
  282. TUnZipper = Class(TObject)
  283. Private
  284. FUnZipping : Boolean;
  285. FBufSize : LongWord;
  286. FFileName : String; { Name of resulting Zip file }
  287. FOutputPath : String;
  288. FFiles : TStrings;
  289. FZipEntries : TFPObjectList;
  290. FOutFile : TFileStream;
  291. FZipFile : TFileStream; { I/O file variables }
  292. LocalHdr : Local_File_Header_Type;
  293. CentralHdr : Central_File_Header_Type;
  294. EndHdr : End_of_Central_Dir_Type;
  295. FOnPercent : LongInt;
  296. FOnProgress : TProgressEvent;
  297. FOnEndOfFile : TOnEndOfFileEvent;
  298. FOnStartFile : TOnStartFileEvent;
  299. Protected
  300. Procedure OpenInput;
  301. Procedure CloseOutput;
  302. Procedure CloseInput;
  303. Procedure ReadZipHeader(Item : TZipItem; out ACRC : LongWord;out AMethod : Word);
  304. Procedure ReadZipDirectory;
  305. Procedure DoEndOfFile;
  306. Procedure UnZipOneFile(Item : TZipItem); virtual;
  307. Function OpenOutput(OutFileName : String) : Boolean;
  308. Procedure SetBufSize(Value : LongWord);
  309. Procedure SetFileName(Value : String);
  310. Procedure SetOutputPath(Value:String);
  311. Function CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor; virtual;
  312. Public
  313. Constructor Create;
  314. Destructor Destroy;override;
  315. Procedure UnZipAllFiles; virtual;
  316. Procedure UnZipFiles(AFileName : String; FileList : TStrings);
  317. Procedure UnZipAllFiles(AFileName : String);
  318. Procedure Clear;
  319. Public
  320. Property BufferSize : LongWord Read FBufSize Write SetBufSize;
  321. Property OnPercent : Integer Read FOnPercent Write FOnPercent;
  322. Property OnProgress : TProgressEvent Read FOnProgress Write FOnProgress;
  323. Property OnStartFile : TOnStartFileEvent Read FOnStartFile Write FOnStartFile;
  324. Property OnEndFile : TOnEndOfFileEvent Read FOnEndOfFile Write FOnEndOfFile;
  325. Property FileName : String Read FFileName Write SetFileName;
  326. Property OutputPath : String Read FOutputPath Write SetOutputPath;
  327. Property Files : TStrings Read FFiles;
  328. end;
  329. EZipError = Class(Exception);
  330. Implementation
  331. ResourceString
  332. SErrBufsizeChange = 'Changing buffer size is not allowed while (un)zipping';
  333. SErrFileChange = 'Changing output file name is not allowed while (un)zipping';
  334. SErrInvalidCRC = 'Invalid CRC checksum while unzipping %s';
  335. SErrCorruptZIP = 'Corrupt ZIP file %s';
  336. SErrUnsupportedCompressionFormat = 'Unsupported compression format %d';
  337. { ---------------------------------------------------------------------
  338. Auxiliary
  339. ---------------------------------------------------------------------}
  340. Procedure DateTimeToZipDateTime(DT : TDateTime; out ZD,ZT : Word);
  341. Var
  342. Y,M,D,H,N,S,MS : Word;
  343. begin
  344. DecodeDate(DT,Y,M,D);
  345. DecodeTime(DT,H,N,S,MS);
  346. Y:=Y-1980;
  347. ZD:=d+(32*M)+(512*Y);
  348. ZT:=(S div 2)+(32*N)+(2048*h);
  349. end;
  350. Procedure ZipDateTimeToDateTime(ZD,ZT : Word;out DT : TDateTime);
  351. Var
  352. Y,M,D,H,N,S,MS : Word;
  353. begin
  354. MS:=0;
  355. S:=(ZT and 31) shl 1;
  356. N:=(ZT shr 5) and 63;
  357. H:=(ZT shr 12) and 31;
  358. D:=ZD and 31;
  359. M:=(ZD shr 5) and 15;
  360. Y:=((ZD shr 9) and 127)+1980;
  361. DT:=ComposeDateTime(EncodeDate(Y,M,D),EncodeTime(H,N,S,MS));
  362. end;
  363. { ---------------------------------------------------------------------
  364. TDeCompressor
  365. ---------------------------------------------------------------------}
  366. Procedure TDeCompressor.UpdC32(Octet: Byte);
  367. Begin
  368. FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
  369. end;
  370. constructor TDeCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
  371. begin
  372. FinFile:=AInFile;
  373. FoutFile:=AOutFile;
  374. FBufferSize:=ABufSize;
  375. CRC32Val:=$FFFFFFFF;
  376. end;
  377. { ---------------------------------------------------------------------
  378. TCompressor
  379. ---------------------------------------------------------------------}
  380. Procedure TCompressor.UpdC32(Octet: Byte);
  381. Begin
  382. FCrc32Val := Crc_32_Tab[Byte(FCrc32Val XOR LongInt(Octet))] XOR ((FCrc32Val SHR 8) AND $00FFFFFF);
  383. end;
  384. constructor TCompressor.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
  385. begin
  386. FinFile:=AInFile;
  387. FoutFile:=AOutFile;
  388. FBufferSize:=ABufSize;
  389. CRC32Val:=$FFFFFFFF;
  390. end;
  391. { ---------------------------------------------------------------------
  392. TDeflater
  393. ---------------------------------------------------------------------}
  394. constructor TDeflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
  395. begin
  396. Inherited;
  397. FCompressionLevel:=clDefault;
  398. end;
  399. procedure TDeflater.Compress;
  400. Var
  401. Buf : PByte;
  402. I,Count,NewCount : Integer;
  403. C : TCompressionStream;
  404. begin
  405. CRC32Val:=$FFFFFFFF;
  406. Buf:=GetMem(FBufferSize);
  407. Try
  408. C:=TCompressionStream.Create(FCompressionLevel,FOutFile,True);
  409. Try
  410. Repeat
  411. Count:=FInFile.Read(Buf^,FBufferSize);
  412. For I:=0 to Count-1 do
  413. UpdC32(Buf[i]);
  414. NewCount:=Count;
  415. While (NewCount>0) do
  416. NewCount:=NewCount-C.Write(Buf^,NewCount);
  417. Until (Count=0);
  418. Finally
  419. C.Free;
  420. end;
  421. Finally
  422. FreeMem(Buf);
  423. end;
  424. Crc32Val:=NOT Crc32Val;
  425. end;
  426. class function TDeflater.ZipID: Word;
  427. begin
  428. Result:=8;
  429. end;
  430. { ---------------------------------------------------------------------
  431. TInflater
  432. ---------------------------------------------------------------------}
  433. constructor TInflater.Create(AInFile, AOutFile: TStream; ABufSize: LongWord);
  434. begin
  435. Inherited;
  436. end;
  437. procedure TInflater.DeCompress;
  438. Var
  439. Buf : PByte;
  440. I,Count : Integer;
  441. C : TDeCompressionStream;
  442. begin
  443. CRC32Val:=$FFFFFFFF;
  444. Buf:=GetMem(FBufferSize);
  445. Try
  446. C:=TDeCompressionStream.Create(FInFile,True);
  447. Try
  448. Repeat
  449. Count:=C.Read(Buf^,FBufferSize);
  450. For I:=0 to Count-1 do
  451. UpdC32(Buf[i]);
  452. FOutFile.Write(Buf^,Count);
  453. Until (Count=0);
  454. Finally
  455. C.Free;
  456. end;
  457. Finally
  458. FreeMem(Buf);
  459. end;
  460. Crc32Val:=NOT Crc32Val;
  461. end;
  462. class function TInflater.ZipID: Word;
  463. begin
  464. Result:=8;
  465. end;
  466. { ---------------------------------------------------------------------
  467. TShrinker
  468. ---------------------------------------------------------------------}
  469. Const
  470. DefaultInMemSize = 256*1024; { Files larger than 256k are processed on disk }
  471. DefaultBufSize = 16384; { Use 16K file buffers }
  472. MINBITS = 9; { Starting code size of 9 bits }
  473. MAXBITS = 13; { Maximum code size of 13 bits }
  474. SPECIAL = 256; { Special function code }
  475. INCSIZE = 1; { Code indicating a jump in code size }
  476. CLEARCODE = 2; { Code indicating code table has been cleared }
  477. STDATTR = $23; { Standard file attribute for DOS Find First/Next }
  478. constructor TShrinker.Create(AInFile, AOutFile : TStream; ABufSize : LongWord);
  479. begin
  480. Inherited;
  481. FBufSize:=ABufSize;
  482. InBuf:=GetMem(FBUFSIZE);
  483. OutBuf:=GetMem(FBUFSIZE);
  484. CodeTable:=GetMem(SizeOf(CodeTable^));
  485. FreeList:=GetMem(SizeOf(FreeList^));
  486. end;
  487. destructor TShrinker.Destroy;
  488. begin
  489. FreeMem(CodeTable);
  490. FreeMem(FreeList);
  491. FreeMem(InBuf);
  492. FreeMem(OutBuf);
  493. inherited Destroy;
  494. end;
  495. Procedure TShrinker.Compress;
  496. Var
  497. OneString : String;
  498. Remaining : Word;
  499. begin
  500. BytesIn := 1;
  501. BytesOut := 1;
  502. InitializeCodeTable;
  503. FillInputBuffer;
  504. FirstCh:= TRUE;
  505. Crc32Val:=$FFFFFFFF;
  506. FOnBytes:=Round((FInFile.Size * FOnPercent) / 100);
  507. While NOT InputEof do
  508. begin
  509. Remaining:=Succ(MaxInBufIdx - InBufIdx);
  510. If Remaining>255 then
  511. Remaining:=255;
  512. If Remaining=0 then
  513. FillInputBuffer
  514. else
  515. begin
  516. SetLength(OneString,Remaining);
  517. Move(InBuf[InBufIdx], OneString[1], Remaining);
  518. Inc(InBufIdx, Remaining);
  519. ProcessLine(OneString);
  520. end;
  521. end;
  522. Crc32Val := NOT Crc32Val;
  523. ProcessLine('');
  524. end;
  525. class function TShrinker.ZipID: Word;
  526. begin
  527. Result:=1;
  528. end;
  529. Procedure TShrinker.DoOnProgress(Const Pct: Double);
  530. begin
  531. If Assigned(FOnProgress) then
  532. FOnProgress(Self,Pct);
  533. end;
  534. Procedure TShrinker.FillInputBuffer;
  535. Begin
  536. MaxInbufIDx:=FInfile.Read(InBuf[0], FBufSize);
  537. If MaxInbufIDx=0 then
  538. InputEof := TRUE
  539. else
  540. InputEOF := FALSE;
  541. InBufIdx := 0;
  542. end;
  543. Procedure TShrinker.WriteOutputBuffer;
  544. Begin
  545. FOutFile.WriteBuffer(OutBuf[0], OutBufIdx);
  546. OutBufIdx := 0;
  547. end;
  548. Procedure TShrinker.PutChar(B : Byte);
  549. Begin
  550. OutBuf[OutBufIdx] := B;
  551. Inc(OutBufIdx);
  552. If OutBufIdx>=FBufSize then
  553. WriteOutputBuffer;
  554. Inc(BytesOut);
  555. end;
  556. Procedure TShrinker.FlushOutput;
  557. Begin
  558. If OutBufIdx>0 then
  559. WriteOutputBuffer;
  560. End;
  561. procedure TShrinker.PutCode(Code : Smallint);
  562. var
  563. ACode : LongInt;
  564. XSize : Smallint;
  565. begin
  566. if (Code=-1) then
  567. begin
  568. if BitsUsed>0 then
  569. PutChar(SaveByte);
  570. end
  571. else
  572. begin
  573. ACode := Longint(Code);
  574. XSize := CodeSize+BitsUsed;
  575. ACode := (ACode shl BitsUsed) or SaveByte;
  576. while (XSize div 8) > 0 do
  577. begin
  578. PutChar(Lo(ACode));
  579. ACode := ACode shr 8;
  580. Dec(XSize,8);
  581. end;
  582. BitsUsed := XSize;
  583. SaveByte := Lo(ACode);
  584. end;
  585. end;
  586. Procedure TShrinker.InitializeCodeTable;
  587. Var
  588. I : Word;
  589. Begin
  590. For I := 0 to TableSize do
  591. begin
  592. With CodeTable^[I] do
  593. begin
  594. Child := -1;
  595. Sibling := -1;
  596. If (I<=255) then
  597. Suffix := I;
  598. end;
  599. If (I>=257) then
  600. FreeList^[I] := I;
  601. end;
  602. NextFree := FIRSTENTRY;
  603. TableFull := FALSE;
  604. end;
  605. Procedure TShrinker.Prune(Parent : Word);
  606. Var
  607. CurrChild : Smallint;
  608. NextSibling : Smallint;
  609. Begin
  610. CurrChild := CodeTable^[Parent].Child;
  611. { Find first Child that has descendants .. clear any that don't }
  612. While (CurrChild <> -1) AND (CodeTable^[CurrChild].Child = -1) do
  613. begin
  614. CodeTable^[Parent].Child := CodeTable^[CurrChild].Sibling;
  615. CodeTable^[CurrChild].Sibling := -1;
  616. { Turn on ClearList bit to indicate a cleared entry }
  617. ClearList[CurrChild DIV 8] := (ClearList[CurrChild DIV 8] OR (1 SHL (CurrChild MOD 8)));
  618. CurrChild := CodeTable^[Parent].Child;
  619. end;
  620. If CurrChild <> -1 then
  621. begin { If there are any children left ...}
  622. Prune(CurrChild);
  623. NextSibling := CodeTable^[CurrChild].Sibling;
  624. While NextSibling <> -1 do
  625. begin
  626. If CodeTable^[NextSibling].Child = -1 then
  627. begin
  628. CodeTable^[CurrChild].Sibling := CodeTable^[NextSibling].Sibling;
  629. CodeTable^[NextSibling].Sibling := -1;
  630. { Turn on ClearList bit to indicate a cleared entry }
  631. ClearList[NextSibling DIV 8] := (ClearList[NextSibling DIV 8] OR (1 SHL (NextSibling MOD 8)));
  632. NextSibling := CodeTable^[CurrChild].Sibling;
  633. end
  634. else
  635. begin
  636. CurrChild := NextSibling;
  637. Prune(CurrChild);
  638. NextSibling := CodeTable^[CurrChild].Sibling;
  639. end;
  640. end;
  641. end;
  642. end;
  643. Procedure TShrinker.Clear_Table;
  644. Var
  645. Node : Word;
  646. Begin
  647. FillChar(ClearList, SizeOf(ClearList), $00);
  648. For Node := 0 to 255 do
  649. Prune(Node);
  650. NextFree := Succ(TABLESIZE);
  651. For Node := TABLESIZE downto FIRSTENTRY do
  652. begin
  653. If (ClearList[Node DIV 8] AND (1 SHL (Node MOD 8))) <> 0 then
  654. begin
  655. Dec(NextFree);
  656. FreeList^[NextFree] := Node;
  657. end;
  658. end;
  659. If NextFree <= TABLESIZE then
  660. TableFull := FALSE;
  661. end;
  662. Procedure TShrinker.Table_Add(Prefix : Word; Suffix : Byte);
  663. Var
  664. FreeNode : Word;
  665. Begin
  666. If NextFree <= TABLESIZE then
  667. begin
  668. FreeNode := FreeList^[NextFree];
  669. Inc(NextFree);
  670. CodeTable^[FreeNode].Child := -1;
  671. CodeTable^[FreeNode].Sibling := -1;
  672. CodeTable^[FreeNode].Suffix := Suffix;
  673. If CodeTable^[Prefix].Child = -1 then
  674. CodeTable^[Prefix].Child := FreeNode
  675. else
  676. begin
  677. Prefix := CodeTable^[Prefix].Child;
  678. While CodeTable^[Prefix].Sibling <> -1 do
  679. Prefix := CodeTable^[Prefix].Sibling;
  680. CodeTable^[Prefix].Sibling := FreeNode;
  681. end;
  682. end;
  683. if NextFree > TABLESIZE then
  684. TableFull := TRUE;
  685. end;
  686. function TShrinker.Table_Lookup( TargetPrefix : Smallint;
  687. TargetSuffix : Byte;
  688. Out FoundAt : Smallint ) : Boolean;
  689. var TempPrefix : Smallint;
  690. begin
  691. TempPrefix := TargetPrefix;
  692. Table_lookup := False;
  693. if CodeTable^[TempPrefix].Child <> -1 then
  694. begin
  695. TempPrefix := CodeTable^[TempPrefix].Child;
  696. repeat
  697. if CodeTable^[TempPrefix].Suffix = TargetSuffix then
  698. begin
  699. Table_lookup := True;
  700. break;
  701. end;
  702. if CodeTable^[TempPrefix].Sibling = -1 then
  703. break;
  704. TempPrefix := CodeTable^[TempPrefix].Sibling;
  705. until False;
  706. end;
  707. if Table_Lookup then
  708. FoundAt := TempPrefix
  709. else
  710. FoundAt := -1;
  711. end;
  712. Procedure TShrinker.Shrink(Suffix : Smallint);
  713. Const
  714. LastCode : Smallint = 0;
  715. Var
  716. WhereFound : Smallint;
  717. Begin
  718. If FirstCh then
  719. begin
  720. SaveByte := $00;
  721. BitsUsed := 0;
  722. CodeSize := MINBITS;
  723. MaxCode := (1 SHL CodeSize) - 1;
  724. LastCode := Suffix;
  725. FirstCh := FALSE;
  726. end
  727. else
  728. begin
  729. If Suffix <> -1 then
  730. begin
  731. If TableFull then
  732. begin
  733. Putcode(LastCode);
  734. PutCode(SPECIAL);
  735. Putcode(CLEARCODE);
  736. Clear_Table;
  737. Table_Add(LastCode, Suffix);
  738. LastCode := Suffix;
  739. end
  740. else
  741. begin
  742. If Table_Lookup(LastCode, Suffix, WhereFound) then
  743. begin
  744. LastCode := WhereFound;
  745. end
  746. else
  747. begin
  748. PutCode(LastCode);
  749. Table_Add(LastCode, Suffix);
  750. LastCode := Suffix;
  751. If (FreeList^[NextFree] > MaxCode) and (CodeSize < MaxBits) then
  752. begin
  753. PutCode(SPECIAL);
  754. PutCode(INCSIZE);
  755. Inc(CodeSize);
  756. MaxCode := (1 SHL CodeSize) -1;
  757. end;
  758. end;
  759. end;
  760. end
  761. else
  762. begin
  763. PutCode(LastCode);
  764. PutCode(-1);
  765. FlushOutput;
  766. end;
  767. end;
  768. end;
  769. Procedure TShrinker.ProcessLine(Const Source : String);
  770. Var
  771. I : Word;
  772. Begin
  773. If Source = '' then
  774. Shrink(-1)
  775. else
  776. For I := 1 to Length(Source) do
  777. begin
  778. Inc(BytesIn);
  779. If (Pred(BytesIn) MOD FOnBytes) = 0 then
  780. DoOnProgress(100 * ( BytesIn / FInFile.Size));
  781. UpdC32(Ord(Source[I]));
  782. Shrink(Ord(Source[I]));
  783. end;
  784. end;
  785. { ---------------------------------------------------------------------
  786. TZipper
  787. ---------------------------------------------------------------------}
  788. Procedure TZipper.GetFileInfo;
  789. Var
  790. Info : TSearchRec;
  791. I : Word;
  792. NewNode : TZipItem;
  793. Begin
  794. For I := 0 to FFiles.Count-1 do
  795. If FindFirst(FFiles[I], STDATTR, Info)=0 then
  796. try
  797. NewNode:=TZipItem.Create;
  798. NewNode.Path := ExtractFilePath(FFiles[i]);
  799. NewNode.Name := Info.Name;
  800. NewNode.Size := Info.Size;
  801. NewNode.DateTime:=FileDateToDateTime(Info.Time);
  802. FFiles.Objects[i]:=NewNode;
  803. finally
  804. FindClose(Info);
  805. end;
  806. end;
  807. Procedure TZipper.OpenOutput;
  808. Begin
  809. FOutFile:=TFileStream.Create(FFileName,fmCreate);
  810. End;
  811. Function TZipper.OpenInput(InFileName : String) : Boolean;
  812. Begin
  813. FInFile:=TFileStream.Create(InFileName,fmOpenRead);
  814. Result:=True;
  815. If Assigned(FOnStartFile) then
  816. FOnStartFile(Self,InFileName);
  817. End;
  818. Procedure TZipper.CloseOutput;
  819. Begin
  820. FreeAndNil(FOutFile);
  821. end;
  822. Procedure TZipper.CloseInput;
  823. Begin
  824. FreeAndNil(FInFile);
  825. end;
  826. Procedure TZipper.StartZipFile(Item : TZipItem);
  827. Begin
  828. FillChar(LocalHdr,SizeOf(LocalHdr),0);
  829. With LocalHdr do
  830. begin
  831. Signature := LOCAL_FILE_HEADER_SIGNATURE;
  832. Extract_Version_Reqd := 10;
  833. Bit_Flag := 0;
  834. Compress_Method := 1;
  835. DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
  836. Crc32 := 0;
  837. Compressed_Size := 0;
  838. Uncompressed_Size := Item.Size;
  839. FileName_Length := Length(Item.Name);
  840. Extra_Field_Length := 0;
  841. end ;
  842. End;
  843. Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
  844. Begin
  845. With LocalHdr do
  846. begin
  847. Compressed_Size := FZip.Size;
  848. Crc32 := ACRC;
  849. Compress_method:=AMethod;
  850. Result:=Not (Compressed_Size >= Uncompressed_Size);
  851. If Not Result then
  852. begin { No... }
  853. Compress_Method := 0; { ...change stowage type }
  854. Compressed_Size := Uncompressed_Size; { ...update compressed size }
  855. end;
  856. end;
  857. FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
  858. FOutFile.WriteBuffer(Item.Name[1],Length(Item.Name));
  859. End;
  860. Procedure TZipper.BuildZipDirectory;
  861. Var
  862. SavePos : LongInt;
  863. HdrPos : LongInt;
  864. CenDirPos : LongInt;
  865. Entries : Word;
  866. ZFileName : ShortString;
  867. Begin
  868. Entries := 0;
  869. CenDirPos := FOutFile.Position;
  870. FOutFile.Seek(0,soFrombeginning); { Rewind output file }
  871. HdrPos := FOutFile.Position;
  872. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  873. Repeat
  874. SetLength(ZFileName,LocalHdr.FileName_Length);
  875. FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
  876. SavePos := FOutFile.Position;
  877. FillChar(CentralHdr,SizeOf(CentralHdr),0);
  878. With CentralHdr do
  879. begin
  880. Signature := CENTRAL_FILE_HEADER_SIGNATURE;
  881. MadeBy_Version := LocalHdr.Extract_Version_Reqd;
  882. Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
  883. Last_Mod_Time:=localHdr.Last_Mod_Time;
  884. Last_Mod_Date:=localHdr.Last_Mod_Date;
  885. File_Comment_Length := 0;
  886. Starting_Disk_Num := 0;
  887. Internal_Attributes := 0;
  888. External_Attributes := faARCHIVE;
  889. Local_Header_Offset := HdrPos;
  890. end;
  891. FOutFile.Seek(0,soFromEnd);
  892. FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
  893. FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
  894. Inc(Entries);
  895. FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
  896. HdrPos:=FOutFile.Position;
  897. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  898. Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
  899. FOutFile.Seek(0,soFromEnd);
  900. FillChar(EndHdr,SizeOf(EndHdr),0);
  901. With EndHdr do
  902. begin
  903. Signature := END_OF_CENTRAL_DIR_SIGNATURE;
  904. Disk_Number := 0;
  905. Central_Dir_Start_Disk := 0;
  906. Entries_This_Disk := Entries;
  907. Total_Entries := Entries;
  908. Central_Dir_Size := FOutFile.Size-CenDirPos;
  909. Start_Disk_Offset := CenDirPos;
  910. ZipFile_Comment_Length := 0;
  911. FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
  912. end;
  913. end;
  914. Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
  915. begin
  916. Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
  917. end;
  918. Procedure TZipper.ZipOneFile(Item : TZipItem);
  919. Var
  920. CRC : Integer;
  921. ZMethod : Word;
  922. ZipStream : TStream;
  923. TmpFileName : String;
  924. Begin
  925. OpenInput(Item.Path+Item.Name);
  926. Try
  927. StartZipFile(Item);
  928. If (FInfile.Size<=FInMemSize) then
  929. ZipStream:=TMemoryStream.Create
  930. else
  931. begin
  932. TmpFileName:=ChangeFileExt(FFileName,'.tmp');
  933. ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
  934. end;
  935. Try
  936. With CreateCompressor(Item, FinFile,ZipStream) do
  937. Try
  938. OnProgress:=Self.OnProgress;
  939. OnPercent:=Self.OnPercent;
  940. Compress;
  941. CRC:=Crc32Val;
  942. ZMethod:=ZipID;
  943. Finally
  944. Free;
  945. end;
  946. If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
  947. // Compressed file smaller than original file.
  948. FOutFile.CopyFrom(ZipStream,0)
  949. else
  950. begin
  951. // Original file smaller than compressed file.
  952. FInfile.Seek(0,soFromBeginning);
  953. FOutFile.CopyFrom(FInFile,0);
  954. end;
  955. finally
  956. ZipStream.Free;
  957. If (TmpFileName<>'') then
  958. DeleteFile(TmpFileName);
  959. end;
  960. Finally
  961. CloseInput;
  962. end;
  963. end;
  964. Procedure TZipper.ZipAllFiles;
  965. Var
  966. Item : TZipItem;
  967. I : Integer;
  968. Begin
  969. FZipping:=True;
  970. Try
  971. GetFileInfo;
  972. OpenOutput;
  973. Try
  974. For I:=0 to FFiles.Count-1 do
  975. begin
  976. Item:=FFiles.Objects[i] as TZipItem;
  977. ZipOneFile(Item);
  978. end;
  979. BuildZipDirectory;
  980. Finally
  981. CloseOutput;
  982. end;
  983. finally
  984. FZipping:=False;
  985. end;
  986. end;
  987. Procedure TZipper.SetBufSize(Value : LongWord);
  988. begin
  989. If FZipping then
  990. Raise EZipError.Create(SErrBufsizeChange);
  991. If Value>=DefaultBufSize then
  992. FBufSize:=Value;
  993. end;
  994. Procedure TZipper.SetFileName(Value : String);
  995. begin
  996. If FZipping then
  997. Raise EZipError.Create(SErrFileChange);
  998. FFileName:=Value;
  999. end;
  1000. Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
  1001. begin
  1002. FFiles.Assign(FileList);
  1003. FFileName:=AFileName;
  1004. ZipAllFiles;
  1005. end;
  1006. Procedure TZipper.DoEndOfFile;
  1007. Var
  1008. ComprPct : Double;
  1009. begin
  1010. If (LocalHdr.Uncompressed_Size>0) then
  1011. ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
  1012. else
  1013. ComprPct := 0;
  1014. If Assigned(FOnEndOfFile) then
  1015. FOnEndOfFile(Self,ComprPct);
  1016. end;
  1017. Constructor TZipper.Create;
  1018. begin
  1019. FBufSize:=DefaultBufSize;
  1020. FInMemSize:=DefaultInMemSize;
  1021. FFiles:=TStringList.Create;
  1022. TStringlist(FFiles).Sorted:=True;
  1023. FOnPercent:=1;
  1024. end;
  1025. Procedure TZipper.Clear;
  1026. Var
  1027. I : Integer;
  1028. begin
  1029. For I:=0 to FFiles.Count-1 do
  1030. FFiles.Objects[i].Free;
  1031. FFiles.Clear;
  1032. end;
  1033. Destructor TZipper.Destroy;
  1034. begin
  1035. Clear;
  1036. FreeAndNil(FFiles);
  1037. Inherited;
  1038. end;
  1039. { ---------------------------------------------------------------------
  1040. TUnZipper
  1041. ---------------------------------------------------------------------}
  1042. Procedure TUnZipper.OpenInput;
  1043. Begin
  1044. FZipFile:=TFileStream.Create(FFileName,fmOpenRead);
  1045. End;
  1046. Function TUnZipper.OpenOutput(OutFileName : String) : Boolean;
  1047. Begin
  1048. FOutFile:=TFileStream.Create(OutFileName,fmCreate);
  1049. Result:=True;
  1050. If Assigned(FOnStartFile) then
  1051. FOnStartFile(Self,OutFileName);
  1052. End;
  1053. Procedure TUnZipper.CloseOutput;
  1054. Begin
  1055. FreeAndNil(FOutFile);
  1056. end;
  1057. Procedure TUnZipper.CloseInput;
  1058. Begin
  1059. FreeAndNil(FZipFile);
  1060. end;
  1061. Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
  1062. Begin
  1063. FZipFile.Seek(Item.HdrPos,soFromBeginning);
  1064. FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
  1065. With LocalHdr do
  1066. begin
  1067. SetLength(Item.Name,Filename_Length);
  1068. FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
  1069. FZipFile.Seek(Extra_Field_Length,soCurrent);
  1070. Item.Size:=Uncompressed_Size;
  1071. ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
  1072. ACrc:=Crc32;
  1073. AMethod:=Compress_method;
  1074. end;
  1075. End;
  1076. Procedure TUnZipper.ReadZipDirectory;
  1077. Var
  1078. i,
  1079. EndHdrPos,
  1080. CenDirPos : LongInt;
  1081. NewNode : TZipItem;
  1082. Begin
  1083. EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
  1084. if EndHdrPos < 0 then
  1085. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1086. FZipFile.Seek(EndHdrPos,soFromBeginning);
  1087. FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
  1088. With EndHdr do
  1089. begin
  1090. if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
  1091. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1092. CenDirPos:=Start_Disk_Offset;
  1093. end;
  1094. FZipFile.Seek(CenDirPos,soFrombeginning);
  1095. for i:=0 to EndHdr.Entries_This_Disk-1 do
  1096. begin
  1097. FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
  1098. With CentralHdr do
  1099. begin
  1100. if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
  1101. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1102. NewNode:=TZipItem.Create;
  1103. NewNode.HdrPos := Local_Header_Offset;
  1104. SetLength(NewNode.Name,Filename_Length);
  1105. FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
  1106. FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
  1107. FZipEntries.Add(NewNode);
  1108. end;
  1109. end;
  1110. end;
  1111. Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
  1112. var
  1113. Count : Int64;
  1114. begin
  1115. case AMethod of
  1116. 8 :
  1117. Result:=TInflater.Create(AZipFile,AOutFile,FBufSize);
  1118. else
  1119. raise EZipError.CreateFmt(SErrUnsupportedCompressionFormat,[AMethod]);
  1120. end;
  1121. end;
  1122. Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
  1123. Var
  1124. Count : Longint;
  1125. CRC : LongWord;
  1126. ZMethod : Word;
  1127. OutputFileName : string;
  1128. Begin
  1129. Try
  1130. ReadZipHeader(Item,CRC,ZMethod);
  1131. OutputFileName:=Item.Name;
  1132. if FOutputPath<>'' then
  1133. OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
  1134. OpenOutput(OutputFileName);
  1135. if ZMethod=0 then
  1136. begin
  1137. Count:=FOutFile.CopyFrom(FZipFile,LocalHdr.Compressed_Size);
  1138. {$warning TODO: Implement CRC Check}
  1139. end
  1140. else
  1141. With CreateDecompressor(Item, ZMethod, FZipFile, FOutFile) do
  1142. Try
  1143. OnProgress:=Self.OnProgress;
  1144. OnPercent:=Self.OnPercent;
  1145. DeCompress;
  1146. if CRC<>Crc32Val then
  1147. raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
  1148. Finally
  1149. Free;
  1150. end;
  1151. Finally
  1152. CloseOutput;
  1153. end;
  1154. end;
  1155. Procedure TUnZipper.UnZipAllFiles;
  1156. Var
  1157. Item : TZipItem;
  1158. I : Integer;
  1159. Begin
  1160. FUnZipping:=True;
  1161. Try
  1162. OpenInput;
  1163. Try
  1164. ReadZipDirectory;
  1165. For I:=0 to FZipEntries.Count-1 do
  1166. begin
  1167. Item:=FZipEntries[i] as TZipItem;
  1168. UnZipOneFile(Item);
  1169. end;
  1170. Finally
  1171. CloseInput;
  1172. end;
  1173. finally
  1174. FUnZipping:=False;
  1175. end;
  1176. end;
  1177. Procedure TUnZipper.SetBufSize(Value : LongWord);
  1178. begin
  1179. If FUnZipping then
  1180. Raise EZipError.Create(SErrBufsizeChange);
  1181. If Value>=DefaultBufSize then
  1182. FBufSize:=Value;
  1183. end;
  1184. Procedure TUnZipper.SetFileName(Value : String);
  1185. begin
  1186. If FUnZipping then
  1187. Raise EZipError.Create(SErrFileChange);
  1188. FFileName:=Value;
  1189. end;
  1190. Procedure TUnZipper.SetOutputPath(Value:String);
  1191. begin
  1192. If FUnZipping then
  1193. Raise EZipError.Create(SErrFileChange);
  1194. FOutputPath:=Value;
  1195. end;
  1196. Procedure TUnZipper.UnZipFiles(AFileName : String; FileList : TStrings);
  1197. begin
  1198. FFiles.Assign(FileList);
  1199. FFileName:=AFileName;
  1200. UnZipAllFiles;
  1201. end;
  1202. Procedure TUnZipper.UnZipAllFiles(AFileName : String);
  1203. begin
  1204. FFileName:=AFileName;
  1205. UnZipAllFiles;
  1206. end;
  1207. Procedure TUnZipper.DoEndOfFile;
  1208. Var
  1209. ComprPct : Double;
  1210. begin
  1211. If (LocalHdr.Uncompressed_Size>0) then
  1212. ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
  1213. else
  1214. ComprPct := 0;
  1215. If Assigned(FOnEndOfFile) then
  1216. FOnEndOfFile(Self,ComprPct);
  1217. end;
  1218. Constructor TUnZipper.Create;
  1219. begin
  1220. FBufSize:=DefaultBufSize;
  1221. FFiles:=TStringList.Create;
  1222. FZipEntries:=TFPObjectList.Create(true);
  1223. TStringlist(FFiles).Sorted:=True;
  1224. FOnPercent:=1;
  1225. end;
  1226. Procedure TUnZipper.Clear;
  1227. Var
  1228. I : Integer;
  1229. begin
  1230. For I:=0 to FFiles.Count-1 do
  1231. FFiles.Objects[i].Free;
  1232. FFiles.Clear;
  1233. FZipEntries.Clear;
  1234. end;
  1235. Destructor TUnZipper.Destroy;
  1236. begin
  1237. Clear;
  1238. FreeAndNil(FFiles);
  1239. FreeAndNil(FZipEntries);
  1240. Inherited;
  1241. end;
  1242. End.