Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

577 lines
11 KiB

  1. //
  2. // MODULE: CABUNCOMPRESS.CPP
  3. //
  4. // PURPOSE: CAB File Support Class
  5. //
  6. // PROJECT: Generic Troubleshooter DLL for Microsoft AnswerPoint
  7. //
  8. // COMPANY: Saltmine Creative, Inc. (206)-284-7511 [email protected]
  9. //
  10. // AUTHOR: Richard Meadows
  11. //
  12. // ORIGINAL DATE: 8/7/97
  13. //
  14. // NOTES:
  15. // 1.
  16. //
  17. // Version Date By Comments
  18. //--------------------------------------------------------------------
  19. // V0.2 6/4/97 RM Local Version for Memphis
  20. // V0.3 04/09/98 JM/OK+ Local Version for NT5
  21. //
  22. #include "stdafx.h"
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <io.h>
  27. #include <fcntl.h>
  28. #include <dos.h>
  29. #include <sys/stat.h>
  30. #include "CabUnCompress.h"
  31. #include "chmread.h"
  32. #include "apgts.h"
  33. #ifdef _DEBUG
  34. #ifndef _UNICODE
  35. #define PRINT_OUT ::AfxTrace
  36. //#define PRINT_OUT 1 ? (void)0 : ::AfxTrace
  37. #else
  38. #define PRINT_OUT 1 ? (void)0 : ::AfxTrace
  39. #endif
  40. #else
  41. #define PRINT_OUT 1 ? (void)0 : ::AfxTrace
  42. #endif
  43. // Need this to compile unicode builds.
  44. bool TcharToChar(char szOut[], LPCTSTR szIn, int &OutLen)
  45. {
  46. int x = 0;
  47. while(NULL != szIn[x] && x < OutLen)
  48. {
  49. szOut[x] = (char) szIn[x];
  50. x++;
  51. }
  52. if (x < OutLen)
  53. szOut[x] = NULL;
  54. return x < OutLen;
  55. }
  56. // Call back functions needed to use the fdi library.
  57. /*
  58. * Memory allocation function
  59. */
  60. FNALLOC(mem_alloc)
  61. {
  62. return malloc(cb);
  63. }
  64. /*
  65. * Memory free function
  66. */
  67. FNFREE(mem_free)
  68. {
  69. free(pv);
  70. }
  71. FNOPEN(file_open)
  72. {
  73. return _open(pszFile, oflag, pmode);
  74. }
  75. FNREAD(file_read)
  76. {
  77. return _read(hf, pv, cb);
  78. }
  79. FNWRITE(file_write)
  80. {
  81. return _write(hf, pv, cb);
  82. }
  83. FNCLOSE(file_close)
  84. {
  85. return _close(hf);
  86. }
  87. FNSEEK(file_seek)
  88. {
  89. return _lseek(hf, dist, seektype);
  90. }
  91. /*
  92. * Function prototypes
  93. */
  94. BOOL test_fdi(TCHAR *cabinet_file);
  95. int get_percentage(unsigned long a, unsigned long b);
  96. TCHAR *return_fdi_error_string(FDIERROR err);
  97. /*
  98. * Destination directory for extracted files
  99. */
  100. char dest_dir[MAX_PATH];
  101. // Last file to be extracted.
  102. char last_extracted[MAX_PATH];
  103. FNFDINOTIFY(notification_function)
  104. {
  105. switch (fdint)
  106. {
  107. case fdintCABINET_INFO: // general information about the cabinet
  108. PRINT_OUT(
  109. _T("fdintCABINET_INFO\n")
  110. _T(" next cabinet = %s\n")
  111. _T(" next disk = %s\n")
  112. _T(" cabinet path = %s\n")
  113. _T(" cabinet set ID = %d\n")
  114. _T(" cabinet # in set = %d (zero based)\n")
  115. _T("\n"),
  116. pfdin->psz1,
  117. pfdin->psz2,
  118. pfdin->psz3,
  119. pfdin->setID,
  120. pfdin->iCabinet);
  121. return 0;
  122. case fdintPARTIAL_FILE: // first file in cabinet is continuation
  123. PRINT_OUT(
  124. _T("fdintPARTIAL_FILE\n")
  125. _T(" name of continued file = %s\n")
  126. _T(" name of cabinet where file starts = %s\n")
  127. _T(" name of disk where file starts = %s\n"),
  128. pfdin->psz1,
  129. pfdin->psz2,
  130. pfdin->psz3);
  131. return 0;
  132. case fdintCOPY_FILE: // file to be copied
  133. {
  134. int handle;
  135. char destination[MAX_PATH];
  136. PRINT_OUT(
  137. _T("fdintCOPY_FILE\n")
  138. _T(" file name in cabinet = %s\n")
  139. _T(" uncompressed file size = %d\n")
  140. _T(" copy this file? (y/n): y"),
  141. pfdin->psz1,
  142. pfdin->cb);
  143. strcpy(last_extracted, pfdin->psz1);
  144. PRINT_OUT(_T("\n"));
  145. sprintf(
  146. destination,
  147. "%s%s",
  148. dest_dir,
  149. pfdin->psz1
  150. );
  151. handle = file_open(
  152. destination,
  153. _O_BINARY | _O_CREAT | _O_TRUNC | _O_WRONLY | _O_SEQUENTIAL,
  154. _S_IREAD | _S_IWRITE
  155. );
  156. return handle;
  157. }
  158. case fdintCLOSE_FILE_INFO: // close the file, set relevant info
  159. {
  160. HANDLE handle;
  161. DWORD attrs;
  162. char destination[MAX_PATH];
  163. PRINT_OUT(
  164. _T("fdintCLOSE_FILE_INFO\n")
  165. _T(" file name in cabinet = %s\n")
  166. _T("\n"),
  167. pfdin->psz1);
  168. sprintf(
  169. destination,
  170. "%s%s",
  171. dest_dir,
  172. pfdin->psz1);
  173. file_close(pfdin->hf);
  174. /*
  175. * Set date/time
  176. *
  177. * Need Win32 type handle for to set date/time
  178. */
  179. handle = CreateFileA(
  180. destination,
  181. GENERIC_READ | GENERIC_WRITE,
  182. FILE_SHARE_READ,
  183. NULL,
  184. OPEN_EXISTING,
  185. FILE_ATTRIBUTE_NORMAL,
  186. NULL);
  187. if (handle != INVALID_HANDLE_VALUE)
  188. {
  189. FILETIME datetime;
  190. if (TRUE == DosDateTimeToFileTime(
  191. pfdin->date,
  192. pfdin->time,
  193. &datetime))
  194. {
  195. FILETIME local_filetime;
  196. if (TRUE == LocalFileTimeToFileTime(
  197. &datetime,
  198. &local_filetime))
  199. {
  200. (void) SetFileTime(
  201. handle,
  202. &local_filetime,
  203. NULL,
  204. &local_filetime);
  205. }
  206. }
  207. CloseHandle(handle);
  208. }
  209. /*
  210. * Mask out attribute bits other than readonly,
  211. * hidden, system, and archive, since the other
  212. * attribute bits are reserved for use by
  213. * the cabinet format.
  214. */
  215. attrs = pfdin->attribs;
  216. attrs &= (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_ARCH);
  217. (void) SetFileAttributesA(
  218. destination,
  219. attrs);
  220. return TRUE;
  221. }
  222. case fdintNEXT_CABINET: // file continued to next cabinet
  223. PRINT_OUT(
  224. _T("fdintNEXT_CABINET\n")
  225. _T(" name of next cabinet where file continued = %s\n")
  226. _T(" name of next disk where file continued = %s\n")
  227. _T(" cabinet path name = %s\n")
  228. _T("\n"),
  229. pfdin->psz1,
  230. pfdin->psz2,
  231. pfdin->psz3);
  232. return 0;
  233. }
  234. return 0;
  235. }
  236. TCHAR *return_fdi_error_string(FDIERROR err)
  237. {
  238. switch (err)
  239. {
  240. case FDIERROR_NONE:
  241. return _T("No error");
  242. case FDIERROR_CABINET_NOT_FOUND:
  243. return _T("Cabinet not found");
  244. case FDIERROR_NOT_A_CABINET:
  245. return _T("Not a cabinet");
  246. case FDIERROR_UNKNOWN_CABINET_VERSION:
  247. return _T("Unknown cabinet version");
  248. case FDIERROR_CORRUPT_CABINET:
  249. return _T("Corrupt cabinet");
  250. case FDIERROR_ALLOC_FAIL:
  251. return _T("Memory allocation failed");
  252. case FDIERROR_BAD_COMPR_TYPE:
  253. return _T("Unknown compression type");
  254. case FDIERROR_MDI_FAIL:
  255. return _T("Failure decompressing data");
  256. case FDIERROR_TARGET_FILE:
  257. return _T("Failure writing to target file");
  258. case FDIERROR_RESERVE_MISMATCH:
  259. return _T("Cabinets in set have different RESERVE sizes");
  260. case FDIERROR_WRONG_CABINET:
  261. return _T("Cabinet returned on fdintNEXT_CABINET is incorrect");
  262. case FDIERROR_USER_ABORT:
  263. return _T("User aborted");
  264. default:
  265. return _T("Unknown error");
  266. }
  267. }
  268. CCabUnCompress::CCabUnCompress()
  269. {
  270. m_strError = _T("");
  271. m_nError = NO_ERROR;
  272. return;
  273. }
  274. BOOL CCabUnCompress::ExtractCab(CString &strCabFile, CString &strDestDir, const CString& strFile)
  275. {
  276. HFDI hfdi;
  277. ERF erf;
  278. FDICABINETINFO fdici;
  279. int hf;
  280. char *p;
  281. char cabinet_name[MAX_PATH];
  282. char cabinet_path[MAX_PATH];
  283. bool bUseCHM = strFile.GetLength() != 0;
  284. BOOL bRet = FALSE;
  285. BOOL bWasRenamed = FALSE;
  286. char sznCabFile[MAX_PATH];
  287. char sznDestDir[MAX_PATH * 3];
  288. int Len = MAX_PATH;
  289. TcharToChar(sznCabFile, (LPCTSTR) strCabFile, Len);
  290. Len = MAX_PATH * 3;
  291. TcharToChar(sznDestDir, (LPCTSTR) strDestDir, Len);
  292. ASSERT(strDestDir.GetLength() < MAX_PATH);
  293. strcpy(dest_dir, sznDestDir);
  294. hfdi = FDICreate(
  295. mem_alloc,
  296. mem_free,
  297. file_open,
  298. file_read,
  299. file_write,
  300. file_close,
  301. file_seek,
  302. cpu80386,
  303. &erf
  304. );
  305. if (hfdi == NULL)
  306. {
  307. m_strError.Format(_T("FDICreate() failed: code %d [%s]\n"),
  308. erf.erfOper, return_fdi_error_string(erf.erfOper));
  309. return FALSE;
  310. }
  311. if (bUseCHM)
  312. {
  313. /*
  314. * If strCabFile is CHM file - extract data from *.dsz file inside CHM
  315. * and save this data in strDestDir directory as temperary file
  316. * It means that we are copying *.dsz file in temp directory, then
  317. * decode it to *.dsc file.
  318. * *.dsz file fill be removed in this function, *.dsc file will be renoved
  319. * later.
  320. */
  321. // modify sznCabFile from path\*.chm to temp_path\network.dsz
  322. strcpy(sznCabFile, strDestDir);
  323. strcat(sznCabFile, strFile);
  324. hf = file_open(
  325. sznCabFile,
  326. _O_CREAT | _O_TRUNC | /*_O_TEMPORARY |*/
  327. _O_BINARY | _O_RDWR | _O_SEQUENTIAL ,
  328. _S_IREAD | _S_IWRITE
  329. );
  330. if (hf != -1)
  331. {
  332. // write in temp file now
  333. void* buf =NULL;
  334. DWORD size =0;
  335. if (S_OK == ::ReadChmFile(strCabFile, strFile, &buf, &size))
  336. {
  337. int ret = _write(hf, buf, size);
  338. delete [] buf;
  339. if (-1 == ret)
  340. {
  341. FDIDestroy(hfdi);
  342. _close(hf);
  343. return FALSE;
  344. }
  345. }
  346. else
  347. {
  348. FDIDestroy(hfdi);
  349. _close(hf);
  350. return FALSE;
  351. }
  352. }
  353. else
  354. {
  355. FDIDestroy(hfdi);
  356. return FALSE;
  357. }
  358. _close(hf);
  359. }
  360. /*
  361. * Is this file really a cabinet?
  362. */
  363. hf = file_open(
  364. sznCabFile,
  365. _O_BINARY | _O_RDONLY | _O_SEQUENTIAL,
  366. 0
  367. );
  368. if (hf == -1)
  369. {
  370. (void) FDIDestroy(hfdi);
  371. m_strError.Format(_T("Unable to open '%s' for input\n"), (LPCTSTR) strCabFile);
  372. return FALSE;
  373. }
  374. bRet = FDIIsCabinet(hfdi,
  375. hf,
  376. &fdici);
  377. _close(hf);
  378. if (FALSE == bRet)
  379. {
  380. /*
  381. * No, it's not a cabinet!
  382. */
  383. if (bUseCHM)
  384. {
  385. // But if we were using CHM -
  386. // we have extracted this *.dsz (that has *.dsc format)
  387. // in TEMP directory and all we heed - just rename it to
  388. // *.dsc.
  389. // This would EMULATE case where we have *.dsz compressed.
  390. CString strUncompressedFile, strCabFile(sznCabFile);
  391. strUncompressedFile = strCabFile.Left(strCabFile.GetLength() - 4);
  392. strUncompressedFile += DSC_UNCOMPRESSED;
  393. remove(strUncompressedFile); // remove if exists
  394. if (0 != rename(strCabFile, strUncompressedFile))
  395. {
  396. FDIDestroy(hfdi);
  397. goto AWAY;
  398. }
  399. CString strJustUncompressedFileName = ::ExtractFileName(strUncompressedFile);
  400. strcpy(last_extracted, strJustUncompressedFileName);
  401. bWasRenamed = TRUE;
  402. bRet = TRUE;
  403. }
  404. else
  405. {
  406. m_strError.Format(
  407. _T("FDIIsCabinet() failed: '%s' is not a cabinet\n"),
  408. (LPCTSTR) strCabFile);
  409. m_nError = NOT_A_CAB;
  410. }
  411. (void) FDIDestroy(hfdi);
  412. goto AWAY;
  413. }
  414. else
  415. {
  416. PRINT_OUT(
  417. _T("Information on cabinet file '%s'\n")
  418. _T(" Total length of cabinet file : %d\n")
  419. _T(" Number of folders in cabinet : %d\n")
  420. _T(" Number of files in cabinet : %d\n")
  421. _T(" Cabinet set ID : %d\n")
  422. _T(" Cabinet number in set : %d\n")
  423. _T(" RESERVE area in cabinet? : %s\n")
  424. _T(" Chained to prev cabinet? : %s\n")
  425. _T(" Chained to next cabinet? : %s\n")
  426. _T("\n"),
  427. (LPCTSTR) strCabFile,
  428. fdici.cbCabinet,
  429. fdici.cFolders,
  430. fdici.cFiles,
  431. fdici.setID,
  432. fdici.iCabinet,
  433. fdici.fReserve == TRUE ? _T("yes") : _T("no"),
  434. fdici.hasprev == TRUE ? _T("yes") : _T("no"),
  435. fdici.hasnext == TRUE ? _T("yes") : _T("no")
  436. );
  437. }
  438. p = strchr(sznCabFile, '\\');
  439. if (p == NULL)
  440. {
  441. strcpy(cabinet_name, sznCabFile);
  442. strcpy(cabinet_path, "");
  443. }
  444. else
  445. {
  446. strcpy(cabinet_name, p+1);
  447. char *pCab = sznCabFile;
  448. strncpy(cabinet_path, sznCabFile, (int) (p-pCab)+1);
  449. cabinet_path[ (int) (p-pCab)+1 ] = 0;
  450. }
  451. if (TRUE != FDICopy(
  452. hfdi,
  453. cabinet_name,
  454. cabinet_path,
  455. 0,
  456. notification_function,
  457. NULL,
  458. NULL))
  459. {
  460. m_strError.Format(
  461. _T("FDICopy() failed: code %d [%s]\n"),
  462. erf.erfOper, return_fdi_error_string(erf.erfOper));
  463. (void) FDIDestroy(hfdi);
  464. bRet = FALSE;
  465. goto AWAY;
  466. }
  467. if (FDIDestroy(hfdi) != TRUE)
  468. {
  469. m_strError.Format(
  470. _T("FDIDestroy() failed: code %d [%s]\n"),
  471. erf.erfOper, return_fdi_error_string(erf.erfOper));
  472. bRet = FALSE;
  473. goto AWAY;
  474. }
  475. AWAY:
  476. if (bUseCHM && !bWasRenamed)
  477. remove(sznCabFile);
  478. return bRet;
  479. }
  480. CString CCabUnCompress::GetLastFile()
  481. {
  482. CString str = last_extracted;
  483. return str;
  484. }