PageRenderTime 52ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/archiver.cc

https://github.com/yukke64/mingw_xyzzy
C++ | 1251 lines | 1140 code | 110 blank | 1 comment | 159 complexity | 5e9d420eccc0051b3f5cf501c470190a MD5 | raw file
  1. #ifdef __XYZZY__
  2. # include "ed.h"
  3. # include "except.h"
  4. # define ERROR_DEAD 0x8fff
  5. #else
  6. # include <malloc.h>
  7. # include <mbstring.h>
  8. # include <mbctype.h>
  9. # include <string.h>
  10. # ifdef DEBUG
  11. # include <stdio.h>
  12. # endif
  13. # define alloca _alloca
  14. # define jrindex(a, b) (char *)_mbsrchr ((const u_char *)(a), (b))
  15. typedef unsigned char u_char;
  16. #endif /* not __XYZZY__ */
  17. #include <io.h>
  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. 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—p
  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", 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. {
  389. char *dest = (char *)alloca (strlen (path) + 16);
  390. docopy (dest, path);
  391. char *backsl = jrindex (dest, '\\');
  392. if (backsl)
  393. dest = backsl + 1;
  394. int l = strlen (dest);
  395. if (l > 2 && (!_stricmp (dest + l - 2, ".Z")
  396. || !_stricmp (dest + l - 2, "_Z")))
  397. dest[l - 2] = 0;
  398. else if (l > 3 && (!_stricmp (dest + l - 3, ".gz")
  399. || !_stricmp (dest + l - 3, "_gz")))
  400. dest[l - 3] = 0;
  401. else if (l > 4 && (!_stricmp (dest + l - 4, ".bz2")
  402. || !_stricmp (dest + l - 4, "_bz2")))
  403. dest[l - 4] = 0;
  404. else
  405. strcat (dest, ".extracted");
  406. x = ArchiverP::extract (hwnd, path, destdir, "", "xfo", "", dest);
  407. }
  408. break;
  409. default:
  410. x = ArchiverP::extract (hwnd, path, destdir, "",
  411. *respfile ? "--check-all-path=1 -xfo" : "xfo", "@", respfile);
  412. break;
  413. }
  414. return x < 0x8000 ? 0 : x;
  415. }
  416. int
  417. Tar::create (HWND hwnd, const char *path, const char *respfile) const
  418. {
  419. int l = strlen (path);
  420. #define EQ(EXT) (sizeof (EXT) - 1 <= l \
  421. && !_memicmp (path + l - (sizeof (EXT) - 1), (EXT), \
  422. sizeof (EXT) - 1))
  423. const char *cmd;
  424. if (EQ (".tgz") || EQ (".tar.gz"))
  425. cmd = "cfz";
  426. else if (EQ (".taz") || EQ (".tar.Z"))
  427. cmd = "cfZ";
  428. else if (EQ (".tar.bz2"))
  429. cmd = "cfB";
  430. else if (EQ (".gz"))
  431. cmd = "cfzG";
  432. else if (EQ (".bz2"))
  433. cmd = "cfBG";
  434. else if (EQ (".Z"))
  435. cmd = "cfZG";
  436. else
  437. cmd = "cf";
  438. #undef EQ
  439. return ArchiverP::create (hwnd, path, respfile, "@", cmd);
  440. }
  441. const char *const Arj::suffixes[] = {".arj", 0};
  442. int
  443. Arj::extract (HWND hwnd, const char *path,
  444. const char *destdir, const char *respfile) const
  445. {
  446. return ArchiverP::extract (hwnd, path, destdir, "",
  447. *respfile ? "x -iup" : "x -iu", "!", respfile);
  448. }
  449. const char *const Lha::csuffixes[] = {".lzh", 0};
  450. const char *const Lha::esuffixes[] = {".lzh", ".exe", 0};
  451. int
  452. Lha::extract (HWND hwnd, const char *path,
  453. const char *destdir, const char *respfile) const
  454. {
  455. return ArchiverP::extract (hwnd, path, destdir, "",
  456. *respfile ? "e -a1m1nx1p1jf0" : "e -a1m1nx1jf0",
  457. "@", respfile);
  458. }
  459. int
  460. Lha::check_archive (const char *path) const
  461. {
  462. try
  463. {
  464. return lha.check_archive (path, CHECKARCHIVE_RAPID | CHECKARCHIVE_RECOVERY);
  465. }
  466. catch (Win32Exception &)
  467. {
  468. return 0;
  469. }
  470. }
  471. int
  472. Lha::create (HWND hwnd, const char *path, const char *respfile) const
  473. {
  474. return ArchiverP::create (hwnd, path, respfile, "@", "a -d1n");
  475. }
  476. int
  477. Lha::remove (HWND hwnd, const char *path, const char *respfile) const
  478. {
  479. return ArchiverP::remove (hwnd, path, respfile, "@", "d -p1n");
  480. }
  481. int
  482. Lha::create_sfx (HWND hwnd, const char *path, const char *opt) const
  483. {
  484. return ArchiverP::create_sfx (hwnd, path, "s", opt);
  485. }
  486. void
  487. Lha::puts_extract (FILE *fp, char *name) const
  488. {
  489. sepbacksl (name);
  490. putc ('"', fp);
  491. if (*name == '-')
  492. fputs ("-gb", fp);
  493. fputs (name, fp);
  494. putc ('"', fp);
  495. }
  496. static void
  497. zip_puts (FILE *fp, const char *name)
  498. {
  499. for (const u_char *p = (const u_char *)name; *p;)
  500. {
  501. u_char c = *p++;
  502. if (_ismbblead (c) && *p)
  503. {
  504. putc (c, fp);
  505. putc (*p++, fp);
  506. }
  507. else if (c == '\\')
  508. putc ('/', fp);
  509. else if (c == '[')
  510. {
  511. putc ('[', fp);
  512. putc ('[', fp);
  513. putc (']', fp);
  514. }
  515. else
  516. putc (c, fp);
  517. }
  518. }
  519. const char *const Unzip::esuffixes[] = {".zip", ".exe", 0};
  520. int
  521. Unzip::extract (HWND hwnd, const char *path,
  522. const char *destdir, const char *respfile) const
  523. {
  524. return ArchiverP::extract (hwnd, path, destdir, "", "-u --i -o", "@", respfile);
  525. }
  526. void
  527. Unzip::puts_extract (FILE *fp, char *name) const
  528. {
  529. putc ('"', fp);
  530. zip_puts (fp, name);
  531. putc ('"', fp);
  532. }
  533. const char *const Zip::csuffixes[] = {".zip", 0};
  534. int
  535. Zip::create (HWND hwnd, const char *path, const char *respfile) const
  536. {
  537. return ArchiverP::create (hwnd, path, respfile, "@", "-r -q");
  538. }
  539. int
  540. Zip::remove (HWND hwnd, const char *path, const char *respfile) const
  541. {
  542. return ArchiverP::remove (hwnd, path, respfile, "@", "-d -q");
  543. }
  544. int
  545. Zip::check_archive (const char *path) const
  546. {
  547. try
  548. {
  549. return zip.get_version () && unzip.check_archive (path);
  550. }
  551. catch (Win32Exception &)
  552. {
  553. return 0;
  554. }
  555. }
  556. void
  557. Zip::puts_create (FILE *fp, char *name, const char *) const
  558. {
  559. putc ('"', fp);
  560. if (*name == '-')
  561. {
  562. putc ('.', fp);
  563. putc ('/', fp);
  564. }
  565. zip_puts (fp, name);
  566. putc ('"', fp);
  567. }
  568. const char *const Cab::csuffixes[] = {".cab", 0};
  569. const char *const Cab::esuffixes[] = {".cab", ".exe", 0};
  570. int
  571. Cab::extract (HWND hwnd, const char *path,
  572. const char *destdir, const char *respfile) const
  573. {
  574. return ArchiverP::extract (hwnd, path, destdir, "", "-x -n -i", "@", respfile);
  575. }
  576. int
  577. Cab::create (HWND hwnd, const char *path, const char *respfile) const
  578. {
  579. return ArchiverP::create (hwnd, path, respfile, "@", "-a -r");
  580. }
  581. const char *const Unrar::esuffixes[] = {".rar", ".exe", 0};
  582. int
  583. Unrar::extract (HWND hwnd, const char *path,
  584. const char *destdir, const char *respfile) const
  585. {
  586. return ArchiverP::extract (hwnd, path, destdir, "", "-x -u -s --", "@", respfile);
  587. }
  588. const char *const Bga::suffixes[] = {".gza", ".bza", 0};
  589. int
  590. Bga::extract (HWND hwnd, const char *path,
  591. const char *destdir, const char *respfile) const
  592. {
  593. return ArchiverP::extract (hwnd, path, destdir, "",
  594. "x -a -i -n -r", "@", respfile);
  595. }
  596. int
  597. Bga::create (HWND hwnd, const char *path, const char *respfile) const
  598. {
  599. return ArchiverP::create (hwnd, path, respfile, "@", "a -a -i -n -r");
  600. }
  601. int
  602. Bga::remove (HWND hwnd, const char *path, const char *respfile) const
  603. {
  604. return ArchiverP::remove (hwnd, path, respfile, "@", "d -i");
  605. }
  606. const char *const Yz1::suffixes[] = {".yz1", 0};
  607. int
  608. Yz1::extract (HWND hwnd, const char *path,
  609. const char *destdir, const char *respfile) const
  610. {
  611. return ArchiverP::extract (hwnd, path, destdir, "",
  612. "x -i -y", 0, respfile);
  613. }
  614. int
  615. Yz1::create (HWND hwnd, const char *path, const char *respfile) const
  616. {
  617. return ArchiverP::create (hwnd, path, respfile, 0, "c -i -y");
  618. }
  619. const char *const UnGCA::esuffixes[] = {".gca", 0};
  620. int
  621. UnGCA::extract (HWND hwnd, const char *path,
  622. const char *destdir, const char *respfile) const
  623. {
  624. return ArchiverP::extract (hwnd, path, destdir, "",
  625. *respfile ? "ex -xx1 -yx1" : "e -yx1",
  626. "@", respfile);
  627. }
  628. const char *const SevenZip::suffixes[] = {".7z", 0};
  629. int
  630. SevenZip::extract (HWND hwnd, const char *path,
  631. const char *destdir, const char *respfile) const
  632. {
  633. return ArchiverP::extract (hwnd, path, destdir, "",
  634. "x -hide", "@", respfile);
  635. }
  636. int
  637. SevenZip::create (HWND hwnd, const char *path, const char *respfile) const
  638. {
  639. return ArchiverP::create (hwnd, path, respfile, "@", "a -hide -ms=off");
  640. }
  641. int
  642. SevenZip::remove (HWND hwnd, const char *path, const char *respfile) const
  643. {
  644. return ArchiverP::remove (hwnd, path, respfile, "@", "d -hide -ms=off");
  645. }
  646. void
  647. SevenZip::puts_create (FILE *fp, char *name, const char *path) const
  648. {
  649. sepbacksl (name);
  650. putc ('"', fp);
  651. if (*name == '-')
  652. {
  653. putc ('.', fp);
  654. putc ('\\', fp);
  655. }
  656. fputs (name, fp);
  657. DWORD a = GetFileAttributes (path);
  658. if (a != ~0 && a & FILE_ATTRIBUTE_DIRECTORY)
  659. {
  660. if (!has_trail_slash (path))
  661. putc ('\\', fp);
  662. putc ('*', fp);
  663. }
  664. putc ('"', fp);
  665. }
  666. Archiver::Archiver ()
  667. : a_zip (a_unzip)
  668. {
  669. arcs[0] = &a_lha;
  670. arcs[1] = &a_unzip;
  671. arcs[2] = &a_tar;
  672. arcs[3] = &a_arj;
  673. arcs[4] = &a_ish;
  674. arcs[5] = &a_zip;
  675. arcs[6] = &a_cab;
  676. arcs[7] = &a_unrar;
  677. arcs[8] = &a_bga;
  678. arcs[9] = &a_yz1;
  679. arcs[10] = &a_ungca;
  680. arcs[11] = &a_seven_zip;
  681. }
  682. const ArchiverP *
  683. Archiver::get_creator (const char *path) const
  684. {
  685. int l = strlen (path);
  686. for (int i = 0; i < NARCS; i++)
  687. if (arcs[i]->match_csuffix (path, l))
  688. return arcs[i];
  689. return 0;
  690. }
  691. int
  692. Archiver::check_file_size (const char *path)
  693. {
  694. WIN32_FIND_DATA fd;
  695. return (strict_get_file_data (path, fd)
  696. && (fd.nFileSizeHigh || fd.nFileSizeLow));
  697. }
  698. const ArchiverP *
  699. Archiver::check_archive (const char *path) const
  700. {
  701. for (int i = 0; i < NARCS; i++)
  702. if (arcs[i]->reliable_checker_p ()
  703. && arcs[i]->check_archive (path))
  704. return arcs[i];
  705. return 0;
  706. }
  707. const ArchiverP *
  708. Archiver::get_extractor (const char *path) const
  709. {
  710. if (!check_file_size (path))
  711. return 0;
  712. int l = strlen (path);
  713. for (int i = 0; i < NARCS; i++)
  714. if (arcs[i]->match_esuffix (path, l) && arcs[i]->check_archive (path))
  715. return arcs[i];
  716. return check_archive (path);
  717. }
  718. const ArchiverP *
  719. Archiver::get_remover (const char *path) const
  720. {
  721. if (!check_file_size (path))
  722. return 0;
  723. int l = strlen (path);
  724. for (int i = 0; i < NARCS; i++)
  725. if (arcs[i]->match_rsuffix (path, l) && arcs[i]->check_archive (path))
  726. return arcs[i];
  727. return check_archive (path);
  728. }
  729. int
  730. Archiver::extract (HWND hwnd, const char *path, const char *destdir,
  731. const char *respfile) const
  732. {
  733. const ArchiverP *ar = get_extractor (path);
  734. return ar ? ar->extract (hwnd, path, destdir, respfile) : ERROR_NOT_ARC_FILE;
  735. }
  736. int
  737. Archiver::create (HWND hwnd, const char *path, const char *respfile) const
  738. {
  739. const ArchiverP *ar = get_creator (path);
  740. return ar ? ar->create (hwnd, path, respfile) : ERROR_NOT_ARC_FILE;
  741. }
  742. int
  743. Archiver::create_sfx (HWND hwnd, const char *path, const char *opt) const
  744. {
  745. int l = strlen (path);
  746. for (int i = 0; i < NARCS; i++)
  747. if (arcs[i]->match_csuffix (path, l))
  748. return arcs[i]->create_sfx (hwnd, path, opt);
  749. return ERROR_NOT_ARC_FILE;
  750. }
  751. union obsolete_date
  752. {
  753. struct
  754. {
  755. u_int sec: 5;
  756. u_int min: 6;
  757. u_int hour: 5;
  758. u_int day: 5;
  759. u_int mon: 4;
  760. u_int year: 7;
  761. } b;
  762. struct
  763. {
  764. WORD time;
  765. WORD date;
  766. } w;
  767. };
  768. lisp
  769. Archiver::list (const char *path, int file_name_only) const
  770. {
  771. const ArchiverP *ar = get_extractor (path);
  772. if (!ar)
  773. return 0;
  774. try
  775. {
  776. const ArchiverInterface &ai = ar->ar_interface;
  777. ArchiverInterface::lock lk (ai);
  778. HARC harc = ai.open (0, path, 0);
  779. if (!harc)
  780. return 0;
  781. ar->post_open (harc);
  782. lisp result = Qnil;
  783. protect_gc gcpro (result);
  784. try
  785. {
  786. INDIVIDUALINFO ii;
  787. for (int nomore = ai.find_first (harc, ar->match_any (), &ii);
  788. !nomore; nomore = ai.find_next (harc, &ii))
  789. {
  790. obsolete_date d;
  791. d.w.time = ii.wTime;
  792. d.w.date = ii.wDate;
  793. if (file_name_only)
  794. result = xcons (make_string (ii.szFileName), result);
  795. else
  796. result = xcons (make_list
  797. (make_string (ii.szFileName),
  798. make_string (ii.szAttribute),
  799. make_integer (long_to_large_int (ii.dwOriginalSize)),
  800. make_list (make_fixnum (1980 + d.b.year),
  801. make_fixnum (d.b.mon),
  802. make_fixnum (d.b.day),
  803. make_fixnum (d.b.hour),
  804. make_fixnum (d.b.min),
  805. make_fixnum (d.b.sec * 2),
  806. 0),
  807. 0),
  808. result);
  809. }
  810. ai.close (harc);
  811. }
  812. catch (...)
  813. {
  814. ai.close (harc);
  815. throw;
  816. }
  817. return Fnreverse (result);
  818. }
  819. catch (Win32Exception &)
  820. {
  821. return Qnil;
  822. }
  823. }
  824. int
  825. Archiver::get_version (const ArchiverP &a, char *buf)
  826. {
  827. try
  828. {
  829. ArchiverInterface::lock lk (a.ar_interface);
  830. WORD v = a.ar_interface.get_version ();
  831. if (!v)
  832. return 0;
  833. WORD sv = a.ar_interface.get_sub_version ();
  834. if (sv)
  835. sprintf (buf, "%d.%d.%d.%d", v / 100, v % 100, sv / 100, sv % 100);
  836. else
  837. sprintf (buf, "%d.%02d", v / 100, v % 100);
  838. return 1;
  839. }
  840. catch (Win32Exception &)
  841. {
  842. return 0;
  843. }
  844. }
  845. int
  846. Archiver::config_dialog (const ArchiverP &a, HWND hwnd, int mode)
  847. {
  848. char buf[1024];
  849. *buf = 0;
  850. try
  851. {
  852. return a.ar_interface.config_dialog (hwnd, buf, (mode ? PACK_CONFIG_MODE
  853. : UNPACK_CONFIG_MODE)) == 1;
  854. }
  855. catch (Win32Exception &)
  856. {
  857. return 0;
  858. }
  859. }
  860. const ArchiverP *
  861. Archiver::get (lisp dll) const
  862. {
  863. if (dll == Kish32)
  864. return &a_ish;
  865. if (dll == Ktar32)
  866. return &a_tar;
  867. if (dll == Kunlha32)
  868. return &a_lha;
  869. if (dll == Kunarj32)
  870. return &a_arj;
  871. if (dll == Kunzip32)
  872. return &a_unzip;
  873. if (dll == Kzip32j)
  874. return &a_zip;
  875. if (dll == Kcab32)
  876. return &a_cab;
  877. if (dll == Kunrar32)
  878. return &a_unrar;
  879. if (dll == Kbga32)
  880. return &a_bga;
  881. if (dll == Kyz1)
  882. return &a_yz1;
  883. if (dll == Kungca32)
  884. return &a_ungca;
  885. if (dll == K7_zip)
  886. return &a_seven_zip;
  887. return 0;
  888. }
  889. #ifdef __XYZZY__
  890. static Archiver archiver;
  891. static void
  892. archiver_error (int e, lisp path, message_code mc)
  893. {
  894. static const struct
  895. {
  896. message_code ae;
  897. int xe;
  898. int warn;
  899. } ec[] =
  900. {
  901. {ARC_ERROR_DISK_SPACE, ERROR_DISK_SPACE, 1},
  902. {ARC_ERROR_READ_ONLY, ERROR_READ_ONLY, 1},
  903. {ARC_ERROR_USER_SKIP, ERROR_USER_SKIP, 1},
  904. {ARC_ERROR_UNKNOWN_TYPE, ERROR_UNKNOWN_TYPE, 1},
  905. {ARC_ERROR_METHOD, ERROR_METHOD, 1},
  906. {ARC_ERROR_PASSWORD_FILE, ERROR_PASSWORD_FILE, 1},
  907. {ARC_ERROR_VERSION, ERROR_VERSION, 1},
  908. {ARC_ERROR_FILE_CRC, ERROR_FILE_CRC, 1},
  909. {ARC_ERROR_FILE_OPEN, ERROR_FILE_OPEN, 1},
  910. {ARC_ERROR_MORE_FRESH, ERROR_MORE_FRESH, 1},
  911. {ARC_ERROR_NOT_EXIST, ERROR_NOT_EXIST, 1},
  912. {ARC_ERROR_ALREADY_EXIST, ERROR_ALREADY_EXIST, 1},
  913. {ARC_ERROR_TOO_MANY_FILES, ERROR_TOO_MANY_FILES, 1},
  914. {ARC_ERROR_DIRECTORY, ERROR_DIRECTORY, 0},
  915. {ARC_ERROR_CANNOT_WRITE, ERROR_CANNOT_WRITE, 0},
  916. {ARC_ERROR_HUFFMAN_CODE, ERROR_HUFFMAN_CODE, 0},
  917. {ARC_ERROR_COMMENT_HEADER, ERROR_COMMENT_HEADER, 0},
  918. {ARC_ERROR_HEADER_CRC, ERROR_HEADER_CRC, 0},
  919. {ARC_ERROR_HEADER_BROKEN, ERROR_HEADER_BROKEN, 0},
  920. {ARC_ERROR_ARC_FILE_OPEN, ERROR_ARC_FILE_OPEN, 0},
  921. {ARC_ERROR_NOT_ARC_FILE, ERROR_NOT_ARC_FILE, 0},
  922. {ARC_ERROR_CANNOT_READ, ERROR_CANNOT_READ, 0},
  923. {ARC_ERROR_FILE_STYLE, ERROR_FILE_STYLE, 0},
  924. {ARC_ERROR_COMMAND_NAME, ERROR_COMMAND_NAME, 0},
  925. {ARC_ERROR_MORE_HEAP_MEMORY, ERROR_MORE_HEAP_MEMORY, 0},
  926. {ARC_ERROR_ENOUGH_MEMORY, ERROR_ENOUGH_MEMORY, 0},
  927. {ARC_ERROR_DEAD, ERROR_DEAD, 0},
  928. {ARC_ERROR_NOT_SUPPORT, ERROR_NOT_SUPPORT, 0},
  929. };
  930. if (e < 0x8000)
  931. return;
  932. for (int i = 0; i < numberof (ec); i++)
  933. if (e == ec[i].xe)
  934. {
  935. if (ec[i].warn)
  936. {
  937. warn (ec[i].ae, path);
  938. return;
  939. }
  940. mc = ec[i].ae;
  941. break;
  942. }
  943. FEarchiver_error (mc, path);
  944. }
  945. static lisp
  946. extract_or_remove (lisp lpath, lisp ldir, lisp lfiles)
  947. {
  948. char path[PATH_MAX + 1], dir[PATH_MAX + 1];
  949. char temp_name[PATH_MAX + 1];
  950. pathname2cstr (lpath, path);
  951. if (ldir)
  952. pathname2cstr (ldir, dir);
  953. const ArchiverP *ar;
  954. if (ldir)
  955. {
  956. ar = archiver.get_extractor (path);
  957. if (!ar)
  958. file_error (Euncompress_not_supported, lpath);
  959. }
  960. else
  961. {
  962. if (!consp (lfiles))
  963. return Qnil;
  964. ar = archiver.get_remover (path);
  965. if (!ar)
  966. file_error (Eremove_not_supported, lpath);
  967. }
  968. if (!consp (lfiles))
  969. *temp_name = 0;
  970. else
  971. {
  972. char temp_path[PATH_MAX + 1];
  973. GetTempPath (sizeof temp_path, temp_path);
  974. WINFS::GetTempFileName (temp_path, "xyz", 0, temp_name);
  975. stdio_file fp (fopen (temp_name, "w"));
  976. if (!fp)
  977. {
  978. WINFS::DeleteFile (temp_name);
  979. file_error (Ecannot_make_temp_file_name);
  980. }
  981. for (; consp (lfiles); lfiles = xcdr (lfiles))
  982. {
  983. char name[PATH_MAX * 2 + 1];
  984. lisp lname = xcar (lfiles);
  985. check_string (lname);
  986. if (xstring_length (lname) > PATH_MAX)
  987. FEsimple_error (Epath_name_too_long, lname);
  988. w2s (name, lname);
  989. ar->puts_extract (fp, name);
  990. putc ('\n', fp);
  991. }
  992. }
  993. try
  994. {
  995. if (ldir)
  996. archiver_error (ar->extract (get_active_window (), path, dir, temp_name),
  997. lpath, Eextract_error);
  998. else
  999. archiver_error (ar->remove (get_active_window (), path, temp_name),
  1000. lpath, Eremove_error);
  1001. }
  1002. catch (nonlocal_jump &)
  1003. {
  1004. if (*temp_name)
  1005. WINFS::DeleteFile (temp_name);
  1006. throw;
  1007. }
  1008. if (*temp_name)
  1009. WINFS::DeleteFile (temp_name);
  1010. return Qt;
  1011. }
  1012. lisp
  1013. Fextract_archive (lisp lpath, lisp ldir, lisp lfiles)
  1014. {
  1015. return extract_or_remove (lpath, ldir, lfiles);
  1016. }
  1017. lisp
  1018. Fdelete_file_in_archive (lisp lpath, lisp lfiles)
  1019. {
  1020. return extract_or_remove (lpath, 0, lfiles);
  1021. }
  1022. lisp
  1023. Fcreate_archive (lisp larcname, lisp lfiles, lisp ldir)
  1024. {
  1025. char arcname[PATH_MAX + 1], dir[PATH_MAX + 1];
  1026. pathname2cstr (larcname, arcname);
  1027. pathname2cstr (ldir, dir);
  1028. if (!consp (lfiles))
  1029. return Qnil;
  1030. const ArchiverP *ar = archiver.get_creator (arcname);
  1031. if (!ar)
  1032. file_error (Ecompress_not_supported, larcname);
  1033. docopy (dir, dir); // '/' -> '\\'
  1034. if (!has_trail_slash (dir))
  1035. strcat (dir, "\\");
  1036. size_t dirl = strlen (dir);
  1037. char temp_name[PATH_MAX + 1], temp_path[PATH_MAX + 1];
  1038. GetTempPath (sizeof temp_path, temp_path);
  1039. WINFS::GetTempFileName (temp_path, "xyz", 0, temp_name);
  1040. WINFS::SetCurrentDirectory (dir);
  1041. try
  1042. {
  1043. {
  1044. stdio_file fp (fopen (temp_name, "w"));
  1045. if (!fp)
  1046. file_error (Ecannot_make_temp_file_name);
  1047. for (; consp (lfiles); lfiles = xcdr (lfiles))
  1048. {
  1049. pathname2cstr (xcar (lfiles), temp_path);
  1050. docopy (temp_path, temp_path); // '/' -> '\\'
  1051. char *b = temp_path;
  1052. if (!_memicmp (temp_path, dir, dirl))
  1053. b += dirl;
  1054. else if (strlen (temp_path) == dirl - 1
  1055. && !_memicmp (temp_path, dir, dirl))
  1056. continue;
  1057. ar->puts_create (fp, b, temp_path);
  1058. putc ('\n', fp);
  1059. }
  1060. }
  1061. int e = ar->create (get_active_window (), arcname, temp_name);
  1062. if (e == -1)
  1063. file_error (Ecompress_not_supported, larcname);
  1064. archiver_error (e, larcname, Ecompress_error);
  1065. }
  1066. catch (nonlocal_jump &)
  1067. {
  1068. WINFS::DeleteFile (temp_name);
  1069. WINFS::SetCurrentDirectory (sysdep.curdir);
  1070. throw;
  1071. }
  1072. WINFS::DeleteFile (temp_name);
  1073. WINFS::SetCurrentDirectory (sysdep.curdir);
  1074. return Qnil;
  1075. }
  1076. lisp
  1077. Fconvert_to_SFX (lisp larcname, lisp lopt)
  1078. {
  1079. char arcname[PATH_MAX + 1], dirname[PATH_MAX + 1];
  1080. pathname2cstr (larcname, arcname);
  1081. strcpy (dirname, arcname);
  1082. char *sl = find_last_slash (dirname);
  1083. if (sl)
  1084. {
  1085. *sl = 0;
  1086. WINFS::SetCurrentDirectory (dirname);
  1087. }
  1088. char *opt = "";
  1089. if (lopt && lopt != Qnil)
  1090. {
  1091. opt = (char *)alloca (w2sl (lopt) + 1);
  1092. w2s (opt, lopt);
  1093. }
  1094. try
  1095. {
  1096. archiver_error (archiver.create_sfx (get_active_window (), arcname, opt),
  1097. larcname, Ecompress_error);
  1098. }
  1099. catch (nonlocal_jump &)
  1100. {
  1101. WINFS::SetCurrentDirectory (sysdep.curdir);
  1102. throw;
  1103. }
  1104. WINFS::SetCurrentDirectory (sysdep.curdir);
  1105. return Qt;
  1106. }
  1107. lisp
  1108. Flist_archive (lisp larcname, lisp file_name_only)
  1109. {
  1110. char arcname[PATH_MAX + 1];
  1111. pathname2cstr (larcname, arcname);
  1112. lisp x = archiver.list (arcname, file_name_only && file_name_only != Qnil);
  1113. if (!x)
  1114. FEarchiver_error (ARC_ERROR_NOT_ARC_FILE, larcname);
  1115. return x;
  1116. }
  1117. lisp
  1118. Farchiver_dll_version (lisp dll)
  1119. {
  1120. char buf[128];
  1121. const ArchiverP *p = archiver.get (dll);
  1122. return p && Archiver::get_version (*p, buf) ? make_string (buf) : Qnil;
  1123. }
  1124. lisp
  1125. Farchiver_dll_config_dialog (lisp dll, lisp mode)
  1126. {
  1127. const ArchiverP *p = archiver.get (dll);
  1128. return boole (p && Archiver::config_dialog (*p, get_active_window (),
  1129. mode && mode != Qnil));
  1130. }
  1131. #endif /* __XYZZY__ */