cabarc.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * Tool to manipulate cabinet files
  3. *
  4. * Copyright 2011 Alexandre Julliard
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  19. */
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <fcntl.h>
  23. #include <io.h>
  24. #include <share.h>
  25. #define WIN32_LEAN_AND_MEAN
  26. #include "windows.h"
  27. #include "fci.h"
  28. #include "fdi.h"
  29. #include "wine/debug.h"
  30. WINE_DEFAULT_DEBUG_CHANNEL(cabarc);
  31. /* command-line options */
  32. static int opt_cabinet_size = CB_MAX_DISK;
  33. static int opt_cabinet_id;
  34. static int opt_compression = tcompTYPE_MSZIP;
  35. static BOOL opt_recurse;
  36. static BOOL opt_preserve_paths;
  37. static int opt_reserve_space;
  38. static int opt_verbose;
  39. static char *opt_cab_file;
  40. static WCHAR *opt_dest_dir;
  41. static WCHAR **opt_files;
  42. static void * CDECL cab_alloc( ULONG size )
  43. {
  44. return HeapAlloc( GetProcessHeap(), 0, size );
  45. }
  46. static void CDECL cab_free( void *ptr )
  47. {
  48. HeapFree( GetProcessHeap(), 0, ptr );
  49. }
  50. static WCHAR *strdupAtoW( UINT cp, const char *str )
  51. {
  52. WCHAR *ret = NULL;
  53. if (str)
  54. {
  55. DWORD len = MultiByteToWideChar( cp, 0, str, -1, NULL, 0 );
  56. if ((ret = cab_alloc( len * sizeof(WCHAR) )))
  57. MultiByteToWideChar( cp, 0, str, -1, ret, len );
  58. }
  59. return ret;
  60. }
  61. static char *strdupWtoA( UINT cp, const WCHAR *str )
  62. {
  63. char *ret = NULL;
  64. if (str)
  65. {
  66. DWORD len = WideCharToMultiByte( cp, 0, str, -1, NULL, 0, NULL, NULL );
  67. if ((ret = cab_alloc( len )))
  68. WideCharToMultiByte( cp, 0, str, -1, ret, len, NULL, NULL );
  69. }
  70. return ret;
  71. }
  72. /* format a cabinet name by replacing the '*' wildcard by the cabinet id */
  73. static BOOL format_cab_name( char *dest, int id, const char *name )
  74. {
  75. const char *num = strchr( name, '*' );
  76. int len;
  77. if (!num)
  78. {
  79. if (id == 1)
  80. {
  81. strcpy( dest, name );
  82. return TRUE;
  83. }
  84. WINE_MESSAGE( "cabarc: Cabinet name must contain a '*' character\n" );
  85. return FALSE;
  86. }
  87. len = num - name;
  88. memcpy( dest, name, len );
  89. len += sprintf( dest + len, "%u", id );
  90. lstrcpynA( dest + len, num + 1, CB_MAX_CABINET_NAME - len );
  91. return TRUE;
  92. }
  93. static int CDECL fci_file_placed( CCAB *cab, char *file, LONG size, BOOL continuation, void *ptr )
  94. {
  95. if (!continuation && opt_verbose) printf( "adding %s\n", file );
  96. return 0;
  97. }
  98. static INT_PTR CDECL fci_open( char *file, int oflag, int pmode, int *err, void *ptr )
  99. {
  100. DWORD creation = 0, sharing = 0;
  101. int ioflag = 0;
  102. HANDLE handle;
  103. switch (oflag & _O_ACCMODE)
  104. {
  105. case _O_RDONLY: ioflag |= GENERIC_READ; break;
  106. case _O_WRONLY: ioflag |= GENERIC_WRITE; break;
  107. case _O_RDWR: ioflag |= GENERIC_READ | GENERIC_WRITE; break;
  108. }
  109. if (oflag & _O_CREAT)
  110. {
  111. if (oflag & _O_EXCL) creation = CREATE_NEW;
  112. else if (oflag & _O_TRUNC) creation = CREATE_ALWAYS;
  113. else creation = OPEN_ALWAYS;
  114. }
  115. else
  116. {
  117. if (oflag & _O_TRUNC) creation = TRUNCATE_EXISTING;
  118. else creation = OPEN_EXISTING;
  119. }
  120. switch (pmode & 0x70)
  121. {
  122. case _SH_DENYRW: sharing = 0; break;
  123. case _SH_DENYWR: sharing = FILE_SHARE_READ; break;
  124. case _SH_DENYRD: sharing = FILE_SHARE_WRITE; break;
  125. default: sharing = FILE_SHARE_READ | FILE_SHARE_WRITE; break;
  126. }
  127. handle = CreateFileA( file, ioflag, sharing, NULL, creation, FILE_ATTRIBUTE_NORMAL, NULL );
  128. if (handle == INVALID_HANDLE_VALUE) *err = GetLastError();
  129. return (INT_PTR)handle;
  130. }
  131. static UINT CDECL fci_read( INT_PTR hf, void *pv, UINT cb, int *err, void *ptr )
  132. {
  133. DWORD num_read;
  134. if (!ReadFile( (HANDLE)hf, pv, cb, &num_read, NULL ))
  135. {
  136. *err = GetLastError();
  137. return -1;
  138. }
  139. return num_read;
  140. }
  141. static UINT CDECL fci_write( INT_PTR hf, void *pv, UINT cb, int *err, void *ptr )
  142. {
  143. DWORD written;
  144. if (!WriteFile( (HANDLE) hf, pv, cb, &written, NULL ))
  145. {
  146. *err = GetLastError();
  147. return -1;
  148. }
  149. return written;
  150. }
  151. static int CDECL fci_close( INT_PTR hf, int *err, void *ptr )
  152. {
  153. if (!CloseHandle( (HANDLE)hf ))
  154. {
  155. *err = GetLastError();
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. static LONG CDECL fci_lseek( INT_PTR hf, LONG dist, int seektype, int *err, void *ptr )
  161. {
  162. DWORD ret;
  163. ret = SetFilePointer( (HANDLE)hf, dist, NULL, seektype );
  164. if (ret == INVALID_SET_FILE_POINTER && GetLastError())
  165. {
  166. *err = GetLastError();
  167. return -1;
  168. }
  169. return ret;
  170. }
  171. static int CDECL fci_delete( char *file, int *err, void *ptr )
  172. {
  173. if (!DeleteFileA( file ))
  174. {
  175. *err = GetLastError();
  176. return -1;
  177. }
  178. return 0;
  179. }
  180. static BOOL CDECL fci_get_temp( char *name, int size, void *ptr )
  181. {
  182. char path[MAX_PATH];
  183. if (!GetTempPathA( MAX_PATH, path )) return FALSE;
  184. if (!GetTempFileNameA( path, "cab", 0, name )) return FALSE;
  185. DeleteFileA( name );
  186. return TRUE;
  187. }
  188. static BOOL CDECL fci_get_next_cab( CCAB *cab, ULONG prev_size, void *ptr )
  189. {
  190. return format_cab_name( cab->szCab, cab->iCab + 1, opt_cab_file );
  191. }
  192. static LONG CDECL fci_status( UINT type, ULONG cb1, ULONG cb2, void *ptr )
  193. {
  194. return 0;
  195. }
  196. static INT_PTR CDECL fci_get_open_info( char *name, USHORT *date, USHORT *time,
  197. USHORT *attribs, int *err, void *ptr )
  198. {
  199. HANDLE handle;
  200. BY_HANDLE_FILE_INFORMATION info;
  201. WCHAR *p, *nameW = strdupAtoW( CP_UTF8, name );
  202. handle = CreateFileW( nameW, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  203. NULL, OPEN_EXISTING, 0, NULL );
  204. if (handle == INVALID_HANDLE_VALUE)
  205. {
  206. *err = GetLastError();
  207. WINE_ERR( "failed to open %s: error %u\n", wine_dbgstr_w(nameW), *err );
  208. cab_free( nameW );
  209. return -1;
  210. }
  211. if (!GetFileInformationByHandle( handle, &info ))
  212. {
  213. *err = GetLastError();
  214. CloseHandle( handle );
  215. cab_free( nameW );
  216. return -1;
  217. }
  218. FileTimeToDosDateTime( &info.ftLastWriteTime, date, time );
  219. *attribs = info.dwFileAttributes & (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
  220. for (p = nameW; *p; p++) if (*p >= 0x80) break;
  221. if (*p) *attribs |= _A_NAME_IS_UTF;
  222. cab_free( nameW );
  223. return (INT_PTR)handle;
  224. }
  225. static INT_PTR CDECL fdi_open( char *file, int oflag, int pmode )
  226. {
  227. int err;
  228. return fci_open( file, oflag, pmode, &err, NULL );
  229. }
  230. static UINT CDECL fdi_read( INT_PTR hf, void *pv, UINT cb )
  231. {
  232. int err;
  233. return fci_read( hf, pv, cb, &err, NULL );
  234. }
  235. static UINT CDECL fdi_write( INT_PTR hf, void *pv, UINT cb )
  236. {
  237. int err;
  238. return fci_write( hf, pv, cb, &err, NULL );
  239. }
  240. static int CDECL fdi_close( INT_PTR hf )
  241. {
  242. int err;
  243. return fci_close( hf, &err, NULL );
  244. }
  245. static LONG CDECL fdi_lseek( INT_PTR hf, LONG dist, int whence )
  246. {
  247. int err;
  248. return fci_lseek( hf, dist, whence, &err, NULL );
  249. }
  250. /* create directories leading to a given file */
  251. static void create_directories( const WCHAR *name )
  252. {
  253. WCHAR *path, *p;
  254. /* create the directory/directories */
  255. path = cab_alloc( (lstrlenW(name) + 1) * sizeof(WCHAR) );
  256. lstrcpyW(path, name);
  257. p = wcschr(path, '\\');
  258. while (p != NULL)
  259. {
  260. *p = 0;
  261. if (!CreateDirectoryW( path, NULL ))
  262. WINE_TRACE("Couldn't create directory %s - error: %ld\n", wine_dbgstr_w(path), GetLastError());
  263. *p = '\\';
  264. p = wcschr(p+1, '\\');
  265. }
  266. cab_free( path );
  267. }
  268. /* check if file name matches against one of the files specification */
  269. static BOOL match_files( const WCHAR *name )
  270. {
  271. int i;
  272. if (!*opt_files) return TRUE;
  273. for (i = 0; opt_files[i]; i++)
  274. {
  275. unsigned int len = lstrlenW( opt_files[i] );
  276. /* FIXME: do smarter matching, and wildcards */
  277. if (!len) continue;
  278. if (wcsnicmp( name, opt_files[i], len )) continue;
  279. if (opt_files[i][len - 1] == '\\' || !name[len] || name[len] == '\\') return TRUE;
  280. }
  281. return FALSE;
  282. }
  283. static INT_PTR CDECL list_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
  284. {
  285. WCHAR *nameW;
  286. switch (fdint)
  287. {
  288. case fdintCABINET_INFO:
  289. return 0;
  290. case fdintCOPY_FILE:
  291. nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 );
  292. if (match_files( nameW ))
  293. {
  294. if (opt_verbose)
  295. {
  296. WCHAR attrs[] = L"rxash";
  297. if (!(pfdin->attribs & _A_RDONLY)) attrs[0] = '-';
  298. if (!(pfdin->attribs & _A_EXEC)) attrs[1] = '-';
  299. if (!(pfdin->attribs & _A_ARCH)) attrs[2] = '-';
  300. if (!(pfdin->attribs & _A_SYSTEM)) attrs[3] = '-';
  301. if (!(pfdin->attribs & _A_HIDDEN)) attrs[4] = '-';
  302. wprintf( L" %s %9u %04u/%02u/%02u %02u:%02u:%02u ", attrs, pfdin->cb,
  303. (pfdin->date >> 9) + 1980, (pfdin->date >> 5) & 0x0f, pfdin->date & 0x1f,
  304. pfdin->time >> 11, (pfdin->time >> 5) & 0x3f, (pfdin->time & 0x1f) * 2 );
  305. }
  306. wprintf( L"%s\n", nameW );
  307. }
  308. cab_free( nameW );
  309. return 0;
  310. default:
  311. WINE_FIXME( "Unexpected notification type %d.\n", fdint );
  312. return 0;
  313. }
  314. }
  315. static int list_cabinet( char *cab_dir )
  316. {
  317. ERF erf;
  318. int ret = 0;
  319. HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
  320. fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );
  321. if (!FDICopy( fdi, opt_cab_file, cab_dir, 0, list_notify, NULL, NULL )) ret = GetLastError();
  322. FDIDestroy( fdi );
  323. return ret;
  324. }
  325. static INT_PTR CDECL extract_notify( FDINOTIFICATIONTYPE fdint, PFDINOTIFICATION pfdin )
  326. {
  327. WCHAR *file, *nameW, *path = NULL;
  328. INT_PTR ret;
  329. switch (fdint)
  330. {
  331. case fdintCABINET_INFO:
  332. return 0;
  333. case fdintCOPY_FILE:
  334. nameW = strdupAtoW( (pfdin->attribs & _A_NAME_IS_UTF) ? CP_UTF8 : CP_ACP, pfdin->psz1 );
  335. if (opt_preserve_paths)
  336. {
  337. file = nameW;
  338. while (*file == '\\') file++; /* remove leading backslashes */
  339. }
  340. else
  341. {
  342. if ((file = wcsrchr( nameW, '\\' ))) file++;
  343. else file = nameW;
  344. }
  345. if (opt_dest_dir)
  346. {
  347. path = cab_alloc( (lstrlenW(opt_dest_dir) + lstrlenW(file) + 1) * sizeof(WCHAR) );
  348. lstrcpyW( path, opt_dest_dir );
  349. lstrcatW( path, file );
  350. }
  351. else path = file;
  352. if (match_files( file ))
  353. {
  354. if (opt_verbose) wprintf( L"extracting %s\n", path );
  355. create_directories( path );
  356. /* FIXME: check for existing file and overwrite mode */
  357. ret = (INT_PTR)CreateFileW( path, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
  358. NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
  359. }
  360. else ret = 0;
  361. cab_free( nameW );
  362. if (path != file) cab_free( path );
  363. return ret;
  364. case fdintCLOSE_FILE_INFO:
  365. CloseHandle( (HANDLE)pfdin->hf );
  366. return 0;
  367. case fdintNEXT_CABINET:
  368. WINE_TRACE("Next cab: status %u, path '%s', file '%s'\n", pfdin->fdie, pfdin->psz3, pfdin->psz1);
  369. return pfdin->fdie == FDIERROR_NONE ? 0 : -1;
  370. case fdintENUMERATE:
  371. return 0;
  372. default:
  373. WINE_FIXME( "Unexpected notification type %d.\n", fdint );
  374. return 0;
  375. }
  376. }
  377. static int extract_cabinet( char *cab_dir )
  378. {
  379. ERF erf;
  380. int ret = 0;
  381. HFDI fdi = FDICreate( cab_alloc, cab_free, fdi_open, fdi_read,
  382. fdi_write, fdi_close, fdi_lseek, cpuUNKNOWN, &erf );
  383. if (!FDICopy( fdi, opt_cab_file, cab_dir, 0, extract_notify, NULL, NULL ))
  384. {
  385. ret = GetLastError();
  386. WINE_WARN("FDICopy() failed: code %u\n", ret);
  387. }
  388. FDIDestroy( fdi );
  389. return ret;
  390. }
  391. static BOOL add_file( HFCI fci, WCHAR *name )
  392. {
  393. BOOL ret;
  394. char *filename, *path = strdupWtoA( CP_UTF8, name );
  395. if (!opt_preserve_paths)
  396. {
  397. if ((filename = strrchr( path, '\\' ))) filename++;
  398. else filename = path;
  399. }
  400. else
  401. {
  402. filename = path;
  403. while (*filename == '\\') filename++; /* remove leading backslashes */
  404. }
  405. ret = FCIAddFile( fci, path, filename, FALSE,
  406. fci_get_next_cab, fci_status, fci_get_open_info, opt_compression );
  407. cab_free( path );
  408. return ret;
  409. }
  410. static BOOL add_directory( HFCI fci, WCHAR *dir )
  411. {
  412. WCHAR *p, *buffer;
  413. HANDLE handle;
  414. WIN32_FIND_DATAW data;
  415. BOOL ret = TRUE;
  416. if (!(buffer = cab_alloc( (lstrlenW(dir) + MAX_PATH + 2) * sizeof(WCHAR) ))) return FALSE;
  417. lstrcpyW( buffer, dir );
  418. p = buffer + lstrlenW( buffer );
  419. if (p > buffer && p[-1] != '\\') *p++ = '\\';
  420. lstrcpyW( p, L"*" );
  421. if ((handle = FindFirstFileW( buffer, &data )) != INVALID_HANDLE_VALUE)
  422. {
  423. do
  424. {
  425. if (data.cFileName[0] == '.' && !data.cFileName[1]) continue;
  426. if (data.cFileName[0] == '.' && data.cFileName[1] == '.' && !data.cFileName[2]) continue;
  427. if (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) continue;
  428. lstrcpyW( p, data.cFileName );
  429. if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  430. ret = add_directory( fci, buffer );
  431. else
  432. ret = add_file( fci, buffer );
  433. if (!ret) break;
  434. } while (FindNextFileW( handle, &data ));
  435. FindClose( handle );
  436. }
  437. cab_free( buffer );
  438. return TRUE;
  439. }
  440. static BOOL add_file_or_directory( HFCI fci, WCHAR *name )
  441. {
  442. DWORD attr = GetFileAttributesW( name );
  443. if (attr == INVALID_FILE_ATTRIBUTES)
  444. {
  445. WINE_MESSAGE( "cannot open %s\n", wine_dbgstr_w(name) );
  446. return FALSE;
  447. }
  448. if (attr & FILE_ATTRIBUTE_DIRECTORY)
  449. {
  450. if (opt_recurse) return add_directory( fci, name );
  451. WINE_MESSAGE( "cabarc: Cannot add %s, it's a directory (use -r for recursive add)\n",
  452. wine_dbgstr_w(name) );
  453. return FALSE;
  454. }
  455. return add_file( fci, name );
  456. }
  457. static int new_cabinet( char *cab_dir )
  458. {
  459. WCHAR **file;
  460. ERF erf;
  461. BOOL ret = FALSE;
  462. HFCI fci;
  463. CCAB cab;
  464. cab.cb = opt_cabinet_size;
  465. cab.cbFolderThresh = CB_MAX_DISK;
  466. cab.cbReserveCFHeader = opt_reserve_space;
  467. cab.cbReserveCFFolder = 0;
  468. cab.cbReserveCFData = 0;
  469. cab.iCab = 0;
  470. cab.iDisk = 0;
  471. cab.setID = opt_cabinet_id;
  472. cab.szDisk[0] = 0;
  473. strcpy( cab.szCabPath, cab_dir );
  474. strcat( cab.szCabPath, "\\" );
  475. format_cab_name( cab.szCab, 1, opt_cab_file );
  476. fci = FCICreate( &erf, fci_file_placed, cab_alloc, cab_free,fci_open, fci_read,
  477. fci_write, fci_close, fci_lseek, fci_delete, fci_get_temp, &cab, NULL );
  478. for (file = opt_files; *file; file++)
  479. {
  480. if (!lstrcmpW( *file, L"+" ))
  481. FCIFlushFolder( fci, fci_get_next_cab, fci_status );
  482. else
  483. if (!(ret = add_file_or_directory( fci, *file ))) break;
  484. }
  485. if (ret)
  486. {
  487. if (!(ret = FCIFlushCabinet( fci, FALSE, fci_get_next_cab, fci_status )))
  488. WINE_MESSAGE( "cabarc: Failed to create cabinet %s\n", wine_dbgstr_a(opt_cab_file) );
  489. }
  490. FCIDestroy( fci );
  491. return !ret;
  492. }
  493. static void usage( void )
  494. {
  495. WINE_MESSAGE(
  496. "Usage: cabarc [options] command file.cab [files...] [dest_dir\\]\n"
  497. "\nCommands:\n"
  498. " L List the contents of the cabinet\n"
  499. " N Create a new cabinet\n"
  500. " X Extract files from the cabinet into dest_dir\n"
  501. "\nOptions:\n"
  502. " -d size Set maximum disk size\n"
  503. " -h Display this help\n"
  504. " -i id Set cabinet id\n"
  505. " -m type Set compression type (mszip|none)\n"
  506. " -p Preserve directory names\n"
  507. " -r Recurse into directories\n"
  508. " -s size Reserve space in the cabinet header\n"
  509. " -v More verbose output\n" );
  510. }
  511. int __cdecl wmain( int argc, WCHAR *argv[] )
  512. {
  513. WCHAR *p, *command;
  514. char buffer[MAX_PATH];
  515. char filename[MAX_PATH];
  516. char *cab_file, *file_part;
  517. int i;
  518. while (argv[1] && argv[1][0] == '-')
  519. {
  520. switch (argv[1][1])
  521. {
  522. case 'd':
  523. argv++; argc--;
  524. opt_cabinet_size = wcstol( argv[1], NULL, 10 );
  525. if (opt_cabinet_size < 50000)
  526. {
  527. WINE_MESSAGE( "cabarc: Cabinet size must be at least 50000\n" );
  528. return 1;
  529. }
  530. break;
  531. case 'h':
  532. usage();
  533. return 0;
  534. case 'i':
  535. argv++; argc--;
  536. opt_cabinet_id = wcstol( argv[1], NULL, 10 );
  537. break;
  538. case 'm':
  539. argv++; argc--;
  540. if (!wcscmp( argv[1], L"none" )) opt_compression = tcompTYPE_NONE;
  541. else if (!wcscmp( argv[1], L"mszip" )) opt_compression = tcompTYPE_MSZIP;
  542. else
  543. {
  544. WINE_MESSAGE( "cabarc: Unknown compression type %s\n", debugstr_w(argv[1]));
  545. return 1;
  546. }
  547. break;
  548. case 'p':
  549. opt_preserve_paths = TRUE;
  550. break;
  551. case 'r':
  552. opt_recurse = TRUE;
  553. break;
  554. case 's':
  555. argv++; argc--;
  556. opt_reserve_space = wcstol( argv[1], NULL, 10 );
  557. break;
  558. case 'v':
  559. opt_verbose++;
  560. break;
  561. default:
  562. usage();
  563. return 1;
  564. }
  565. argv++; argc--;
  566. }
  567. command = argv[1];
  568. if (argc < 3 || !command[0] || command[1])
  569. {
  570. usage();
  571. return 1;
  572. }
  573. cab_file = strdupWtoA( CP_ACP, argv[2] );
  574. argv += 2;
  575. argc -= 2;
  576. if (!GetFullPathNameA( cab_file, MAX_PATH, buffer, &file_part ) || !file_part)
  577. {
  578. WINE_ERR( "cannot get full name for %s\n", wine_dbgstr_a( cab_file ));
  579. return 1;
  580. }
  581. strcpy(filename, file_part);
  582. file_part[0] = 0;
  583. /* map slash to backslash in all file arguments */
  584. for (i = 1; i < argc; i++)
  585. for (p = argv[i]; *p; p++)
  586. if (*p == '/') *p = '\\';
  587. opt_files = argv + 1;
  588. opt_cab_file = filename;
  589. switch (*command)
  590. {
  591. case 'l':
  592. case 'L':
  593. return list_cabinet( buffer );
  594. case 'n':
  595. case 'N':
  596. return new_cabinet( buffer );
  597. case 'x':
  598. case 'X':
  599. if (argc > 1) /* check for destination dir as last argument */
  600. {
  601. WCHAR *last = argv[argc - 1];
  602. if (last[0] && last[lstrlenW(last) - 1] == '\\')
  603. {
  604. opt_dest_dir = last;
  605. argv[--argc] = NULL;
  606. }
  607. }
  608. WINE_TRACE("Extracting file(s) from cabinet %s\n", wine_dbgstr_a(cab_file));
  609. return extract_cabinet( buffer );
  610. default:
  611. usage();
  612. return 1;
  613. }
  614. }