miniunz.pas 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557
  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: PAnsiChar; 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: PAnsiChar): 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: PAnsiChar): boolean;
  81. var
  82. buffer: PAnsiChar;
  83. p: PAnsiChar;
  84. len: cint;
  85. var
  86. hold: AnsiChar;
  87. begin
  88. makedir := False;
  89. len := strlen(newdir);
  90. if (len <= 0) then
  91. exit;
  92. buffer := PAnsiChar(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 do_list(uf: unzFile): cint;
  148. var
  149. i: longword;
  150. gi: unz_global_info;
  151. err: cint;
  152. var
  153. filename_inzip: array[0..255] of AnsiChar;
  154. file_info: unz_file_info;
  155. ratio: longword;
  156. string_method: string[255];
  157. var
  158. iLevel: cuInt;
  159. begin
  160. err := unzGetGlobalInfo(uf, gi);
  161. if (err <> UNZ_OK) then
  162. WriteLn('error ', err, ' with zipfile in unzGetGlobalInfo');
  163. WriteLn(' Length Method Size Ratio Date Time CRC-32 Name');
  164. WriteLn(' ------ ------ ---- ----- ---- ---- ------ ----');
  165. for i := 0 to gi.number_entry - 1 do
  166. begin
  167. ratio := 0;
  168. err := unzGetCurrentFileInfo(uf, @file_info, filename_inzip, sizeof(filename_inzip), nil, 0, nil, 0);
  169. if (err <> UNZ_OK) then
  170. begin
  171. WriteLn('error ', err, ' with zipfile in unzGetCurrentFileInfo');
  172. break;
  173. end;
  174. if (file_info.uncompressed_size > 0) then
  175. ratio := (file_info.compressed_size * 100) div file_info.uncompressed_size;
  176. if (file_info.compression_method = 0) then
  177. string_method := 'Stored'
  178. else
  179. if (file_info.compression_method = Z_DEFLATED) then
  180. begin
  181. iLevel := cuInt((file_info.flag and $06) div 2);
  182. case iLevel of
  183. 0: string_method := 'Defl:N';
  184. 1: string_method := 'Defl:X';
  185. 2, 3: string_method := 'Defl:F'; { 2:fast , 3 : extra fast}
  186. else
  187. string_method := 'Unkn. ';
  188. end;
  189. end;
  190. WriteLn(file_info.uncompressed_size: 7, ' ',
  191. string_method: 6, ' ',
  192. file_info.compressed_size: 7, ' ',
  193. ratio: 3, '% ', LeadingZero(longword(file_info.tmu_date.tm_mon) + 1), '-',
  194. LeadingZero(longword(file_info.tmu_date.tm_mday)): 2, '-',
  195. LeadingZero(longword(file_info.tmu_date.tm_year mod 100)): 2, ' ',
  196. LeadingZero(longword(file_info.tmu_date.tm_hour)), ':',
  197. LeadingZero(longword(file_info.tmu_date.tm_min)), ' ',
  198. HexStr(longword(file_info.crc),8), ' ',
  199. filename_inzip);
  200. if ((i + 1) < gi.number_entry) then
  201. begin
  202. err := unzGoToNextFile(uf);
  203. if (err <> UNZ_OK) then
  204. begin
  205. WriteLn('error ', err, ' with zipfile in unzGoToNextFile');
  206. break;
  207. end;
  208. end;
  209. end;
  210. do_list := 0;
  211. end;
  212. function do_extract_currentfile(uf: unzFile; const popt_extract_without_path: cint; var popt_overwrite: cint): cint;
  213. var
  214. filename_inzip: packed array[0..255] of AnsiChar;
  215. filename_withoutpath: PAnsiChar;
  216. p: PAnsiChar;
  217. err: cint;
  218. fout: FILEptr;
  219. buf: pointer;
  220. size_buf: cuInt;
  221. file_info: unz_file_info;
  222. var
  223. write_filename: PAnsiChar;
  224. skip: cint;
  225. var
  226. rep: AnsiChar;
  227. ftestexist: FILEptr;
  228. var
  229. answer: string[127];
  230. var
  231. c: AnsiChar;
  232. begin
  233. fout := nil;
  234. err := unzGetCurrentFileInfo(uf, @file_info, filename_inzip,
  235. sizeof(filename_inzip), nil, 0, nil, 0);
  236. if (err <> UNZ_OK) then
  237. begin
  238. WriteLn('error ', err, ' with zipfile in unzGetCurrentFileInfo');
  239. do_extract_currentfile := err;
  240. exit;
  241. end;
  242. size_buf := WRITEBUFFERSIZE;
  243. buf := allocmem(size_buf);
  244. if (buf = nil) then
  245. begin
  246. WriteLn('Error allocating memory');
  247. do_extract_currentfile := UNZ_INTERNALERROR;
  248. exit;
  249. end;
  250. filename_withoutpath := filename_inzip;
  251. p := filename_withoutpath;
  252. while (p^ <> #0) do
  253. begin
  254. if (p^ = '/') or (p^ = '\') then
  255. filename_withoutpath := p + 1;
  256. Inc(p);
  257. end;
  258. if (filename_withoutpath^ = #0) then
  259. begin
  260. if (popt_extract_without_path = 0) then
  261. begin
  262. WriteLn('creating directory: ', filename_inzip);
  263. mymkdir(filename_inzip);
  264. end;
  265. end
  266. else
  267. begin
  268. skip := 0;
  269. if (popt_extract_without_path = 0) then
  270. write_filename := filename_inzip
  271. else
  272. write_filename := filename_withoutpath;
  273. err := unzOpenCurrentFile(uf);
  274. if (err <> UNZ_OK) then
  275. WriteLn('error ', err, ' with zipfile in unzOpenCurrentFile');
  276. if ((popt_overwrite = 0) and (err = UNZ_OK)) then
  277. begin
  278. rep := #0;
  279. ftestexist := fopen(write_filename, fopenread);
  280. if (ftestexist <> nil) then
  281. begin
  282. fclose(ftestexist);
  283. repeat
  284. Write('The file ', write_filename,
  285. ' exist. Overwrite ? [y]es, [n]o, [A]ll: ');
  286. ReadLn(answer);
  287. rep := answer[1];
  288. if ((rep >= 'a') and (rep <= 'z')) then
  289. Dec(rep, $20);
  290. until (rep = 'Y') or (rep = 'N') or (rep = 'A');
  291. end;
  292. if (rep = 'N') then
  293. skip := 1;
  294. if (rep = 'A') then
  295. popt_overwrite := 1;
  296. end;
  297. if (skip = 0) and (err = UNZ_OK) then
  298. begin
  299. fout := fopen(write_filename, fopenwrite);
  300. { some zipfile don't contain directory alone before file }
  301. if (fout = nil) and (popt_extract_without_path = 0) and
  302. (filename_withoutpath <> PAnsiChar(@filename_inzip)) then
  303. begin
  304. c := (filename_withoutpath - 1)^;
  305. (filename_withoutpath -1)^ := #0;
  306. makedir(write_filename);
  307. (filename_withoutpath -1)^ := c;
  308. fout := fopen(write_filename, fopenwrite);
  309. end;
  310. if (fout = nil) then
  311. WriteLn('error opening ', write_filename);
  312. end;
  313. if (fout <> nil) then
  314. begin
  315. WriteLn(' extracting: ', write_filename);
  316. repeat
  317. err := unzReadCurrentFile(uf, buf, size_buf);
  318. if (err < 0) then
  319. begin
  320. WriteLn('error ', err, ' with zipfile in unzReadCurrentFile');
  321. break;
  322. end;
  323. if (err > 0) then
  324. if (fwrite(buf, err, 1, fout) <> 1) then
  325. begin
  326. WriteLn('error in writing extracted file');
  327. err := UNZ_ERRNO;
  328. break;
  329. end;
  330. until (err = 0);
  331. fclose(fout);
  332. if (err = 0) then
  333. change_file_date(write_filename, file_info.dosDate,
  334. file_info.tmu_date);
  335. end;
  336. if (err = UNZ_OK) then
  337. begin
  338. err := unzCloseCurrentFile(uf);
  339. if (err <> UNZ_OK) then
  340. WriteLn('error ', err, ' with zipfile in unzCloseCurrentFile')
  341. else
  342. unzCloseCurrentFile(uf); { don't lose the error }
  343. end;
  344. end;
  345. if buf <> nil then
  346. freemem( buf);
  347. do_extract_currentfile := err;
  348. end;
  349. function do_extract(uf: unzFile; opt_extract_without_path: cint; opt_overwrite: cint): cint;
  350. var
  351. i: longword;
  352. gi: unz_global_info;
  353. err: cint;
  354. begin
  355. err := unzGetGlobalInfo(uf, gi);
  356. if (err <> UNZ_OK) then
  357. WriteLn('error ', err, ' with zipfile in unzGetGlobalInfo ');
  358. for i := 0 to gi.number_entry - 1 do
  359. begin
  360. if (do_extract_currentfile(uf, opt_extract_without_path,
  361. opt_overwrite) <> UNZ_OK) then
  362. break;
  363. if ((i + 1) < gi.number_entry) then
  364. begin
  365. err := unzGoToNextFile(uf);
  366. if (err <> UNZ_OK) then
  367. begin
  368. WriteLn('error ', err, ' with zipfile in unzGoToNextFile');
  369. break;
  370. end;
  371. end;
  372. end;
  373. do_extract := 0;
  374. end;
  375. function do_extract_onefile(uf: unzFile; const filename: PAnsiChar; opt_extract_without_path: cint; opt_overwrite: cint): cint;
  376. begin
  377. if (unzLocateFile(uf, filename, CASESENSITIVITY) <> UNZ_OK) then
  378. begin
  379. WriteLn('file ', filename, ' not found in the zipfile');
  380. do_extract_onefile := 2;
  381. exit;
  382. end;
  383. if (do_extract_currentfile(uf, opt_extract_without_path,
  384. opt_overwrite) = UNZ_OK) then
  385. do_extract_onefile := 0
  386. else
  387. do_extract_onefile := 1;
  388. end;
  389. { -------------------------------------------------------------------- }
  390. function main: cint;
  391. const
  392. zipfilename: PAnsiChar = nil;
  393. filename_to_extract: PAnsiChar = nil;
  394. var
  395. i: cint;
  396. opt_do_list: cint;
  397. opt_do_extract: cint;
  398. opt_do_extract_withoutpath: cint;
  399. opt_overwrite: cint;
  400. filename_try: array[0..512 - 1] of AnsiChar;
  401. uf: unzFile;
  402. var
  403. p: cint;
  404. pstr: string[255];
  405. c: AnsiChar;
  406. begin
  407. opt_do_list := 0;
  408. opt_do_extract := 1;
  409. opt_do_extract_withoutpath := 0;
  410. opt_overwrite := 0;
  411. uf := nil;
  412. do_banner;
  413. if (ParamCount = 0) then
  414. begin
  415. do_help;
  416. Halt(0);
  417. end
  418. else
  419. for i := 1 to ParamCount do
  420. begin
  421. pstr := ParamStr(i);
  422. if pstr[1] = '-' then
  423. for p := 2 to Length(pstr) do
  424. begin
  425. c := pstr[p];
  426. case UpCase(c) of
  427. 'L',
  428. 'V': opt_do_list := 1;
  429. 'X': opt_do_extract := 1;
  430. 'E':
  431. begin
  432. opt_do_extract := 1;
  433. opt_do_extract_withoutpath := 1;
  434. end;
  435. 'O': opt_overwrite := 1;
  436. end;
  437. end
  438. else
  439. begin
  440. pstr := pstr + #0;
  441. if (zipfilename = nil) then
  442. zipfilename := StrNew(PAnsiChar(@pstr[1]))
  443. else
  444. if (filename_to_extract = nil) then
  445. filename_to_extract := StrNew(PAnsiChar(@pstr[1]));
  446. end;
  447. end{ for };
  448. if (zipfilename <> nil) then
  449. begin
  450. strcopy(filename_try, zipfilename);
  451. uf := unzOpen(zipfilename);
  452. if (uf = nil) then
  453. begin
  454. strcat(filename_try, '.zip');
  455. uf := unzOpen(filename_try);
  456. end;
  457. end;
  458. if (uf = nil) then
  459. begin
  460. WriteLn('Cannot open ', zipfilename, ' or ', zipfilename, '.zip');
  461. Halt(1);
  462. end;
  463. WriteLn(filename_try, ' opened');
  464. if (opt_do_list = 1) then
  465. begin
  466. main := do_list(uf);
  467. exit;
  468. end
  469. else
  470. if (opt_do_extract = 1) then
  471. if (filename_to_extract = nil) then
  472. begin
  473. main := do_extract(uf, opt_do_extract_withoutpath, opt_overwrite);
  474. exit;
  475. end
  476. else
  477. begin
  478. main := do_extract_onefile(uf, filename_to_extract,
  479. opt_do_extract_withoutpath, opt_overwrite);
  480. exit;
  481. end;
  482. unzCloseCurrentFile(uf);
  483. strDispose(zipfilename);
  484. strDispose(filename_to_extract);
  485. main := 0;
  486. end;
  487. begin
  488. main;
  489. Write('Done...');
  490. Readln;
  491. end.