miniunz.pas 14 KB

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