PageRenderTime 116ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 1ms

/src/archiver.cc

https://github.com/snmsts/xyzzy
C++ | 1266 lines | 1155 code | 110 blank | 1 comment | 173 complexity | 7a04b5e1b976c9607e1a4be762808122 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #include "stdafx.h"
  2. #ifdef __XYZZY__
  3. # include "ed.h"
  4. # include "except.h"
  5. # define ERROR_DEAD 0x8fff
  6. #else
  7. # include <malloc.h>
  8. # include <mbstring.h>
  9. # include <mbctype.h>
  10. # include <string.h>
  11. # ifdef DEBUG
  12. # include <stdio.h>
  13. # endif
  14. # define alloca _alloca
  15. # define jrindex(a, b) (char *)_mbsrchr ((const u_char *)(a), (b))
  16. typedef unsigned char u_char;
  17. #endif /* not __XYZZY__ */
  18. #include "arc-if.h"
  19. #include "archiver.h"
  20. #include "safe_ptr.h"
  21. class stdio_file
  22. {
  23. FILE *fp;
  24. public:
  25. stdio_file () : fp (0) {}
  26. stdio_file (FILE *fp_) : fp (fp_) {}
  27. ~stdio_file () {if (fp) fclose (fp);}
  28. operator FILE * () const {return fp;}
  29. FILE *operator -> () const {return fp;}
  30. };
  31. #if defined (__XYZZY__) && !defined (NEED_EXTRACTINGINFO)
  32. # define NEED_EXTRACTINGINFO
  33. #endif
  34. #ifndef __XYZZY__
  35. static char *
  36. stpcpy (char *dest, const char *src)
  37. {
  38. int l = strlen (src);
  39. memcpy (dest, src, l + 1);
  40. return dest + l;
  41. }
  42. #endif
  43. static char *
  44. docopy (char *d, const char *s)
  45. {
  46. while (*s)
  47. {
  48. u_char c = u_char (*s++);
  49. if (_ismbblead (c) && *s)
  50. {
  51. *d++ = c;
  52. *d++ = *s++;
  53. }
  54. else if (c == '/')
  55. *d++ = '\\';
  56. else
  57. *d++ = c;
  58. }
  59. *d = 0;
  60. return d;
  61. }
  62. static int
  63. has_trail_slash (const char *b)
  64. {
  65. char *backsl = jrindex (b, '\\');
  66. return backsl && !backsl[1];
  67. }
  68. static char *
  69. copy_path (char *b, const char *o, const char *d, int dirp = 0)
  70. {
  71. const char *spc = strchr (d, ' ');
  72. if (spc)
  73. *b++ = '"';
  74. b = stpcpy (b, o);
  75. char *b0 = b;
  76. b = docopy (b, d);
  77. if (dirp && !has_trail_slash (b0))
  78. *b++ = '\\';
  79. if (spc)
  80. *b++ = '"';
  81. *b = 0;
  82. return b;
  83. }
  84. inline static char *
  85. copy_dir (char *b, const char *opt, const char *d)
  86. {
  87. return copy_path (b, opt, d, 1);
  88. }
  89. const char *const ArchiverP::null_suffixes[] = {0};
  90. void
  91. ArchiverP::sepmap (char *s, int f, int t)
  92. {
  93. while (*s)
  94. {
  95. u_char c = u_char (*s);
  96. if (_ismbblead (c) && s[1])
  97. s += 2;
  98. else if (c == f)
  99. *s++ = t;
  100. else
  101. s++;
  102. }
  103. }
  104. int
  105. ArchiverP::match_suffix (const char *path, int l,
  106. const char *const *list) const
  107. {
  108. for (; *list; list++)
  109. {
  110. int x = strlen (*list);
  111. if (l >= x && !_memicmp (*list, path + l - x, x))
  112. return 1;
  113. }
  114. return 0;
  115. }
  116. #ifdef NEED_EXTRACTINGINFO
  117. static LRESULT CALLBACK
  118. NotifyWndProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
  119. {
  120. static const UINT extract = RegisterWindowMessage (WM_ARCEXTRACT);
  121. if (msg == extract)
  122. {
  123. EXTRACTINGINFO *i = (EXTRACTINGINFO *)lparam;
  124. if (i)
  125. {
  126. #ifdef __XYZZY__
  127. # ifdef DEBUG
  128. printf ("%d: %s %s %d/%d\n", wparam, i->szSourceFileName,
  129. i->szDestFileName, i->dwWriteSize, i->dwFileSize);
  130. # endif
  131. char buf[1024];
  132. if (*i->szDestFileName)
  133. {
  134. if (!wparam)
  135. app.status_window.puts (i->szDestFileName, 1);
  136. else if (wparam == 1)
  137. {
  138. sprintf (buf, "%s(%u/%u)...",
  139. i->szDestFileName, i->dwWriteSize, i->dwFileSize);
  140. app.status_window.puts (buf, 1);
  141. }
  142. }
  143. else if (wparam == 4)
  144. {
  145. sprintf (buf, "Updating %s...", i->szSourceFileName);
  146. app.status_window.puts (buf, 1);
  147. }
  148. if (QUITP)
  149. return 1;
  150. #else /* not __XYZZY__ */
  151. # ifdef DEBUG
  152. printf ("%s -> %s %u/%u\n",
  153. i->szSourceFileName,
  154. i->szDestFileName,
  155. i->dwWriteSize,
  156. i->dwFileSize);
  157. fflush (stdout);
  158. # endif /* DEBUG */
  159. #endif /* not __XYZZY__ */
  160. }
  161. return 0;
  162. }
  163. return DefWindowProc (hwnd, msg, wparam, lparam);
  164. }
  165. static const char NotifyClass[] = "ArcNotify";
  166. int
  167. register_wndclass ()
  168. {
  169. WNDCLASS wc;
  170. wc.style = 0;
  171. wc.lpfnWndProc = NotifyWndProc;
  172. wc.cbClsExtra = 0;
  173. wc.cbWndExtra = 0;
  174. wc.hInstance = GetModuleHandle (0);
  175. wc.hIcon = 0;
  176. wc.hCursor = 0;
  177. wc.hbrBackground = 0;
  178. wc.lpszMenuName = 0;
  179. wc.lpszClassName = NotifyClass;
  180. return RegisterClass (&wc);
  181. }
  182. static HWND
  183. create_notify_window (HWND parent)
  184. {
  185. static int done;
  186. if (!done)
  187. done = register_wndclass ();
  188. return CreateWindow (NotifyClass, "", parent ? WS_CHILD : WS_OVERLAPPEDWINDOW,
  189. 0, 0, 0, 0, parent, 0, GetModuleHandle (0), 0);
  190. }
  191. #endif /* NEED_EXTRACTINGINFO */
  192. int
  193. ArchiverP::doit (HWND hwnd, const char *data) const
  194. {
  195. ArchiverInterface::lock lk (ar_interface);
  196. #ifdef NEED_EXTRACTINGINFO
  197. HWND hfocus = GetFocus ();
  198. HWND notify = create_notify_window (hwnd);
  199. if (notify)
  200. ar_interface.set_owner_window (notify);
  201. #endif /* NEED_EXTRACTINGINFO */
  202. int enabled = hwnd && IsWindowEnabled (hwnd);
  203. char buf[1024];
  204. #ifndef __XYZZY__
  205. int r = ar_interface.doit (hwnd, data, buf, sizeof buf - 2);
  206. #else
  207. int r = ERROR_DEAD;
  208. try
  209. {
  210. r = ar_interface.doit (hwnd, data, buf, sizeof buf - 2);
  211. }
  212. catch (Win32Exception &)
  213. {
  214. }
  215. #endif /* __XYZZY__ */
  216. if (enabled)
  217. EnableWindow (hwnd, 1);
  218. #ifdef __XYZZY__
  219. app.status_window.puts ("done", 1);
  220. #endif
  221. #ifdef NEED_EXTRACTINGINFO
  222. if (notify)
  223. {
  224. ar_interface.clear_owner_window ();
  225. DestroyWindow (notify);
  226. }
  227. if (hfocus)
  228. SetFocus (hfocus);
  229. #endif /* NEED_EXTRACTINGINFO */
  230. // tar32用
  231. BYTE state[256];
  232. GetKeyboardState (state);
  233. for (int i = 0; i < 256; i++)
  234. if (state[i] & 0x80 && GetAsyncKeyState (i) >= 0)
  235. state[i] &= ~0x80;
  236. SetKeyboardState (state);
  237. return r;
  238. }
  239. int
  240. ArchiverP::extract (HWND hwnd, const char *data) const
  241. {
  242. #ifdef DEBUG
  243. printf ("Command: %s\n", data);
  244. fflush (stdout);
  245. #endif
  246. Fbegin_wait_cursor ();
  247. int x = doit (hwnd, data);
  248. Fend_wait_cursor ();
  249. #ifdef DEBUG
  250. printf ("RESULT=%x\n", x);
  251. fflush (stdout);
  252. #endif
  253. return x;
  254. }
  255. int
  256. ArchiverP::extract_noresp (HWND hwnd, const char *cmd,
  257. int cmdl, const char *path) const
  258. {
  259. stdio_file fp (fopen (path, "rb"));
  260. if (!fp)
  261. return ARC_ERROR_FILE_OPEN;
  262. size_t size = _filelength (_fileno (fp));
  263. safe_ptr <char> buf = new char [cmdl + size + 1];
  264. memcpy (buf, cmd, cmdl);
  265. if (fread (buf + cmdl, 1, size, fp) != size)
  266. return ARC_ERROR_CANNOT_READ;
  267. buf[cmdl + size] = 0;
  268. for (char *p = buf; *p; p++)
  269. if (*p == '\r' || *p == '\n')
  270. *p = ' ';
  271. return extract (hwnd, buf);
  272. }
  273. int
  274. ArchiverP::extract (HWND hwnd, const char *path, const char *destdir,
  275. const char *dir_opt, const char *opt,
  276. const char *respopt, const char *respfile) const
  277. {
  278. int len = (strlen (path) + strlen (destdir)
  279. + strlen (dir_opt) + strlen (opt)
  280. + strlen (respfile) + 128);
  281. if (respopt)
  282. len += strlen (respopt);
  283. char *b0 = (char *)alloca (len);
  284. char *b = stpcpy (b0, opt);
  285. *b++ = ' ';
  286. b = copy_path (b, "", path);
  287. *b++ = ' ';
  288. b = copy_dir (b, dir_opt, destdir);
  289. if (*respfile)
  290. {
  291. *b++ = ' ';
  292. if (!respopt)
  293. return extract_noresp (hwnd, b0, b - b0, respfile);
  294. copy_path (b, respopt, respfile);
  295. }
  296. return extract (hwnd, b0);
  297. }
  298. int
  299. ArchiverP::check_archive (const char *path) const
  300. {
  301. try
  302. {
  303. return ar_interface.check_archive (path, CHECKARCHIVE_BASIC);
  304. }
  305. catch (Win32Exception &)
  306. {
  307. return 0;
  308. }
  309. }
  310. int
  311. ArchiverP::create (HWND hwnd, const char *path, const char *respfile,
  312. const char *respopt, const char *opt) const
  313. {
  314. int len = strlen (path) + strlen (respfile) + strlen (opt) + 128;
  315. if (respopt)
  316. len += strlen (respopt);
  317. char *b0 = (char *)alloca (len);
  318. char *b = stpcpy (b0, opt);
  319. *b++ = ' ';
  320. b = copy_path (b, "", path);
  321. *b++ = ' ';
  322. if (!respopt)
  323. return extract_noresp (hwnd, b0, b - b0, respfile);
  324. copy_path (b, respopt, respfile);
  325. return extract (hwnd, b0);
  326. }
  327. int
  328. ArchiverP::remove (HWND hwnd, const char *path, const char *respfile,
  329. const char *respopt, const char *opt) const
  330. {
  331. return create (hwnd, path, respfile, respopt, opt);
  332. }
  333. int
  334. ArchiverP::create_sfx (HWND hwnd, const char *path,
  335. const char *opt1, const char *opt2) const
  336. {
  337. char *b0 = (char *)alloca (strlen (path) + strlen (opt1) + strlen (opt2) + 32);
  338. char *b = stpcpy (b0, opt1);
  339. *b++ = ' ';
  340. b = stpcpy (b, opt2);
  341. *b++ = ' ';
  342. copy_path (b, "", path);
  343. return extract (hwnd, b0);
  344. }
  345. void
  346. ArchiverP::puts_extract (FILE *fp, char *name) const
  347. {
  348. sepbacksl (name);
  349. putc ('"', fp);
  350. fputs (name, fp);
  351. putc ('"', fp);
  352. }
  353. void
  354. ArchiverP::puts_create (FILE *fp, char *name, const char *) const
  355. {
  356. sepbacksl (name);
  357. putc ('"', fp);
  358. if (*name == '-')
  359. {
  360. putc ('.', fp);
  361. putc ('\\', fp);
  362. }
  363. fputs (name, fp);
  364. putc ('"', fp);
  365. }
  366. const char *const Ish::suffixes[] = {".ish", 0};
  367. int
  368. Ish::extract (HWND hwnd, const char *path,
  369. const char *destdir, const char *respfile) const
  370. {
  371. if (*respfile)
  372. return ERROR_NOT_SUPPORT;
  373. int x = ArchiverP::extract (hwnd, path, destdir, "/f=", "/r", "", "");
  374. return x == ERROR_ALREADY_EXIST ? 0 : x;
  375. }
  376. const char *const Tar::suffixes[] =
  377. {".tgz", ".taz", ".gz", ".Z", ".tar", ".bz2", ".lzma", ".xz", 0};
  378. int
  379. Tar::extract (HWND hwnd, const char *path,
  380. const char *destdir, const char *respfile) const
  381. {
  382. int x;
  383. switch (*respfile ? -1 : tar.get_archive_type (path))
  384. {
  385. case ARCHIVETYPE_GZ:
  386. case ARCHIVETYPE_Z:
  387. case ARCHIVETYPE_BZ2:
  388. case ARCHIVETYPE_LZMA:
  389. case ARCHIVETYPE_XZ:
  390. {
  391. char *dest = (char *)alloca (strlen (path) + 16);
  392. docopy (dest, path);
  393. char *backsl = jrindex (dest, '\\');
  394. if (backsl)
  395. dest = backsl + 1;
  396. int l = strlen (dest);
  397. if (l > 2 && (!_stricmp (dest + l - 2, ".Z")
  398. || !_stricmp (dest + l - 2, "_Z")))
  399. dest[l - 2] = 0;
  400. else if (l > 3 && (!_stricmp (dest + l - 3, ".gz")
  401. || !_stricmp (dest + l - 3, "_gz")
  402. || !_stricmp (dest + l - 3, ".xz")
  403. || !_stricmp (dest + l - 3, "_xz")))
  404. dest[l - 3] = 0;
  405. else if (l > 4 && (!_stricmp (dest + l - 4, ".bz2")
  406. || !_stricmp (dest + l - 4, "_bz2")))
  407. dest[l - 4] = 0;
  408. else if (l > 5 && (!_stricmp (dest + l - 5, ".lzma")
  409. || !_stricmp (dest + l - 5, "_lzma")))
  410. dest[l - 5] = 0;
  411. else
  412. strcat (dest, ".extracted");
  413. x = ArchiverP::extract (hwnd, path, destdir, "", "xfo", "", dest);
  414. }
  415. break;
  416. default:
  417. x = ArchiverP::extract (hwnd, path, destdir, "",
  418. *respfile ? "--check-all-path=1 -xfo" : "xfo", "@", respfile);
  419. break;
  420. }
  421. return x < 0x8000 ? 0 : x;
  422. }
  423. int
  424. Tar::create (HWND hwnd, const char *path, const char *respfile) const
  425. {
  426. int l = strlen (path);
  427. #define EQ(EXT) (sizeof (EXT) - 1 <= l \
  428. && !_memicmp (path + l - (sizeof (EXT) - 1), (EXT), \
  429. sizeof (EXT) - 1))
  430. const char *cmd;
  431. if (EQ (".tgz") || EQ (".tar.gz"))
  432. cmd = "cfz";
  433. else if (EQ (".taz") || EQ (".tar.Z"))
  434. cmd = "cfZ";
  435. else if (EQ (".tar.bz2"))
  436. cmd = "cfB";
  437. else if (EQ (".tar.lzma"))
  438. cmd = "-c --lzma --";
  439. else if (EQ (".tar.xz"))
  440. cmd = "cfJ";
  441. else if (EQ (".gz"))
  442. cmd = "cfzG";
  443. else if (EQ (".bz2"))
  444. cmd = "cfBG";
  445. else if (EQ (".Z"))
  446. cmd = "cfZG";
  447. else if (EQ (".lzma"))
  448. cmd = "-c --lzma -G --";
  449. else if (EQ (".xz"))
  450. cmd = "cfJG";
  451. else
  452. cmd = "cf";
  453. #undef EQ
  454. return ArchiverP::create (hwnd, path, respfile, "@", cmd);
  455. }
  456. const char *const Arj::suffixes[] = {".arj", 0};
  457. int
  458. Arj::extract (HWND hwnd, const char *path,
  459. const char *destdir, const char *respfile) const
  460. {
  461. return ArchiverP::extract (hwnd, path, destdir, "",
  462. *respfile ? "x -iup" : "x -iu", "!", respfile);
  463. }
  464. const char *const Lha::csuffixes[] = {".lzh", 0};
  465. const char *const Lha::esuffixes[] = {".lzh", ".exe", 0};
  466. int
  467. Lha::extract (HWND hwnd, const char *path,
  468. const char *destdir, const char *respfile) const
  469. {
  470. return ArchiverP::extract (hwnd, path, destdir, "",
  471. *respfile ? "e -a1m1nx1p1jf0" : "e -a1m1nx1jf0",
  472. "@", respfile);
  473. }
  474. int
  475. Lha::check_archive (const char *path) const
  476. {
  477. try
  478. {
  479. return lha.check_archive (path, CHECKARCHIVE_RAPID | CHECKARCHIVE_RECOVERY);
  480. }
  481. catch (Win32Exception &)
  482. {
  483. return 0;
  484. }
  485. }
  486. int
  487. Lha::create (HWND hwnd, const char *path, const char *respfile) const
  488. {
  489. return ArchiverP::create (hwnd, path, respfile, "@", "a -d1n");
  490. }
  491. int
  492. Lha::remove (HWND hwnd, const char *path, const char *respfile) const
  493. {
  494. return ArchiverP::remove (hwnd, path, respfile, "@", "d -p1n");
  495. }
  496. int
  497. Lha::create_sfx (HWND hwnd, const char *path, const char *opt) const
  498. {
  499. return ArchiverP::create_sfx (hwnd, path, "s", opt);
  500. }
  501. void
  502. Lha::puts_extract (FILE *fp, char *name) const
  503. {
  504. sepbacksl (name);
  505. putc ('"', fp);
  506. if (*name == '-')
  507. fputs ("-gb", fp);
  508. fputs (name, fp);
  509. putc ('"', fp);
  510. }
  511. static void
  512. zip_puts (FILE *fp, const char *name)
  513. {
  514. for (const u_char *p = (const u_char *)name; *p;)
  515. {
  516. u_char c = *p++;
  517. if (_ismbblead (c) && *p)
  518. {
  519. putc (c, fp);
  520. putc (*p++, fp);
  521. }
  522. else if (c == '\\')
  523. putc ('/', fp);
  524. else if (c == '[')
  525. {
  526. putc ('[', fp);
  527. putc ('[', fp);
  528. putc (']', fp);
  529. }
  530. else
  531. putc (c, fp);
  532. }
  533. }
  534. const char *const Unzip::esuffixes[] = {".zip", ".exe", 0};
  535. int
  536. Unzip::extract (HWND hwnd, const char *path,
  537. const char *destdir, const char *respfile) const
  538. {
  539. return ArchiverP::extract (hwnd, path, destdir, "", "-u --i -o", "@", respfile);
  540. }
  541. void
  542. Unzip::puts_extract (FILE *fp, char *name) const
  543. {
  544. putc ('"', fp);
  545. zip_puts (fp, name);
  546. putc ('"', fp);
  547. }
  548. const char *const Zip::csuffixes[] = {".zip", 0};
  549. int
  550. Zip::create (HWND hwnd, const char *path, const char *respfile) const
  551. {
  552. return ArchiverP::create (hwnd, path, respfile, "@", "-r -q");
  553. }
  554. int
  555. Zip::remove (HWND hwnd, const char *path, const char *respfile) const
  556. {
  557. return ArchiverP::remove (hwnd, path, respfile, "@", "-d -q");
  558. }
  559. int
  560. Zip::check_archive (const char *path) const
  561. {
  562. try
  563. {
  564. return zip.get_version () && unzip.check_archive (path);
  565. }
  566. catch (Win32Exception &)
  567. {
  568. return 0;
  569. }
  570. }
  571. void
  572. Zip::puts_create (FILE *fp, char *name, const char *) const
  573. {
  574. putc ('"', fp);
  575. if (*name == '-')
  576. {
  577. putc ('.', fp);
  578. putc ('/', fp);
  579. }
  580. zip_puts (fp, name);
  581. putc ('"', fp);
  582. }
  583. const char *const Cab::csuffixes[] = {".cab", 0};
  584. const char *const Cab::esuffixes[] = {".cab", ".exe", 0};
  585. int
  586. Cab::extract (HWND hwnd, const char *path,
  587. const char *destdir, const char *respfile) const
  588. {
  589. return ArchiverP::extract (hwnd, path, destdir, "", "-x -n -i", "@", respfile);
  590. }
  591. int
  592. Cab::create (HWND hwnd, const char *path, const char *respfile) const
  593. {
  594. return ArchiverP::create (hwnd, path, respfile, "@", "-a -r");
  595. }
  596. const char *const Unrar::esuffixes[] = {".rar", ".exe", 0};
  597. int
  598. Unrar::extract (HWND hwnd, const char *path,
  599. const char *destdir, const char *respfile) const
  600. {
  601. return ArchiverP::extract (hwnd, path, destdir, "", "-x -u -s --", "@", respfile);
  602. }
  603. const char *const Bga::suffixes[] = {".gza", ".bza", 0};
  604. int
  605. Bga::extract (HWND hwnd, const char *path,
  606. const char *destdir, const char *respfile) const
  607. {
  608. return ArchiverP::extract (hwnd, path, destdir, "",
  609. "x -a -i -n -r", "@", respfile);
  610. }
  611. int
  612. Bga::create (HWND hwnd, const char *path, const char *respfile) const
  613. {
  614. return ArchiverP::create (hwnd, path, respfile, "@", "a -a -i -n -r");
  615. }
  616. int
  617. Bga::remove (HWND hwnd, const char *path, const char *respfile) const
  618. {
  619. return ArchiverP::remove (hwnd, path, respfile, "@", "d -i");
  620. }
  621. const char *const Yz1::suffixes[] = {".yz1", 0};
  622. int
  623. Yz1::extract (HWND hwnd, const char *path,
  624. const char *destdir, const char *respfile) const
  625. {
  626. return ArchiverP::extract (hwnd, path, destdir, "",
  627. "x -i -y", 0, respfile);
  628. }
  629. int
  630. Yz1::create (HWND hwnd, const char *path, const char *respfile) const
  631. {
  632. return ArchiverP::create (hwnd, path, respfile, 0, "c -i -y");
  633. }
  634. const char *const UnGCA::esuffixes[] = {".gca", 0};
  635. int
  636. UnGCA::extract (HWND hwnd, const char *path,
  637. const char *destdir, const char *respfile) const
  638. {
  639. return ArchiverP::extract (hwnd, path, destdir, "",
  640. *respfile ? "ex -xx1 -yx1" : "e -yx1",
  641. "@", respfile);
  642. }
  643. const char *const SevenZip::suffixes[] = {".7z", 0};
  644. int
  645. SevenZip::extract (HWND hwnd, const char *path,
  646. const char *destdir, const char *respfile) const
  647. {
  648. return ArchiverP::extract (hwnd, path, destdir, "",
  649. "x -hide", "@", respfile);
  650. }
  651. int
  652. SevenZip::create (HWND hwnd, const char *path, const char *respfile) const
  653. {
  654. return ArchiverP::create (hwnd, path, respfile, "@", "a -hide -ms=off");
  655. }
  656. int
  657. SevenZip::remove (HWND hwnd, const char *path, const char *respfile) const
  658. {
  659. return ArchiverP::remove (hwnd, path, respfile, "@", "d -hide -ms=off");
  660. }
  661. void
  662. SevenZip::puts_create (FILE *fp, char *name, const char *path) const
  663. {
  664. sepbacksl (name);
  665. putc ('"', fp);
  666. if (*name == '-')
  667. {
  668. putc ('.', fp);
  669. putc ('\\', fp);
  670. }
  671. fputs (name, fp);
  672. DWORD a = GetFileAttributes (path);
  673. if (a != ~0 && a & FILE_ATTRIBUTE_DIRECTORY)
  674. {
  675. if (!has_trail_slash (path))
  676. putc ('\\', fp);
  677. putc ('*', fp);
  678. }
  679. putc ('"', fp);
  680. }
  681. Archiver::Archiver ()
  682. : a_zip (a_unzip)
  683. {
  684. arcs[0] = &a_lha;
  685. arcs[1] = &a_unzip;
  686. arcs[2] = &a_tar;
  687. arcs[3] = &a_arj;
  688. arcs[4] = &a_ish;
  689. arcs[5] = &a_zip;
  690. arcs[6] = &a_cab;
  691. arcs[7] = &a_unrar;
  692. arcs[8] = &a_bga;
  693. arcs[9] = &a_yz1;
  694. arcs[10] = &a_ungca;
  695. arcs[11] = &a_seven_zip;
  696. }
  697. const ArchiverP *
  698. Archiver::get_creator (const char *path) const
  699. {
  700. int l = strlen (path);
  701. for (int i = 0; i < NARCS; i++)
  702. if (arcs[i]->match_csuffix (path, l))
  703. return arcs[i];
  704. return 0;
  705. }
  706. int
  707. Archiver::check_file_size (const char *path)
  708. {
  709. WIN32_FIND_DATA fd;
  710. return (strict_get_file_data (path, fd)
  711. && (fd.nFileSizeHigh || fd.nFileSizeLow));
  712. }
  713. const ArchiverP *
  714. Archiver::check_archive (const char *path) const
  715. {
  716. for (int i = 0; i < NARCS; i++)
  717. if (arcs[i]->reliable_checker_p ()
  718. && arcs[i]->check_archive (path))
  719. return arcs[i];
  720. return 0;
  721. }
  722. const ArchiverP *
  723. Archiver::get_extractor (const char *path) const
  724. {
  725. if (!check_file_size (path))
  726. return 0;
  727. int l = strlen (path);
  728. for (int i = 0; i < NARCS; i++)
  729. if (arcs[i]->match_esuffix (path, l) && arcs[i]->check_archive (path))
  730. return arcs[i];
  731. return check_archive (path);
  732. }
  733. const ArchiverP *
  734. Archiver::get_remover (const char *path) const
  735. {
  736. if (!check_file_size (path))
  737. return 0;
  738. int l = strlen (path);
  739. for (int i = 0; i < NARCS; i++)
  740. if (arcs[i]->match_rsuffix (path, l) && arcs[i]->check_archive (path))
  741. return arcs[i];
  742. return check_archive (path);
  743. }
  744. int
  745. Archiver::extract (HWND hwnd, const char *path, const char *destdir,
  746. const char *respfile) const
  747. {
  748. const ArchiverP *ar = get_extractor (path);
  749. return ar ? ar->extract (hwnd, path, destdir, respfile) : ERROR_NOT_ARC_FILE;
  750. }
  751. int
  752. Archiver::create (HWND hwnd, const char *path, const char *respfile) const
  753. {
  754. const ArchiverP *ar = get_creator (path);
  755. return ar ? ar->create (hwnd, path, respfile) : ERROR_NOT_ARC_FILE;
  756. }
  757. int
  758. Archiver::create_sfx (HWND hwnd, const char *path, const char *opt) const
  759. {
  760. int l = strlen (path);
  761. for (int i = 0; i < NARCS; i++)
  762. if (arcs[i]->match_csuffix (path, l))
  763. return arcs[i]->create_sfx (hwnd, path, opt);
  764. return ERROR_NOT_ARC_FILE;
  765. }
  766. union obsolete_date
  767. {
  768. struct
  769. {
  770. u_int sec: 5;
  771. u_int min: 6;
  772. u_int hour: 5;
  773. u_int day: 5;
  774. u_int mon: 4;
  775. u_int year: 7;
  776. } b;
  777. struct
  778. {
  779. WORD time;
  780. WORD date;
  781. } w;
  782. };
  783. lisp
  784. Archiver::list (const char *path, int file_name_only) const
  785. {
  786. const ArchiverP *ar = get_extractor (path);
  787. if (!ar)
  788. return 0;
  789. try
  790. {
  791. const ArchiverInterface &ai = ar->ar_interface;
  792. ArchiverInterface::lock lk (ai);
  793. HARC harc = ai.open (0, path, 0);
  794. if (!harc)
  795. return 0;
  796. ar->post_open (harc);
  797. lisp result = Qnil;
  798. protect_gc gcpro (result);
  799. try
  800. {
  801. INDIVIDUALINFO ii;
  802. for (int nomore = ai.find_first (harc, ar->match_any (), &ii);
  803. !nomore; nomore = ai.find_next (harc, &ii))
  804. {
  805. obsolete_date d;
  806. d.w.time = ii.wTime;
  807. d.w.date = ii.wDate;
  808. if (file_name_only)
  809. result = xcons (make_string (ii.szFileName), result);
  810. else
  811. result = xcons (make_list
  812. (make_string (ii.szFileName),
  813. make_string (ii.szAttribute),
  814. make_integer (long_to_large_int (ii.dwOriginalSize)),
  815. make_list (make_fixnum (1980 + d.b.year),
  816. make_fixnum (d.b.mon),
  817. make_fixnum (d.b.day),
  818. make_fixnum (d.b.hour),
  819. make_fixnum (d.b.min),
  820. make_fixnum (d.b.sec * 2),
  821. 0),
  822. 0),
  823. result);
  824. }
  825. ai.close (harc);
  826. }
  827. catch (...)
  828. {
  829. ai.close (harc);
  830. throw;
  831. }
  832. return Fnreverse (result);
  833. }
  834. catch (Win32Exception &)
  835. {
  836. return Qnil;
  837. }
  838. }
  839. int
  840. Archiver::get_version (const ArchiverP &a, char *buf)
  841. {
  842. try
  843. {
  844. ArchiverInterface::lock lk (a.ar_interface);
  845. WORD v = a.ar_interface.get_version ();
  846. if (!v)
  847. return 0;
  848. WORD sv = a.ar_interface.get_sub_version ();
  849. if (sv)
  850. sprintf (buf, "%d.%d.%d.%d", v / 100, v % 100, sv / 100, sv % 100);
  851. else
  852. sprintf (buf, "%d.%02d", v / 100, v % 100);
  853. return 1;
  854. }
  855. catch (Win32Exception &)
  856. {
  857. return 0;
  858. }
  859. }
  860. int
  861. Archiver::config_dialog (const ArchiverP &a, HWND hwnd, int mode)
  862. {
  863. char buf[1024];
  864. *buf = 0;
  865. try
  866. {
  867. return a.ar_interface.config_dialog (hwnd, buf, (mode ? PACK_CONFIG_MODE
  868. : UNPACK_CONFIG_MODE)) == 1;
  869. }
  870. catch (Win32Exception &)
  871. {
  872. return 0;
  873. }
  874. }
  875. const ArchiverP *
  876. Archiver::get (lisp dll) const
  877. {
  878. if (dll == Kish32)
  879. return &a_ish;
  880. if (dll == Ktar32)
  881. return &a_tar;
  882. if (dll == Kunlha32)
  883. return &a_lha;
  884. if (dll == Kunarj32)
  885. return &a_arj;
  886. if (dll == Kunzip32)
  887. return &a_unzip;
  888. if (dll == Kzip32j)
  889. return &a_zip;
  890. if (dll == Kcab32)
  891. return &a_cab;
  892. if (dll == Kunrar32)
  893. return &a_unrar;
  894. if (dll == Kbga32)
  895. return &a_bga;
  896. if (dll == Kyz1)
  897. return &a_yz1;
  898. if (dll == Kungca32)
  899. return &a_ungca;
  900. if (dll == K7_zip)
  901. return &a_seven_zip;
  902. return 0;
  903. }
  904. #ifdef __XYZZY__
  905. static Archiver archiver;
  906. static void
  907. archiver_error (int e, lisp path, message_code mc)
  908. {
  909. static const struct
  910. {
  911. message_code ae;
  912. int xe;
  913. int warn;
  914. } ec[] =
  915. {
  916. {ARC_ERROR_DISK_SPACE, ERROR_DISK_SPACE, 1},
  917. {ARC_ERROR_READ_ONLY, ERROR_READ_ONLY, 1},
  918. {ARC_ERROR_USER_SKIP, ERROR_USER_SKIP, 1},
  919. {ARC_ERROR_UNKNOWN_TYPE, ERROR_UNKNOWN_TYPE, 1},
  920. {ARC_ERROR_METHOD, ERROR_METHOD, 1},
  921. {ARC_ERROR_PASSWORD_FILE, ERROR_PASSWORD_FILE, 1},
  922. {ARC_ERROR_VERSION, ERROR_VERSION, 1},
  923. {ARC_ERROR_FILE_CRC, ERROR_FILE_CRC, 1},
  924. {ARC_ERROR_FILE_OPEN, ERROR_FILE_OPEN, 1},
  925. {ARC_ERROR_MORE_FRESH, ERROR_MORE_FRESH, 1},
  926. {ARC_ERROR_NOT_EXIST, ERROR_NOT_EXIST, 1},
  927. {ARC_ERROR_ALREADY_EXIST, ERROR_ALREADY_EXIST, 1},
  928. {ARC_ERROR_TOO_MANY_FILES, ERROR_TOO_MANY_FILES, 1},
  929. {ARC_ERROR_DIRECTORY, ERROR_DIRECTORY, 0},
  930. {ARC_ERROR_CANNOT_WRITE, ERROR_CANNOT_WRITE, 0},
  931. {ARC_ERROR_HUFFMAN_CODE, ERROR_HUFFMAN_CODE, 0},
  932. {ARC_ERROR_COMMENT_HEADER, ERROR_COMMENT_HEADER, 0},
  933. {ARC_ERROR_HEADER_CRC, ERROR_HEADER_CRC, 0},
  934. {ARC_ERROR_HEADER_BROKEN, ERROR_HEADER_BROKEN, 0},
  935. {ARC_ERROR_ARC_FILE_OPEN, ERROR_ARC_FILE_OPEN, 0},
  936. {ARC_ERROR_NOT_ARC_FILE, ERROR_NOT_ARC_FILE, 0},
  937. {ARC_ERROR_CANNOT_READ, ERROR_CANNOT_READ, 0},
  938. {ARC_ERROR_FILE_STYLE, ERROR_FILE_STYLE, 0},
  939. {ARC_ERROR_COMMAND_NAME, ERROR_COMMAND_NAME, 0},
  940. {ARC_ERROR_MORE_HEAP_MEMORY, ERROR_MORE_HEAP_MEMORY, 0},
  941. {ARC_ERROR_ENOUGH_MEMORY, ERROR_ENOUGH_MEMORY, 0},
  942. {ARC_ERROR_DEAD, ERROR_DEAD, 0},
  943. {ARC_ERROR_NOT_SUPPORT, ERROR_NOT_SUPPORT, 0},
  944. };
  945. if (e < 0x8000)
  946. return;
  947. for (int i = 0; i < numberof (ec); i++)
  948. if (e == ec[i].xe)
  949. {
  950. if (ec[i].warn)
  951. {
  952. warn (ec[i].ae, path);
  953. return;
  954. }
  955. mc = ec[i].ae;
  956. break;
  957. }
  958. FEarchiver_error (mc, path);
  959. }
  960. static lisp
  961. extract_or_remove (lisp lpath, lisp ldir, lisp lfiles)
  962. {
  963. char path[PATH_MAX + 1], dir[PATH_MAX + 1];
  964. char temp_name[PATH_MAX + 1];
  965. pathname2cstr (lpath, path);
  966. if (ldir)
  967. pathname2cstr (ldir, dir);
  968. const ArchiverP *ar;
  969. if (ldir)
  970. {
  971. ar = archiver.get_extractor (path);
  972. if (!ar)
  973. file_error (Euncompress_not_supported, lpath);
  974. }
  975. else
  976. {
  977. if (!consp (lfiles))
  978. return Qnil;
  979. ar = archiver.get_remover (path);
  980. if (!ar)
  981. file_error (Eremove_not_supported, lpath);
  982. }
  983. if (!consp (lfiles))
  984. *temp_name = 0;
  985. else
  986. {
  987. char temp_path[PATH_MAX + 1];
  988. GetTempPath (sizeof temp_path, temp_path);
  989. WINFS::GetTempFileName (temp_path, "xyz", 0, temp_name);
  990. stdio_file fp (fopen (temp_name, "w"));
  991. if (!fp)
  992. {
  993. WINFS::DeleteFile (temp_name);
  994. file_error (Ecannot_make_temp_file_name);
  995. }
  996. for (; consp (lfiles); lfiles = xcdr (lfiles))
  997. {
  998. char name[PATH_MAX * 2 + 1];
  999. lisp lname = xcar (lfiles);
  1000. check_string (lname);
  1001. if (xstring_length (lname) > PATH_MAX)
  1002. FEsimple_error (Epath_name_too_long, lname);
  1003. w2s (name, lname);
  1004. ar->puts_extract (fp, name);
  1005. putc ('\n', fp);
  1006. }
  1007. }
  1008. try
  1009. {
  1010. if (ldir)
  1011. archiver_error (ar->extract (get_active_window (), path, dir, temp_name),
  1012. lpath, Eextract_error);
  1013. else
  1014. archiver_error (ar->remove (get_active_window (), path, temp_name),
  1015. lpath, Eremove_error);
  1016. }
  1017. catch (nonlocal_jump &)
  1018. {
  1019. if (*temp_name)
  1020. WINFS::DeleteFile (temp_name);
  1021. throw;
  1022. }
  1023. if (*temp_name)
  1024. WINFS::DeleteFile (temp_name);
  1025. return Qt;
  1026. }
  1027. lisp
  1028. Fextract_archive (lisp lpath, lisp ldir, lisp lfiles)
  1029. {
  1030. return extract_or_remove (lpath, ldir, lfiles);
  1031. }
  1032. lisp
  1033. Fdelete_file_in_archive (lisp lpath, lisp lfiles)
  1034. {
  1035. return extract_or_remove (lpath, 0, lfiles);
  1036. }
  1037. lisp
  1038. Fcreate_archive (lisp larcname, lisp lfiles, lisp ldir)
  1039. {
  1040. char arcname[PATH_MAX + 1], dir[PATH_MAX + 1];
  1041. pathname2cstr (larcname, arcname);
  1042. pathname2cstr (ldir, dir);
  1043. if (!consp (lfiles))
  1044. return Qnil;
  1045. const ArchiverP *ar = archiver.get_creator (arcname);
  1046. if (!ar)
  1047. file_error (Ecompress_not_supported, larcname);
  1048. docopy (dir, dir); // '/' -> '\\'
  1049. if (!has_trail_slash (dir))
  1050. strcat (dir, "\\");
  1051. size_t dirl = strlen (dir);
  1052. char temp_name[PATH_MAX + 1], temp_path[PATH_MAX + 1];
  1053. GetTempPath (sizeof temp_path, temp_path);
  1054. WINFS::GetTempFileName (temp_path, "xyz", 0, temp_name);
  1055. WINFS::SetCurrentDirectory (dir);
  1056. try
  1057. {
  1058. {
  1059. stdio_file fp (fopen (temp_name, "w"));
  1060. if (!fp)
  1061. file_error (Ecannot_make_temp_file_name);
  1062. for (; consp (lfiles); lfiles = xcdr (lfiles))
  1063. {
  1064. pathname2cstr (xcar (lfiles), temp_path);
  1065. docopy (temp_path, temp_path); // '/' -> '\\'
  1066. char *b = temp_path;
  1067. if (!_memicmp (temp_path, dir, dirl))
  1068. b += dirl;
  1069. else if (strlen (temp_path) == dirl - 1
  1070. && !_memicmp (temp_path, dir, dirl))
  1071. continue;
  1072. ar->puts_create (fp, b, temp_path);
  1073. putc ('\n', fp);
  1074. }
  1075. }
  1076. int e = ar->create (get_active_window (), arcname, temp_name);
  1077. if (e == -1)
  1078. file_error (Ecompress_not_supported, larcname);
  1079. archiver_error (e, larcname, Ecompress_error);
  1080. }
  1081. catch (nonlocal_jump &)
  1082. {
  1083. WINFS::DeleteFile (temp_name);
  1084. WINFS::SetCurrentDirectory (sysdep.curdir);
  1085. throw;
  1086. }
  1087. WINFS::DeleteFile (temp_name);
  1088. WINFS::SetCurrentDirectory (sysdep.curdir);
  1089. return Qnil;
  1090. }
  1091. lisp
  1092. Fconvert_to_SFX (lisp larcname, lisp lopt)
  1093. {
  1094. char arcname[PATH_MAX + 1], dirname[PATH_MAX + 1];
  1095. pathname2cstr (larcname, arcname);
  1096. strcpy (dirname, arcname);
  1097. char *sl = find_last_slash (dirname);
  1098. if (sl)
  1099. {
  1100. *sl = 0;
  1101. WINFS::SetCurrentDirectory (dirname);
  1102. }
  1103. char *opt = "";
  1104. if (lopt && lopt != Qnil)
  1105. {
  1106. opt = (char *)alloca (w2sl (lopt) + 1);
  1107. w2s (opt, lopt);
  1108. }
  1109. try
  1110. {
  1111. archiver_error (archiver.create_sfx (get_active_window (), arcname, opt),
  1112. larcname, Ecompress_error);
  1113. }
  1114. catch (nonlocal_jump &)
  1115. {
  1116. WINFS::SetCurrentDirectory (sysdep.curdir);
  1117. throw;
  1118. }
  1119. WINFS::SetCurrentDirectory (sysdep.curdir);
  1120. return Qt;
  1121. }
  1122. lisp
  1123. Flist_archive (lisp larcname, lisp file_name_only)
  1124. {
  1125. char arcname[PATH_MAX + 1];
  1126. pathname2cstr (larcname, arcname);
  1127. lisp x = archiver.list (arcname, file_name_only && file_name_only != Qnil);
  1128. if (!x)
  1129. FEarchiver_error (ARC_ERROR_NOT_ARC_FILE, larcname);
  1130. return x;
  1131. }
  1132. lisp
  1133. Farchiver_dll_version (lisp dll)
  1134. {
  1135. char buf[128];
  1136. const ArchiverP *p = archiver.get (dll);
  1137. return p && Archiver::get_version (*p, buf) ? make_string (buf) : Qnil;
  1138. }
  1139. lisp
  1140. Farchiver_dll_config_dialog (lisp dll, lisp mode)
  1141. {
  1142. const ArchiverP *p = archiver.get (dll);
  1143. return boole (p && Archiver::config_dialog (*p, get_active_window (),
  1144. mode && mode != Qnil));
  1145. }
  1146. #endif /* __XYZZY__ */