miniunz.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. program MiniUnz;
  2. { mini unzip demo package by Gilles Vollant
  3. Usage : miniunz [-exvlo] file.zip [file_to_extract]
  4. -l or -v list the content of the zipfile.
  5. -e extract a specific file or all files if [file_to_extract] is missing
  6. -x like -e, but extract without path information
  7. -o overwrite an existing file without warning
  8. Pascal tranlastion
  9. Copyright (C) 2000 by Jacques Nomssi Nzali
  10. For conditions of distribution and use, see copyright notice in readme.txt
  11. }{$ifdef WIN32}
  12. {$define Delphi}
  13. {$ifndef FPC}
  14. {$define Delphi32}
  15. {$endif}
  16. {$endif}
  17. uses
  18. sysutils,
  19. {$ifdef Delphi}
  20. Windows,
  21. {$else}
  22. zlib,ctypes,
  23. {$endif}
  24. ziputils,
  25. unzip;
  26. const
  27. CASESENSITIVITY = 0;
  28. WRITEBUFFERSIZE = 8192;
  29. { change_file_date : change the date/time of a file
  30. filename : the filename of the file where date/time must be modified
  31. dosdate : the new date at the MSDos format (4 bytes)
  32. tmu_date : the SAME new date at the tm_unz format }
  33. procedure change_file_date(const filename: PChar; dosdate: longword; tmu_date: tm_unz);
  34. {$ifdef Delphi32}
  35. var
  36. hFile: THandle;
  37. ftm, ftLocal, ftCreate, ftLastAcc, ftLastWrite: TFileTime;
  38. begin
  39. hFile := CreateFile(filename, GENERIC_READ or GENERIC_WRITE,
  40. 0, nil, OPEN_EXISTING, 0, 0);
  41. GetFileTime(hFile, @ftCreate, @ftLastAcc, @ftLastWrite);
  42. DosDateTimeToFileTime(word((dosdate shl 16)), word(dosdate), ftLocal);
  43. LocalFileTimeToFileTime(ftLocal, ftm);
  44. SetFileTime(hFile, @ftm, @ftLastAcc, @ftm);
  45. CloseHandle(hFile);
  46. end;
  47. {$else}
  48. {$if defined(FPC) and defined(win32)}
  49. var
  50. hFile : THandle;
  51. ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite : TFileTime;
  52. begin
  53. hFile := CreateFile(filename,GENERIC_READ or GENERIC_WRITE,
  54. 0,NIL,OPEN_EXISTING,0,0);
  55. GetFileTime(hFile, @ftCreate, @ftLastAcc, @ftLastWrite);
  56. DosDateTimeToFileTime(WORD((dosdate shl 16)), WORD(dosdate), @ftLocal);
  57. LocalFileTimeToFileTime(ftLocal, @ftm);
  58. SetFileTime(hFile,ftm, ftLastAcc, ftm);
  59. CloseHandle(hFile);
  60. end;
  61. {$else} { msdos }
  62. begin
  63. FileSetDate(filename,dosdate);
  64. end;
  65. {$endif}
  66. {$endif}
  67. { mymkdir and change_file_date are not 100 % portable
  68. As I don't know well Unix, I wait feedback for the unix portion }
  69. function mymkdir(dirname: PChar): boolean;
  70. var
  71. S: string;
  72. begin
  73. S := StrPas(dirname);
  74. {$I-}
  75. mkdir(S);
  76. mymkdir := IOresult = 0;
  77. end;
  78. function makedir(newdir: PChar): boolean;
  79. var
  80. buffer: PChar;
  81. p: PChar;
  82. len: cint;
  83. var
  84. hold: char;
  85. begin
  86. makedir := False;
  87. len := strlen(newdir);
  88. if (len <= 0) then
  89. exit;
  90. buffer := PChar(allocmem( len + 1));
  91. strcopy(buffer, newdir);
  92. if (buffer[len - 1] = '/') then
  93. buffer[len - 1] := #0;
  94. if mymkdir(buffer) then
  95. begin
  96. if Assigned(buffer) then
  97. freemem( buffer);
  98. makedir := True;
  99. exit;
  100. end;
  101. p := buffer + 1;
  102. while True do
  103. begin
  104. while ((p^ <> #0) and (p^ <> '\') and (p^ <> '/')) do
  105. Inc(p);
  106. hold := p^;
  107. p^ := #0;
  108. if (not mymkdir(buffer)) {and (errno = ENOENT)} then
  109. begin
  110. WriteLn('couldn''t create directory ', buffer);
  111. if Assigned(buffer) then
  112. freemem( buffer);
  113. exit;
  114. end;
  115. if (hold = #0) then
  116. break;
  117. p^ := hold;
  118. Inc(p);
  119. end;
  120. if Assigned(buffer) then
  121. freemem( buffer);
  122. makedir := True;
  123. end;
  124. procedure do_banner;
  125. begin
  126. WriteLn('MiniUnz 0.15, demo package written by Gilles Vollant');
  127. WriteLn('Pascal port by Jacques Nomssi Nzali');
  128. WriteLn('more info at http://wwww.tu-chemnitz.de/~nomssi/paszlib.html');
  129. WriteLn;
  130. end;
  131. procedure do_help;
  132. begin
  133. WriteLn('Usage : miniunz [-exvlo] file.zip [file_to_extract]');
  134. WriteLn;
  135. end;
  136. function LeadingZero(w: word): string;
  137. var
  138. s: string;
  139. begin
  140. Str(w: 0, s);
  141. if Length(s) = 1 then
  142. s := '0' + s;
  143. LeadingZero := s;
  144. end;
  145. function HexToStr(w: clong): string;
  146. const
  147. ByteToChar: array[0..$F] of char = '0123456789ABCDEF';
  148. var
  149. s: string;
  150. i: cint;
  151. x: clong;
  152. begin
  153. s := '';
  154. x := w;
  155. for i := 0 to 3 do
  156. begin
  157. s := ByteToChar[byte(x) shr 4] + ByteToChar[byte(x) and $F] + s;
  158. x := x shr 8;
  159. end;
  160. HexToStr := s;
  161. end;
  162. function do_list(uf: unzFile): cint;
  163. var
  164. i: longword;
  165. gi: unz_global_info;
  166. err: cint;
  167. var
  168. filename_inzip: array[0..255] of char;
  169. file_info: unz_file_info;
  170. ratio: longword;
  171. string_method: string[255];
  172. var
  173. iLevel: cuInt;
  174. begin
  175. err := unzGetGlobalInfo(uf, gi);
  176. if (err <> UNZ_OK) then
  177. WriteLn('error ', err, ' with zipfile in unzGetGlobalInfo');
  178. WriteLn(' Length Method Size Ratio Date Time CRC-32 Name');
  179. WriteLn(' ------ ------ ---- ----- ---- ---- ------ ----');
  180. for i := 0 to gi.number_entry - 1 do
  181. begin
  182. ratio := 0;
  183. err := unzGetCurrentFileInfo(uf, @file_info, filename_inzip, sizeof(filename_inzip), nil, 0, nil, 0);
  184. if (err <> UNZ_OK) then
  185. begin
  186. WriteLn('error ', err, ' with zipfile in unzGetCurrentFileInfo');
  187. break;
  188. end;
  189. if (file_info.uncompressed_size > 0) then
  190. ratio := (file_info.compressed_size * 100) div file_info.uncompressed_size;
  191. if (file_info.compression_method = 0) then
  192. string_method := 'Stored'
  193. else
  194. if (file_info.compression_method = Z_DEFLATED) then
  195. begin
  196. iLevel := cuInt((file_info.flag and $06) div 2);
  197. case iLevel of
  198. 0: string_method := 'Defl:N';
  199. 1: string_method := 'Defl:X';
  200. 2, 3: string_method := 'Defl:F'; { 2:fast , 3 : extra fast}
  201. else
  202. string_method := 'Unkn. ';
  203. end;
  204. end;
  205. WriteLn(file_info.uncompressed_size: 7, ' ',
  206. string_method: 6, ' ',
  207. file_info.compressed_size: 7, ' ',
  208. ratio: 3, '% ', LeadingZero(longword(file_info.tmu_date.tm_mon) + 1), '-',
  209. LeadingZero(longword(file_info.tmu_date.tm_mday)): 2, '-',
  210. LeadingZero(longword(file_info.tmu_date.tm_year mod 100)): 2, ' ',
  211. LeadingZero(longword(file_info.tmu_date.tm_hour)), ':',
  212. LeadingZero(longword(file_info.tmu_date.tm_min)), ' ',
  213. HexToStr(longword(file_info.crc)), ' ',
  214. filename_inzip);
  215. if ((i + 1) < gi.number_entry) then
  216. begin
  217. err := unzGoToNextFile(uf);
  218. if (err <> UNZ_OK) then
  219. begin
  220. WriteLn('error ', err, ' with zipfile in unzGoToNextFile');
  221. break;
  222. end;
  223. end;
  224. end;
  225. do_list := 0;
  226. end;
  227. function do_extract_currentfile(uf: unzFile; const popt_extract_without_path: cint; var popt_overwrite: cint): cint;
  228. var
  229. filename_inzip: packed array[0..255] of char;
  230. filename_withoutpath: PChar;
  231. p: PChar;
  232. err: cint;
  233. fout: FILEptr;
  234. buf: pointer;
  235. size_buf: cuInt;
  236. file_info: unz_file_info;
  237. var
  238. write_filename: PChar;
  239. skip: cint;
  240. var
  241. rep: char;
  242. ftestexist: FILEptr;
  243. var
  244. answer: string[127];
  245. var
  246. c: char;
  247. begin
  248. fout := nil;
  249. err := unzGetCurrentFileInfo(uf, @file_info, filename_inzip,
  250. sizeof(filename_inzip), nil, 0, nil, 0);
  251. if (err <> UNZ_OK) then
  252. begin
  253. WriteLn('error ', err, ' with zipfile in unzGetCurrentFileInfo');
  254. do_extract_currentfile := err;
  255. exit;
  256. end;
  257. size_buf := WRITEBUFFERSIZE;
  258. buf := allocmem(size_buf);
  259. if (buf = nil) then
  260. begin
  261. WriteLn('Error allocating memory');
  262. do_extract_currentfile := UNZ_INTERNALERROR;
  263. exit;
  264. end;
  265. filename_withoutpath := filename_inzip;
  266. p := filename_withoutpath;
  267. while (p^ <> #0) do
  268. begin
  269. if (p^ = '/') or (p^ = '\') then
  270. filename_withoutpath := p + 1;
  271. Inc(p);
  272. end;
  273. if (filename_withoutpath^ = #0) then
  274. begin
  275. if (popt_extract_without_path = 0) then
  276. begin
  277. WriteLn('creating directory: ', filename_inzip);
  278. mymkdir(filename_inzip);
  279. end;
  280. end
  281. else
  282. begin
  283. skip := 0;
  284. if (popt_extract_without_path = 0) then
  285. write_filename := filename_inzip
  286. else
  287. write_filename := filename_withoutpath;
  288. err := unzOpenCurrentFile(uf);
  289. if (err <> UNZ_OK) then
  290. WriteLn('error ', err, ' with zipfile in unzOpenCurrentFile');
  291. if ((popt_overwrite = 0) and (err = UNZ_OK)) then
  292. begin
  293. rep := #0;
  294. ftestexist := fopen(write_filename, fopenread);
  295. if (ftestexist <> nil) then
  296. begin
  297. fclose(ftestexist);
  298. repeat
  299. Write('The file ', write_filename,
  300. ' exist. Overwrite ? [y]es, [n]o, [A]ll: ');
  301. ReadLn(answer);
  302. rep := answer[1];
  303. if ((rep >= 'a') and (rep <= 'z')) then
  304. Dec(rep, $20);
  305. until (rep = 'Y') or (rep = 'N') or (rep = 'A');
  306. end;
  307. if (rep = 'N') then
  308. skip := 1;
  309. if (rep = 'A') then
  310. popt_overwrite := 1;
  311. end;
  312. if (skip = 0) and (err = UNZ_OK) then
  313. begin
  314. fout := fopen(write_filename, fopenwrite);
  315. { some zipfile don't contain directory alone before file }
  316. if (fout = nil) and (popt_extract_without_path = 0) and
  317. (filename_withoutpath <> PChar(@filename_inzip)) then
  318. begin
  319. c := (filename_withoutpath - 1)^;
  320. (filename_withoutpath -1)^ := #0;
  321. makedir(write_filename);
  322. (filename_withoutpath -1)^ := c;
  323. fout := fopen(write_filename, fopenwrite);
  324. end;
  325. if (fout = nil) then
  326. WriteLn('error opening ', write_filename);
  327. end;
  328. if (fout <> nil) then
  329. begin
  330. WriteLn(' extracting: ', write_filename);
  331. repeat
  332. err := unzReadCurrentFile(uf, buf, size_buf);
  333. if (err < 0) then
  334. begin
  335. WriteLn('error ', err, ' with zipfile in unzReadCurrentFile');
  336. break;
  337. end;
  338. if (err > 0) then
  339. if (fwrite(buf, err, 1, fout) <> 1) then
  340. begin
  341. WriteLn('error in writing extracted file');
  342. err := UNZ_ERRNO;
  343. break;
  344. end;
  345. until (err = 0);
  346. fclose(fout);
  347. if (err = 0) then
  348. change_file_date(write_filename, file_info.dosDate,
  349. file_info.tmu_date);
  350. end;
  351. if (err = UNZ_OK) then
  352. begin
  353. err := unzCloseCurrentFile(uf);
  354. if (err <> UNZ_OK) then
  355. WriteLn('error ', err, ' with zipfile in unzCloseCurrentFile')
  356. else
  357. unzCloseCurrentFile(uf); { don't lose the error }
  358. end;
  359. end;
  360. if buf <> nil then
  361. freemem( buf);
  362. do_extract_currentfile := err;
  363. end;
  364. function do_extract(uf: unzFile; opt_extract_without_path: cint; opt_overwrite: cint): cint;
  365. var
  366. i: longword;
  367. gi: unz_global_info;
  368. err: cint;
  369. begin
  370. err := unzGetGlobalInfo(uf, gi);
  371. if (err <> UNZ_OK) then
  372. WriteLn('error ', err, ' with zipfile in unzGetGlobalInfo ');
  373. for i := 0 to gi.number_entry - 1 do
  374. begin
  375. if (do_extract_currentfile(uf, opt_extract_without_path,
  376. opt_overwrite) <> UNZ_OK) then
  377. break;
  378. if ((i + 1) < gi.number_entry) then
  379. begin
  380. err := unzGoToNextFile(uf);
  381. if (err <> UNZ_OK) then
  382. begin
  383. WriteLn('error ', err, ' with zipfile in unzGoToNextFile');
  384. break;
  385. end;
  386. end;
  387. end;
  388. do_extract := 0;
  389. end;
  390. function do_extract_onefile(uf: unzFile; const filename: PChar; opt_extract_without_path: cint; opt_overwrite: cint): cint;
  391. begin
  392. if (unzLocateFile(uf, filename, CASESENSITIVITY) <> UNZ_OK) then
  393. begin
  394. WriteLn('file ', filename, ' not found in the zipfile');
  395. do_extract_onefile := 2;
  396. exit;
  397. end;
  398. if (do_extract_currentfile(uf, opt_extract_without_path,
  399. opt_overwrite) = UNZ_OK) then
  400. do_extract_onefile := 0
  401. else
  402. do_extract_onefile := 1;
  403. end;
  404. { -------------------------------------------------------------------- }
  405. function main: cint;
  406. const
  407. zipfilename: PChar = nil;
  408. filename_to_extract: PChar = nil;
  409. var
  410. i: cint;
  411. opt_do_list: cint;
  412. opt_do_extract: cint;
  413. opt_do_extract_withoutpath: cint;
  414. opt_overwrite: cint;
  415. filename_try: array[0..512 - 1] of char;
  416. uf: unzFile;
  417. var
  418. p: cint;
  419. pstr: string[255];
  420. c: char;
  421. begin
  422. opt_do_list := 0;
  423. opt_do_extract := 1;
  424. opt_do_extract_withoutpath := 0;
  425. opt_overwrite := 0;
  426. uf := nil;
  427. do_banner;
  428. if (ParamCount = 0) then
  429. begin
  430. do_help;
  431. Halt(0);
  432. end
  433. else
  434. for i := 1 to ParamCount do
  435. begin
  436. pstr := ParamStr(i);
  437. if pstr[1] = '-' then
  438. for p := 2 to Length(pstr) do
  439. begin
  440. c := pstr[p];
  441. case UpCase(c) of
  442. 'L',
  443. 'V': opt_do_list := 1;
  444. 'X': opt_do_extract := 1;
  445. 'E':
  446. begin
  447. opt_do_extract := 1;
  448. opt_do_extract_withoutpath := 1;
  449. end;
  450. 'O': opt_overwrite := 1;
  451. end;
  452. end
  453. else
  454. begin
  455. pstr := pstr + #0;
  456. if (zipfilename = nil) then
  457. zipfilename := StrNew(PChar(@pstr[1]))
  458. else
  459. if (filename_to_extract = nil) then
  460. filename_to_extract := StrNew(PChar(@pstr[1]));
  461. end;
  462. end{ for };
  463. if (zipfilename <> nil) then
  464. begin
  465. strcopy(filename_try, zipfilename);
  466. uf := unzOpen(zipfilename);
  467. if (uf = nil) then
  468. begin
  469. strcat(filename_try, '.zip');
  470. uf := unzOpen(filename_try);
  471. end;
  472. end;
  473. if (uf = nil) then
  474. begin
  475. WriteLn('Cannot open ', zipfilename, ' or ', zipfilename, '.zip');
  476. Halt(1);
  477. end;
  478. WriteLn(filename_try, ' opened');
  479. if (opt_do_list = 1) then
  480. begin
  481. main := do_list(uf);
  482. exit;
  483. end
  484. else
  485. if (opt_do_extract = 1) then
  486. if (filename_to_extract = nil) then
  487. begin
  488. main := do_extract(uf, opt_do_extract_withoutpath, opt_overwrite);
  489. exit;
  490. end
  491. else
  492. begin
  493. main := do_extract_onefile(uf, filename_to_extract,
  494. opt_do_extract_withoutpath, opt_overwrite);
  495. exit;
  496. end;
  497. unzCloseCurrentFile(uf);
  498. strDispose(zipfilename);
  499. strDispose(filename_to_extract);
  500. main := 0;
  501. end;
  502. begin
  503. main;
  504. Write('Done...');
  505. Readln;
  506. end.