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.

466 lines
14 KiB

  1. /*++
  2. Copyright (C) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. MRCICLASS.CPP
  5. Abstract:
  6. Implements the Wrapper class for MRCI 1 & MRCI 2 maxcompress
  7. and decompress functions
  8. History:
  9. paulall 1-Jul-97 Created
  10. --*/
  11. #include "precomp.h"
  12. #include <io.h>
  13. #include <stdio.h>
  14. #include <fcntl.h>
  15. #include <sys\stat.h>
  16. #include "MRCIclass.h"
  17. #include <TCHAR.H>
  18. class CMRCICompressionHeaderV1
  19. {
  20. public:
  21. char cVersion; //Compression file format
  22. char compressionLevel; //Is this a level 1 or level 2 compression
  23. DWORD dwReadBufferSize; //Buffer size used to read original file
  24. FILETIME ftCreateTime; //Time and date file created
  25. __int64 dwOriginalSize; //Original file length
  26. // ... for each buffer
  27. // CMRCICompressionBlockV1 block;
  28. // ... until dwNextBufferSize is 0
  29. };
  30. class CMRCICompressionBlockV1
  31. {
  32. public:
  33. char bCompressed; //Was this block compressed
  34. DWORD dwNextBufferSize; //Size of the proceeding buffer
  35. DWORD dwUncompressedBufferSize; //Size needed for uncompress buffer
  36. //char[dwNextBufferSize]; //next block is the compression part
  37. };
  38. CMRCICompression::CMRCICompression()
  39. {
  40. }
  41. CMRCICompression::~CMRCICompression()
  42. {
  43. }
  44. BOOL CMRCICompression::GetCompressedFileInfo(const TCHAR *pchFile,
  45. CompressionLevel &compressionLevel,
  46. DWORD &dwReadBufferSize,
  47. FILETIME &ftCreateTime,
  48. __int64 &dwOriginalSize)
  49. {
  50. BOOL bStatus = FALSE;
  51. int hFile = _topen(pchFile,_O_BINARY | _O_RDONLY, 0);
  52. if (hFile != -1)
  53. {
  54. CMRCICompressionHeaderV1 header;
  55. if (_read(hFile, &header, sizeof(CMRCICompressionHeaderV1)) ==
  56. sizeof(CMRCICompressionHeaderV1))
  57. {
  58. compressionLevel = (CompressionLevel)header.cVersion;
  59. dwReadBufferSize = header.dwReadBufferSize;
  60. ftCreateTime = header.ftCreateTime;
  61. dwOriginalSize = header.dwOriginalSize;
  62. //If the version is 0xFF, the file is not valid!
  63. if (header.cVersion != 0xFF)
  64. bStatus = TRUE;
  65. }
  66. _close(hFile);
  67. }
  68. return bStatus;
  69. }
  70. BOOL CMRCICompression::CompressFile(const TCHAR *pchFileFrom,
  71. const TCHAR *pchFileTo,
  72. DWORD dwBufferSize,
  73. CompressionLevel compressionLevel,
  74. CMRCIControl *pControlObject)
  75. {
  76. BOOL bStatus = FALSE;
  77. int fileFrom;
  78. int fileTo;
  79. //Open the files for processing
  80. //=============================
  81. fileFrom = _topen(pchFileFrom,_O_BINARY | _O_RDONLY, 0);
  82. fileTo = _topen(pchFileTo, _O_BINARY | _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
  83. //If open sucessful
  84. //=================
  85. if ((fileFrom != -1) && (fileTo != -1))
  86. {
  87. //DO the compression using the latest and greatest version
  88. //========================================================
  89. bStatus = CompressFileV1(fileFrom, fileTo, dwBufferSize, compressionLevel, pControlObject);
  90. }
  91. //Close the files
  92. //===============
  93. if (fileFrom != -1)
  94. _close(fileFrom);
  95. if (fileTo != -1)
  96. _close(fileTo);
  97. if (pControlObject && pControlObject->AbortRequested())
  98. {
  99. //User requested an abort, so we need to delete the compressed file...
  100. _tunlink(pchFileTo);
  101. bStatus = FALSE;
  102. }
  103. return bStatus;
  104. }
  105. BOOL CMRCICompression::CompressFileV1(int hFileFrom,
  106. int hFileTo,
  107. DWORD dwBufferSize,
  108. CompressionLevel compressionLevel,
  109. CMRCIControl *pControlObject)
  110. {
  111. BOOL bStatus = FALSE;
  112. unsigned char *pBufferFrom = new unsigned char[dwBufferSize + 4];
  113. unsigned char *pBufferTo = new unsigned char[dwBufferSize + 4];
  114. if (pBufferFrom && pBufferTo)
  115. {
  116. //Write the header to the new file
  117. //================================
  118. CMRCICompressionHeaderV1 header;
  119. header.cVersion = char(0xFF); //INVALID. We write the header back when we have
  120. //finished! When we read this, we check to see
  121. //if this is invalid. We do not uncompress if it is
  122. //this value....
  123. header.compressionLevel = compressionLevel;
  124. header.dwReadBufferSize = dwBufferSize;
  125. SYSTEMTIME sysTime;
  126. GetSystemTime(&sysTime);
  127. SystemTimeToFileTime(&sysTime, &header.ftCreateTime);
  128. header.dwOriginalSize = _filelengthi64(hFileFrom);
  129. if (_write(hFileTo, &header, sizeof(CMRCICompressionHeaderV1)) != sizeof(CMRCICompressionHeaderV1))
  130. {
  131. delete [] pBufferFrom;
  132. delete [] pBufferTo;
  133. bStatus = FALSE;
  134. return bStatus;
  135. }
  136. __int64 remainingFileSize = header.dwOriginalSize;
  137. unsigned cbChunk;
  138. unsigned cbCompressed;
  139. bStatus = TRUE;
  140. //While we have some file to write...
  141. //===================================
  142. while (remainingFileSize)
  143. {
  144. //See if we need to abort the compression...
  145. if (pControlObject && pControlObject->AbortRequested())
  146. {
  147. break;
  148. }
  149. //Calculate the size of this buffer to compress
  150. //=============================================
  151. if (remainingFileSize > dwBufferSize)
  152. {
  153. cbChunk = dwBufferSize;
  154. }
  155. else
  156. {
  157. cbChunk = (unsigned) remainingFileSize;
  158. }
  159. //Read from the source file
  160. //=========================
  161. if (_read(hFileFrom, pBufferFrom, cbChunk) != (int) cbChunk)
  162. {
  163. bStatus = FALSE;
  164. break;
  165. }
  166. //Calculate what is left to read
  167. //==============================
  168. remainingFileSize -= cbChunk;
  169. //Compress the buffer
  170. //===================
  171. cbCompressed = CompressBuffer(pBufferFrom, cbChunk, pBufferTo, dwBufferSize, compressionLevel);
  172. //Create the compression block header
  173. CMRCICompressionBlockV1 block;
  174. unsigned char *pWriteBuffer;
  175. unsigned thisBufferSize;
  176. if ((cbCompressed == (unsigned) -1) || (cbCompressed >= cbChunk))
  177. {
  178. //This means compression failed or there was no compression...
  179. block.bCompressed = FALSE;
  180. pWriteBuffer = pBufferFrom;
  181. thisBufferSize = cbChunk;
  182. }
  183. else
  184. {
  185. block.bCompressed = TRUE;
  186. pWriteBuffer = pBufferTo;
  187. thisBufferSize = cbCompressed;
  188. }
  189. block.dwNextBufferSize = thisBufferSize;
  190. block.dwUncompressedBufferSize = cbChunk;
  191. //Write the block header
  192. //======================
  193. if (_write(hFileTo, &block, sizeof(CMRCICompressionBlockV1)) != sizeof(CMRCICompressionBlockV1))
  194. {
  195. bStatus = FALSE;
  196. break;
  197. }
  198. //Write the compressed block
  199. //==========================
  200. if (_write(hFileTo, pWriteBuffer, thisBufferSize) != (int)thisBufferSize)
  201. {
  202. bStatus = FALSE;
  203. break;
  204. }
  205. }
  206. if (pControlObject && pControlObject->AbortRequested())
  207. {
  208. //User requested an abort...
  209. }
  210. else
  211. {
  212. //Write final block header with zero length buffer marker
  213. CMRCICompressionBlockV1 block;
  214. block.dwNextBufferSize = 0;
  215. block.bCompressed = FALSE;
  216. if (_write(hFileTo, &block, sizeof(CMRCICompressionBlockV1)) != -1 &&
  217. _lseek(hFileTo, 0, SEEK_SET) != -1)
  218. {
  219. //Write a valid block header to the start with a correct version number
  220. header.cVersion = 1; //Set this to the correct version
  221. bStatus =
  222. _write(hFileTo, &header, sizeof(CMRCICompressionHeaderV1)) != -1;
  223. }
  224. else
  225. bStatus = FALSE;
  226. }
  227. }
  228. //Tidy up
  229. delete [] pBufferFrom;
  230. delete [] pBufferTo;
  231. return bStatus;
  232. }
  233. unsigned CMRCICompression::CompressBuffer(unsigned char *pFromBuffer,
  234. DWORD dwFromBufferSize,
  235. unsigned char *pToBuffer,
  236. DWORD dwToBufferSize,
  237. CompressionLevel compressionLevel)
  238. {
  239. unsigned cbCompressed;
  240. if (compressionLevel == level1)
  241. {
  242. cbCompressed = Mrci1MaxCompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize);
  243. }
  244. else
  245. {
  246. cbCompressed = Mrci2MaxCompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize);
  247. }
  248. return cbCompressed;
  249. }
  250. BOOL CMRCICompression::UncompressFile(const TCHAR *pchFromFile, const TCHAR *pchToFile)
  251. {
  252. BOOL bStatus = FALSE;
  253. int fileFrom;
  254. int fileTo;
  255. //Open the files
  256. //==============
  257. fileFrom = _topen(pchFromFile,_O_BINARY | _O_RDONLY, 0);
  258. fileTo = _topen(pchToFile, _O_BINARY | _O_TRUNC | _O_CREAT | _O_WRONLY, _S_IREAD | _S_IWRITE);
  259. if ((fileFrom != -1) && (fileTo != -1))
  260. {
  261. //Read the version...
  262. //===================
  263. char cVer;
  264. if (_read(fileFrom, &cVer, sizeof(char)) == sizeof(char))
  265. {
  266. //Reset the file position to the start
  267. //====================================
  268. if (_lseek(fileFrom, 0, SEEK_SET) != -1)
  269. {
  270. //Call the uncompress with the equivelant method which created
  271. //the compression
  272. //============================================================
  273. switch(cVer)
  274. {
  275. case 1:
  276. bStatus = UncompressFileV1(fileFrom, fileTo);
  277. break;
  278. case 0xFF:
  279. //INVALID FILE!
  280. default:
  281. //Unsupported version
  282. break;
  283. }
  284. }
  285. }
  286. }
  287. //CLose the files
  288. //===============
  289. if (fileFrom != -1)
  290. _close(fileFrom);
  291. if (fileTo != -1)
  292. _close(fileTo);
  293. return bStatus;
  294. }
  295. BOOL CMRCICompression::UncompressFileV1(int hFileFrom, int hFileTo)
  296. {
  297. BOOL bStatus = FALSE;
  298. unsigned char *pBufferFrom = NULL;
  299. unsigned char *pBufferTo = NULL;
  300. //Read the header
  301. //===============
  302. CMRCICompressionHeaderV1 header;
  303. if (_read(hFileFrom, &header, sizeof(CMRCICompressionHeaderV1)) !=
  304. sizeof(CMRCICompressionHeaderV1))
  305. return FALSE;
  306. //Allocate buffers. The read buffer is never buffer than the write buffer
  307. //cos if it would have been we saved the uncompressed version!
  308. pBufferFrom = new unsigned char[header.dwReadBufferSize + 4];
  309. if (pBufferFrom == 0)
  310. return FALSE;
  311. pBufferTo = new unsigned char[header.dwReadBufferSize + 4];
  312. if (pBufferTo == 0)
  313. {
  314. delete [] pBufferFrom;
  315. return FALSE;
  316. }
  317. bStatus = TRUE;
  318. while (1)
  319. {
  320. //Read the block header
  321. //=====================
  322. CMRCICompressionBlockV1 block;
  323. if (_read(hFileFrom, &block, sizeof(CMRCICompressionBlockV1)) !=
  324. sizeof(CMRCICompressionBlockV1))
  325. {
  326. bStatus = FALSE;
  327. break;
  328. }
  329. if (block.dwNextBufferSize == 0)
  330. {
  331. bStatus = TRUE;
  332. break;
  333. }
  334. //Read the block data
  335. //===================
  336. if (_read(hFileFrom, pBufferFrom, block.dwNextBufferSize) != (int)block.dwNextBufferSize)
  337. {
  338. bStatus = FALSE;
  339. break;
  340. }
  341. unsigned char *pWriteBuffer;
  342. unsigned cbChunk, cbUncompressed;
  343. //If this block was compressed
  344. //============================
  345. if (block.bCompressed)
  346. {
  347. //Uncompress the block
  348. //====================
  349. if ((cbUncompressed = UncompressBuffer(pBufferFrom, block.dwNextBufferSize, pBufferTo, block.dwUncompressedBufferSize, (CompressionLevel)header.compressionLevel)) == (unsigned) -1)
  350. {
  351. bStatus = FALSE;
  352. break;
  353. }
  354. pWriteBuffer = pBufferTo;
  355. cbChunk = cbUncompressed;
  356. }
  357. else
  358. {
  359. //Otherwise we use the existing block
  360. pWriteBuffer = pBufferFrom;
  361. cbChunk = block.dwNextBufferSize;
  362. }
  363. //Write the file data
  364. _write(hFileTo, pWriteBuffer, cbChunk);
  365. }
  366. //Sanity check the file. It should be the same size as the original
  367. //compressed file
  368. if (_filelengthi64(hFileTo) != header.dwOriginalSize)
  369. {
  370. bStatus = FALSE;
  371. }
  372. //Tidy up
  373. delete [] pBufferFrom;
  374. delete [] pBufferTo;
  375. return bStatus;
  376. }
  377. unsigned CMRCICompression::UncompressBuffer(unsigned char *pFromBuffer,
  378. DWORD dwFromBufferSize,
  379. unsigned char *pToBuffer,
  380. DWORD dwToBufferSize,
  381. CompressionLevel compressionLevel)
  382. {
  383. unsigned cbCompressed;
  384. if (compressionLevel == level1)
  385. {
  386. cbCompressed = Mrci1Decompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize);
  387. }
  388. else
  389. {
  390. cbCompressed = Mrci2Decompress(pFromBuffer, dwFromBufferSize, pToBuffer, dwToBufferSize);
  391. }
  392. return cbCompressed;
  393. }