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.

457 lines
10 KiB

  1. //=======================================================================
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation. All Rights Reserved.
  4. //
  5. // File: diamond.cpp
  6. //
  7. // Owner: YanL
  8. //
  9. // Description:
  10. //
  11. // Diamond decompressor implementation
  12. //
  13. //=======================================================================
  14. #include <windows.h>
  15. #include <shlwapi.h>
  16. #include <fcntl.h>
  17. #include <sys/stat.h>
  18. #include <tchar.h>
  19. #include <atlconv.h>
  20. #include <wustl.h>
  21. //#define LOGGING_LEVEL 3
  22. //#include <log.h>
  23. #include <diamond.h>
  24. //Note: The use of statics means that this code is not thread safe. It also means that
  25. //this code can only perform 1 decompression at a time. I think that I may need to
  26. //rewrite this to be callable from multiple places as it may end up that CDM and
  27. //Active Setup both need to access this class at the same time.
  28. CHInfoArray CDiamond::s_handles;
  29. byte_buffer* CDiamond::s_pbufIn = NULL;
  30. byte_buffer* CDiamond::s_pbufOut = NULL;
  31. CDiamond::CDiamond(
  32. void
  33. ) :
  34. m_hfdi(0)
  35. {
  36. ZeroMemory(&m_erf, sizeof(ERF));
  37. m_hfdi = FDICreate(DEXMemAlloc, DEXMemFree, DEXFileOpen, DEXFileRead, DEXFileWrite, DEXFileClose, DEXFileSeek, cpu80386, &m_erf);
  38. }
  39. CDiamond::~CDiamond(
  40. void
  41. ) {
  42. if (NULL != m_hfdi)
  43. FDIDestroy(m_hfdi);
  44. }
  45. bool CDiamond::IsValidCAB
  46. (
  47. IN byte_buffer& bufIn // Mem buffer in
  48. ) {
  49. //LOG_block("CDiamond::IsValidCAB");
  50. s_pbufIn = &bufIn;
  51. int hf = DEXFileOpen("?", _O_RDWR, 0);
  52. if ((INT_PTR)INVALID_HANDLE_VALUE == hf)
  53. return FALSE;
  54. FDICABINETINFO fdici;
  55. bool bRc = TRUE == FDIIsCabinet(m_hfdi, hf, &fdici);
  56. DEXFileClose(hf);
  57. return bRc;
  58. }
  59. bool CDiamond::IsValidCAB(
  60. IN LPCTSTR szCabPath
  61. ) {
  62. //LOG_block("CDiamond::IsValidCAB");
  63. USES_CONVERSION;
  64. int hf = DEXFileOpen(T2A(const_cast<TCHAR*>(szCabPath)), _O_RDWR, 0);
  65. if ((INT_PTR)INVALID_HANDLE_VALUE == hf)
  66. return FALSE;
  67. FDICABINETINFO fdici;
  68. bool bRc = TRUE == FDIIsCabinet(m_hfdi, hf, &fdici);
  69. DEXFileClose(hf);
  70. return bRc;
  71. }
  72. bool CDiamond::Decompress(
  73. IN LPCTSTR szFileIn, // Full path to input cab file.
  74. IN LPCTSTR szFileOut
  75. ) {
  76. SetInput(szFileIn);
  77. SetOutput(szFileOut);
  78. return DoDecompress();
  79. }
  80. bool CDiamond::Decompress(
  81. IN LPCTSTR szFileIn, // Full path to input cab file.
  82. IN byte_buffer& bufOut // Mem buffer out
  83. ) {
  84. SetInput(szFileIn);
  85. SetOutput(bufOut);
  86. return DoDecompress();
  87. }
  88. bool CDiamond::Decompress(
  89. IN byte_buffer& bufIn, // Mem buffer in
  90. IN LPCTSTR szFileOut
  91. ) {
  92. SetInput(bufIn);
  93. SetOutput(szFileOut);
  94. return DoDecompress();
  95. }
  96. bool CDiamond::Decompress(
  97. IN byte_buffer& bufIn, // Mem buffer in
  98. IN byte_buffer& bufOut // Mem buffer out
  99. ) {
  100. SetInput(bufIn);
  101. SetOutput(bufOut);
  102. return DoDecompress();
  103. }
  104. bool CDiamond::DoDecompress(
  105. void
  106. ) {
  107. //LOG_block("CDiamond::DoDecompress");
  108. USES_CONVERSION;
  109. const static TCHAR szQuestion[] = _T("?");
  110. TCHAR szCabinet[MAX_PATH] = {0};
  111. TCHAR szCabPath[MAX_PATH] = {0};
  112. if (NULL != m_szFileIn)
  113. {
  114. lstrcpy(szCabinet, PathFindFileName(m_szFileIn));
  115. lstrcpy(szCabPath, m_szFileIn);
  116. PathRemoveFileSpec(szCabPath);
  117. PathAddBackslash(szCabPath);
  118. }
  119. else
  120. {
  121. lstrcpy(szCabinet, szQuestion);
  122. }
  123. if (NULL == m_szFileOut)
  124. m_szFileOut = szQuestion;
  125. //LOG_out("FDICopy(szCabinet= %s, szCabPath = %s)", szCabinet, szCabPath);
  126. return TRUE == FDICopy(m_hfdi, T2A(szCabinet), T2A(szCabPath), 0, Notification, NULL, this);
  127. }
  128. void *DIAMONDAPI CDiamond::DEXMemAlloc(
  129. ULONG cb
  130. ) {
  131. return malloc(cb);
  132. }
  133. void DIAMONDAPI CDiamond::DEXMemFree(
  134. void HUGE *pv
  135. ) {
  136. free(pv);
  137. }
  138. BOOL CreatePath(LPCTSTR pszPath)
  139. {
  140. if (CreateDirectory(pszPath, NULL) || GetLastError() == ERROR_ALREADY_EXISTS)
  141. return TRUE;
  142. TCHAR* pcLastSlash = _tcsrchr(pszPath, _T('\\'));
  143. if (NULL == pcLastSlash)
  144. return FALSE;
  145. *pcLastSlash = 0;
  146. if (!CreatePath(pszPath))
  147. return FALSE;
  148. *pcLastSlash = _T('\\');
  149. return CreateDirectory(pszPath, NULL);
  150. }
  151. INT_PTR DIAMONDAPI CDiamond::DEXFileOpen(
  152. char *pszFile,
  153. int oflag,
  154. int pmode
  155. ) {
  156. USES_CONVERSION;
  157. HANDLEINFO hinfo;
  158. ZeroMemory(&hinfo, sizeof(HANDLEINFO));
  159. //if the file name begins with an invalid ? character then we have
  160. //an in memory operation.
  161. hinfo.offset = 0L; //Set memory file pointer to beginning of file
  162. hinfo.handle = INVALID_HANDLE_VALUE; // It will stay that way if it's in memory operation
  163. if ('?' != pszFile[0]) // if not in memory op
  164. {
  165. if (oflag & _O_CREAT)
  166. {
  167. // file to be opened for write.
  168. // Make sure that path exists
  169. TCHAR szPath[MAX_PATH];
  170. lstrcpy(szPath, A2T(pszFile));
  171. PathRemoveFileSpec(szPath);
  172. CreatePath(szPath);
  173. hinfo.handle = CreateFile(A2T(pszFile), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
  174. }
  175. else
  176. {
  177. //file to be opened for reading.
  178. hinfo.handle = CreateFile(A2T(pszFile), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  179. }
  180. if (hinfo.handle == INVALID_HANDLE_VALUE)
  181. return (INT_PTR)INVALID_HANDLE_VALUE;
  182. }
  183. return s_handles.add(hinfo) + 1;
  184. }
  185. UINT DIAMONDAPI CDiamond::DEXFileRead(
  186. INT_PTR hf,
  187. void *pv,
  188. UINT cb
  189. ) {
  190. //LOG_block("CDiamond::DEXFileRead");
  191. HANDLEINFO& rhinfo = s_handles[hf-1];
  192. ULONG cnLength = -1;
  193. //if this is a file read operation use normal 32 bit I/O
  194. if (rhinfo.handle == INVALID_HANDLE_VALUE)
  195. {
  196. // we have an in memory operation and need to copy the requested data.
  197. //Note: while we would like to avoid even this memory copy we can't since
  198. //the diamond libary is allocating an internal read buffer.
  199. byte_buffer& rbuf = *s_pbufIn;
  200. if (rhinfo.offset + cb < rbuf.size())
  201. cnLength = cb;
  202. else
  203. cnLength = rbuf.size() - rhinfo.offset;
  204. if ((int)cnLength > 0)
  205. {
  206. memcpy(pv, (LPBYTE)rbuf + rhinfo.offset, cnLength);
  207. rhinfo.offset += cnLength;
  208. }
  209. else
  210. {
  211. cnLength = 0;
  212. }
  213. }
  214. else
  215. {
  216. // this is a file read operation use normal 32 bit I/O
  217. (void)ReadFile(rhinfo.handle, pv, cb, &cnLength, NULL);
  218. //if( !ReadFile(rhinfo.handle, pv, cb, &cnLength, NULL))
  219. // LOG_error("ReadFile - GetLastError() = %d", ::GetLastError());
  220. }
  221. return cnLength;
  222. }
  223. UINT DIAMONDAPI CDiamond::DEXFileWrite(
  224. INT_PTR hf,
  225. void *pv,
  226. UINT cb
  227. ) {
  228. //LOG_block("CDiamond::DEXFileWrite");
  229. HANDLEINFO& rhinfo = s_handles[hf-1];
  230. ULONG cnLength = -1;
  231. if (rhinfo.handle == INVALID_HANDLE_VALUE)
  232. {
  233. //Since we can dynamically increase the output buffer array and also
  234. //access it in the normal C++ way though a pointer writes are very easy
  235. //we simply need to make sure that there is sufficient space in the
  236. //output buffer, get a pointer to the current file offset and memcpy
  237. //the new data into the file buffer.
  238. byte_buffer& rbuf = *s_pbufOut;
  239. if (rbuf.size() < rhinfo.offset + cb)
  240. {
  241. rbuf.resize(rhinfo.offset + cb);
  242. if (!rbuf.valid())
  243. return 0;
  244. }
  245. memcpy((LPBYTE)rbuf + rhinfo.offset, pv, cb);
  246. rhinfo.offset += cb;
  247. cnLength = cb;
  248. }
  249. else
  250. {
  251. // this is a file write operation use normal 32 bit I/O
  252. (void)WriteFile(rhinfo.handle, pv, cb, &cnLength, NULL);
  253. //if( !WriteFile(rhinfo.handle, pv, cb, &cnLength, NULL))
  254. //LOG_error("WriteFile - GetLastError() = %d", ::GetLastError());
  255. }
  256. return cnLength;
  257. }
  258. long DIAMONDAPI CDiamond::DEXFileSeek(
  259. INT_PTR hf,
  260. long dist,
  261. int seektype
  262. ) {
  263. HANDLEINFO& rhinfo = s_handles[hf-1];
  264. //Since we are using 32 bit file io we need to remap the seek method
  265. DWORD dwMoveMethod;
  266. switch (seektype)
  267. {
  268. case SEEK_CUR:
  269. dwMoveMethod = FILE_CURRENT;
  270. break;
  271. case SEEK_END:
  272. dwMoveMethod = FILE_END;
  273. break;
  274. case SEEK_SET:
  275. default:
  276. dwMoveMethod = FILE_BEGIN;
  277. break;
  278. }
  279. //if this is a file read operation use normal 32 bit I/O
  280. if (rhinfo.handle != INVALID_HANDLE_VALUE)
  281. return SetFilePointer(rhinfo.handle, dist, NULL, dwMoveMethod);
  282. //else we need to interpret the seek based on the type
  283. switch (dwMoveMethod)
  284. {
  285. case FILE_CURRENT:
  286. rhinfo.offset += dist;
  287. break;
  288. case FILE_END:
  289. rhinfo.offset -= dist;
  290. break;
  291. case FILE_BEGIN:
  292. default:
  293. rhinfo.offset = dist;
  294. break;
  295. }
  296. return rhinfo.offset;
  297. }
  298. int DIAMONDAPI CDiamond::DEXFileClose(
  299. INT_PTR hf
  300. ) {
  301. HANDLEINFO& rhinfo = s_handles[hf-1];
  302. //if this is a file operation close the file handle and make the
  303. //internal handle structure available for use.
  304. if (rhinfo.handle != INVALID_HANDLE_VALUE)
  305. {
  306. CloseHandle(rhinfo.handle);
  307. }
  308. //If this is a write buffer then we exit and let the Decompress
  309. //function take care of allocating and copying the data back
  310. //to the caller if necessary.
  311. s_handles.remove(hf-1);
  312. return 0;
  313. }
  314. INT_PTR __cdecl CDiamond::Notification(
  315. FDINOTIFICATIONTYPE fdiNotifType,
  316. PFDINOTIFICATION pfdin
  317. ) {
  318. USES_CONVERSION;
  319. switch (fdiNotifType)
  320. {
  321. case fdintCABINET_INFO: // general information about the cabinet
  322. return 0;
  323. case fdintNEXT_CABINET: // file continued to next cabinet
  324. case fdintPARTIAL_FILE: // first file in cabinet is continuation
  325. return 0;
  326. case fdintCOPY_FILE: // file to be copied, returns 0 = skip, -1 = abort, else file handle
  327. case fdintCLOSE_FILE_INFO:
  328. break;
  329. default:
  330. return 0;
  331. }
  332. CDiamond *pDiamond = (CDiamond *)pfdin->pv;
  333. // prepare output file name
  334. TCHAR szFileOut[MAX_PATH];
  335. if (pDiamond->m_szFileOut[0] == _T('*'))
  336. {
  337. //Special case where the caller has asked for all files in the cab to
  338. //be expanded. In this case we need to construct an output file name
  339. //for this imput file.
  340. lstrcpy(szFileOut, pDiamond->m_szFileIn);
  341. PathRemoveFileSpec(szFileOut);
  342. PathAppend(szFileOut, A2T(pfdin->psz1));
  343. }
  344. else if (StrChr(pDiamond->m_szFileOut, _T('*')))
  345. {
  346. lstrcpy(szFileOut, pDiamond->m_szFileOut);
  347. PathRemoveFileSpec(szFileOut);
  348. PathAppend(szFileOut, A2T(pfdin->psz1));
  349. }
  350. else
  351. {
  352. lstrcpy(szFileOut, pDiamond->m_szFileOut);
  353. }
  354. // two cases we want to do
  355. if (fdintCOPY_FILE == fdiNotifType)
  356. {
  357. return pDiamond->DEXFileOpen(T2A(szFileOut), _O_CREAT | _O_BINARY | _O_TRUNC | _O_RDWR, _S_IREAD | _S_IWRITE);
  358. }
  359. else // fdintCLOSE_FILE_INFO == fdiNotifType
  360. {
  361. pDiamond->DEXFileClose(pfdin->hf);
  362. if( '?' != pfdin->psz1[0])
  363. {
  364. auto_hfile hFile = CreateFile(
  365. szFileOut,
  366. GENERIC_READ | GENERIC_WRITE,
  367. FILE_SHARE_READ,
  368. NULL,
  369. OPEN_EXISTING,
  370. FILE_ATTRIBUTE_NORMAL,
  371. NULL
  372. );
  373. if (hFile.valid())
  374. {
  375. FILETIME ftLocal;
  376. FILETIME ftUTC;
  377. SetFileAttributes(szFileOut, FILE_ATTRIBUTE_NORMAL);
  378. if (DosDateTimeToFileTime(pfdin->date, pfdin->time, &ftLocal) &&
  379. LocalFileTimeToFileTime(&ftLocal, &ftUTC))
  380. {
  381. SetFileTime(hFile, NULL, NULL, &ftUTC);
  382. }
  383. }
  384. }
  385. return 1;
  386. }
  387. }