zipper.pp 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470
  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. { 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 : TFPList; { don't use TFPObjectList, becuase of Contnrs dependency }
  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 : Longint;
  792. NewNode : TZipItem;
  793. Begin
  794. For I := 0 to FFiles.Count-1 do
  795. begin
  796. If FindFirst(FFiles[I], STDATTR, Info)=0 then
  797. try
  798. NewNode:=TZipItem.Create;
  799. NewNode.Path := ExtractFilePath(FFiles[i]);
  800. NewNode.Name := Info.Name;
  801. NewNode.Size := Info.Size;
  802. NewNode.DateTime:=FileDateToDateTime(Info.Time);
  803. FFiles.Objects[i]:=NewNode;
  804. finally
  805. FindClose(Info);
  806. end;
  807. end;
  808. end;
  809. Procedure TZipper.OpenOutput;
  810. Begin
  811. FOutFile:=TFileStream.Create(FFileName,fmCreate);
  812. End;
  813. Function TZipper.OpenInput(InFileName : String) : Boolean;
  814. Begin
  815. FInFile:=TFileStream.Create(InFileName,fmOpenRead);
  816. Result:=True;
  817. If Assigned(FOnStartFile) then
  818. FOnStartFile(Self,InFileName);
  819. End;
  820. Procedure TZipper.CloseOutput;
  821. Begin
  822. FreeAndNil(FOutFile);
  823. end;
  824. Procedure TZipper.CloseInput;
  825. Begin
  826. FreeAndNil(FInFile);
  827. end;
  828. Procedure TZipper.StartZipFile(Item : TZipItem);
  829. Begin
  830. FillChar(LocalHdr,SizeOf(LocalHdr),0);
  831. With LocalHdr do
  832. begin
  833. Signature := LOCAL_FILE_HEADER_SIGNATURE;
  834. Extract_Version_Reqd := 10;
  835. Bit_Flag := 0;
  836. Compress_Method := 1;
  837. DateTimeToZipDateTime(Item.DateTime,Last_Mod_Date,Last_Mod_Time);
  838. Crc32 := 0;
  839. Compressed_Size := 0;
  840. Uncompressed_Size := Item.Size;
  841. FileName_Length := 0;
  842. Extra_Field_Length := 0;
  843. end ;
  844. End;
  845. Function TZipper.UpdateZipHeader(Item : TZipItem; FZip : TStream; ACRC : LongWord; AMethod : Word) : Boolean;
  846. var
  847. ZFileName : ShortString;
  848. Begin
  849. ZFileName:=Item.Path+Item.Name;
  850. With LocalHdr do
  851. begin
  852. FileName_Length := Length(ZFileName);
  853. Compressed_Size := FZip.Size;
  854. Crc32 := ACRC;
  855. Compress_method:=AMethod;
  856. Result:=Not (Compressed_Size >= Uncompressed_Size);
  857. If Not Result then
  858. begin { No... }
  859. Compress_Method := 0; { ...change stowage type }
  860. Compressed_Size := Uncompressed_Size; { ...update compressed size }
  861. end;
  862. end;
  863. FOutFile.WriteBuffer(LocalHdr,SizeOf(LocalHdr));
  864. FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
  865. End;
  866. Procedure TZipper.BuildZipDirectory;
  867. Var
  868. SavePos : LongInt;
  869. HdrPos : LongInt;
  870. CenDirPos : LongInt;
  871. Entries : Word;
  872. ZFileName : ShortString;
  873. Begin
  874. Entries := 0;
  875. CenDirPos := FOutFile.Position;
  876. FOutFile.Seek(0,soFrombeginning); { Rewind output file }
  877. HdrPos := FOutFile.Position;
  878. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  879. Repeat
  880. SetLength(ZFileName,LocalHdr.FileName_Length);
  881. FOutFile.ReadBuffer(ZFileName[1], LocalHdr.FileName_Length);
  882. SavePos := FOutFile.Position;
  883. FillChar(CentralHdr,SizeOf(CentralHdr),0);
  884. With CentralHdr do
  885. begin
  886. Signature := CENTRAL_FILE_HEADER_SIGNATURE;
  887. MadeBy_Version := LocalHdr.Extract_Version_Reqd;
  888. Move(LocalHdr.Extract_Version_Reqd, Extract_Version_Reqd, 26);
  889. Last_Mod_Time:=localHdr.Last_Mod_Time;
  890. Last_Mod_Date:=localHdr.Last_Mod_Date;
  891. File_Comment_Length := 0;
  892. Starting_Disk_Num := 0;
  893. Internal_Attributes := 0;
  894. External_Attributes := faARCHIVE;
  895. Local_Header_Offset := HdrPos;
  896. end;
  897. FOutFile.Seek(0,soFromEnd);
  898. FOutFile.WriteBuffer(CentralHdr,SizeOf(CentralHdr));
  899. FOutFile.WriteBuffer(ZFileName[1],Length(ZFileName));
  900. Inc(Entries);
  901. FOutFile.Seek(SavePos + LocalHdr.Compressed_Size,soFromBeginning);
  902. HdrPos:=FOutFile.Position;
  903. FOutFile.ReadBuffer(LocalHdr, SizeOf(LocalHdr));
  904. Until LocalHdr.Signature = CENTRAL_FILE_HEADER_SIGNATURE;
  905. FOutFile.Seek(0,soFromEnd);
  906. FillChar(EndHdr,SizeOf(EndHdr),0);
  907. With EndHdr do
  908. begin
  909. Signature := END_OF_CENTRAL_DIR_SIGNATURE;
  910. Disk_Number := 0;
  911. Central_Dir_Start_Disk := 0;
  912. Entries_This_Disk := Entries;
  913. Total_Entries := Entries;
  914. Central_Dir_Size := FOutFile.Size-CenDirPos;
  915. Start_Disk_Offset := CenDirPos;
  916. ZipFile_Comment_Length := 0;
  917. FOutFile.WriteBuffer(EndHdr, SizeOf(EndHdr));
  918. end;
  919. end;
  920. Function TZipper.CreateCompressor(Item : TZipItem; AInFile,AZipStream : TStream) : TCompressor;
  921. begin
  922. Result:=TDeflater.Create(AinFile,AZipStream,FBufSize);
  923. end;
  924. Procedure TZipper.ZipOneFile(Item : TZipItem);
  925. Var
  926. CRC : LongWord;
  927. ZMethod : Word;
  928. ZipStream : TStream;
  929. TmpFileName : String;
  930. Begin
  931. OpenInput(Item.Path+Item.Name);
  932. Try
  933. StartZipFile(Item);
  934. If (FInfile.Size<=FInMemSize) then
  935. ZipStream:=TMemoryStream.Create
  936. else
  937. begin
  938. TmpFileName:=ChangeFileExt(FFileName,'.tmp');
  939. ZipStream:=TFileStream.Create(TmpFileName,fmCreate);
  940. end;
  941. Try
  942. With CreateCompressor(Item, FinFile,ZipStream) do
  943. Try
  944. OnProgress:=Self.OnProgress;
  945. OnPercent:=Self.OnPercent;
  946. Compress;
  947. CRC:=Crc32Val;
  948. ZMethod:=ZipID;
  949. Finally
  950. Free;
  951. end;
  952. If UpdateZipHeader(Item,ZipStream,CRC,ZMethod) then
  953. // Compressed file smaller than original file.
  954. FOutFile.CopyFrom(ZipStream,0)
  955. else
  956. begin
  957. // Original file smaller than compressed file.
  958. FInfile.Seek(0,soFromBeginning);
  959. FOutFile.CopyFrom(FInFile,0);
  960. end;
  961. finally
  962. ZipStream.Free;
  963. If (TmpFileName<>'') then
  964. DeleteFile(TmpFileName);
  965. end;
  966. Finally
  967. CloseInput;
  968. end;
  969. end;
  970. Procedure TZipper.ZipAllFiles;
  971. Var
  972. Item : TZipItem;
  973. I : Integer;
  974. filecnt : integer;
  975. Begin
  976. if FFiles.Count=0 then
  977. exit;
  978. FZipping:=True;
  979. Try
  980. GetFileInfo;
  981. OpenOutput;
  982. Try
  983. filecnt:=0;
  984. For I:=0 to FFiles.Count-1 do
  985. begin
  986. Item:=FFiles.Objects[i] as TZipItem;
  987. if assigned(Item) then
  988. begin
  989. ZipOneFile(Item);
  990. inc(filecnt);
  991. end;
  992. end;
  993. if filecnt>0 then
  994. BuildZipDirectory;
  995. finally
  996. CloseOutput;
  997. end;
  998. finally
  999. FZipping:=False;
  1000. end;
  1001. end;
  1002. Procedure TZipper.SetBufSize(Value : LongWord);
  1003. begin
  1004. If FZipping then
  1005. Raise EZipError.Create(SErrBufsizeChange);
  1006. If Value>=DefaultBufSize then
  1007. FBufSize:=Value;
  1008. end;
  1009. Procedure TZipper.SetFileName(Value : String);
  1010. begin
  1011. If FZipping then
  1012. Raise EZipError.Create(SErrFileChange);
  1013. FFileName:=Value;
  1014. end;
  1015. Procedure TZipper.ZipFiles(AFileName : String; FileList : TStrings);
  1016. begin
  1017. FFiles.Assign(FileList);
  1018. FFileName:=AFileName;
  1019. ZipAllFiles;
  1020. end;
  1021. Procedure TZipper.DoEndOfFile;
  1022. Var
  1023. ComprPct : Double;
  1024. begin
  1025. If (LocalHdr.Uncompressed_Size>0) then
  1026. ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
  1027. else
  1028. ComprPct := 0;
  1029. If Assigned(FOnEndOfFile) then
  1030. FOnEndOfFile(Self,ComprPct);
  1031. end;
  1032. Constructor TZipper.Create;
  1033. begin
  1034. FBufSize:=DefaultBufSize;
  1035. FInMemSize:=DefaultInMemSize;
  1036. FFiles:=TStringList.Create;
  1037. TStringlist(FFiles).Sorted:=True;
  1038. FOnPercent:=1;
  1039. end;
  1040. Procedure TZipper.Clear;
  1041. Var
  1042. I : Integer;
  1043. begin
  1044. For I:=0 to FFiles.Count-1 do
  1045. FFiles.Objects[i].Free;
  1046. FFiles.Clear;
  1047. end;
  1048. Destructor TZipper.Destroy;
  1049. begin
  1050. Clear;
  1051. FreeAndNil(FFiles);
  1052. Inherited;
  1053. end;
  1054. { ---------------------------------------------------------------------
  1055. TUnZipper
  1056. ---------------------------------------------------------------------}
  1057. Procedure TUnZipper.OpenInput;
  1058. Begin
  1059. FZipFile:=TFileStream.Create(FFileName,fmOpenRead);
  1060. End;
  1061. Function TUnZipper.OpenOutput(OutFileName : String) : Boolean;
  1062. Begin
  1063. FOutFile:=TFileStream.Create(OutFileName,fmCreate);
  1064. Result:=True;
  1065. If Assigned(FOnStartFile) then
  1066. FOnStartFile(Self,OutFileName);
  1067. End;
  1068. Procedure TUnZipper.CloseOutput;
  1069. Begin
  1070. FreeAndNil(FOutFile);
  1071. end;
  1072. Procedure TUnZipper.CloseInput;
  1073. Begin
  1074. FreeAndNil(FZipFile);
  1075. end;
  1076. Procedure TUnZipper.ReadZipHeader(Item : TZipItem; out ACRC : LongWord; out AMethod : Word);
  1077. Begin
  1078. FZipFile.Seek(Item.HdrPos,soFromBeginning);
  1079. FZipFile.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
  1080. With LocalHdr do
  1081. begin
  1082. SetLength(Item.Name,Filename_Length);
  1083. FZipFile.ReadBuffer(Item.Name[1],Filename_Length);
  1084. FZipFile.Seek(Extra_Field_Length,soCurrent);
  1085. Item.Size:=Uncompressed_Size;
  1086. ZipDateTimeToDateTime(Last_Mod_Date,Last_Mod_Time,Item.DateTime);
  1087. ACrc:=Crc32;
  1088. AMethod:=Compress_method;
  1089. end;
  1090. End;
  1091. Procedure TUnZipper.ReadZipDirectory;
  1092. Var
  1093. i,
  1094. EndHdrPos,
  1095. CenDirPos : LongInt;
  1096. NewNode : TZipItem;
  1097. Begin
  1098. EndHdrPos:=FZipFile.Size-SizeOf(EndHdr);
  1099. if EndHdrPos < 0 then
  1100. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1101. FZipFile.Seek(EndHdrPos,soFromBeginning);
  1102. FZipFile.ReadBuffer(EndHdr, SizeOf(EndHdr));
  1103. With EndHdr do
  1104. begin
  1105. if Signature <> END_OF_CENTRAL_DIR_SIGNATURE then
  1106. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1107. CenDirPos:=Start_Disk_Offset;
  1108. end;
  1109. FZipFile.Seek(CenDirPos,soFrombeginning);
  1110. for i:=0 to EndHdr.Entries_This_Disk-1 do
  1111. begin
  1112. FZipFile.ReadBuffer(CentralHdr, SizeOf(CentralHdr));
  1113. With CentralHdr do
  1114. begin
  1115. if Signature<>CENTRAL_FILE_HEADER_SIGNATURE then
  1116. raise EZipError.CreateFmt(SErrCorruptZIP,[FZipFile.FileName]);
  1117. NewNode:=TZipItem.Create;
  1118. NewNode.HdrPos := Local_Header_Offset;
  1119. SetLength(NewNode.Name,Filename_Length);
  1120. FZipFile.ReadBuffer(NewNode.Name[1],Filename_Length);
  1121. FZipFile.Seek(Extra_Field_Length+File_Comment_Length,soCurrent);
  1122. FZipEntries.Add(NewNode);
  1123. end;
  1124. end;
  1125. end;
  1126. Function TUnZipper.CreateDeCompressor(Item : TZipItem; AMethod : Word;AZipFile,AOutFile : TStream) : TDeCompressor;
  1127. begin
  1128. case AMethod of
  1129. 8 :
  1130. Result:=TInflater.Create(AZipFile,AOutFile,FBufSize);
  1131. else
  1132. raise EZipError.CreateFmt(SErrUnsupportedCompressionFormat,[AMethod]);
  1133. end;
  1134. end;
  1135. Procedure TUnZipper.UnZipOneFile(Item : TZipItem);
  1136. Var
  1137. Count : Longint;
  1138. CRC : LongWord;
  1139. ZMethod : Word;
  1140. OutputFileName : string;
  1141. Begin
  1142. Try
  1143. ReadZipHeader(Item,CRC,ZMethod);
  1144. OutputFileName:=Item.Name;
  1145. if FOutputPath<>'' then
  1146. OutputFileName:=IncludeTrailingPathDelimiter(FOutputPath)+OutputFileName;
  1147. OpenOutput(OutputFileName);
  1148. if ZMethod=0 then
  1149. begin
  1150. Count:=FOutFile.CopyFrom(FZipFile,LocalHdr.Compressed_Size);
  1151. {$warning TODO: Implement CRC Check}
  1152. end
  1153. else
  1154. With CreateDecompressor(Item, ZMethod, FZipFile, FOutFile) do
  1155. Try
  1156. OnProgress:=Self.OnProgress;
  1157. OnPercent:=Self.OnPercent;
  1158. DeCompress;
  1159. if CRC<>Crc32Val then
  1160. raise EZipError.CreateFmt(SErrInvalidCRC,[Item.Name]);
  1161. Finally
  1162. Free;
  1163. end;
  1164. Finally
  1165. CloseOutput;
  1166. end;
  1167. end;
  1168. Procedure TUnZipper.UnZipAllFiles;
  1169. Var
  1170. Item : TZipItem;
  1171. I : Integer;
  1172. Begin
  1173. FUnZipping:=True;
  1174. Try
  1175. OpenInput;
  1176. Try
  1177. ReadZipDirectory;
  1178. For I:=0 to FZipEntries.Count-1 do
  1179. begin
  1180. Item:=TZipItem(FZipEntries[i]);
  1181. if (FFiles=nil) or
  1182. (FFiles.IndexOf(Item.Name)<>-1) then
  1183. UnZipOneFile(Item);
  1184. end;
  1185. Finally
  1186. CloseInput;
  1187. end;
  1188. finally
  1189. FUnZipping:=False;
  1190. end;
  1191. end;
  1192. Procedure TUnZipper.SetBufSize(Value : LongWord);
  1193. begin
  1194. If FUnZipping then
  1195. Raise EZipError.Create(SErrBufsizeChange);
  1196. If Value>=DefaultBufSize then
  1197. FBufSize:=Value;
  1198. end;
  1199. Procedure TUnZipper.SetFileName(Value : String);
  1200. begin
  1201. If FUnZipping then
  1202. Raise EZipError.Create(SErrFileChange);
  1203. FFileName:=Value;
  1204. end;
  1205. Procedure TUnZipper.SetOutputPath(Value:String);
  1206. begin
  1207. If FUnZipping then
  1208. Raise EZipError.Create(SErrFileChange);
  1209. FOutputPath:=Value;
  1210. end;
  1211. Procedure TUnZipper.UnZipFiles(AFileName : String; FileList : TStrings);
  1212. begin
  1213. FFiles.Assign(FileList);
  1214. FFileName:=AFileName;
  1215. UnZipAllFiles;
  1216. end;
  1217. Procedure TUnZipper.UnZipAllFiles(AFileName : String);
  1218. begin
  1219. FFileName:=AFileName;
  1220. UnZipAllFiles;
  1221. end;
  1222. Procedure TUnZipper.DoEndOfFile;
  1223. Var
  1224. ComprPct : Double;
  1225. begin
  1226. If (LocalHdr.Uncompressed_Size>0) then
  1227. ComprPct := (100.0 * (LocalHdr.Uncompressed_Size - LocalHdr.Compressed_Size)) / LocalHdr.Uncompressed_Size
  1228. else
  1229. ComprPct := 0;
  1230. If Assigned(FOnEndOfFile) then
  1231. FOnEndOfFile(Self,ComprPct);
  1232. end;
  1233. Constructor TUnZipper.Create;
  1234. begin
  1235. FBufSize:=DefaultBufSize;
  1236. FFiles:=TStringList.Create;
  1237. FZipEntries:=TFPList.Create;
  1238. TStringlist(FFiles).Sorted:=True;
  1239. FOnPercent:=1;
  1240. end;
  1241. Procedure TUnZipper.Clear;
  1242. Var
  1243. I : Integer;
  1244. begin
  1245. For I:=0 to FFiles.Count-1 do
  1246. FFiles.Objects[i].Free;
  1247. FFiles.Clear;
  1248. For I:=0 to FZipEntries.Count-1 do
  1249. TZipItem(FZipEntries[i]).Free;
  1250. FZipEntries.Clear;
  1251. end;
  1252. Destructor TUnZipper.Destroy;
  1253. begin
  1254. Clear;
  1255. FreeAndNil(FFiles);
  1256. FreeAndNil(FZipEntries);
  1257. Inherited;
  1258. end;
  1259. End.