miniunz.pas 14 KB

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