unzip.pas 95 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261
  1. UNIT Unzip;
  2. {
  3. Unzips deflated, imploded, shrunk and stored files
  4. ** COMPATIBLE WITH
  5. * Turbo Pascal v7.x (DOS)
  6. * Borland Pascal v7.x (Dos, DPMI, and Windows)
  7. * Delphi v1.x
  8. * Delphi v2.x
  9. * Delphi v3.x
  10. * Virtual Pascal v2.0 (Win32)
  11. }
  12. {
  13. Original version (1.x): Christian Ghisler
  14. C code by info-zip group, translated to pascal by Christian Ghisler
  15. based on unz51g.zip;
  16. Special thanks go to Mark Adler,who wrote the main inflate and
  17. explode code, and did NOT copyright it!!!
  18. v2.00: March 1998: Dr Abimbola Olowofoyeku (The African Chief)
  19. Homepage: http://ourworld.compuserve.com/homepages/African_Chief
  20. * modified to compile for Delphi v2.x and Delphi v3.x
  21. v2.01: April 1998: Dr Abimbola Olowofoyeku (The African Chief)
  22. * source files merged into a single source (this) file
  23. * several high level functions added - i.e.,
  24. FileUnzip()
  25. FileUnzipEx()
  26. ViewZip()
  27. UnzipSize()
  28. SetUnzipReportProc()
  29. SetUnzipQuestionProc()
  30. ChfUnzip_Init()
  31. * callbacks added
  32. * modified to support Virtual Pascal v2.0 (Win32)
  33. * Delphi component added (chfunzip.pas)
  34. }
  35. INTERFACE
  36. {$IFNDEF FPC}
  37. {$F+}
  38. {$ENDIF}
  39. {$R-} {No range checking}
  40. USES
  41. {$ifdef windows}
  42. wintypes,
  43. winprocs,
  44. {$ifdef Delphi}
  45. Messages,
  46. Sysutils,
  47. {$else Delphi}
  48. strings,
  49. windos,
  50. {$endif Delphi}
  51. {$else Windows}
  52. strings,
  53. crt,
  54. dos,
  55. {$endif Windows}
  56. ziptypes;
  57. {**********************************************************************}
  58. {**********************************************************************}
  59. {****** HIGH LEVEL FUNCTIONS: BY THE AFRICAN CHIEF ********************}
  60. {**********************************************************************}
  61. {**********************************************************************}
  62. FUNCTION FileUnzip
  63. ( SourceZipFile, TargetDirectory, FileSpecs : pChar;
  64. Report : UnzipReportProc;Question : UnzipQuestionProc ) : integer;
  65. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  66. {$ifdef DPMI} EXPORT; {$endif DPMI}
  67. {
  68. high level unzip
  69. usage:
  70. SourceZipFile: source zip file;
  71. TargetDirectory: target directory
  72. FileSpecs: "*.*", etc.
  73. Report: Report callback or Nil;
  74. Question: Question callback (for confirmation of whether to replace existing
  75. files) or Nil;
  76. * REFER to ZIPTYPES.PAS for information on callback functions
  77. e.g.,
  78. Count := FileUnzip('test.zip', 'c:\temp', '*.*', MyReportProc, Nil);
  79. }
  80. FUNCTION FileUnzipEx ( SourceZipFile, TargetDirectory, FileSpecs : pChar ) : integer;
  81. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  82. {$ifdef DPMI} EXPORT; {$endif DPMI}
  83. {
  84. high level unzip with no callback parameters;
  85. passes ZipReport & ZipQuestion internally, so you
  86. can use SetZipReportProc and SetZipQuestionProc before calling this;
  87. e.g.,
  88. Count := FileUnzipEx('test.zip', 'c:\temp', '*.*');
  89. }
  90. FUNCTION ViewZip ( SourceZipFile, FileSpecs : pChar; Report : UnzipReportProc ) : integer;
  91. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  92. {$ifdef DPMI} EXPORT; {$endif DPMI}
  93. {
  94. view contents of zip file
  95. usage:
  96. SourceZipFile: source zip file;
  97. FileSpecs: "*.*", etc.
  98. Report: callback procedure to process the reported contents of ZIP file;
  99. * REFER to ZIPTYPES.PAS for information on callback functions
  100. e.g.,
  101. ViewZip('test.zip', '*.*', MyReportProc);
  102. }
  103. FUNCTION SetUnZipReportProc ( aProc : UnzipReportProc ) : Pointer;
  104. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  105. {$ifdef DPMI} EXPORT; {$endif DPMI}
  106. {
  107. sets the internal unzip report procedure to aproc
  108. Returns: pointer to the original report procedure
  109. (return value should normally be ignored)
  110. e.g.,
  111. SetUnZipReportProc(MyReportProc);
  112. }
  113. FUNCTION SetUnZipQuestionProc ( aProc : UnzipQuestionProc ) : Pointer;
  114. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  115. {$ifdef DPMI} EXPORT; {$endif DPMI}
  116. {
  117. sets the internal unzip question procedure to aproc
  118. Returns: pointer to the original "question" procedure
  119. (return value should normally be ignored)
  120. e.g.,
  121. SetUnZipQuestionProc(QueryFileExistProc);
  122. }
  123. FUNCTION UnzipSize ( SourceZipFile : pChar;VAR Compressed : Longint ) : longint;
  124. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  125. {$ifdef DPMI} EXPORT; {$endif DPMI}
  126. { uncompressed and compressed zip size
  127. usage:
  128. SourceZipFile = the zip file
  129. Compressed = the compressed size of the files in the archive
  130. Returns: the uncompressed size of the ZIP archive
  131. e.g.,
  132. Var
  133. Size,CSize:longint;
  134. begin
  135. Size := UnzipSize('test.zip', CSize);
  136. end;
  137. }
  138. PROCEDURE ChfUnzip_Init;
  139. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  140. {$ifdef DPMI} EXPORT; {$endif DPMI}
  141. {
  142. initialise or reinitialise the shared data: !!! use with care !!!
  143. }
  144. FUNCTION SetNoRecurseDirs ( DontRecurse : Boolean ) : Boolean;
  145. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  146. {$ifdef DPMI} EXPORT; {$endif DPMI}
  147. {
  148. determine whether the UNZIP function should recreate
  149. the subdirectory structure;
  150. DontRecurse = TRUE : don't recurse
  151. DontRecurse = FALSE : recurse (default)
  152. }
  153. {**********************************************************************}
  154. {**********************************************************************}
  155. {************ LOW LEVEL FUNCTIONS: BY CHRISTIAN GHISLER ***************}
  156. {**********************************************************************}
  157. {**********************************************************************}
  158. FUNCTION GetSupportedMethods : longint;
  159. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  160. {$ifdef DPMI} EXPORT; {$endif DPMI}
  161. {Checks which pack methods are supported by the dll}
  162. {bit 8=1 -> Format 8 supported, etc.}
  163. FUNCTION UnzipFile ( in_name : pchar;out_name : pchar;offset : longint;hFileAction : word;cm_index : integer ) : integer;
  164. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  165. {$ifdef DPMI} EXPORT; {$endif DPMI}
  166. {usage:
  167. in_name: name of zip file with full path
  168. out_name: desired name for out file
  169. offset: header position of desired file in zipfile
  170. hFileAction: handle to dialog box showing advance of decompression (optional)
  171. cm_index: notification code sent in a wm_command message to the dialog
  172. to update percent-bar
  173. Return value: one of the above unzip_xxx codes
  174. Example for handling the cm_index message in a progress dialog:
  175. unzipfile(......,cm_showpercent);
  176. ...
  177. procedure TFileActionDialog.wmcommand(var msg:tmessage);
  178. var ppercent:^word;
  179. begin
  180. TDialog.WMCommand(msg);
  181. if msg.wparam=cm_showpercent then begin
  182. ppercent:=pointer(lparam);
  183. if ppercent<>nil then begin
  184. if (ppercent^>=0) and (ppercent^<=100) then
  185. SetProgressBar(ppercent^);
  186. if UserPressedAbort then
  187. ppercent^:=$ffff
  188. else
  189. ppercent^:=0;
  190. end;
  191. end;
  192. end;
  193. end;
  194. }
  195. FUNCTION GetFirstInZip ( zipfilename : pchar;VAR zprec : tZipRec ) : integer;
  196. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  197. {$ifdef DPMI} EXPORT; {$endif DPMI}
  198. {
  199. Get first entry from ZIP file
  200. e.g.,
  201. rc:=GetFirstInZip('test.zip', myZipRec);
  202. }
  203. FUNCTION GetNextInZip ( VAR Zprec : tZiprec ) : integer;
  204. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  205. {$ifdef DPMI} EXPORT; {$endif DPMI}
  206. {
  207. Get next entry from ZIP file
  208. e.g.,
  209. rc:=GetNextInZip(myZipRec);
  210. }
  211. FUNCTION IsZip ( filename : pchar ) : boolean;
  212. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  213. {$ifdef DPMI} EXPORT; {$endif DPMI}
  214. {
  215. VERY simple test for zip file
  216. e.g.,
  217. ItsaZipFile := IsZip('test.zip');
  218. }
  219. PROCEDURE CloseZipFile ( VAR Zprec : tZiprec ); {Only free buffer, file only open in Getfirstinzip}
  220. {$ifdef Windows}{$ifdef Win32}STDCALL;{$else}EXPORT;{$endif Win32}{$endif Windows}
  221. {$ifdef DPMI} EXPORT; {$endif DPMI}
  222. {
  223. free ZIP buffers
  224. e.g.,
  225. CloseZipFile(myZipRec);
  226. }
  227. IMPLEMENTATION
  228. VAR
  229. ZipReport : UnzipReportProc; {Global Status Report Callback}
  230. ZipQuestion : UnzipQuestionProc; {Global "Question" Callback}
  231. ZipRec : TReportRec; {Global ZIP record for callbacks}
  232. NoRecurseDirs : Boolean; {Global Recurse variable}
  233. {*************************************************************************}
  234. {$ifdef Delphi}
  235. PROCEDURE SetCurDir ( p : pChar );
  236. BEGIN
  237. Chdir ( strpas ( p ) );
  238. END;
  239. FUNCTION DosError : integer; {Delphi DosError kludge}
  240. BEGIN
  241. Result := Ioresult;
  242. END;
  243. FUNCTION SetFTime ( VAR f : File; CONST l : longint ) : integer;
  244. BEGIN
  245. {$ifdef Win32}Result := {$endif}FileSetDate ( TFileRec ( f ) .Handle, l );
  246. END;
  247. PROCEDURE CreateDir ( p : pchar );
  248. BEGIN
  249. mkdir ( strpas ( p ) );
  250. END;
  251. {/////////////////////////////////////////////////////////}
  252. {$endif Delphi}
  253. {.$I z_global.pas} {global constants, types and variables}
  254. {Include file for unzip.pas: global constants, types and variables}
  255. {C code by info-zip group, translated to pascal by Christian Ghisler}
  256. {based on unz51g.zip}
  257. CONST {Error codes returned by huft_build}
  258. huft_complete = 0; {Complete tree}
  259. huft_incomplete = 1; {Incomplete tree <- sufficient in some cases!}
  260. huft_error = 2; {bad tree constructed}
  261. huft_outofmem = 3; {not enough memory}
  262. MaxMax = {$ifdef Win32}256 * 1024 {Win32 = 256kb buffer}
  263. {$else}Maxint -1{$endif}; {16-bit = 32kb buffer}
  264. CONST wsize = $8000; {Size of sliding dictionary}
  265. INBUFSIZ = 1024 * 4; {Size of input buffer}
  266. CONST lbits : integer = 9;
  267. dbits : integer = 6;
  268. CONST b_max = 16;
  269. n_max = 288;
  270. BMAX = 16;
  271. TYPE push = ^ush;
  272. ush = word;
  273. pbyte = ^byte;
  274. pushlist = ^ushlist;
  275. ushlist = ARRAY [ 0..maxmax ] of ush; {only pseudo-size!!}
  276. pword = ^word;
  277. pwordarr = ^twordarr;
  278. twordarr = ARRAY [ 0..maxmax ] of word;
  279. iobuf = ARRAY [ 0..inbufsiz -1 ] of byte;
  280. TYPE pphuft = ^phuft;
  281. phuft = ^huft;
  282. phuftlist = ^huftlist;
  283. huft = PACKED RECORD
  284. e, {# of extra bits}
  285. b : byte; {# of bits in code}
  286. v_n : ush;
  287. v_t : phuftlist; {Linked List}
  288. END;
  289. huftlist = ARRAY [ 0..8190 ] of huft;
  290. TYPE li = PACKED RECORD
  291. lo, hi : word;
  292. END;
  293. {pkzip header in front of every file in archive}
  294. TYPE
  295. plocalheader = ^tlocalheader;
  296. tlocalheader = PACKED RECORD
  297. signature : ARRAY [ 0..3 ] of char; {'PK'#1#2}
  298. extract_ver,
  299. bit_flag,
  300. zip_type : word;
  301. file_timedate : longint;
  302. crc_32,
  303. compress_size,
  304. uncompress_size : longint;
  305. filename_len,
  306. extra_field_len : word;
  307. END;
  308. VAR slide : pchar; {Sliding dictionary for unzipping}
  309. inbuf : iobuf; {input buffer}
  310. inpos, readpos : integer; {position in input buffer, position read from file}
  311. dlghandle : word; {optional: handle of a cancel and "%-done"-dialog}
  312. dlgnotify : integer; {notification code to tell dialog how far the decompression is}
  313. VAR w : longint; {Current Position in slide}
  314. b : longint; {Bit Buffer}
  315. k : byte; {Bits in bit buffer}
  316. infile, {handle to zipfile}
  317. outfile : file; {handle to extracted file}
  318. compsize, {comressed size of file}
  319. reachedsize, {number of bytes read from zipfile}
  320. uncompsize : longint; {uncompressed size of file}
  321. oldpercent : integer; {last percent value shown}
  322. crc32val : longint; {crc calculated from data}
  323. hufttype : word; {coding type=bit_flag from header}
  324. totalabort, {User pressed abort button, set in showpercent!}
  325. zipeof : boolean; {read over end of zip section for this file}
  326. inuse : boolean; {is unit already in use -> don't call it again!!!}
  327. {$ifdef windows}
  328. lastusedtime : longint; {Time of last usage in timer ticks for timeout!}
  329. {$endif}
  330. (***************************************************************************)
  331. {.$I z_tables.pas} {Tables for bit masking, huffman codes and CRC checking}
  332. {include file for unzip.pas: Tables for bit masking, huffman codes and CRC checking}
  333. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  334. {based on unz51g.zip}
  335. {b and mask_bits[i] gets lower i bits out of i}
  336. CONST mask_bits : ARRAY [ 0..16 ] of word =
  337. ( $0000,
  338. $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff,
  339. $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff );
  340. { Tables for deflate from PKZIP's appnote.txt. }
  341. CONST border : ARRAY [ 0..18 ] of byte = { Order of the bit length code lengths }
  342. ( 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 );
  343. CONST cplens : ARRAY [ 0..30 ] of word = { Copy lengths for literal codes 257..285 }
  344. ( 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  345. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 );
  346. { note: see note #13 above about the 258 in this list.}
  347. CONST cplext : ARRAY [ 0..30 ] of word = { Extra bits for literal codes 257..285 }
  348. ( 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2,
  349. 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99 ); { 99==invalid }
  350. CONST cpdist : ARRAY [ 0..29 ] of word = { Copy offsets for distance codes 0..29 }
  351. ( 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  352. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  353. 8193, 12289, 16385, 24577 );
  354. CONST cpdext : ARRAY [ 0..29 ] of word = { Extra bits for distance codes }
  355. ( 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6,
  356. 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
  357. 12, 12, 13, 13 );
  358. { Tables for explode }
  359. CONST cplen2 : ARRAY [ 0..63 ] of word = ( 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
  360. 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
  361. 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,
  362. 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65 );
  363. CONST cplen3 : ARRAY [ 0..63 ] of word = ( 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
  364. 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35,
  365. 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52,
  366. 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66 );
  367. CONST extra : ARRAY [ 0..63 ] of word = ( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  368. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  369. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  370. 8 );
  371. CONST cpdist4 : ARRAY [ 0..63 ] of word = ( 1, 65, 129, 193, 257, 321, 385, 449, 513, 577, 641, 705,
  372. 769, 833, 897, 961, 1025, 1089, 1153, 1217, 1281, 1345, 1409, 1473,
  373. 1537, 1601, 1665, 1729, 1793, 1857, 1921, 1985, 2049, 2113, 2177,
  374. 2241, 2305, 2369, 2433, 2497, 2561, 2625, 2689, 2753, 2817, 2881,
  375. 2945, 3009, 3073, 3137, 3201, 3265, 3329, 3393, 3457, 3521, 3585,
  376. 3649, 3713, 3777, 3841, 3905, 3969, 4033 );
  377. CONST cpdist8 : ARRAY [ 0..63 ] of word = ( 1, 129, 257, 385, 513, 641, 769, 897, 1025, 1153, 1281,
  378. 1409, 1537, 1665, 1793, 1921, 2049, 2177, 2305, 2433, 2561, 2689,
  379. 2817, 2945, 3073, 3201, 3329, 3457, 3585, 3713, 3841, 3969, 4097,
  380. 4225, 4353, 4481, 4609, 4737, 4865, 4993, 5121, 5249, 5377, 5505,
  381. 5633, 5761, 5889, 6017, 6145, 6273, 6401, 6529, 6657, 6785, 6913,
  382. 7041, 7169, 7297, 7425, 7553, 7681, 7809, 7937, 8065 );
  383. {************************************ CRC-Calculation ************************************}
  384. CONST crc_32_tab : ARRAY [ 0..255 ] of longint =
  385. (
  386. $00000000, $77073096, $ee0e612c, $990951ba, $076dc419,
  387. $706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4,
  388. $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07,
  389. $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de,
  390. $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856,
  391. $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9,
  392. $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4,
  393. $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b,
  394. $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3,
  395. $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a,
  396. $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599,
  397. $b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924,
  398. $2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190,
  399. $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f,
  400. $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e,
  401. $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01,
  402. $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed,
  403. $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950,
  404. $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3,
  405. $fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2,
  406. $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a,
  407. $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5,
  408. $aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010,
  409. $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f,
  410. $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17,
  411. $2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6,
  412. $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615,
  413. $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8,
  414. $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344,
  415. $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb,
  416. $196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a,
  417. $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5,
  418. $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1,
  419. $a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c,
  420. $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef,
  421. $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236,
  422. $cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe,
  423. $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31,
  424. $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c,
  425. $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713,
  426. $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b,
  427. $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242,
  428. $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1,
  429. $18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c,
  430. $8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278,
  431. $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7,
  432. $4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66,
  433. $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9,
  434. $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605,
  435. $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8,
  436. $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b,
  437. $2d02ef8d ); { end crc_32_tab[] }
  438. (***************************************************************************)
  439. {.$I z_generl.pas} {General functions used by both inflate and explode}
  440. {include for unzip.pas: General functions used by both inflate and explode}
  441. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  442. {based on unz51g.zip}
  443. {*********************************** CRC Checking ********************************}
  444. PROCEDURE UpdateCRC ( VAR s : iobuf;len : word );
  445. VAR i : word;
  446. BEGIN
  447. {$ifndef assembler}
  448. FOR i := 0 TO Pred ( len ) DO BEGIN
  449. { update running CRC calculation with contents of a buffer }
  450. crc32val := crc_32_tab [ ( byte ( crc32val ) XOR s [ i ] ) AND $ff ] XOR ( crc32val SHR 8 );
  451. END;
  452. {$else}
  453. ASM
  454. les di, s
  455. mov ax, li.lo ( crc32val )
  456. mov dx, li.hi ( crc32val )
  457. mov si, offset crc_32_tab {Segment remains DS!!!}
  458. mov cx, len
  459. OR cx, cx
  460. jz @finished
  461. @again :
  462. mov bl, al {byte(crcval)}
  463. mov al, ah {shift DX:AX by 8 bits to the right}
  464. mov ah, dl
  465. mov dl, dh
  466. XOR dh, dh
  467. XOR bh, bh
  468. XOR bl, es : [ di ] {xor s^}
  469. inc di
  470. SHL bx, 1 {Offset: Index*4}
  471. SHL bx, 1
  472. XOR ax, [ si + bx ]
  473. XOR dx, [ si + bx + 2 ]
  474. dec cx
  475. jnz @again
  476. @finished :
  477. mov li.lo ( crc32val ), ax
  478. mov li.hi ( crc32val ), dx
  479. END;
  480. {$endif}
  481. END;
  482. {************************ keep other programs running ***************************}
  483. PROCEDURE messageloop;
  484. {$ifdef windows}
  485. VAR msg : tmsg;
  486. BEGIN
  487. lastusedtime := gettickcount;
  488. WHILE PeekMessage ( Msg, 0, 0, 0, PM_Remove ) DO
  489. IF ( dlghandle = 0 ) OR NOT IsDialogMessage ( dlghandle, msg ) THEN BEGIN
  490. TranslateMessage ( Msg );
  491. DispatchMessage ( Msg );
  492. END;
  493. END;
  494. {$else}
  495. VAR ch : word;
  496. BEGIN
  497. IF keypressed THEN BEGIN
  498. ch := byte ( readkey );
  499. IF ch = 0 THEN ch := 256 + byte ( readkey ); {Extended code}
  500. IF ch = dlgnotify THEN totalabort := TRUE;
  501. END
  502. END;
  503. {$endif}
  504. {************************* tell dialog to show % ******************************}
  505. {$ifdef windows}
  506. PROCEDURE showpercent; {use this with the low level functions only !!!}
  507. VAR percent : word;
  508. BEGIN
  509. IF compsize <> 0 THEN BEGIN
  510. percent := reachedsize * 100 DIV compsize;
  511. IF percent > 100 THEN percent := 100;
  512. IF ( percent <> oldpercent ) THEN BEGIN
  513. oldpercent := percent;
  514. IF dlghandle <> 0 THEN BEGIN {Use dialog box for aborting}
  515. {Sendmessage returns directly -> ppercent contains result}
  516. sendmessage ( dlghandle, wm_command, dlgnotify, longint ( @percent ) );
  517. totalabort := ( percent = $FFFF ); {Abort pressed!}
  518. END ELSE
  519. IF dlgnotify <> 0 THEN
  520. totalabort := getasynckeystate ( dlgnotify ) < 0; {break Key pressed!}
  521. END;
  522. END;
  523. END;
  524. {$endif}
  525. {************************** fill inbuf from infile *********************}
  526. PROCEDURE readbuf;
  527. BEGIN
  528. IF reachedsize > compsize + 2 THEN BEGIN {+2: last code is smaller than requested!}
  529. readpos := sizeof ( inbuf ); {Simulates reading -> no blocking}
  530. zipeof := TRUE
  531. END ELSE BEGIN
  532. messageloop; {Other programs, or in DOS: keypressed?}
  533. {$ifdef windows}
  534. showpercent; {Before, because it shows the data processed, not read!}
  535. {$endif}
  536. {$I-}
  537. blockread ( infile, inbuf, sizeof ( inbuf ), readpos );
  538. {$I+}
  539. IF ( ioresult <> 0 ) OR ( readpos = 0 ) THEN BEGIN {readpos=0: kein Fehler gemeldet!!!}
  540. readpos := sizeof ( inbuf ); {Simulates reading -> CRC error}
  541. zipeof := TRUE;
  542. END;
  543. inc ( reachedsize, readpos );
  544. dec ( readpos ); {Reason: index of inbuf starts at 0}
  545. END;
  546. inpos := 0;
  547. END;
  548. {**** read byte, only used by explode ****}
  549. PROCEDURE READBYTE ( VAR bt : byte );
  550. BEGIN
  551. IF inpos > readpos THEN readbuf;
  552. bt := inbuf [ inpos ];
  553. inc ( inpos );
  554. END;
  555. {*********** read at least n bits into the global variable b *************}
  556. PROCEDURE NEEDBITS ( n : byte );
  557. VAR nb : longint;
  558. BEGIN
  559. {$ifndef assembler}
  560. WHILE k < n DO BEGIN
  561. IF inpos > readpos THEN readbuf;
  562. nb := inbuf [ inpos ];
  563. inc ( inpos );
  564. b := b OR nb SHL k;
  565. inc ( k, 8 );
  566. END;
  567. {$else}
  568. ASM
  569. mov si, offset inbuf
  570. mov ch, n
  571. mov cl, k
  572. mov bx, inpos {bx=inpos}
  573. @again :
  574. cmp cl, ch
  575. JAE @finished {k>=n -> finished}
  576. cmp bx, readpos
  577. jg @readbuf
  578. @fullbuf :
  579. mov al, [ si + bx ] {dx:ax=nb}
  580. XOR ah, ah
  581. XOR dx, dx
  582. cmp cl, 8 {cl>=8 -> shift into DX or directly by 1 byte}
  583. JAE @bigger8
  584. SHL ax, cl {Normal shifting!}
  585. jmp @continue
  586. @bigger8 :
  587. mov di, cx {save cx}
  588. mov ah, al {shift by 8}
  589. XOR al, al
  590. sub cl, 8 {8 bits shifted}
  591. @rotate :
  592. OR cl, cl
  593. jz @continue1 {all shifted -> finished}
  594. SHL ah, 1 {al ist empty!}
  595. rcl dx, 1
  596. dec cl
  597. jmp @rotate
  598. @continue1 :
  599. mov cx, di
  600. @continue :
  601. OR li.hi ( b ), dx {b=b or nb shl k}
  602. OR li.lo ( b ), ax
  603. inc bx {inpos}
  604. add cl, 8 {inc k by 8 Bits}
  605. jmp @again
  606. @readbuf :
  607. push si
  608. push cx
  609. call readbuf {readbuf not critical, called only every 2000 bytes}
  610. pop cx
  611. pop si
  612. mov bx, inpos {New inpos}
  613. jmp @fullbuf
  614. @finished :
  615. mov k, cl
  616. mov inpos, bx
  617. END;
  618. {$endif}
  619. END;
  620. {***************** dump n bits no longer needed from global variable b *************}
  621. PROCEDURE DUMPBITS ( n : byte );
  622. BEGIN
  623. {$ifndef assembler}
  624. b := b SHR n;
  625. k := k -n;
  626. {$else}
  627. ASM
  628. mov cl, n
  629. mov ax, li.lo ( b )
  630. mov dx, li.hi ( b )
  631. mov ch, cl
  632. OR ch, ch
  633. jz @finished
  634. @rotate :
  635. SHR dx, 1 {Lower Bit in Carry}
  636. rcr ax, 1
  637. dec ch
  638. jnz @rotate
  639. @finished :
  640. mov li.lo ( b ), ax
  641. mov li.hi ( b ), dx
  642. sub k, cl
  643. END;
  644. {$endif}
  645. END;
  646. {********************* Flush w bytes directly from slide to file ******************}
  647. FUNCTION flush ( w : word ) : boolean;
  648. VAR n : nword; {True wenn OK}
  649. b : boolean;
  650. BEGIN
  651. {$I-}
  652. blockwrite ( outfile, slide [ 0 ], w, n );
  653. {$I+}
  654. b := ( n = w ) AND ( ioresult = 0 ); {True-> alles ok}
  655. UpdateCRC ( iobuf ( pointer ( @slide [ 0 ] ) ^ ), w );
  656. {--}
  657. IF ( b = TRUE ) AND ( @ZipReport <> NIL ) {callback report for high level functions}
  658. THEN BEGIN
  659. WITH ZipRec DO BEGIN
  660. Status := file_unzipping;
  661. ZipReport ( n, @ZipRec ); {report the actual bytes written}
  662. END;
  663. END; {report}
  664. flush := b;
  665. END;
  666. {******************************* Break string into tokens ****************************}
  667. VAR
  668. _Token : PChar;
  669. FUNCTION StrTok ( Source : PChar; Token : CHAR ) : PChar;
  670. VAR P : PChar;
  671. BEGIN
  672. IF Source <> NIL THEN _Token := Source;
  673. IF _Token = NIL THEN BEGIN
  674. strTok := NIL;
  675. exit
  676. END;
  677. P := StrScan ( _Token, Token );
  678. StrTok := _Token;
  679. IF P <> NIL THEN BEGIN
  680. P^ := #0;
  681. Inc ( P );
  682. END;
  683. _Token := P;
  684. END;
  685. (***************************************************************************)
  686. {.$I z_huft.pas} {Huffman tree generating and destroying}
  687. {include for unzip.pas: Huffman tree generating and destroying}
  688. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  689. {based on unz51g.zip}
  690. {*************** free huffman tables starting with table where t points to ************}
  691. PROCEDURE huft_free ( t : phuftlist );
  692. VAR p, q : phuftlist;
  693. z : integer;
  694. BEGIN
  695. p := pointer ( t );
  696. WHILE p <> NIL DO BEGIN
  697. dec ( longint ( p ), sizeof ( huft ) );
  698. q := p^ [ 0 ].v_t;
  699. z := p^ [ 0 ].v_n; {Size in Bytes, required by TP ***}
  700. freemem ( p, ( z + 1 ) * sizeof ( huft ) );
  701. p := q
  702. END;
  703. END;
  704. {*********** build huffman table from code lengths given by array b^ *******************}
  705. FUNCTION huft_build ( b : pword;n : word;s : word;d, e : pushlist;t : pphuft;VAR m : integer ) : integer;
  706. VAR a : word; {counter for codes of length k}
  707. c : ARRAY [ 0..b_max + 1 ] of word; {bit length count table}
  708. f : word; {i repeats in table every f entries}
  709. g, {max. code length}
  710. h : integer; {table level}
  711. i, {counter, current code}
  712. j : word; {counter}
  713. k : integer; {number of bits in current code}
  714. p : pword; {pointer into c, b and v}
  715. q : phuftlist; {points to current table}
  716. r : huft; {table entry for structure assignment}
  717. u : ARRAY [ 0..b_max ] of phuftlist;{table stack}
  718. v : ARRAY [ 0..n_max ] of word; {values in order of bit length}
  719. w : integer; {bits before this table}
  720. x : ARRAY [ 0..b_max + 1 ] of word; {bit offsets, then code stack}
  721. l : ARRAY [ -1..b_max + 1 ] of word; {l[h] bits in table of level h}
  722. xp : ^word; {pointer into x}
  723. y : integer; {number of dummy codes added}
  724. z : word; {number of entries in current table}
  725. tryagain : boolean; {bool for loop}
  726. pt : phuft; {for test against bad input}
  727. el : word; {length of eob code=code 256}
  728. BEGIN
  729. IF n > 256 THEN el := pword ( longint ( b ) + 256 * sizeof ( word ) ) ^
  730. ELSE el := BMAX;
  731. {generate counts for each bit length}
  732. fillchar ( c, sizeof ( c ), #0 );
  733. p := b; i := n; {p points to array of word}
  734. REPEAT
  735. IF p^ > b_max THEN BEGIN
  736. t^ := NIL;
  737. m := 0;
  738. huft_build := huft_error;
  739. exit
  740. END;
  741. inc ( c [ p^ ] );
  742. inc ( longint ( p ), sizeof ( word ) ); {point to next item}
  743. dec ( i );
  744. UNTIL i = 0;
  745. IF c [ 0 ] = n THEN BEGIN
  746. t^ := NIL;
  747. m := 0;
  748. huft_build := huft_complete;
  749. exit
  750. END;
  751. {find minimum and maximum length, bound m by those}
  752. j := 1;
  753. WHILE ( j <= b_max ) AND ( c [ j ] = 0 ) DO inc ( j );
  754. k := j;
  755. IF m < j THEN m := j;
  756. i := b_max;
  757. WHILE ( i > 0 ) AND ( c [ i ] = 0 ) DO dec ( i );
  758. g := i;
  759. IF m > i THEN m := i;
  760. {adjust last length count to fill out codes, if needed}
  761. y := 1 SHL j;
  762. WHILE j < i DO BEGIN
  763. y := y -c [ j ];
  764. IF y < 0 THEN BEGIN
  765. huft_build := huft_error;
  766. exit
  767. END;
  768. y := y SHL 1;
  769. inc ( j );
  770. END;
  771. dec ( y, c [ i ] );
  772. IF y < 0 THEN BEGIN
  773. huft_build := huft_error;
  774. exit
  775. END;
  776. inc ( c [ i ], y );
  777. {generate starting offsets into the value table for each length}
  778. x [ 1 ] := 0;
  779. j := 0;
  780. p := @c; inc ( longint ( p ), sizeof ( word ) );
  781. xp := @x;inc ( longint ( xp ), 2 * sizeof ( word ) );
  782. dec ( i );
  783. WHILE i <> 0 DO BEGIN
  784. inc ( j, p^ );
  785. xp^ := j;
  786. inc ( longint ( p ), 2 );
  787. inc ( longint ( xp ), 2 );
  788. dec ( i );
  789. END;
  790. {make table of values in order of bit length}
  791. p := b; i := 0;
  792. REPEAT
  793. j := p^;
  794. inc ( longint ( p ), sizeof ( word ) );
  795. IF j <> 0 THEN BEGIN
  796. v [ x [ j ] ] := i;
  797. inc ( x [ j ] );
  798. END;
  799. inc ( i );
  800. UNTIL i >= n;
  801. {generate huffman codes and for each, make the table entries}
  802. x [ 0 ] := 0; i := 0;
  803. p := @v;
  804. h := -1;
  805. l [ -1 ] := 0;
  806. w := 0;
  807. u [ 0 ] := NIL;
  808. q := NIL;
  809. z := 0;
  810. {go through the bit lengths (k already is bits in shortest code)}
  811. FOR k := k TO g DO BEGIN
  812. FOR a := c [ k ] DOWNTO 1 DO BEGIN
  813. {here i is the huffman code of length k bits for value p^}
  814. WHILE k > w + l [ h ] DO BEGIN
  815. inc ( w, l [ h ] ); {Length of tables to this position}
  816. inc ( h );
  817. z := g -w;
  818. IF z > m THEN z := m;
  819. j := k -w;
  820. f := 1 SHL j;
  821. IF f > a + 1 THEN BEGIN
  822. dec ( f, a + 1 );
  823. xp := @c [ k ];
  824. inc ( j );
  825. tryagain := TRUE;
  826. WHILE ( j < z ) AND tryagain DO BEGIN
  827. f := f SHL 1;
  828. inc ( longint ( xp ), sizeof ( word ) );
  829. IF f <= xp^ THEN tryagain := FALSE
  830. ELSE BEGIN
  831. dec ( f, xp^ );
  832. inc ( j );
  833. END;
  834. END;
  835. END;
  836. IF ( w + j > el ) AND ( w < el ) THEN
  837. j := el -w; {Make eob code end at table}
  838. IF w = 0 THEN BEGIN
  839. j := m; {*** Fix: main table always m bits!}
  840. END;
  841. z := 1 SHL j;
  842. l [ h ] := j;
  843. {allocate and link new table}
  844. getmem ( q, ( z + 1 ) * sizeof ( huft ) );
  845. IF q = NIL THEN BEGIN
  846. IF h <> 0 THEN huft_free ( pointer ( u [ 0 ] ) );
  847. huft_build := huft_outofmem;
  848. exit
  849. END;
  850. fillchar ( q^, ( z + 1 ) * sizeof ( huft ), #0 );
  851. q^ [ 0 ].v_n := z; {Size of table, needed in freemem ***}
  852. t^ := @q^ [ 1 ]; {first item starts at 1}
  853. t := @q^ [ 0 ].v_t;
  854. t^ := NIL;
  855. q := @q^ [ 1 ]; {pointer(longint(q)+sizeof(huft));} {???}
  856. u [ h ] := q;
  857. {connect to last table, if there is one}
  858. IF h <> 0 THEN BEGIN
  859. x [ h ] := i;
  860. r.b := l [ h -1 ];
  861. r.e := 16 + j;
  862. r.v_t := q;
  863. j := ( i AND ( ( 1 SHL w ) -1 ) ) SHR ( w -l [ h -1 ] );
  864. {test against bad input!}
  865. pt := phuft ( longint ( u [ h -1 ] ) -sizeof ( huft ) );
  866. IF j > pt^.v_n THEN BEGIN
  867. huft_free ( pointer ( u [ 0 ] ) );
  868. huft_build := huft_error;
  869. exit
  870. END;
  871. pt := @u [ h -1 ]^ [ j ];
  872. pt^ := r;
  873. END;
  874. END;
  875. {set up table entry in r}
  876. r.b := word ( k -w );
  877. r.v_t := NIL; {Unused} {***********}
  878. IF longint ( p ) >= longint ( @v [ n ] ) THEN r.e := 99
  879. ELSE IF p^ < s THEN BEGIN
  880. IF p^ < 256 THEN r.e := 16 ELSE r.e := 15;
  881. r.v_n := p^;
  882. inc ( longint ( p ), sizeof ( word ) );
  883. END ELSE BEGIN
  884. IF ( d = NIL ) OR ( e = NIL ) THEN BEGIN
  885. huft_free ( pointer ( u [ 0 ] ) );
  886. huft_build := huft_error;
  887. exit
  888. END;
  889. r.e := word ( e^ [ p^ -s ] );
  890. r.v_n := d^ [ p^ -s ];
  891. inc ( longint ( p ), sizeof ( word ) );
  892. END;
  893. {fill code like entries with r}
  894. f := 1 SHL ( k -w );
  895. j := i SHR w;
  896. WHILE j < z DO BEGIN
  897. q^ [ j ] := r;
  898. inc ( j, f );
  899. END;
  900. {backwards increment the k-bit code i}
  901. j := 1 SHL ( k -1 );
  902. WHILE ( i AND j ) <> 0 DO BEGIN
  903. {i:=i^j;}
  904. i := i XOR j;
  905. j := j SHR 1;
  906. END;
  907. i := i XOR j;
  908. {backup over finished tables}
  909. WHILE ( ( i AND ( ( 1 SHL w ) -1 ) ) <> x [ h ] ) DO BEGIN
  910. dec ( h );
  911. dec ( w, l [ h ] ); {Size of previous table!}
  912. END;
  913. END;
  914. END;
  915. IF ( y <> 0 ) AND ( g <> 1 ) THEN huft_build := huft_incomplete
  916. ELSE huft_build := huft_complete;
  917. END;
  918. (***************************************************************************)
  919. {.$I z_inflat.pas} {Inflate deflated file}
  920. {include for unzip.pas: Inflate deflated file}
  921. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  922. {based on unz51g.zip}
  923. FUNCTION inflate_codes ( tl, td : phuftlist;bl, bd : integer ) : integer;
  924. VAR
  925. n, d, e1, {length and index for copy}
  926. ml, md : longint; {masks for bl and bd bits}
  927. t : phuft; {pointer to table entry}
  928. e : byte; {table entry flag/number of extra bits}
  929. BEGIN
  930. { inflate the coded data }
  931. ml := mask_bits [ bl ]; {precompute masks for speed}
  932. md := mask_bits [ bd ];
  933. WHILE NOT ( totalabort OR zipeof ) DO BEGIN
  934. NEEDBITS ( bl );
  935. t := @tl^ [ b AND ml ];
  936. e := t^.e;
  937. IF e > 16 THEN REPEAT {then it's a literal}
  938. IF e = 99 THEN BEGIN
  939. inflate_codes := unzip_ZipFileErr;
  940. exit
  941. END;
  942. DUMPBITS ( t^.b );
  943. dec ( e, 16 );
  944. NEEDBITS ( e );
  945. t := @t^.v_t^ [ b AND mask_bits [ e ] ];
  946. e := t^.e;
  947. UNTIL e <= 16;
  948. DUMPBITS ( t^.b );
  949. IF e = 16 THEN BEGIN
  950. slide [ w ] := char ( t^.v_n );
  951. inc ( w );
  952. IF w = WSIZE THEN BEGIN
  953. IF NOT flush ( w ) THEN BEGIN
  954. inflate_codes := unzip_WriteErr;
  955. exit;
  956. END;
  957. w := 0
  958. END;
  959. END ELSE BEGIN {it's an EOB or a length}
  960. IF e = 15 THEN BEGIN {Ende} {exit if end of block}
  961. inflate_codes := unzip_Ok;
  962. exit;
  963. END;
  964. NEEDBITS ( e ); {get length of block to copy}
  965. n := t^.v_n + ( b AND mask_bits [ e ] );
  966. DUMPBITS ( e );
  967. NEEDBITS ( bd ); {decode distance of block to copy}
  968. t := @td^ [ b AND md ];
  969. e := t^.e;
  970. IF e > 16 THEN REPEAT
  971. IF e = 99 THEN BEGIN
  972. inflate_codes := unzip_ZipFileErr;
  973. exit
  974. END;
  975. DUMPBITS ( t^.b );
  976. dec ( e, 16 );
  977. NEEDBITS ( e );
  978. t := @t^.v_t^ [ b AND mask_bits [ e ] ];
  979. e := t^.e;
  980. UNTIL e <= 16;
  981. DUMPBITS ( t^.b );
  982. NEEDBITS ( e );
  983. d := w -t^.v_n -b AND mask_bits [ e ];
  984. DUMPBITS ( e );
  985. {do the copy}
  986. REPEAT
  987. d := d AND ( WSIZE -1 );
  988. IF d > w THEN e1 := WSIZE -d
  989. ELSE e1 := WSIZE -w;
  990. IF e1 > n THEN e1 := n;
  991. dec ( n, e1 );
  992. IF ( longint(w) -d >= e1 ) THEN BEGIN
  993. move ( slide [ d ], slide [ w ], e1 );
  994. inc ( w, e1 );
  995. inc ( d, e1 );
  996. END ELSE REPEAT
  997. slide [ w ] := slide [ d ];
  998. inc ( w );
  999. inc ( d );
  1000. dec ( e1 );
  1001. UNTIL ( e1 = 0 );
  1002. IF w = WSIZE THEN BEGIN
  1003. IF NOT flush ( w ) THEN BEGIN
  1004. inflate_codes := unzip_WriteErr;
  1005. exit;
  1006. END;
  1007. w := 0;
  1008. END;
  1009. UNTIL n = 0;
  1010. END;
  1011. END;
  1012. IF totalabort THEN
  1013. inflate_codes := unzip_userabort
  1014. ELSE
  1015. inflate_codes := unzip_readErr;
  1016. END;
  1017. {**************************** "decompress" stored block **************************}
  1018. FUNCTION inflate_stored : integer;
  1019. VAR n : word; {number of bytes in block}
  1020. BEGIN
  1021. {go to byte boundary}
  1022. n := k AND 7;
  1023. dumpbits ( n );
  1024. {get the length and its complement}
  1025. NEEDBITS ( 16 );
  1026. n := b AND $ffff;
  1027. DUMPBITS ( 16 );
  1028. NEEDBITS ( 16 );
  1029. IF ( n <> ( NOT b ) AND $ffff ) THEN BEGIN
  1030. inflate_stored := unzip_zipFileErr;
  1031. exit
  1032. END;
  1033. DUMPBITS ( 16 );
  1034. WHILE ( n > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN {read and output the compressed data}
  1035. dec ( n );
  1036. NEEDBITS ( 8 );
  1037. slide [ w ] := char ( b );
  1038. inc ( w );
  1039. IF w = WSIZE THEN BEGIN
  1040. IF NOT flush ( w ) THEN BEGIN
  1041. inflate_stored := unzip_WriteErr;
  1042. exit
  1043. END;
  1044. w := 0;
  1045. END;
  1046. DUMPBITS ( 8 );
  1047. END;
  1048. IF totalabort THEN inflate_stored := unzip_UserAbort
  1049. ELSE IF zipeof THEN inflate_stored := unzip_readErr
  1050. ELSE inflate_stored := unzip_Ok;
  1051. END;
  1052. {**************************** decompress fixed block **************************}
  1053. FUNCTION inflate_fixed : integer;
  1054. VAR i : integer; {temporary variable}
  1055. tl, {literal/length code table}
  1056. td : phuftlist; {distance code table}
  1057. bl, bd : integer; {lookup bits for tl/bd}
  1058. l : ARRAY [ 0..287 ] of word; {length list for huft_build}
  1059. BEGIN
  1060. {set up literal table}
  1061. FOR i := 0 TO 143 DO l [ i ] := 8;
  1062. FOR i := 144 TO 255 DO l [ i ] := 9;
  1063. FOR i := 256 TO 279 DO l [ i ] := 7;
  1064. FOR i := 280 TO 287 DO l [ i ] := 8; {make a complete, but wrong code set}
  1065. bl := 7;
  1066. i := huft_build ( pword ( @l ), 288, 257, pushlist ( @cplens ), pushlist ( @cplext ), @tl, bl );
  1067. IF i <> huft_complete THEN BEGIN
  1068. inflate_fixed := i;
  1069. exit
  1070. END;
  1071. FOR i := 0 TO 29 DO l [ i ] := 5; {make an incomplete code set}
  1072. bd := 5;
  1073. i := huft_build ( pword ( @l ), 30, 0, pushlist ( @cpdist ), pushlist ( @cpdext ), @td, bd );
  1074. IF i > huft_incomplete THEN BEGIN
  1075. huft_free ( tl );
  1076. inflate_fixed := unzip_ZipFileErr;
  1077. exit
  1078. END;
  1079. inflate_fixed := inflate_codes ( tl, td, bl, bd );
  1080. huft_free ( tl );
  1081. huft_free ( td );
  1082. END;
  1083. {**************************** decompress dynamic block **************************}
  1084. FUNCTION inflate_dynamic : integer;
  1085. VAR i : integer; {temporary variables}
  1086. j,
  1087. l, {last length}
  1088. m, {mask for bit length table}
  1089. n : word; {number of lengths to get}
  1090. tl, {literal/length code table}
  1091. td : phuftlist; {distance code table}
  1092. bl, bd : integer; {lookup bits for tl/bd}
  1093. nb, nl, nd : word; {number of bit length/literal length/distance codes}
  1094. ll : ARRAY [ 0..288 + 32 -1 ] of word; {literal/length and distance code lengths}
  1095. BEGIN
  1096. {read in table lengths}
  1097. NEEDBITS ( 5 );
  1098. nl := 257 + word ( b ) AND $1f;
  1099. DUMPBITS ( 5 );
  1100. NEEDBITS ( 5 );
  1101. nd := 1 + word ( b ) AND $1f;
  1102. DUMPBITS ( 5 );
  1103. NEEDBITS ( 4 );
  1104. nb := 4 + word ( b ) AND $f;
  1105. DUMPBITS ( 4 );
  1106. IF ( nl > 288 ) OR ( nd > 32 ) THEN BEGIN
  1107. inflate_dynamic := 1;
  1108. exit
  1109. END;
  1110. fillchar ( ll, sizeof ( ll ), #0 );
  1111. {read in bit-length-code lengths}
  1112. FOR j := 0 TO nb -1 DO BEGIN
  1113. NEEDBITS ( 3 );
  1114. ll [ border [ j ] ] := b AND 7;
  1115. DUMPBITS ( 3 );
  1116. END;
  1117. FOR j := nb TO 18 DO ll [ border [ j ] ] := 0;
  1118. {build decoding table for trees--single level, 7 bit lookup}
  1119. bl := 7;
  1120. i := huft_build ( pword ( @ll ), 19, 19, NIL, NIL, @tl, bl );
  1121. IF i <> huft_complete THEN BEGIN
  1122. IF i = huft_incomplete THEN huft_free ( tl ); {other errors: already freed}
  1123. inflate_dynamic := unzip_ZipFileErr;
  1124. exit
  1125. END;
  1126. {read in literal and distance code lengths}
  1127. n := nl + nd;
  1128. m := mask_bits [ bl ];
  1129. i := 0; l := 0;
  1130. WHILE word ( i ) < n DO BEGIN
  1131. NEEDBITS ( bl );
  1132. td := @tl^ [ b AND m ];
  1133. j := phuft ( td ) ^.b;
  1134. DUMPBITS ( j );
  1135. j := phuft ( td ) ^.v_n;
  1136. IF j < 16 THEN BEGIN {length of code in bits (0..15)}
  1137. l := j; {ave last length in l}
  1138. ll [ i ] := l;
  1139. inc ( i )
  1140. END ELSE IF j = 16 THEN BEGIN {repeat last length 3 to 6 times}
  1141. NEEDBITS ( 2 );
  1142. j := 3 + b AND 3;
  1143. DUMPBITS ( 2 );
  1144. IF i + j > n THEN BEGIN
  1145. inflate_dynamic := 1;
  1146. exit
  1147. END;
  1148. WHILE j > 0 DO BEGIN
  1149. ll [ i ] := l;
  1150. dec ( j );
  1151. inc ( i );
  1152. END;
  1153. END ELSE IF j = 17 THEN BEGIN {3 to 10 zero length codes}
  1154. NEEDBITS ( 3 );
  1155. j := 3 + b AND 7;
  1156. DUMPBITS ( 3 );
  1157. IF i + j > n THEN BEGIN
  1158. inflate_dynamic := 1;
  1159. exit
  1160. END;
  1161. WHILE j > 0 DO BEGIN
  1162. ll [ i ] := 0;
  1163. inc ( i );
  1164. dec ( j );
  1165. END;
  1166. l := 0;
  1167. END ELSE BEGIN {j == 18: 11 to 138 zero length codes}
  1168. NEEDBITS ( 7 );
  1169. j := 11 + b AND $7f;
  1170. DUMPBITS ( 7 );
  1171. IF i + j > n THEN BEGIN
  1172. inflate_dynamic := unzip_zipfileErr;
  1173. exit
  1174. END;
  1175. WHILE j > 0 DO BEGIN
  1176. ll [ i ] := 0;
  1177. dec ( j );
  1178. inc ( i );
  1179. END;
  1180. l := 0;
  1181. END;
  1182. END;
  1183. huft_free ( tl ); {free decoding table for trees}
  1184. {build the decoding tables for literal/length and distance codes}
  1185. bl := lbits;
  1186. i := huft_build ( pword ( @ll ), nl, 257, pushlist ( @cplens ), pushlist ( @cplext ), @tl, bl );
  1187. IF i <> huft_complete THEN BEGIN
  1188. IF i = huft_incomplete THEN huft_free ( tl );
  1189. inflate_dynamic := unzip_ZipFileErr;
  1190. exit
  1191. END;
  1192. bd := dbits;
  1193. i := huft_build ( pword ( @ll [ nl ] ), nd, 0, pushlist ( @cpdist ), pushlist ( @cpdext ), @td, bd );
  1194. IF i > huft_incomplete THEN BEGIN {pkzip bug workaround}
  1195. IF i = huft_incomplete THEN huft_free ( td );
  1196. huft_free ( tl );
  1197. inflate_dynamic := unzip_ZipFileErr;
  1198. exit
  1199. END;
  1200. {decompress until an end-of-block code}
  1201. inflate_dynamic := inflate_codes ( tl, td, bl, bd );
  1202. huft_free ( tl );
  1203. huft_free ( td );
  1204. END;
  1205. {**************************** decompress a block ******************************}
  1206. FUNCTION inflate_block ( VAR e : integer ) : integer;
  1207. VAR t : word; {block type}
  1208. BEGIN
  1209. NEEDBITS ( 1 );
  1210. e := b AND 1;
  1211. DUMPBITS ( 1 );
  1212. NEEDBITS ( 2 );
  1213. t := b AND 3;
  1214. DUMPBITS ( 2 );
  1215. CASE t of
  1216. 2 : inflate_block := inflate_dynamic;
  1217. 0 : inflate_block := inflate_stored;
  1218. 1 : inflate_block := inflate_fixed;
  1219. ELSE
  1220. inflate_block := unzip_ZipFileErr; {bad block type}
  1221. END;
  1222. END;
  1223. {**************************** decompress an inflated entry **************************}
  1224. FUNCTION inflate : integer;
  1225. VAR e, {last block flag}
  1226. r : integer; {result code}
  1227. BEGIN
  1228. inpos := 0; {Input buffer position}
  1229. readpos := -1; {Nothing read}
  1230. {initialize window, bit buffer}
  1231. w := 0;
  1232. k := 0;
  1233. b := 0;
  1234. {decompress until the last block}
  1235. REPEAT
  1236. r := inflate_block ( e );
  1237. IF r <> 0 THEN BEGIN
  1238. inflate := r;
  1239. exit
  1240. END;
  1241. UNTIL e <> 0;
  1242. {flush out slide}
  1243. IF NOT flush ( w ) THEN inflate := unzip_WriteErr
  1244. ELSE inflate := unzip_Ok;
  1245. END;
  1246. (***************************************************************************)
  1247. {.$I z_copyst.pas} {Copy stored file}
  1248. {include for unzip.pas: Copy stored file}
  1249. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  1250. {based on unz51g.zip}
  1251. {************************* copy stored file ************************************}
  1252. FUNCTION copystored : integer;
  1253. VAR readin : longint;
  1254. outcnt : nword;
  1255. BEGIN
  1256. WHILE ( reachedsize < compsize ) AND NOT totalabort DO BEGIN
  1257. readin := compsize -reachedsize;
  1258. IF readin > wsize THEN readin := wsize;
  1259. {$I-}
  1260. blockread ( infile, slide [ 0 ], readin, outcnt ); {Use slide as buffer}
  1261. {$I+}
  1262. IF ( outcnt <> readin ) OR ( ioresult <> 0 ) THEN BEGIN
  1263. copystored := unzip_ReadErr;
  1264. exit
  1265. END;
  1266. IF NOT flush ( outcnt ) THEN BEGIN {Flushoutput takes care of CRC too}
  1267. copystored := unzip_WriteErr;
  1268. exit
  1269. END;
  1270. inc ( reachedsize, outcnt );
  1271. messageloop; {Other programs, or in DOS: keypressed?}
  1272. {$ifdef windows}
  1273. showpercent;
  1274. {$endif}
  1275. END;
  1276. IF NOT totalabort THEN
  1277. copystored := unzip_Ok
  1278. ELSE
  1279. copystored := unzip_Userabort;
  1280. END;
  1281. (***************************************************************************)
  1282. {.$I z_explod.pas} {Explode imploded file}
  1283. {include for unzip.pas: Explode imploded file}
  1284. {C code by info-zip group, translated to Pascal by Christian Ghisler}
  1285. {based on unz51g.zip}
  1286. {************************************* explode ********************************}
  1287. {*********************************** read in tree *****************************}
  1288. FUNCTION get_tree ( l : pword;n : word ) : integer;
  1289. VAR i, k, j, b : word;
  1290. bytebuf : byte;
  1291. BEGIN
  1292. READBYTE ( bytebuf );
  1293. i := bytebuf;
  1294. inc ( i );
  1295. k := 0;
  1296. REPEAT
  1297. READBYTE ( bytebuf );
  1298. j := bytebuf;
  1299. b := ( j AND $F ) + 1;
  1300. j := ( ( j AND $F0 ) SHR 4 ) + 1;
  1301. IF ( k + j ) > n THEN BEGIN
  1302. get_tree := 4;
  1303. exit
  1304. END;
  1305. REPEAT
  1306. l^ := b;
  1307. inc ( longint ( l ), sizeof ( word ) );
  1308. inc ( k );
  1309. dec ( j );
  1310. UNTIL j = 0;
  1311. dec ( i );
  1312. UNTIL i = 0;
  1313. IF k <> n THEN get_tree := 4 ELSE get_tree := 0;
  1314. END;
  1315. {******************exploding, method: 8k slide, 3 trees ***********************}
  1316. FUNCTION explode_lit8 ( tb, tl, td : phuftlist;bb, bl, bd : integer ) : integer;
  1317. VAR s : longint;
  1318. e : word;
  1319. n, d : word;
  1320. w : word;
  1321. t : phuft;
  1322. mb, ml, md : word;
  1323. u : word;
  1324. BEGIN
  1325. b := 0; k := 0; w := 0;
  1326. u := 1;
  1327. mb := mask_bits [ bb ];
  1328. ml := mask_bits [ bl ];
  1329. md := mask_bits [ bd ];
  1330. s := uncompsize;
  1331. WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
  1332. NEEDBITS ( 1 );
  1333. IF ( b AND 1 ) <> 0 THEN BEGIN {Litteral}
  1334. DUMPBITS ( 1 );
  1335. dec ( s );
  1336. NEEDBITS ( bb );
  1337. t := @tb^ [ ( NOT b ) AND mb ];
  1338. e := t^.e;
  1339. IF e > 16 THEN REPEAT
  1340. IF e = 99 THEN BEGIN
  1341. explode_lit8 := unzip_ZipFileErr;
  1342. exit
  1343. END;
  1344. DUMPBITS ( t^.b );
  1345. dec ( e, 16 );
  1346. NEEDBITS ( e );
  1347. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1348. e := t^.e;
  1349. UNTIL e <= 16;
  1350. DUMPBITS ( t^.b );
  1351. slide [ w ] := char ( t^.v_n );
  1352. inc ( w );
  1353. IF w = WSIZE THEN BEGIN
  1354. IF NOT flush ( w ) THEN BEGIN
  1355. explode_lit8 := unzip_WriteErr;
  1356. exit
  1357. END;
  1358. w := 0; u := 0;
  1359. END;
  1360. END ELSE BEGIN
  1361. DUMPBITS ( 1 );
  1362. NEEDBITS ( 7 );
  1363. d := b AND $7F;
  1364. DUMPBITS ( 7 );
  1365. NEEDBITS ( bd );
  1366. t := @td^ [ ( NOT b ) AND md ];
  1367. e := t^.e;
  1368. IF e > 16 THEN REPEAT
  1369. IF e = 99 THEN BEGIN
  1370. explode_lit8 := unzip_ZipFileErr;
  1371. exit
  1372. END;
  1373. DUMPBITS ( t^.b );
  1374. dec ( e, 16 );
  1375. NEEDBITS ( e );
  1376. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1377. e := t^.e;
  1378. UNTIL e <= 16;
  1379. DUMPBITS ( t^.b );
  1380. d := w -d -t^.v_n;
  1381. NEEDBITS ( bl );
  1382. t := @tl^ [ ( NOT b ) AND ml ];
  1383. e := t^.e;
  1384. IF e > 16 THEN REPEAT
  1385. IF e = 99 THEN BEGIN
  1386. explode_lit8 := unzip_ZipFileErr;
  1387. exit
  1388. END;
  1389. DUMPBITS ( t^.b );
  1390. dec ( e, 16 );
  1391. NEEDBITS ( e );
  1392. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1393. e := t^.e;
  1394. UNTIL e <= 16;
  1395. DUMPBITS ( t^.b );
  1396. n := t^.v_n;
  1397. IF e <> 0 THEN BEGIN
  1398. NEEDBITS ( 8 );
  1399. inc ( n, byte ( b ) AND $ff );
  1400. DUMPBITS ( 8 );
  1401. END;
  1402. dec ( s, n );
  1403. REPEAT
  1404. d := d AND pred ( WSIZE );
  1405. IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
  1406. IF e > n THEN e := n;
  1407. dec ( n, e );
  1408. IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
  1409. fillchar ( slide [ w ], e, #0 );
  1410. inc ( w, e );
  1411. inc ( d, e );
  1412. END ELSE IF ( w -d >= e ) THEN BEGIN
  1413. move ( slide [ d ], slide [ w ], e );
  1414. inc ( w, e );
  1415. inc ( d, e );
  1416. END ELSE REPEAT
  1417. slide [ w ] := slide [ d ];
  1418. inc ( w );
  1419. inc ( d );
  1420. dec ( e );
  1421. UNTIL e = 0;
  1422. IF w = WSIZE THEN BEGIN
  1423. IF NOT flush ( w ) THEN BEGIN
  1424. explode_lit8 := unzip_WriteErr;
  1425. exit
  1426. END;
  1427. w := 0; u := 0;
  1428. END;
  1429. UNTIL n = 0;
  1430. END;
  1431. END;
  1432. IF totalabort THEN explode_lit8 := unzip_userabort
  1433. ELSE
  1434. IF NOT flush ( w ) THEN explode_lit8 := unzip_WriteErr
  1435. ELSE
  1436. IF zipeof THEN explode_lit8 := unzip_readErr
  1437. ELSE
  1438. explode_lit8 := unzip_Ok;
  1439. END;
  1440. {******************exploding, method: 4k slide, 3 trees ***********************}
  1441. FUNCTION explode_lit4 ( tb, tl, td : phuftlist;bb, bl, bd : integer ) : integer;
  1442. VAR s : longint;
  1443. e : word;
  1444. n, d : word;
  1445. w : word;
  1446. t : phuft;
  1447. mb, ml, md : word;
  1448. u : word;
  1449. BEGIN
  1450. b := 0; k := 0; w := 0;
  1451. u := 1;
  1452. mb := mask_bits [ bb ];
  1453. ml := mask_bits [ bl ];
  1454. md := mask_bits [ bd ];
  1455. s := uncompsize;
  1456. WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
  1457. NEEDBITS ( 1 );
  1458. IF ( b AND 1 ) <> 0 THEN BEGIN {Litteral}
  1459. DUMPBITS ( 1 );
  1460. dec ( s );
  1461. NEEDBITS ( bb );
  1462. t := @tb^ [ ( NOT b ) AND mb ];
  1463. e := t^.e;
  1464. IF e > 16 THEN REPEAT
  1465. IF e = 99 THEN BEGIN
  1466. explode_lit4 := unzip_ZipFileErr;
  1467. exit
  1468. END;
  1469. DUMPBITS ( t^.b );
  1470. dec ( e, 16 );
  1471. NEEDBITS ( e );
  1472. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1473. e := t^.e;
  1474. UNTIL e <= 16;
  1475. DUMPBITS ( t^.b );
  1476. slide [ w ] := char ( t^.v_n );
  1477. inc ( w );
  1478. IF w = WSIZE THEN BEGIN
  1479. IF NOT flush ( w ) THEN BEGIN
  1480. explode_lit4 := unzip_WriteErr;
  1481. exit
  1482. END;
  1483. w := 0; u := 0;
  1484. END;
  1485. END ELSE BEGIN
  1486. DUMPBITS ( 1 );
  1487. NEEDBITS ( 6 );
  1488. d := b AND $3F;
  1489. DUMPBITS ( 6 );
  1490. NEEDBITS ( bd );
  1491. t := @td^ [ ( NOT b ) AND md ];
  1492. e := t^.e;
  1493. IF e > 16 THEN REPEAT
  1494. IF e = 99 THEN BEGIN
  1495. explode_lit4 := unzip_ZipFileErr;
  1496. exit
  1497. END;
  1498. DUMPBITS ( t^.b );
  1499. dec ( e, 16 );
  1500. NEEDBITS ( e );
  1501. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1502. e := t^.e;
  1503. UNTIL e <= 16;
  1504. DUMPBITS ( t^.b );
  1505. d := w -d -t^.v_n;
  1506. NEEDBITS ( bl );
  1507. t := @tl^ [ ( NOT b ) AND ml ];
  1508. e := t^.e;
  1509. IF e > 16 THEN REPEAT
  1510. IF e = 99 THEN BEGIN
  1511. explode_lit4 := unzip_ZipFileErr;
  1512. exit
  1513. END;
  1514. DUMPBITS ( t^.b );
  1515. dec ( e, 16 );
  1516. NEEDBITS ( e );
  1517. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1518. e := t^.e;
  1519. UNTIL e <= 16;
  1520. DUMPBITS ( t^.b );
  1521. n := t^.v_n;
  1522. IF e <> 0 THEN BEGIN
  1523. NEEDBITS ( 8 );
  1524. inc ( n, b AND $ff );
  1525. DUMPBITS ( 8 );
  1526. END;
  1527. dec ( s, n );
  1528. REPEAT
  1529. d := d AND pred ( WSIZE );
  1530. IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
  1531. IF e > n THEN e := n;
  1532. dec ( n, e );
  1533. IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
  1534. fillchar ( slide [ w ], e, #0 );
  1535. inc ( w, e );
  1536. inc ( d, e );
  1537. END ELSE IF ( w -d >= e ) THEN BEGIN
  1538. move ( slide [ d ], slide [ w ], e );
  1539. inc ( w, e );
  1540. inc ( d, e );
  1541. END ELSE REPEAT
  1542. slide [ w ] := slide [ d ];
  1543. inc ( w );
  1544. inc ( d );
  1545. dec ( e );
  1546. UNTIL e = 0;
  1547. IF w = WSIZE THEN BEGIN
  1548. IF NOT flush ( w ) THEN BEGIN
  1549. explode_lit4 := unzip_WriteErr;
  1550. exit
  1551. END;
  1552. w := 0; u := 0;
  1553. END;
  1554. UNTIL n = 0;
  1555. END;
  1556. END;
  1557. IF totalabort THEN explode_lit4 := unzip_userabort
  1558. ELSE
  1559. IF NOT flush ( w ) THEN explode_lit4 := unzip_WriteErr
  1560. ELSE
  1561. IF zipeof THEN explode_lit4 := unzip_readErr
  1562. ELSE explode_lit4 := unzip_Ok;
  1563. END;
  1564. {******************exploding, method: 8k slide, 2 trees ***********************}
  1565. FUNCTION explode_nolit8 ( tl, td : phuftlist;bl, bd : integer ) : integer;
  1566. VAR s : longint;
  1567. e : word;
  1568. n, d : word;
  1569. w : word;
  1570. t : phuft;
  1571. ml, md : word;
  1572. u : word;
  1573. BEGIN
  1574. b := 0; k := 0; w := 0;
  1575. u := 1;
  1576. ml := mask_bits [ bl ];
  1577. md := mask_bits [ bd ];
  1578. s := uncompsize;
  1579. WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
  1580. NEEDBITS ( 1 );
  1581. IF ( b AND 1 ) <> 0 THEN BEGIN {Litteral}
  1582. DUMPBITS ( 1 );
  1583. dec ( s );
  1584. NEEDBITS ( 8 );
  1585. slide [ w ] := char ( b );
  1586. inc ( w );
  1587. IF w = WSIZE THEN BEGIN
  1588. IF NOT flush ( w ) THEN BEGIN
  1589. explode_nolit8 := unzip_WriteErr;
  1590. exit
  1591. END;
  1592. w := 0; u := 0;
  1593. END;
  1594. DUMPBITS ( 8 );
  1595. END ELSE BEGIN
  1596. DUMPBITS ( 1 );
  1597. NEEDBITS ( 7 );
  1598. d := b AND $7F;
  1599. DUMPBITS ( 7 );
  1600. NEEDBITS ( bd );
  1601. t := @td^ [ ( NOT b ) AND md ];
  1602. e := t^.e;
  1603. IF e > 16 THEN REPEAT
  1604. IF e = 99 THEN BEGIN
  1605. explode_nolit8 := unzip_ZipFileErr;
  1606. exit
  1607. END;
  1608. DUMPBITS ( t^.b );
  1609. dec ( e, 16 );
  1610. NEEDBITS ( e );
  1611. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1612. e := t^.e;
  1613. UNTIL e <= 16;
  1614. DUMPBITS ( t^.b );
  1615. d := w -d -t^.v_n;
  1616. NEEDBITS ( bl );
  1617. t := @tl^ [ ( NOT b ) AND ml ];
  1618. e := t^.e;
  1619. IF e > 16 THEN REPEAT
  1620. IF e = 99 THEN BEGIN
  1621. explode_nolit8 := unzip_ZipFileErr;
  1622. exit
  1623. END;
  1624. DUMPBITS ( t^.b );
  1625. dec ( e, 16 );
  1626. NEEDBITS ( e );
  1627. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1628. e := t^.e;
  1629. UNTIL e <= 16;
  1630. DUMPBITS ( t^.b );
  1631. n := t^.v_n;
  1632. IF e <> 0 THEN BEGIN
  1633. NEEDBITS ( 8 );
  1634. inc ( n, b AND $ff );
  1635. DUMPBITS ( 8 );
  1636. END;
  1637. dec ( s, n );
  1638. REPEAT
  1639. d := d AND pred ( WSIZE );
  1640. IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
  1641. IF e > n THEN e := n;
  1642. dec ( n, e );
  1643. IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
  1644. fillchar ( slide [ w ], e, #0 );
  1645. inc ( w, e );
  1646. inc ( d, e );
  1647. END ELSE IF ( w -d >= e ) THEN BEGIN
  1648. move ( slide [ d ], slide [ w ], e );
  1649. inc ( w, e );
  1650. inc ( d, e );
  1651. END ELSE REPEAT
  1652. slide [ w ] := slide [ d ];
  1653. inc ( w );
  1654. inc ( d );
  1655. dec ( e );
  1656. UNTIL e = 0;
  1657. IF w = WSIZE THEN BEGIN
  1658. IF NOT flush ( w ) THEN BEGIN
  1659. explode_nolit8 := unzip_WriteErr;
  1660. exit
  1661. END;
  1662. w := 0; u := 0;
  1663. END;
  1664. UNTIL n = 0;
  1665. END;
  1666. END;
  1667. IF totalabort THEN explode_nolit8 := unzip_userabort
  1668. ELSE
  1669. IF NOT flush ( w ) THEN explode_nolit8 := unzip_WriteErr
  1670. ELSE
  1671. IF zipeof THEN explode_nolit8 := unzip_readErr
  1672. ELSE explode_nolit8 := unzip_Ok;
  1673. END;
  1674. {******************exploding, method: 4k slide, 2 trees ***********************}
  1675. FUNCTION explode_nolit4 ( tl, td : phuftlist;bl, bd : integer ) : integer;
  1676. VAR s : longint;
  1677. e : word;
  1678. n, d : word;
  1679. w : word;
  1680. t : phuft;
  1681. ml, md : word;
  1682. u : word;
  1683. BEGIN
  1684. b := 0; k := 0; w := 0;
  1685. u := 1;
  1686. ml := mask_bits [ bl ];
  1687. md := mask_bits [ bd ];
  1688. s := uncompsize;
  1689. WHILE ( s > 0 ) AND NOT ( totalabort OR zipeof ) DO BEGIN
  1690. NEEDBITS ( 1 );
  1691. IF ( b AND 1 ) <> 0 THEN BEGIN {Litteral}
  1692. DUMPBITS ( 1 );
  1693. dec ( s );
  1694. NEEDBITS ( 8 );
  1695. slide [ w ] := char ( b );
  1696. inc ( w );
  1697. IF w = WSIZE THEN BEGIN
  1698. IF NOT flush ( w ) THEN BEGIN
  1699. explode_nolit4 := unzip_WriteErr;
  1700. exit
  1701. END;
  1702. w := 0; u := 0;
  1703. END;
  1704. DUMPBITS ( 8 );
  1705. END ELSE BEGIN
  1706. DUMPBITS ( 1 );
  1707. NEEDBITS ( 6 );
  1708. d := b AND $3F;
  1709. DUMPBITS ( 6 );
  1710. NEEDBITS ( bd );
  1711. t := @td^ [ ( NOT b ) AND md ];
  1712. e := t^.e;
  1713. IF e > 16 THEN REPEAT
  1714. IF e = 99 THEN BEGIN
  1715. explode_nolit4 := unzip_ZipFileErr;
  1716. exit
  1717. END;
  1718. DUMPBITS ( t^.b );
  1719. dec ( e, 16 );
  1720. NEEDBITS ( e );
  1721. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1722. e := t^.e;
  1723. UNTIL e <= 16;
  1724. DUMPBITS ( t^.b );
  1725. d := w -d -t^.v_n;
  1726. NEEDBITS ( bl );
  1727. t := @tl^ [ ( NOT b ) AND ml ];
  1728. e := t^.e;
  1729. IF e > 16 THEN REPEAT
  1730. IF e = 99 THEN BEGIN
  1731. explode_nolit4 := unzip_ZipFileErr;
  1732. exit
  1733. END;
  1734. DUMPBITS ( t^.b );
  1735. dec ( e, 16 );
  1736. NEEDBITS ( e );
  1737. t := @t^.v_t^ [ ( NOT b ) AND mask_bits [ e ] ];
  1738. e := t^.e;
  1739. UNTIL e <= 16;
  1740. DUMPBITS ( t^.b );
  1741. n := t^.v_n;
  1742. IF e <> 0 THEN BEGIN
  1743. NEEDBITS ( 8 );
  1744. inc ( n, b AND $ff );
  1745. DUMPBITS ( 8 );
  1746. END;
  1747. dec ( s, n );
  1748. REPEAT
  1749. d := d AND pred ( WSIZE );
  1750. IF d > w THEN e := WSIZE -d ELSE e := WSIZE -w;
  1751. IF e > n THEN e := n;
  1752. dec ( n, e );
  1753. IF ( u <> 0 ) AND ( w <= d ) THEN BEGIN
  1754. fillchar ( slide [ w ], e, #0 );
  1755. inc ( w, e );
  1756. inc ( d, e );
  1757. END ELSE IF ( w -d >= e ) THEN BEGIN
  1758. move ( slide [ d ], slide [ w ], e );
  1759. inc ( w, e );
  1760. inc ( d, e );
  1761. END ELSE REPEAT
  1762. slide [ w ] := slide [ d ];
  1763. inc ( w );
  1764. inc ( d );
  1765. dec ( e );
  1766. UNTIL e = 0;
  1767. IF w = WSIZE THEN BEGIN
  1768. IF NOT flush ( w ) THEN BEGIN
  1769. explode_nolit4 := unzip_WriteErr;
  1770. exit
  1771. END;
  1772. w := 0; u := 0;
  1773. END;
  1774. UNTIL n = 0;
  1775. END;
  1776. END;
  1777. IF totalabort THEN explode_nolit4 := unzip_userabort
  1778. ELSE
  1779. IF NOT flush ( w ) THEN explode_nolit4 := unzip_WriteErr
  1780. ELSE
  1781. IF zipeof THEN explode_nolit4 := unzip_readErr
  1782. ELSE explode_nolit4 := unzip_Ok;
  1783. END;
  1784. {****************************** explode *********************************}
  1785. FUNCTION explode : integer;
  1786. VAR r : integer;
  1787. tb, tl, td : phuftlist;
  1788. bb, bl, bd : integer;
  1789. l : ARRAY [ 0..255 ] of word;
  1790. BEGIN
  1791. inpos := 0;
  1792. readpos := -1; {Nothing read in}
  1793. bl := 7;
  1794. IF compsize > 200000 THEN bd := 8 ELSE bd := 7;
  1795. IF hufttype AND 4 <> 0 THEN BEGIN
  1796. bb := 9;
  1797. r := get_tree ( @l [ 0 ], 256 );
  1798. IF r <> 0 THEN BEGIN
  1799. explode := unzip_ZipFileErr;
  1800. exit
  1801. END;
  1802. r := huft_build ( @l, 256, 256, NIL, NIL, @tb, bb );
  1803. IF r <> 0 THEN BEGIN
  1804. IF r = huft_incomplete THEN huft_free ( tb );
  1805. explode := unzip_ZipFileErr;
  1806. exit
  1807. END;
  1808. r := get_tree ( @l [ 0 ], 64 );
  1809. IF r <> 0 THEN BEGIN
  1810. huft_free ( tb );
  1811. explode := unzip_ZipFileErr;
  1812. exit
  1813. END;
  1814. r := huft_build ( @l, 64, 0, pushlist ( @cplen3 ), pushlist ( @extra ), @tl, bl );
  1815. IF r <> 0 THEN BEGIN
  1816. IF r = huft_incomplete THEN huft_free ( tl );
  1817. huft_free ( tb );
  1818. explode := unzip_ZipFileErr;
  1819. exit
  1820. END;
  1821. r := get_tree ( @l [ 0 ], 64 );
  1822. IF r <> 0 THEN BEGIN
  1823. huft_free ( tb );
  1824. huft_free ( tl );
  1825. explode := unzip_ZipFileErr;
  1826. exit
  1827. END;
  1828. IF hufttype AND 2 <> 0 THEN BEGIN {8k}
  1829. r := huft_build ( @l, 64, 0, pushlist ( @cpdist8 ), pushlist ( @extra ), @td, bd );
  1830. IF r <> 0 THEN BEGIN
  1831. IF r = huft_incomplete THEN huft_free ( td );
  1832. huft_free ( tb );
  1833. huft_free ( tl );
  1834. explode := unzip_ZipFileErr;
  1835. exit
  1836. END;
  1837. r := explode_lit8 ( tb, tl, td, bb, bl, bd );
  1838. END ELSE BEGIN
  1839. r := huft_build ( @l, 64, 0, pushlist ( @cpdist4 ), pushlist ( @extra ), @td, bd );
  1840. IF r <> 0 THEN BEGIN
  1841. IF r = huft_incomplete THEN huft_free ( td );
  1842. huft_free ( tb );
  1843. huft_free ( tl );
  1844. explode := unzip_ZipFileErr;
  1845. exit
  1846. END;
  1847. r := explode_lit4 ( tb, tl, td, bb, bl, bd );
  1848. END;
  1849. huft_free ( td );
  1850. huft_free ( tl );
  1851. huft_free ( tb );
  1852. END ELSE BEGIN {No literal tree}
  1853. r := get_tree ( @l [ 0 ], 64 );
  1854. IF r <> 0 THEN BEGIN
  1855. explode := unzip_ZipFileErr;
  1856. exit
  1857. END;
  1858. r := huft_build ( @l, 64, 0, pushlist ( @cplen2 ), pushlist ( @extra ), @tl, bl );
  1859. IF r <> 0 THEN BEGIN
  1860. IF r = huft_incomplete THEN huft_free ( tl );
  1861. explode := unzip_ZipFileErr;
  1862. exit
  1863. END;
  1864. r := get_tree ( @l [ 0 ], 64 );
  1865. IF r <> 0 THEN BEGIN
  1866. huft_free ( tl );
  1867. explode := unzip_ZipFileErr;
  1868. exit
  1869. END;
  1870. IF hufttype AND 2 <> 0 THEN BEGIN {8k}
  1871. r := huft_build ( @l, 64, 0, pushlist ( @cpdist8 ), pushlist ( @extra ), @td, bd );
  1872. IF r <> 0 THEN BEGIN
  1873. IF r = huft_incomplete THEN huft_free ( td );
  1874. huft_free ( tl );
  1875. explode := unzip_ZipFileErr;
  1876. exit
  1877. END;
  1878. r := explode_nolit8 ( tl, td, bl, bd );
  1879. END ELSE BEGIN
  1880. r := huft_build ( @l, 64, 0, pushlist ( @cpdist4 ), pushlist ( @extra ), @td, bd );
  1881. IF r <> 0 THEN BEGIN
  1882. IF r = huft_incomplete THEN huft_free ( td );
  1883. huft_free ( tl );
  1884. explode := unzip_ZipFileErr;
  1885. exit
  1886. END;
  1887. r := explode_nolit4 ( tl, td, bl, bd );
  1888. END;
  1889. huft_free ( td );
  1890. huft_free ( tl );
  1891. END;
  1892. explode := r;
  1893. END;
  1894. (***************************************************************************)
  1895. {.$I z_shrunk.pas} {Unshrink function}
  1896. {*************************** unshrink **********************************}
  1897. {Written and NOT copyrighted by Christian Ghisler.
  1898. I have rewritten unshrink because the original
  1899. function was copyrighted by Mr. Smith of Info-zip
  1900. This funtion here is now completely FREE!!!!
  1901. The only right I claim on this code is that
  1902. noone else claims a copyright on it!}
  1903. CONST max_code = 8192;
  1904. max_stack = 8192;
  1905. initial_code_size = 9;
  1906. final_code_size = 13;
  1907. write_max = wsize -3 * ( max_code -256 ) -max_stack -2; {Rest of slide=write buffer}
  1908. {=766 bytes}
  1909. TYPE prev = ARRAY [ 257..max_code ] of integer;
  1910. pprev = ^prev;
  1911. cds = ARRAY [ 257..max_code ] of char;
  1912. pcds = ^cds;
  1913. stacktype = ARRAY [ 0..max_stack ] of char;
  1914. pstacktype = ^stacktype;
  1915. writebuftype = ARRAY [ 0..write_max ] of char; {write buffer}
  1916. pwritebuftype = ^writebuftype;
  1917. VAR previous_code : pprev; {previous code trie}
  1918. actual_code : pcds; {actual code trie}
  1919. stack : pstacktype; {Stack for output}
  1920. writebuf : pwritebuftype; {Write buffer}
  1921. next_free, {Next free code in trie}
  1922. write_ptr : integer; {Pointer to output buffer}
  1923. FUNCTION unshrink_flush : boolean;
  1924. VAR
  1925. n : nword;
  1926. b : boolean;
  1927. BEGIN
  1928. {$I-}
  1929. blockwrite ( outfile, writebuf^ [ 0 ], write_ptr, n );
  1930. {$I+}
  1931. b := ( n = write_ptr ) AND ( ioresult = 0 ); {True-> alles ok}
  1932. UpdateCRC ( iobuf ( pointer ( @writebuf^ [ 0 ] ) ^ ), write_ptr );
  1933. {--}
  1934. IF ( b = TRUE ) AND ( @ZipReport <> NIL ) {callback report for high level functions}
  1935. THEN BEGIN
  1936. WITH ZipRec DO BEGIN
  1937. Status := file_unzipping;
  1938. ZipReport ( n, @ZipRec ); {report the actual bytes written}
  1939. END;
  1940. END; {report}
  1941. unshrink_flush := b;
  1942. END;
  1943. FUNCTION write_char ( c : char ) : boolean;
  1944. BEGIN
  1945. writebuf^ [ write_ptr ] := c;
  1946. inc ( write_ptr );
  1947. IF write_ptr > write_max THEN BEGIN
  1948. write_char := unshrink_flush;
  1949. write_ptr := 0;
  1950. END ELSE write_char := TRUE;
  1951. END;
  1952. PROCEDURE ClearLeafNodes;
  1953. VAR pc, {previous code}
  1954. i, {index}
  1955. act_max_code : integer; {max code to be searched for leaf nodes}
  1956. previous : pprev; {previous code trie}
  1957. BEGIN
  1958. previous := previous_code;
  1959. act_max_code := next_free -1;
  1960. FOR i := 257 TO act_max_code DO
  1961. previous^ [ i ] := previous^ [ i ] OR $8000;
  1962. FOR i := 257 TO act_max_code DO BEGIN
  1963. pc := previous^ [ i ] AND NOT $8000;
  1964. IF pc > 256 THEN
  1965. previous^ [ pc ] := previous^ [ pc ] AND ( NOT $8000 );
  1966. END;
  1967. {Build new free list}
  1968. pc := -1;
  1969. next_free := -1;
  1970. FOR i := 257 TO act_max_code DO
  1971. IF previous^ [ i ] AND $C000 <> 0 THEN BEGIN {Either free before or marked now}
  1972. IF pc <> -1 THEN previous^ [ pc ] := -i {Link last item to this item}
  1973. ELSE next_free := i;
  1974. pc := i;
  1975. END;
  1976. IF pc <> -1 THEN
  1977. previous^ [ pc ] := -act_max_code -1;
  1978. END;
  1979. FUNCTION unshrink : integer;
  1980. VAR incode : integer; {code read in}
  1981. lastincode : integer; {last code read in}
  1982. lastoutcode : char; {last code emitted}
  1983. code_size : byte; {Actual code size}
  1984. stack_ptr, {Stackpointer}
  1985. new_code, {Save new code read}
  1986. code_mask, {mask for coding}
  1987. i : integer; {Index}
  1988. bits_to_read : longint;
  1989. BEGIN
  1990. IF compsize = maxlongint THEN BEGIN {Compressed Size was not in header!}
  1991. unshrink := unzip_NotSupported;
  1992. exit
  1993. END;
  1994. inpos := 0; {Input buffer position}
  1995. readpos := -1; {Nothing read}
  1996. {initialize window, bit buffer}
  1997. w := 0;
  1998. k := 0;
  1999. b := 0;
  2000. {Initialize pointers for various buffers}
  2001. previous_code := @slide [ 0 ];
  2002. actual_code := @slide [ sizeof ( prev ) ];
  2003. stack := @slide [ sizeof ( prev ) + sizeof ( cds ) ];
  2004. writebuf := @slide [ sizeof ( prev ) + sizeof ( cds ) + sizeof ( stacktype ) ];
  2005. fillchar ( slide^, wsize, #0 );
  2006. {initialize free codes list}
  2007. FOR i := 257 TO max_code DO
  2008. previous_code^ [ i ] := - ( i + 1 );
  2009. next_free := 257;
  2010. stack_ptr := max_stack;
  2011. write_ptr := 0;
  2012. code_size := initial_code_size;
  2013. code_mask := mask_bits [ code_size ];
  2014. NEEDBITS ( code_size );
  2015. incode := b AND code_mask;
  2016. DUMPBITS ( code_size );
  2017. lastincode := incode;
  2018. lastoutcode := char ( incode );
  2019. IF NOT write_char ( lastoutcode ) THEN BEGIN
  2020. unshrink := unzip_writeErr;
  2021. exit
  2022. END;
  2023. bits_to_read := 8 * compsize -code_size; {Bits to be read}
  2024. WHILE NOT totalabort AND ( bits_to_read >= code_size ) DO BEGIN
  2025. NEEDBITS ( code_size );
  2026. incode := b AND code_mask;
  2027. DUMPBITS ( code_size );
  2028. dec ( bits_to_read, code_size );
  2029. IF incode = 256 THEN BEGIN {Special code}
  2030. NEEDBITS ( code_size );
  2031. incode := b AND code_mask;
  2032. DUMPBITS ( code_size );
  2033. dec ( bits_to_read, code_size );
  2034. CASE incode of
  2035. 1 : BEGIN
  2036. inc ( code_size );
  2037. IF code_size > final_code_size THEN BEGIN
  2038. unshrink := unzip_ZipFileErr;
  2039. exit
  2040. END;
  2041. code_mask := mask_bits [ code_size ];
  2042. END;
  2043. 2 : BEGIN
  2044. ClearLeafNodes;
  2045. END;
  2046. ELSE
  2047. unshrink := unzip_ZipFileErr;
  2048. exit
  2049. END;
  2050. END ELSE BEGIN
  2051. new_code := incode;
  2052. IF incode < 256 THEN BEGIN {Simple char}
  2053. lastoutcode := char ( incode );
  2054. IF NOT write_char ( lastoutcode ) THEN BEGIN
  2055. unshrink := unzip_writeErr;
  2056. exit
  2057. END;
  2058. END ELSE BEGIN
  2059. IF previous_code^ [ incode ] < 0 THEN BEGIN
  2060. stack^ [ stack_ptr ] := lastoutcode;
  2061. dec ( stack_ptr );
  2062. incode := lastincode;
  2063. END;
  2064. WHILE incode > 256 DO BEGIN
  2065. stack^ [ stack_ptr ] := actual_code^ [ incode ];
  2066. dec ( stack_ptr );
  2067. incode := previous_code^ [ incode ];
  2068. END;
  2069. lastoutcode := char ( incode );
  2070. IF NOT write_char ( lastoutcode ) THEN BEGIN
  2071. unshrink := unzip_writeErr;
  2072. exit
  2073. END;
  2074. FOR i := stack_ptr + 1 TO max_stack DO
  2075. IF NOT write_char ( stack^ [ i ] ) THEN BEGIN
  2076. unshrink := unzip_writeErr;
  2077. exit
  2078. END;
  2079. stack_ptr := max_stack;
  2080. END;
  2081. incode := next_free;
  2082. IF incode <= max_code THEN BEGIN
  2083. next_free := -previous_code^ [ incode ]; {Next node in free list}
  2084. previous_code^ [ incode ] := lastincode;
  2085. actual_code^ [ incode ] := lastoutcode;
  2086. END;
  2087. lastincode := new_code;
  2088. END;
  2089. END;
  2090. IF totalabort THEN
  2091. unshrink := unzip_UserAbort
  2092. ELSE IF unshrink_flush THEN
  2093. unshrink := unzip_ok
  2094. ELSE
  2095. unshrink := unzip_WriteErr;
  2096. END;
  2097. (***************************************************************************)
  2098. {***************************************************************************}
  2099. FUNCTION GetSupportedMethods : longint;
  2100. BEGIN
  2101. GetSupportedMethods := 1 + ( 1 SHL 1 ) + ( 1 SHL 6 ) + ( 1 SHL 8 );
  2102. {stored, shrunk, imploded and deflated}
  2103. END;
  2104. {******************** main low level function: unzipfile ********************}
  2105. {written and not copyrighted by Christian Ghisler}
  2106. FUNCTION unzipfile ( in_name : pchar;out_name : pchar;offset : longint;
  2107. hFileAction : word;cm_index : integer ) : integer;
  2108. VAR err : integer;
  2109. header : plocalheader;
  2110. buf : ARRAY [ 0..80 ] of char;
  2111. buf0 : ARRAY [ 0..3 ] of char;
  2112. timedate : longint;
  2113. originalcrc : longint; {crc from zip-header}
  2114. ziptype, aResult : integer;
  2115. p, p1 : pchar;
  2116. isadir : boolean;
  2117. oldcurdir : string [ 80 ];
  2118. BEGIN
  2119. {$ifdef windows}
  2120. IF inuse THEN BEGIN
  2121. {take care of crashed applications!}
  2122. IF ( lastusedtime <> 0 ) AND
  2123. ( abs ( gettickcount -lastusedtime ) > 30000 ) THEN BEGIN {1/2 minute timeout!!!}
  2124. {do not close files or free slide, they were already freed when application crashed!}
  2125. inuse := FALSE;
  2126. {memory for huffman trees is lost}
  2127. END ELSE BEGIN
  2128. unzipfile := unzip_inuse;
  2129. exit
  2130. END;
  2131. END;{inuse}
  2132. inuse := TRUE;
  2133. {$endif}
  2134. getmem ( slide, wsize );
  2135. fillchar ( slide [ 0 ], wsize, #0 );
  2136. assign ( infile, in_name );
  2137. filemode := 0;
  2138. {$I-}
  2139. reset ( infile, 1 );
  2140. {$I+}
  2141. IF ioresult <> 0 THEN BEGIN
  2142. freemem ( slide, wsize );
  2143. unzipfile := unzip_ReadErr;
  2144. inuse := FALSE;
  2145. exit
  2146. END;
  2147. {$I-}
  2148. seek ( infile, offset ); {seek to header position}
  2149. {$I+}
  2150. IF ioresult <> 0 THEN BEGIN
  2151. freemem ( slide, wsize );
  2152. close ( infile );
  2153. unzipfile := unzip_ZipFileErr;
  2154. inuse := FALSE;
  2155. exit
  2156. END;
  2157. header := @inbuf;
  2158. {$I-}
  2159. blockread ( infile, header^, sizeof ( header^ ) ); {read in local header}
  2160. {$I+}
  2161. IF ioresult <> 0 THEN BEGIN
  2162. freemem ( slide, wsize );
  2163. close ( infile );
  2164. unzipfile := unzip_ZipFileErr;
  2165. inuse := FALSE;
  2166. exit
  2167. END;
  2168. IF strlcomp ( header^.signature, 'PK'#3#4, 4 ) <> 0 THEN BEGIN
  2169. freemem ( slide, wsize );
  2170. close ( infile );
  2171. unzipfile := unzip_ZipFileErr;
  2172. inuse := FALSE;
  2173. exit
  2174. END;
  2175. {calculate offset of data}
  2176. offset := offset + header^.filename_len + header^.extra_field_len + sizeof ( tlocalheader );
  2177. timedate := header^.file_timedate;
  2178. IF ( hufttype AND 8 ) = 0 THEN BEGIN {Size and crc at the beginning}
  2179. compsize := header^.compress_size;
  2180. uncompsize := header^.uncompress_size;
  2181. originalcrc := header^.crc_32;
  2182. END ELSE BEGIN
  2183. compsize := maxlongint; {Don't get a sudden zipeof!}
  2184. uncompsize := maxlongint;
  2185. originalcrc := 0
  2186. END;
  2187. ziptype := header^.zip_type; {0=stored, 6=imploded, 8=deflated}
  2188. IF ( 1 SHL ziptype ) AND GetSupportedMethods = 0 THEN BEGIN {Not Supported!!!}
  2189. freemem ( slide, wsize );
  2190. close ( infile );
  2191. unzipfile := unzip_NotSupported;
  2192. inuse := FALSE;
  2193. exit;
  2194. END;
  2195. hufttype := header^.bit_flag;
  2196. IF ( hufttype AND 1 ) <> 0 THEN BEGIN {encrypted}
  2197. freemem ( slide, wsize );
  2198. close ( infile );
  2199. unzipfile := unzip_Encrypted;
  2200. inuse := FALSE;
  2201. exit;
  2202. END;
  2203. reachedsize := 0;
  2204. seek ( infile, offset );
  2205. assign ( outfile, out_name );
  2206. {$I-}
  2207. rewrite ( outfile, 1 );
  2208. {$I+}
  2209. err := ioresult;
  2210. {create directories not yet in path}
  2211. isadir := ( out_name [ strlen ( out_name ) -1 ] = '/' )
  2212. OR ( out_name [ strlen ( out_name ) -1 ] = '\' );
  2213. IF ( err = 3 ) OR isadir THEN BEGIN {path not found}
  2214. {$I-}
  2215. getdir ( 0, oldcurdir );
  2216. {$I+}
  2217. err := ioresult;
  2218. strcopy ( buf, out_name );
  2219. p1 := strrscan ( buf, '\' );
  2220. IF p1 <> NIL THEN inc ( p1 ); {pointer to filename}
  2221. p := strtok ( buf, '\' );
  2222. IF ( p <> NIL ) AND ( p [ 1 ] = ':' ) THEN BEGIN
  2223. strcopy ( buf0, 'c:\' ); {set drive}
  2224. buf0 [ 0 ] := p [ 0 ];
  2225. {$ifdef windows}
  2226. setcurdir ( buf0 );
  2227. {$else}
  2228. {$I-}
  2229. chdir ( buf0 );
  2230. {$I+}
  2231. err := ioresult;
  2232. {$endif}
  2233. p := strtok ( NIL, '\' );
  2234. END;
  2235. WHILE ( p <> NIL ) AND ( p <> p1 ) DO BEGIN
  2236. {$ifdef windows}
  2237. {$ifdef Delphi}
  2238. {$I-}
  2239. chdir ( strpas ( p ) );
  2240. {$I+}
  2241. err := ioresult;
  2242. {$else Delphi}
  2243. setcurdir ( p );
  2244. err := doserror;
  2245. {$endif Delphi}
  2246. {$else Windows}
  2247. {$I-}
  2248. chdir ( strpas ( p ) );
  2249. {$I+}
  2250. err := ioresult;
  2251. {$endif}
  2252. IF err <> 0 THEN BEGIN
  2253. {$ifdef windows}
  2254. createdir ( p );
  2255. err := doserror;
  2256. {$else}
  2257. {$I-}
  2258. mkdir ( strpas ( p ) );
  2259. {$I+}
  2260. err := ioresult;
  2261. {$endif}
  2262. IF err = 0 THEN
  2263. {$I-}
  2264. chdir ( strpas ( p ) );
  2265. {$I+}
  2266. err := ioresult;
  2267. END;
  2268. IF err = 0 THEN
  2269. p := strtok ( NIL, '\' )
  2270. ELSE
  2271. p := NIL;
  2272. END;
  2273. {$I-}
  2274. chdir ( oldcurdir );
  2275. {$I+}
  2276. err := ioresult;
  2277. IF isadir THEN BEGIN
  2278. freemem ( slide, wsize );
  2279. unzipfile := unzip_Ok; {A directory -> ok}
  2280. close ( infile );
  2281. inuse := FALSE;
  2282. exit;
  2283. END;
  2284. {$I-}
  2285. rewrite ( outfile, 1 );
  2286. {$I+}
  2287. err := ioresult;
  2288. END;
  2289. IF err <> 0 THEN BEGIN
  2290. freemem ( slide, wsize );
  2291. unzipfile := unzip_WriteErr;
  2292. close ( infile );
  2293. inuse := FALSE;
  2294. exit
  2295. END;
  2296. totalabort := FALSE;
  2297. zipeof := FALSE;
  2298. dlghandle := hFileAction;
  2299. dlgnotify := cm_index;
  2300. {$ifdef windows}
  2301. messageloop;
  2302. oldpercent := 0;
  2303. {$endif}
  2304. crc32val := $FFFFFFFF;
  2305. {Unzip correct type}
  2306. CASE ziptype of
  2307. 0 : aResult := copystored;
  2308. 1 : aResult := unshrink;
  2309. 6 : aResult := explode;
  2310. 8 : aResult := inflate;
  2311. ELSE
  2312. aResult := unzip_NotSupported;
  2313. END;
  2314. unzipfile := aResult;
  2315. IF ( aResult = unzip_ok ) AND ( ( hufttype AND 8 ) <> 0 ) THEN BEGIN {CRC at the end}
  2316. dumpbits ( k AND 7 );
  2317. needbits ( 16 );
  2318. originalcrc := b AND $FFFF;
  2319. dumpbits ( 16 );
  2320. needbits ( 16 );
  2321. originalcrc := ( b AND $FFFF ) SHL 16;
  2322. dumpbits ( 16 );
  2323. END;
  2324. close ( infile );
  2325. close ( outfile );
  2326. crc32val := NOT ( crc32val ); {one's complement}
  2327. IF aResult <> 0 THEN BEGIN
  2328. erase ( outfile );
  2329. END ELSE IF ( originalcrc <> crc32val ) THEN BEGIN
  2330. unzipfile := unzip_CRCErr;
  2331. erase ( outfile );
  2332. END ELSE BEGIN
  2333. oldpercent := 100; {100 percent}
  2334. {$ifdef windows}
  2335. IF dlghandle <> 0 THEN
  2336. sendmessage ( dlghandle, wm_command, dlgnotify, longint ( @oldpercent ) );
  2337. {$endif}
  2338. filemode := 0;
  2339. reset ( outfile );
  2340. setftime ( outfile, timedate ); {set zipped time and date of oufile}
  2341. close ( outfile );
  2342. END;
  2343. freemem ( slide, wsize );
  2344. inuse := FALSE;
  2345. END;
  2346. {***************************************************************************}
  2347. {***************************************************************************}
  2348. {***************************************************************************}
  2349. { other functions; zipread.pas }
  2350. CONST mainheader : pchar = 'PK'#5#6;
  2351. maxbufsize = 64000; {Can be as low as 500 Bytes; however, }
  2352. {this would lead to extensive disk reading!}
  2353. {If one entry (including Extra field) is bigger}
  2354. {than maxbufsize, you cannot read it :-( }
  2355. TYPE
  2356. pheader = ^theader;
  2357. pmainheader = ^tmainheader;
  2358. tmainheader = PACKED RECORD
  2359. signature : ARRAY [ 0..3 ] of char; {'PK'#5#6}
  2360. thisdisk,
  2361. centralstartdisk,
  2362. entries_this_disk,
  2363. entries_central_dir : word;
  2364. headsize,
  2365. headstart : longint;
  2366. comment_len : longint;
  2367. unknown : word;
  2368. END;
  2369. theader = PACKED RECORD
  2370. signature : ARRAY [ 0..3 ] of char; {'PK'#1#2}
  2371. OSversion, {Operating system version}
  2372. OSmadeby : byte; {MSDOS (FAT): 0}
  2373. extract_ver,
  2374. bit_flag,
  2375. zip_type : word;
  2376. file_timedate : longint;
  2377. crc_32,
  2378. compress_size,
  2379. uncompress_size : longint;
  2380. filename_len,
  2381. extra_field_len,
  2382. file_comment_len,
  2383. disk_number_start,
  2384. internal_attr : word;
  2385. external_attr : ARRAY [ 0..3 ] of byte;
  2386. offset_local_header : longint;
  2387. END;
  2388. {*********** Fill out tZipRec structure with next entry *************}
  2389. FUNCTION filloutRec ( VAR zprec : tZipRec ) : integer;
  2390. VAR p : pchar;
  2391. incr : longint;
  2392. header : pheader;
  2393. offs : word;
  2394. old : char;
  2395. f : file;
  2396. extra, err : nword;
  2397. BEGIN
  2398. WITH zprec DO BEGIN
  2399. header := pheader ( @buf^ [ localstart ] );
  2400. IF ( bufsize = maxbufsize ) THEN BEGIN {Caution: header bigger than 64k!}
  2401. extra := sizeof ( file );
  2402. IF ( ( localstart + sizeof ( theader ) ) > bufsize ) OR
  2403. ( localstart + header^.filename_len + header^.extra_field_len +
  2404. header^.file_comment_len + sizeof ( theader ) > bufsize )
  2405. THEN BEGIN {Read over end of header}
  2406. move ( buf^ [ bufsize + 1 ], f, extra ); {Restore file}
  2407. move ( buf^ [ localstart ], buf^ [ 0 ], bufsize -localstart ); {Move end to beginning in buffer}
  2408. {$I-}
  2409. blockread ( f, buf^ [ bufsize -localstart ], localstart, err ); {Read in full central dir, up to maxbufsize Bytes}
  2410. {$I+}
  2411. IF ( ioresult <> 0 ) OR ( err + localstart < sizeof ( theader ) ) THEN BEGIN
  2412. filloutrec := unzip_nomoreitems;
  2413. exit
  2414. END;
  2415. move ( f, buf^ [ bufsize + 1 ], extra ); {Save changed file info!}
  2416. localstart := 0;
  2417. header := pheader ( @buf^ [ localstart ] );
  2418. END;
  2419. END;
  2420. IF ( localstart + 4 <= bufsize ) AND {Here is the ONLY correct finish!}
  2421. ( strlcomp ( header^.signature, mainheader, 4 ) = 0 ) THEN BEGIN {Main header}
  2422. filloutrec := unzip_nomoreitems;
  2423. exit
  2424. END;
  2425. IF ( localstart + sizeof ( header ) > bufsize ) OR
  2426. ( localstart + header^.filename_len + header^.extra_field_len +
  2427. header^.file_comment_len + sizeof ( theader ) > bufsize ) OR
  2428. ( strlcomp ( header^.signature, 'PK'#1#2, 4 ) <> 0 ) THEN BEGIN
  2429. filloutrec := unzip_nomoreitems;
  2430. exit
  2431. END;
  2432. size := header^.uncompress_size;
  2433. compressSize := header^.compress_size;
  2434. IF header^.osmadeby = 0 THEN
  2435. attr := header^.external_attr [ 0 ]
  2436. ELSE
  2437. attr := 0;
  2438. time := header^.file_timedate;
  2439. headeroffset := header^.offset_local_header; {Other header size}
  2440. Packmethod := header^.zip_type;
  2441. offs := localstart + header^.filename_len + sizeof ( header^ );
  2442. old := buf^ [ offs ];
  2443. buf^ [ offs ] := #0; {Repair signature of next block!}
  2444. strlcopy ( filename, pchar ( @buf^ [ localstart + sizeof ( header^ ) ] ), sizeof ( filename ) -1 );
  2445. buf^ [ offs ] := old;
  2446. REPEAT {Convert slash to backslash!}
  2447. p := strscan ( filename, '/' );
  2448. IF p <> NIL THEN p [ 0 ] := '\';
  2449. UNTIL p = NIL;
  2450. incr := header^.filename_len + header^.extra_field_len +
  2451. header^.file_comment_len + sizeof ( header^ );
  2452. IF incr <= 0 THEN BEGIN
  2453. filloutrec := unzip_InternalError;
  2454. exit
  2455. END;
  2456. localstart := localstart + incr;
  2457. filloutrec := unzip_ok;
  2458. END;
  2459. END;
  2460. {**************** Get first entry from ZIP file ********************}
  2461. FUNCTION GetFirstInZip ( zipfilename : pchar;VAR zprec : tZipRec ) : integer;
  2462. VAR bufstart, headerstart, start : longint;
  2463. err, i : integer;
  2464. mainh : pmainheader;
  2465. f : file;
  2466. extra : word; {Extra bytes for saving File!}
  2467. BEGIN
  2468. WITH zprec DO BEGIN
  2469. assign ( f, zipfilename );
  2470. filemode := 0; {Others may read or write};
  2471. {$I-}
  2472. reset ( f, 1 );
  2473. {$I+}
  2474. IF ioresult <> 0 THEN BEGIN
  2475. GetFirstInZip := unzip_FileError;
  2476. exit
  2477. END;
  2478. size := filesize ( f );
  2479. IF size = 0 THEN BEGIN
  2480. GetFirstInZip := unzip_FileError;
  2481. {$I-}
  2482. close ( f );
  2483. {$I+}
  2484. exit
  2485. END;
  2486. bufsize := 4096; {in 4k-blocks}
  2487. IF size > bufsize THEN BEGIN
  2488. bufstart := size -bufsize;
  2489. END ELSE BEGIN
  2490. bufstart := 0;
  2491. bufsize := size;
  2492. END;
  2493. getmem ( buf, bufsize + 1 ); {#0 at the end of filemname}
  2494. {Search from back of file to central directory start}
  2495. start := -1; {Nothing found}
  2496. REPEAT
  2497. {$I-}
  2498. seek ( f, bufstart );
  2499. {$I+}
  2500. IF ioresult <> 0 THEN BEGIN
  2501. GetFirstInZip := unzip_FileError;
  2502. freeMem ( buf, bufsize + 1 );
  2503. buf := NIL;
  2504. {$I-}
  2505. close ( f );
  2506. {$I+}
  2507. exit
  2508. END;
  2509. {$I-}
  2510. blockread ( f, buf^, bufsize, err );
  2511. {$I+}
  2512. IF ( ioresult <> 0 ) OR ( err <> bufsize ) THEN BEGIN
  2513. GetFirstInZip := unzip_FileError;
  2514. freeMem ( buf, bufsize + 1 );
  2515. buf := NIL;
  2516. {$I-}
  2517. close ( f );
  2518. {$I+}
  2519. exit
  2520. END;
  2521. IF bufstart = 0 THEN start := maxlongint;{Break}
  2522. FOR i := bufsize -22 DOWNTO 0 DO BEGIN {Search buffer backwards}
  2523. IF ( buf^ [ i ] = 'P' ) AND ( buf^ [ i + 1 ] = 'K' ) AND ( buf^ [ i + 2 ] = #5 ) AND ( buf^ [ i + 3 ] = #6 )
  2524. THEN BEGIN {Header found!!!}
  2525. start := bufstart + i;
  2526. break;
  2527. END;
  2528. END;
  2529. IF start = -1 THEN BEGIN {Nothing found yet}
  2530. dec ( bufstart, bufsize -22 ); {Full header in buffer!}
  2531. IF bufstart < 0 THEN bufstart := 0;
  2532. END;
  2533. UNTIL start >= 0;
  2534. IF ( start = maxlongint ) THEN BEGIN {Nothing found}
  2535. GetFirstInZip := unzip_FileError;
  2536. freeMem ( buf, bufsize + 1 );
  2537. buf := NIL;
  2538. {$I-}
  2539. close ( f );
  2540. {$I+}
  2541. exit
  2542. END;
  2543. mainh := pmainheader ( @buf^ [ start -bufstart ] );
  2544. headerstart := mainh^.headstart;
  2545. localstart := 0;
  2546. freeMem ( buf, bufsize + 1 );
  2547. IF ( localstart + sizeof ( theader ) > start ) THEN BEGIN
  2548. buf := NIL;
  2549. GetFirstInZip := unzip_InternalError;
  2550. {$I-}
  2551. close ( f );
  2552. {$I+}
  2553. exit
  2554. END;
  2555. bufstart := headerstart;
  2556. start := start -headerstart + 4; {size for central dir,Including main header signature}
  2557. IF start >= maxbufsize THEN BEGIN
  2558. bufsize := maxbufsize; {Max buffer size, limit of around 1000 items!}
  2559. extra := sizeof ( file ) {Save file information for later reading!}
  2560. END ELSE BEGIN
  2561. bufsize := start;
  2562. extra := 0
  2563. END;
  2564. getmem ( buf, bufsize + 1 + extra );
  2565. {$I-}
  2566. seek ( f, bufstart );
  2567. {$I+}
  2568. IF ioresult <> 0 THEN BEGIN
  2569. GetFirstInZip := unzip_FileError;
  2570. freeMem ( buf, bufsize + 1 + extra );
  2571. buf := NIL;
  2572. {$I-}
  2573. close ( f );
  2574. {$I+}
  2575. exit
  2576. END;
  2577. {$I-}
  2578. blockread ( f, buf^, bufsize, err ); {Read in full central dir, up to maxbufsize Bytes}
  2579. {$I+}
  2580. IF ioresult <> 0 THEN BEGIN
  2581. GetFirstInZip := unzip_FileError;
  2582. freeMem ( buf, bufsize + 1 + extra );
  2583. buf := NIL;
  2584. {$I-}
  2585. close ( f );
  2586. {$I+}
  2587. exit
  2588. END;
  2589. IF extra = 0 THEN
  2590. {$I-} close ( f ) {$I+}
  2591. ELSE move ( f, buf^ [ bufsize + 1 ], extra ); {Save file info!}
  2592. err := filloutRec ( zprec );
  2593. IF err <> unzip_ok THEN BEGIN
  2594. CloseZipFile ( zprec );
  2595. GetFirstInZip := err;
  2596. exit
  2597. END;
  2598. GetFirstInZip := err;
  2599. END;
  2600. END;
  2601. {**************** Get next entry from ZIP file ********************}
  2602. FUNCTION GetNextInZip ( VAR Zprec : tZiprec ) : integer;
  2603. VAR err : integer;
  2604. BEGIN
  2605. WITH zprec DO BEGIN
  2606. IF ( buf <> NIL ) THEN BEGIN {Main Header at the end}
  2607. err := filloutRec ( zprec );
  2608. IF err <> unzip_ok THEN BEGIN
  2609. CloseZipFile ( ZPRec );
  2610. END;
  2611. GetNextInZip := err;
  2612. END ELSE GetNextInZip := unzip_NoMoreItems;
  2613. END
  2614. END;
  2615. {**************** VERY simple test for zip file ********************}
  2616. FUNCTION isZip ( filename : pchar ) : boolean;
  2617. VAR
  2618. myname : tdirtype;
  2619. l, err : integer;
  2620. f : file;
  2621. buf : ARRAY [ 0..4 ] of char;
  2622. oldcurdir : string{$ifndef Win32} [ 80 ]{$endif};
  2623. BEGIN
  2624. filemode := 0;
  2625. {$I-}
  2626. getdir ( 0, oldcurdir );
  2627. {$I+}
  2628. err := ioresult;
  2629. isZip := FALSE;
  2630. IF ( strscan ( filename, '.' ) <> NIL )
  2631. AND ( strpos ( filename, '.exe' ) = NIL ) THEN BEGIN
  2632. strcopy ( myname, filename );
  2633. l := strlen ( myname );
  2634. IF myname [ l -1 ] = '\' THEN myname [ l -1 ] := #0;
  2635. {$I-}
  2636. chdir ( Strpas ( myname ) );
  2637. {$I+}
  2638. IF ioresult <> 0 THEN BEGIN
  2639. assign ( f, Strpas ( myname ) );
  2640. filemode := 0; {Others may read or write};
  2641. {$I-}
  2642. reset ( f, 1 );
  2643. {$I+}
  2644. IF ioresult = 0 THEN BEGIN
  2645. {$I-}
  2646. blockread ( f, buf, 4, err );
  2647. {$I+}
  2648. IF ( ioresult = 0 ) THEN BEGIN
  2649. IF ( err = 4 ) AND ( buf [ 0 ] = 'P' ) AND ( buf [ 1 ] = 'K' )
  2650. AND ( buf [ 2 ] = #3 ) AND ( buf [ 3 ] = #4 ) THEN isZip := TRUE
  2651. END;
  2652. {$I-}
  2653. close ( f );
  2654. {$I+}
  2655. err := ioresult; {only clears ioresult variable}
  2656. END;
  2657. END;
  2658. END;
  2659. {$I-}
  2660. chdir ( oldcurdir );
  2661. {$I+}
  2662. err := ioresult;
  2663. END;
  2664. {**************** free ZIP buffers ********************}
  2665. PROCEDURE CloseZipFile ( VAR Zprec : tZiprec ); {Only free buffer, file only open in Getfirstinzip}
  2666. VAR
  2667. f : file;
  2668. extra : word;
  2669. BEGIN
  2670. WITH zprec DO BEGIN
  2671. IF buf <> NIL THEN BEGIN
  2672. IF ( bufsize = maxbufsize ) THEN BEGIN {Caution: header bigger than 64k!}
  2673. extra := sizeof ( file );
  2674. move ( buf^ [ bufsize + 1 ], f, extra ); {Restore file}
  2675. {$I-}
  2676. close ( f );
  2677. {$I+}
  2678. IF ioresult <> 0 THEN ;
  2679. END ELSE extra := 0;
  2680. freemem ( buf, bufsize + 1 + extra );
  2681. buf := NIL
  2682. END;
  2683. END
  2684. END;
  2685. {***************************************************************************}
  2686. {***************************************************************************}
  2687. {********** routines by the African Chief **********************************}
  2688. {***************************************************************************}
  2689. {***************************************************************************}
  2690. {$ifndef Delphi}
  2691. FUNCTION FileExists ( CONST fname : string ) : boolean; {simple fileexist function}
  2692. VAR
  2693. f : file;
  2694. i : byte;
  2695. BEGIN
  2696. i := filemode;
  2697. filemode := 0;
  2698. assign ( f, fname );
  2699. {$i-}
  2700. Reset ( f, 1 );
  2701. filemode := i;
  2702. FileExists := ioresult = 0;
  2703. Close ( f ); IF ioresult <> 0 THEN;
  2704. {$i+}
  2705. END;
  2706. {$endif Delphi}
  2707. PROCEDURE DummyReport ( Retcode : longint;Rec : pReportRec );
  2708. {$ifdef Windows}{$ifdef win32}STDCALL;{$else}EXPORT;{$endif}{$endif}
  2709. {dummy report procedure}
  2710. BEGIN
  2711. END;
  2712. FUNCTION Matches ( s : String;CONST main : string ) : Boolean;
  2713. {rudimentary matching function;
  2714. accepts only '', '*.*', 'XXX.*' or '*.XXX'
  2715. }
  2716. FUNCTION extensiononly ( CONST s : string ) : string;{return just the extension}
  2717. VAR i : integer;
  2718. BEGIN
  2719. extensiononly := '';
  2720. i := pos ( '.', s );
  2721. IF i = 0 THEN exit;
  2722. extensiononly := copy ( s, succ ( i ), length ( s ) );
  2723. END;
  2724. FUNCTION nameonly ( CONST s : string ) : string;{return just the name}
  2725. VAR i : integer;
  2726. BEGIN
  2727. nameonly := s;
  2728. i := pos ( '.', s );
  2729. IF i = 0 THEN exit;
  2730. nameonly := copy ( s, 1, pred ( i ) );
  2731. END;
  2732. {!!!!!}
  2733. VAR
  2734. b : boolean;
  2735. i : integer;
  2736. BEGIN
  2737. Matches := TRUE;
  2738. IF ( s = '' ) OR ( s = '*.*' ) THEN exit; {'' or '*.*' = all files match}
  2739. s := upper ( s );
  2740. b := copy ( s, 1, 2 ) = '*.'; {e.g., *.PAS}
  2741. IF b THEN BEGIN
  2742. delete ( s, 1, 2 );
  2743. Matches := s = extensiononly ( upper ( main ) );
  2744. END ELSE BEGIN
  2745. i := length ( s );
  2746. b := s [ i ] = '*'; {e.g. TEST.*}
  2747. IF b THEN BEGIN
  2748. IF s [ pred ( i ) ] = '.' THEN delete ( s, pred ( i ), 2 );
  2749. i := length ( s );
  2750. IF s [ i ] in [ '*', '?' ] THEN dec ( i );{e.g. TEST*.*}
  2751. Matches := Copy ( s, 1, i ) = Copy ( nameonly ( upper ( main ) ), 1, i );
  2752. END ELSE Matches := s = upper ( main );
  2753. END;
  2754. END; { Matches }
  2755. {****************************************************}
  2756. FUNCTION FileUnzip ( SourceZipFile, TargetDirectory, FileSpecs : pChar;
  2757. Report : UnzipReportProc;Question : UnzipQuestionProc ) : integer;
  2758. VAR
  2759. rc : integer;
  2760. r : tziprec;
  2761. buf,
  2762. thename,
  2763. target : ARRAY [ 0..tFSize ] of char;
  2764. Count : integer;
  2765. rSize, cSize : longint;
  2766. s : string [ 255 ];
  2767. BEGIN
  2768. Count := 0;
  2769. rSize := 0;
  2770. cSize := 0;
  2771. FileUnzip := unzip_MissingParameter;
  2772. IF ( StrPas ( SourceZipFile ) = '' ) OR ( StrPas ( TargetDirectory ) = '' ) THEN Exit;
  2773. Strcopy ( thename, SourceZipFile );
  2774. Strcopy ( target, TargetDirectory );
  2775. IF ( target [ 0 ] <> #0 ) AND ( target [ strlen ( target ) -1 ] <> '\' )
  2776. THEN strcat ( target, '\' );
  2777. FileUnzip := unzip_NotZipFile;
  2778. IF NOT iszip ( thename ) THEN exit;
  2779. FillChar ( ZipRec, Sizeof ( ZipRec ), #0 );
  2780. IF @Report <> NIL THEN {start of ZIP file}
  2781. WITH ZipRec DO BEGIN
  2782. IsaDir := FALSE;
  2783. strcopy ( FileName, thename );
  2784. Size := UnZipSize ( SourceZipFile, CompressSize );
  2785. IF Size = 0 THEN ratio := 0 ELSE
  2786. Ratio := 100 -Round ( ( CompressSize / Size ) * 100 );
  2787. Status := unzip_starting;
  2788. Report ( Status, @ZipRec );
  2789. END; {start of ZIP file}
  2790. IF @Report = NIL THEN Report := DummyReport;
  2791. ZipReport := Report;
  2792. rc := getfirstinzip ( thename, r );
  2793. WHILE ( rc = unzip_ok )
  2794. DO BEGIN
  2795. IF ( Matches ( StrPas ( FileSpecs ), Strpas ( R.FileName ) ) )
  2796. THEN BEGIN
  2797. Inc ( rSize, r.Size );
  2798. Inc ( cSize, r.CompressSize );
  2799. strcopy ( buf, target );
  2800. IF NoRecurseDirs { no recursion }
  2801. THEN BEGIN
  2802. s := StripPath ( Strpas ( r.filename ) ) + #0;
  2803. Strcat ( buf, @s [ 1 ] );
  2804. END ELSE strcat ( buf, r.filename );
  2805. WITH ZipRec DO BEGIN { report start of file }
  2806. s := StrPas ( Buf );
  2807. IsaDir := s [ length ( s ) ] = '\';
  2808. Time := r.Time;
  2809. Size := r.Size;
  2810. CompressSize := r.CompressSize;
  2811. strcopy ( FileName, buf );
  2812. PackMethod := r.PackMethod;
  2813. Attr := r.Attr;
  2814. IF Size = 0 THEN ratio := 0 ELSE
  2815. Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
  2816. Status := file_starting;
  2817. IF ( IsaDir ) AND ( NoRecurseDirs )
  2818. THEN {} ELSE
  2819. ZipReport ( Status, @ZipRec );
  2820. END; { start of file }
  2821. IF ( @Question <> NIL )
  2822. AND ( FileExists ( StrPas ( buf ) ) )
  2823. AND ( Question ( @ZipRec ) = FALSE )
  2824. THEN BEGIN
  2825. rc := unzip_ok; { we are okay }
  2826. WITH ZipRec DO BEGIN
  2827. Status := file_unzipping;
  2828. PackMethod := 9; { skipped }
  2829. ZipReport ( Size, @ZipRec ); { report uncompressed size }
  2830. END;
  2831. END ELSE BEGIN
  2832. rc := unzipfile ( thename, buf, r.headeroffset, 0,
  2833. {$ifdef windows}vk_escape{$else}27{$endif} ); {Escape interrupts}
  2834. END;
  2835. IF rc = unzip_ok
  2836. THEN BEGIN
  2837. Inc ( Count );
  2838. WITH ZipRec DO BEGIN { report end of file }
  2839. Status := file_completed;
  2840. IF ( IsaDir ) AND ( NoRecurseDirs )
  2841. THEN {} ELSE
  2842. ZipReport ( Status, @ZipRec );
  2843. END; { end of file }
  2844. END ELSE BEGIN
  2845. ZipRec.Status := file_failure; {error}
  2846. CASE rc of
  2847. unzip_CRCErr,
  2848. unzip_WriteErr,
  2849. unzip_Encrypted,
  2850. unzip_NotSupported : ZipReport ( rc, @ZipRec );
  2851. unzip_ReadErr, unzip_Userabort,
  2852. unzip_FileError, unzip_InternalError,
  2853. unzip_InUse, unzip_ZipFileErr :
  2854. BEGIN
  2855. ZipRec.Status := unzip_SeriousError;
  2856. FileUnzip := unzip_SeriousError; {Serious error, force abort}
  2857. ZipReport ( unzip_SeriousError, @ZipRec );
  2858. closezipfile ( r );
  2859. ZipReport := NIL;
  2860. ZipQuestion := NIL;
  2861. exit;
  2862. END;
  2863. END; {case rc}
  2864. Continue;
  2865. {rc:=getnextinzip(r);}
  2866. END; {else}
  2867. END; { if Matches }
  2868. rc := getnextinzip ( r );
  2869. END; {while }
  2870. closezipfile ( r ); {Free memory used for central directory info}
  2871. WITH ZipRec DO BEGIN { report end of ZIP file }
  2872. Time := -1;
  2873. Attr := -1;
  2874. PackMethod := 0;
  2875. Size := rSize;
  2876. CompressSize := cSize;
  2877. strcopy ( FileName, thename );
  2878. IF Size = 0 THEN ratio := 0 ELSE
  2879. Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
  2880. Status := unzip_completed;
  2881. ZipReport ( Status, @ZipRec );
  2882. END; { end of ZIP file }
  2883. ZipReport := NIL;
  2884. ZipQuestion := NIL;
  2885. FileUnzip := Count;
  2886. END; { FileUnzip }
  2887. {***************************************************************************}
  2888. FUNCTION FileUnzipEx ( SourceZipFile, TargetDirectory, FileSpecs : pChar ) : integer;
  2889. BEGIN
  2890. FileUnzipEx :=
  2891. FileUnzip ( SourceZipFile, TargetDirectory, FileSpecs, ZipReport, ZipQuestion );
  2892. END; { FileUnzipEx }
  2893. {***************************************************************************}
  2894. FUNCTION Viewzip ( SourceZipFile, FileSpecs : pChar; Report : UnzipReportProc ) : integer;
  2895. VAR
  2896. rc : integer;
  2897. r : tziprec;
  2898. thename : ARRAY [ 0..tFSize ] of char;
  2899. Count : integer;
  2900. rSize, cSize : longint;
  2901. BEGIN
  2902. Count := 0;
  2903. rSize := 0;
  2904. cSize := 0;
  2905. Viewzip := unzip_MissingParameter;
  2906. IF ( StrPas ( SourceZipFile ) = '' ) OR ( @Report = NIL ) THEN Exit;
  2907. Strcopy ( thename, SourceZipFile );
  2908. ViewZip := unzip_NotZipFile;
  2909. IF NOT iszip ( thename ) THEN exit;
  2910. IF @Report = NIL THEN Report := DummyReport;
  2911. FillChar ( ZipRec, Sizeof ( ZipRec ), #0 );
  2912. rc := getfirstinzip ( thename, r );
  2913. WHILE ( rc = unzip_ok )
  2914. DO BEGIN
  2915. IF ( Matches ( StrPas ( FileSpecs ), Strpas ( R.FileName ) ) ) THEN BEGIN
  2916. Inc ( rSize, r.Size );
  2917. Inc ( cSize, r.CompressSize );
  2918. WITH ZipRec DO BEGIN
  2919. Time := r.Time;
  2920. Size := r.Size;
  2921. CompressSize := r.CompressSize;
  2922. strcopy ( FileName, r.Filename );
  2923. PackMethod := r.PackMethod;
  2924. Attr := r.Attr;
  2925. IF Size = 0 THEN ratio := 0 ELSE
  2926. Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
  2927. END;
  2928. Inc ( Count );
  2929. Report ( rc, @ZipRec );
  2930. END; {matches}
  2931. rc := getnextinzip ( r );
  2932. END; {while }
  2933. closezipfile ( r );
  2934. WITH ZipRec DO BEGIN
  2935. Time := -1;
  2936. Attr := -1;
  2937. PackMethod := 0;
  2938. Size := rSize;
  2939. CompressSize := cSize;
  2940. strcopy ( FileName, thename );
  2941. IF Size = 0 THEN ratio := 0 ELSE
  2942. Ratio := 100 -Round ( ( CompressSize /Size ) * 100 );
  2943. END;
  2944. Report ( Count, @ZipRec );
  2945. ViewZip := Count;
  2946. END; { ViewZip }
  2947. {***************************************************************************}
  2948. FUNCTION UnZipSize ( SourceZipFile : pChar;VAR Compressed : Longint ) : longint;
  2949. VAR
  2950. rc : integer;
  2951. r : tziprec;
  2952. thename : ARRAY [ 0..tFSize ] of char;
  2953. Count : longint;
  2954. f : file;
  2955. BEGIN
  2956. Compressed := 0;
  2957. UnZipSize := 0;
  2958. IF ( StrPas ( SourceZipFile ) = '' ) THEN Exit;
  2959. System.Assign ( f, StrPas ( SourceZipFile ) );
  2960. count := filemode;
  2961. filemode := 0;
  2962. {$i-}
  2963. Reset ( f, 1 );
  2964. filemode := count;
  2965. IF ioresult <> 0 THEN exit;
  2966. Count := filesize ( f );
  2967. close ( f );
  2968. UnZipSize := count;
  2969. Compressed := count;
  2970. Strcopy ( thename, SourceZipFile );
  2971. IF NOT iszip ( thename ) THEN exit;
  2972. Count := 0;
  2973. Compressed := 0;
  2974. rc := getfirstinzip ( thename, r );
  2975. WHILE ( rc = unzip_ok )
  2976. DO BEGIN
  2977. Inc ( Count, r.Size );
  2978. Inc ( Compressed, r.CompressSize );
  2979. rc := getnextinzip ( r );
  2980. END; {while }
  2981. closezipfile ( r );
  2982. UnZipSize := Count;
  2983. END; { UnZipSize }
  2984. {***************************************************************************}
  2985. FUNCTION SetUnZipReportProc ( aProc : UnzipReportProc ) : Pointer;
  2986. BEGIN
  2987. SetUnZipReportProc := @ZipReport; {save and return original}
  2988. ZipReport := aProc;
  2989. END; { SetUnZipReportProc }
  2990. {***************************************************************************}
  2991. FUNCTION SetUnZipQuestionProc ( aProc : UnzipQuestionProc ) : Pointer;
  2992. BEGIN
  2993. SetUnZipQuestionProc := @ZipQuestion; {save and return original}
  2994. ZipQuestion := aProc;
  2995. END; { SetUnZipQuestionProc }
  2996. {***************************************************************************}
  2997. FUNCTION SetNoRecurseDirs ( DontRecurse : Boolean ) : Boolean;
  2998. BEGIN
  2999. SetNoRecurseDirs := NoRecurseDirs;
  3000. NoRecurseDirs := DontRecurse;
  3001. END; { SetNoRecurseDirs }
  3002. {***************************************************************************}
  3003. {***************************************************************************}
  3004. PROCEDURE ChfUnzip_Init;
  3005. BEGIN
  3006. slide := NIL; {unused}
  3007. {$ifdef windows}
  3008. inuse := FALSE; {Not yet in use!}
  3009. lastusedtime := 0; {Not yet used}
  3010. {$endif}
  3011. SetUnZipReportProc ( NIL );
  3012. SetUnZipQuestionProc ( NIL );
  3013. SetNoRecurseDirs ( FALSE );
  3014. END;
  3015. {***************************************************************************}
  3016. {***************************************************************************}
  3017. {***************************************************************************}
  3018. BEGIN
  3019. ChfUnzip_Init;
  3020. END.