Leaked source code of windows server 2003
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.

940 lines
29 KiB

  1. /*
  2. ** lzcomp.c - Routines used in Lempel-Ziv compression (a la 1977 article).
  3. **
  4. ** Author: DavidDi
  5. */
  6. // Headers
  7. ///////////
  8. #include "pch.h"
  9. #include "compress.h"
  10. #include "resource.h"
  11. #ifndef LZA_DLL
  12. #include <dos.h>
  13. #include <errno.h>
  14. #include <io.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #endif
  18. /*
  19. ** N.b., one reason DOS file handles are used for file references in this
  20. ** module is that using FILE *'s for file references poses a problem.
  21. ** fclose()'ing a file which was fopen()'ed in write "w" or append "a" mode
  22. ** stamps the file with the current date. This undoes the intended effect of
  23. ** CopyDateTimeStamp(). We could also get around this fclose() problem by
  24. ** first fclose()'ing the file, and then fopen()'ing it again in read "r"
  25. ** mode.
  26. **
  27. ** Using file handles also allows us to bypass stream buffering, so reads and
  28. ** writes may be done with whatever buffer size we choose. Also, the
  29. ** lower-level DOS file handle functions are faster than their stream
  30. ** counterparts.
  31. */
  32. INT Compress(
  33. NOTIFYPROC pfnNotify,
  34. LPWSTR pszSource,
  35. LPWSTR pszDest,
  36. BYTE byteAlgorithm,
  37. BOOL bDoRename,
  38. PLZINFO pLZI)
  39. /*++
  40. Compress one file to another.
  41. Arguments: pszSource - name of file to compress
  42. pszDest - name of compressed output file
  43. byteAlgorithm - compression algorithm to use
  44. byteExtensionChar - compressed file name extension character
  45. Returns: int - TRUE if compression finished successfully. One of the
  46. LZERROR_ codes if not.
  47. Globals: none
  48. */
  49. {
  50. HANDLE doshSource = NULL; // input file handle
  51. HANDLE doshDest = NULL; // output file handle
  52. INT nRetVal = TRUE;
  53. WCHAR szBuffer[MAX_PATH] = NULL_STRING;
  54. WCHAR szDestFileName[MAX_PATH] = NULL_STRING;
  55. WCHAR byteExtensionChar;
  56. FH FHOut; // compressed header info struct
  57. // Sanity check
  58. if (!pLZI) {
  59. return(FALSE);
  60. }
  61. // Set up input file handle. Set cblInSize to length of input file.
  62. if ((nRetVal = GetIOHandle(pszSource, READ_IT, &doshSource, &pLZI->cblInSize)) != TRUE)
  63. {
  64. DISPLAY_MESSAGE1( stderr, szBuffer, GetResString(IDS_FILE_NOT_FOUND), _X(pszSource) );
  65. return(nRetVal);
  66. }
  67. // Rewind input file.
  68. if( 0 != SetFilePointer(doshSource, 0L, NULL, FILE_BEGIN) )
  69. {
  70. CloseHandle(doshSource);
  71. return(FALSE);
  72. }
  73. // Create destination file name.
  74. STRCPY(szDestFileName, pszDest);
  75. if (bDoRename == TRUE)
  76. // Rename output file.
  77. byteExtensionChar = MakeCompressedNameW(szDestFileName);
  78. else
  79. byteExtensionChar = '\0';
  80. // Ask if we should compress this file.
  81. if (! (*pfnNotify)(pszSource, szDestFileName, NOTIFY_START_COMPRESS))
  82. {
  83. // Don't compress file. This error condition should be handled in
  84. // pfnNotify, so indicate that it is not necessary for the caller to
  85. // display an error message.
  86. CloseHandle( doshSource );
  87. return(FALSE);
  88. }
  89. // Setup output file handle.
  90. if ((nRetVal = GetIOHandle(szDestFileName, WRITE_IT, &doshDest, &pLZI->cblInSize)) != TRUE)
  91. {
  92. DISPLAY_MESSAGE1( stderr, szBuffer, GetResString(IDS_FILE_NOT_FOUND), pszSource );
  93. CloseHandle(doshSource);
  94. return(nRetVal);
  95. }
  96. // Fill in compressed file header.
  97. MakeHeader(& FHOut, byteAlgorithm, byteExtensionChar, pLZI);
  98. // Write compressed file header to output file.
  99. if ((nRetVal = WriteHdr(& FHOut, doshDest, pLZI)) != TRUE)
  100. {
  101. CloseHandle( doshSource );
  102. CloseHandle(doshDest);
  103. DISPLAY_MESSAGE( stderr, GetResString( IDS_FAILED_WRITE_HDR ) );
  104. return( FALSE );
  105. }
  106. // Compress input file into output file.
  107. switch (byteAlgorithm)
  108. {
  109. case ALG_FIRST:
  110. case ALG_LZ:
  111. nRetVal = LZEncode(doshSource, doshDest, pLZI);
  112. break;
  113. default:
  114. nRetVal = FALSE;
  115. break;
  116. }
  117. if (nRetVal != TRUE)
  118. {
  119. CloseHandle(doshSource);
  120. return(FALSE);
  121. }
  122. // Copy date and time stamp from source file to destination file.
  123. nRetVal = CopyDateTimeStamp(doshSource, doshDest);
  124. // Close files.
  125. CloseHandle(doshSource);
  126. CloseHandle(doshDest);
  127. return(nRetVal);
  128. }
  129. INT LZEncode(HANDLE doshSource, HANDLE doshDest, PLZINFO pLZI)
  130. /*
  131. ** int LZEncode(int doshSource, int doshDest);
  132. **
  133. ** Compress input file into output file.
  134. **
  135. ** Arguments: doshSource - open DOS file handle of input file
  136. ** doshDest - open DOS file handle of output file
  137. **
  138. ** Returns: int - TRUE if compression was successful. One of the LZERROR_
  139. ** codes if the compression failed.
  140. **
  141. ** Globals:
  142. */
  143. {
  144. INT i, len, f,
  145. iCurChar, // current ring buffer position
  146. iCurString, // start of current string in ring buffer
  147. iCodeBuf, // index of next open buffer position
  148. cbLastMatch; // length of last match
  149. BYTE byte, // temporary storage for next byte to write
  150. byteMask, // bit mask (and counter) for eight code units
  151. codeBuf[1 + 8 * MAX_LITERAL_LEN]; // temporary storage for encoded data
  152. #if 0
  153. pLZI->cbMaxMatchLen = LZ_MAX_MATCH_LEN;
  154. #else
  155. pLZI->cbMaxMatchLen = FIRST_MAX_MATCH_LEN;
  156. #endif
  157. ResetBuffers();
  158. pLZI->cblOutSize += HEADER_LEN;
  159. // Initialize encoding trees.
  160. if (!LZInitTree(pLZI)) {
  161. return( LZERROR_GLOBALLOC );
  162. }
  163. // CodeBuf[1..16] saves eight units of code, and CodeBuf[0] works as eight
  164. // flags. '1' representing that the unit is an unencoded letter (1 byte),
  165. // '0' a position-and-length pair (2 bytes). Thus, eight units require at
  166. // most 16 bytes of code, plus the one byte of flags.
  167. codeBuf[0] = (BYTE)0;
  168. byteMask = (BYTE)1;
  169. iCodeBuf = 1;
  170. iCurString = 0;
  171. iCurChar = RING_BUF_LEN - pLZI->cbMaxMatchLen;
  172. for (i = 0; i < RING_BUF_LEN - pLZI->cbMaxMatchLen; i++)
  173. pLZI->rgbyteRingBuf[i] = BUF_CLEAR_BYTE;
  174. // Read bytes into the last cbMaxMatchLen bytes of the buffer.
  175. for (len = 0; len < pLZI->cbMaxMatchLen && ((f = ReadByte(byte)) != END_OF_INPUT);
  176. len++)
  177. {
  178. if (f != TRUE) {
  179. return( f );
  180. }
  181. pLZI->rgbyteRingBuf[iCurChar + len] = byte;
  182. }
  183. // Insert the cbMaxMatchLen strings, each of which begins with one or more
  184. // 'space' characters. Note the order in which these strings are inserted.
  185. // This way, degenerate trees will be less likely to occur.
  186. for (i = 1; i <= pLZI->cbMaxMatchLen; i++)
  187. LZInsertNode(iCurChar - i, FALSE, pLZI);
  188. // Finally, insert the whole string just read. The global variables
  189. // cbCurMatch and iCurMatch are set.
  190. LZInsertNode(iCurChar, FALSE, pLZI);
  191. do // while (len > 0)
  192. {
  193. // cbCurMatch may be spuriously long near the end of text.
  194. if (pLZI->cbCurMatch > len)
  195. pLZI->cbCurMatch = len;
  196. if (pLZI->cbCurMatch <= MAX_LITERAL_LEN)
  197. {
  198. // This match isn't long enough to encode, so copy it directly.
  199. pLZI->cbCurMatch = 1;
  200. // Set 'one uncoded byte' bit flag.
  201. codeBuf[0] |= byteMask;
  202. // Write literal byte.
  203. codeBuf[iCodeBuf++] = pLZI->rgbyteRingBuf[iCurChar];
  204. }
  205. else
  206. {
  207. // This match is long enough to encode. Send its position and
  208. // length pair. N.b., pLZI->cbCurMatch > MAX_LITERAL_LEN.
  209. codeBuf[iCodeBuf++] = (BYTE)pLZI->iCurMatch;
  210. codeBuf[iCodeBuf++] = (BYTE)((pLZI->iCurMatch >> 4 & 0xf0) |
  211. (pLZI->cbCurMatch - (MAX_LITERAL_LEN + 1)));
  212. }
  213. // Shift mask left one bit.
  214. if ((byteMask <<= 1) == (BYTE)0)
  215. {
  216. // Send at most 8 units of code together.
  217. for (i = 0; i < iCodeBuf; i++)
  218. if ((f = WriteByte(codeBuf[i])) != TRUE) {
  219. return( f );
  220. }
  221. // Reset flags and mask.
  222. codeBuf[0] = (BYTE)0;
  223. byteMask = (BYTE)1;
  224. iCodeBuf = 1;
  225. }
  226. cbLastMatch = pLZI->cbCurMatch;
  227. for (i = 0; i < cbLastMatch && ((f = ReadByte(byte)) != END_OF_INPUT);
  228. i++)
  229. {
  230. if (f != TRUE) {
  231. return( f );
  232. }
  233. // Delete old string.
  234. LZDeleteNode(iCurString, pLZI);
  235. pLZI->rgbyteRingBuf[iCurString] = byte;
  236. // If the start position is near the end of buffer, extend the
  237. // buffer to make string comparison easier.
  238. if (iCurString < pLZI->cbMaxMatchLen - 1)
  239. pLZI->rgbyteRingBuf[iCurString + RING_BUF_LEN] = byte;
  240. // Increment position in ring buffer modulo RING_BUF_LEN.
  241. iCurString = (iCurString + 1) & (RING_BUF_LEN - 1);
  242. iCurChar = (iCurChar + 1) & (RING_BUF_LEN - 1);
  243. // Register the string in rgbyteRingBuf[r..r + cbMaxMatchLen - 1].
  244. LZInsertNode(iCurChar, FALSE, pLZI);
  245. }
  246. while (i++ < cbLastMatch)
  247. {
  248. // No need to read after the end of the input, but the buffer may
  249. // not be empty.
  250. LZDeleteNode(iCurString, pLZI);
  251. iCurString = (iCurString + 1) & (RING_BUF_LEN - 1);
  252. iCurChar = (iCurChar + 1) & (RING_BUF_LEN - 1);
  253. if (--len)
  254. LZInsertNode(iCurChar, FALSE, pLZI);
  255. }
  256. } while (len > 0); // until there is no input to process
  257. if (iCodeBuf > 1)
  258. // Send remaining code.
  259. for (i = 0; i < iCodeBuf; i++)
  260. if ((f = WriteByte(codeBuf[i])) != TRUE) {
  261. return( f );
  262. }
  263. // Flush output buffer to file.
  264. if ((f = FlushOutputBuffer(doshDest, pLZI)) != TRUE) {
  265. return( f );
  266. }
  267. LZFreeTree(pLZI);
  268. return(TRUE);
  269. }
  270. INT WriteHdr(PFH pFH, HANDLE doshDest, PLZINFO pLZI)
  271. /*
  272. ** int WriteHdr(PFH pFH, int doshDest);
  273. **
  274. ** Write compressed file header to output file.
  275. **
  276. ** Arguments: pFH - pointer to source header information structure
  277. ** doshDest - DOS file handle of open output file
  278. **
  279. ** Returns: int - TRUE if successful. LZERROR_BADOUTHANDLE if
  280. ** unsuccessful.
  281. **
  282. ** Globals: none
  283. **
  284. ** header format:
  285. ** 8 bytes --> compressed file signature
  286. ** 1 byte --> algorithm label
  287. ** 1 byte --> extension char
  288. ** 4 bytes --> uncompressed file size (LSB to MSB)
  289. **
  290. ** length = 14 bytes
  291. */
  292. {
  293. INT i, j;
  294. DWORD ucbWritten;
  295. BYTE rgbyteHeaderBuf[HEADER_LEN]; // temporary storage for next header byte to write
  296. LPWSTR lpBuf = NULL;
  297. // Sanity check
  298. if (!pLZI) {
  299. return(FALSE);
  300. }
  301. // Copy the compressed file signature.
  302. for (i = 0; i < COMP_SIG_LEN; i++)
  303. rgbyteHeaderBuf[i] = pFH->rgbyteMagic[i];
  304. // Copy the algorithm label and file name extension character.
  305. rgbyteHeaderBuf[i++] = pFH->byteAlgorithm;
  306. rgbyteHeaderBuf[i++] = (BYTE) pFH->byteExtensionChar;
  307. rgbyteHeaderBuf[i++] = (BYTE) pFH->byteExtensionChar+1;
  308. // Copy input file size (long ==> 4 bytes),
  309. // LSB first to MSB last.
  310. for (j = 0; j < 4; j++)
  311. rgbyteHeaderBuf[i++] = (BYTE)((pFH->cbulUncompSize >> (8 * j)) &
  312. (DWORD)BYTE_MASK);
  313. // Write header to file.
  314. if ( FALSE == WriteFile(doshDest,
  315. rgbyteHeaderBuf,
  316. HEADER_LEN,
  317. &ucbWritten,
  318. NULL))
  319. {
  320. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  321. NULL,
  322. GetLastError(),
  323. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  324. (LPWSTR) &lpBuf,
  325. 0,
  326. NULL );
  327. DISPLAY_MESSAGE( stdout, lpBuf );
  328. LocalFree( lpBuf );
  329. #ifdef LZA_DLL
  330. if (ucbWritten == (DWORD)(-1))
  331. #else
  332. if (_error != 0U)
  333. #endif
  334. // Bad DOS file handle.
  335. return(FALSE);
  336. else
  337. // Insufficient space on destination drive.
  338. return(FALSE);
  339. }
  340. // Keep track of bytes written.
  341. pLZI->cblOutSize += (LONG)ucbWritten;
  342. // Header written ok.
  343. return(TRUE);
  344. }
  345. INT WriteOutBuf(BYTE byteNext, HANDLE doshDest, PLZINFO pLZI)
  346. /*++
  347. Dumps output buffer to output file. Prompts for new floppy disk if the
  348. old one if full. Continues dumping to output file of same name on new
  349. floppy disk.
  350. Arguments: byteNext - first byte to be added to empty buffer after buffer
  351. is written
  352. doshDest - output DOS file handle
  353. Returns: int - TRUE if successful. LZERROR_BADOUTHANDLE or
  354. LZERROR_WRITE if unsuccessful.
  355. Globals: pbyteOutBuf - reset to point to free byte after byteNext in
  356. rgbyteOutBuf
  357. --*/
  358. {
  359. DWORD ucbToWrite = 0; // number of bytes to write from buffer
  360. DWORD ucbWritten = 0; // number of bytes actually written
  361. DWORD ucbTotWritten = 0; // total number of bytes written to output
  362. BOOL bStatus = FALSE;
  363. // !!! Assumes pLZI parm is valid. No sanity check (should be done above in caller).
  364. // How much of the buffer should be written to the output file?
  365. ucbTotWritten = ucbToWrite = (DWORD)(pLZI->pbyteOutBuf - pLZI->rgbyteOutBuf);
  366. // Reset pointer to beginning of buffer.
  367. pLZI->pbyteOutBuf = pLZI->rgbyteOutBuf;
  368. // Write to ouput file.
  369. bStatus = WriteFile(doshDest, pLZI->pbyteOutBuf, ucbToWrite, &ucbWritten, NULL);
  370. if ( ucbWritten != ucbToWrite )
  371. {
  372. #ifdef LZA_DLL
  373. if (ucbWritten == (DWORD)(-1)) {
  374. #else
  375. if (_error != 0U) {
  376. #endif
  377. // Bad DOS file handle.
  378. return(FALSE);
  379. }
  380. else {
  381. // Insufficient space on destination drive.
  382. return(FALSE);
  383. }
  384. }
  385. // Add the next byte to the buffer.
  386. *pLZI->pbyteOutBuf++ = byteNext;
  387. return(TRUE);
  388. }
  389. INT ReadInBuf(BYTE ARG_PTR *pbyte, HANDLE doshSource, PLZINFO pLZI)
  390. /*++
  391. int ReadInBuf(BYTE ARG_PTR *pbyte, int doshSource);
  392. Read input file into input buffer.
  393. Arguments: pbyte - pointer to storage for first byte read from file
  394. into buffer
  395. doshSource - DOS file handle to open input file
  396. Returns: int - TRUE or END_OF_INPUT if successful. LZERROR_BADINHANDLE
  397. if not.
  398. Globals: rgbyteInBuf[0] - holds last byte from previous buffer
  399. pbyteInBufEnd - set to point to first byte beyond end of data
  400. in input buffer
  401. bLastUsed - reset to FALSE if currently TRUE
  402. --*/
  403. {
  404. DWORD ucbRead = 0; // number of bytes actually read
  405. DWORD dwBytesRead = 0;
  406. // !!! Assumes pLZI parm is valid. No sanity check (should be done above in caller).
  407. pLZI->rgbyteInBuf[0] = *(pLZI->pbyteInBufEnd - 1);
  408. ReadFile(doshSource, &pLZI->rgbyteInBuf[1], pLZI->ucbInBufLen, &ucbRead, NULL);
  409. if (ucbRead != pLZI->ucbInBufLen)
  410. {
  411. #ifdef LZA_DLL
  412. if (ucbRead == (DWORD)(-1)) {
  413. #else
  414. if (_error != 0U) {
  415. #endif
  416. // We were handed a bad input file handle.
  417. return(FALSE);
  418. }
  419. else if (ucbRead > 0U)
  420. // Read last ucbRead bytes of input file. Change input buffer end
  421. // to account for shorter read.
  422. pLZI->pbyteInBufEnd = &pLZI->rgbyteInBuf[1] + ucbRead;
  423. else { // (ucbRead == 0U) {
  424. // We couldn't read any bytes from input file (EOF reached).
  425. return(END_OF_INPUT);
  426. }
  427. }
  428. // Reset read pointer to beginning of input buffer.
  429. pLZI->pbyteInBuf = &pLZI->rgbyteInBuf[1];
  430. // Was an UnreadByte() done at the beginning of the last buffer?
  431. if (pLZI->bLastUsed)
  432. {
  433. // Return the last byte from the previous input buffer
  434. *pbyte = pLZI->rgbyteInBuf[0];
  435. pLZI->bLastUsed = FALSE;
  436. }
  437. else
  438. // Return the first byte from the new input buffer.
  439. *pbyte = *pLZI->pbyteInBuf++;
  440. return(TRUE);
  441. }
  442. VOID MakeHeader(PFH pFHBlank, BYTE byteAlgorithm,
  443. WCHAR byteExtensionChar, PLZINFO pLZI)
  444. /*++
  445. void MakeHeader(PFH pFHBlank, BYTE byteAlgorithm,
  446. BYTE byteExtensionChar);
  447. Arguments: pFHBlank - pointer to compressed file header struct
  448. that is to be filled in
  449. byteAlgorithm - algorithm label
  450. byteExtensionChar - uncompressed file name extension character
  451. Returns: void
  452. Globals: none
  453. Global cblInSize is used to fill in expanded file length field.
  454. Compressed file length field is set to 0 since it isn't written.
  455. --*/
  456. {
  457. INT i;
  458. // !!! Assumes pLZI parm is valid. No sanity check (should be done above in caller).
  459. // Fill in compressed file signature.
  460. for (i = 0; i < COMP_SIG_LEN; i++)
  461. pFHBlank->rgbyteMagic[i] = (BYTE)(*(COMP_SIG + i));
  462. // Fill in algorithm and extesion character.
  463. pFHBlank->byteAlgorithm = byteAlgorithm;
  464. pFHBlank->byteExtensionChar = byteExtensionChar;
  465. // Fill in file sizes. (cbulCompSize not written to compressed file
  466. // header, so just set it to 0UL.)
  467. pFHBlank->cbulUncompSize = (DWORD)pLZI->cblInSize;
  468. pFHBlank->cbulCompSize = 0UL;
  469. }
  470. BOOL
  471. FileTimeIsNewer( LPWSTR pszFile1,
  472. LPWSTR pszFile2 )
  473. /*++ static BOOL FileTimeIsNewer( const char* pszFile1, const char* pszFile2 );
  474. Return value is TRUE if time stamp on pszFile1 is newer than the
  475. time stamp on pszFile2. If either of the two files do not exist,
  476. the return value is also TRUE (for indicating that pszFile2 should
  477. be update from pszFile1). Otherwise, the return value is FALSE.
  478. --*/
  479. {
  480. struct _stat StatBufSource,
  481. StatBufDest;
  482. if (( _wstat( pszFile2, &StatBufDest )) ||
  483. ( _wstat( pszFile1, &StatBufSource )) ||
  484. ( StatBufSource.st_mtime > StatBufDest.st_mtime ))
  485. return TRUE;
  486. return FALSE;
  487. }
  488. PLZINFO InitGlobalBuffers(
  489. DWORD dwOutBufSize,
  490. DWORD dwRingBufSize,
  491. DWORD dwInBufSize)
  492. {
  493. PLZINFO pLZI;
  494. if (!(pLZI = (PLZINFO)LocalAlloc(LPTR, sizeof(LZINFO)))) {
  495. return(NULL);
  496. }
  497. // Set up ring buffer. N.b., extra (cbStrMax - 1) bytes used to
  498. // facilitate string comparisons near end of ring buffer.
  499. // (The size allocated for the ring buffer may be at most 4224, since
  500. // that's the ring buffer length embedded in the LZFile structs in
  501. // lzexpand.h.)
  502. if (dwRingBufSize == 0) {
  503. dwRingBufSize = MAX_RING_BUF_LEN;
  504. }
  505. if ((pLZI->rgbyteRingBuf = (BYTE FAR *)FALLOC(dwRingBufSize * sizeof(BYTE))) == NULL)
  506. // Bail out, since without the ring buffer, we can't decode anything.
  507. return(NULL);
  508. if (dwInBufSize == 0) {
  509. dwInBufSize = MAX_IN_BUF_SIZE;
  510. }
  511. if (dwOutBufSize == 0) {
  512. dwOutBufSize = MAX_OUT_BUF_SIZE;
  513. }
  514. for (pLZI->ucbInBufLen = dwInBufSize, pLZI->ucbOutBufLen = dwOutBufSize;
  515. pLZI->ucbInBufLen > 0U && pLZI->ucbOutBufLen > 0U;
  516. pLZI->ucbInBufLen -= IN_BUF_STEP, pLZI->ucbOutBufLen -= OUT_BUF_STEP)
  517. {
  518. // Try to set up input buffer. N.b., extra byte because rgbyteInBuf[0]
  519. // will be used to hold last byte from previous input buffer.
  520. if ((pLZI->rgbyteInBuf = (BYTE *)FALLOC(pLZI->ucbInBufLen + 1U)) == NULL)
  521. continue;
  522. // And try to set up output buffer...
  523. if ((pLZI->rgbyteOutBuf = (BYTE *)FALLOC(pLZI->ucbOutBufLen)) == NULL)
  524. {
  525. FFREE(pLZI->rgbyteInBuf);
  526. continue;
  527. }
  528. return(pLZI);
  529. }
  530. // Insufficient memory for I/O buffers.
  531. FFREE(pLZI->rgbyteRingBuf);
  532. return(NULL);
  533. }
  534. PLZINFO InitGlobalBuffersEx()
  535. {
  536. return(InitGlobalBuffers(MAX_OUT_BUF_SIZE, MAX_RING_BUF_LEN, MAX_IN_BUF_SIZE));
  537. }
  538. VOID FreeGlobalBuffers(
  539. PLZINFO pLZI)
  540. {
  541. // Sanity check
  542. if (!pLZI) {
  543. return;
  544. }
  545. if (pLZI->rgbyteRingBuf)
  546. {
  547. FFREE(pLZI->rgbyteRingBuf);
  548. pLZI->rgbyteRingBuf = NULL;
  549. }
  550. if (pLZI->rgbyteInBuf)
  551. {
  552. FFREE(pLZI->rgbyteInBuf);
  553. pLZI->rgbyteInBuf = NULL;
  554. }
  555. if (pLZI->rgbyteOutBuf)
  556. {
  557. FFREE(pLZI->rgbyteOutBuf);
  558. pLZI->rgbyteOutBuf = NULL;
  559. }
  560. // Buffers deallocated ok.
  561. // reset thread info
  562. LocalFree(pLZI);
  563. }
  564. INT
  565. GetIOHandle(LPWSTR pszFileName,
  566. BOOL bRead,
  567. HANDLE *pdosh,
  568. LONG *pcblInSize)
  569. /*
  570. ** int GetIOHandle(char ARG_PTR *pszFileName, BOOL bRead, int ARG_PTR *pdosh);
  571. **
  572. ** Opens input and output files.
  573. **
  574. ** Arguments: pszFileName - source file name
  575. ** bRead - mode for opening file TRUE for read and FALSE
  576. ** for write
  577. ** pdosh - pointer to buffer for DOS file handle to be
  578. ** filled in
  579. **
  580. ** Returns: int - TRUE if file opened successfully. LZERROR_BADINHANDLE
  581. ** if input file could not be opened. LZERROR_BADOUTHANDLE
  582. ** if output file could not be opened. Fills in
  583. ** *pdosh with open DOS file handle, or NO_DOSH if
  584. ** pszFileName is NULL.
  585. **
  586. ** Globals: cblInSize - set to length of input file
  587. */
  588. {
  589. LPVOID lpBuf = NULL;
  590. if (pszFileName == NULL)
  591. *pdosh = NULL;
  592. else if (bRead == WRITE_IT)
  593. {
  594. // Set up output DOS file handle.
  595. if ((*pdosh = CreateFile( pszFileName, GENERIC_WRITE,
  596. FILE_SHARE_READ,
  597. NULL,
  598. OPEN_ALWAYS,
  599. FILE_ATTRIBUTE_NORMAL,
  600. NULL)) == INVALID_HANDLE_VALUE )
  601. return(FALSE);
  602. }
  603. else // (bRead == READ_IT)
  604. {
  605. if ((*pdosh = CreateFile( pszFileName, GENERIC_READ,
  606. FILE_SHARE_READ,
  607. NULL,
  608. OPEN_EXISTING,
  609. FILE_ATTRIBUTE_NORMAL,
  610. NULL)) == INVALID_HANDLE_VALUE)
  611. return(FALSE);
  612. // Move to the end of the input file to find its length,
  613. // then return to the beginning.
  614. if ((*pcblInSize = GetFileSize( *pdosh, NULL )) == -1 )
  615. {
  616. CloseHandle(*pdosh);
  617. FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  618. NULL,
  619. GetLastError(),
  620. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  621. (LPWSTR) &lpBuf,
  622. 0,
  623. NULL );
  624. DISPLAY_MESSAGE( stdout, (LPWSTR) lpBuf );
  625. //release memory allocated by LocalAlloc
  626. LocalFree( lpBuf );
  627. return(FALSE);
  628. }
  629. }
  630. return(TRUE);
  631. }
  632. BOOL
  633. ProcessNotification(LPWSTR pszSource,
  634. LPWSTR pszDest,
  635. WORD wNotification
  636. )
  637. /*
  638. static BOOL ProcessNotification(char ARG_PTR *pszSource,
  639. char ARG_PTR *pszDest,
  640. WORD wNotification);
  641. Callback function during file processing.
  642. Arguments: pszSource - source file name
  643. pszDest - destination file name
  644. wNotification - process type query
  645. Returns: BOOL - (wNotification == NOTIFY_START_*):
  646. TRUE if the source file should be "processed" into
  647. the destination file. FALSE if not.
  648. else
  649. TRUE.
  650. Globals: none
  651. --*/
  652. {
  653. WCHAR* szBuffer = NULL;
  654. DWORD dwSize = 0;
  655. switch(wNotification)
  656. {
  657. case NOTIFY_START_COMPRESS:
  658. {
  659. // Fail if the source and destination files are identical.
  660. if( lstrcmp( pszSource, pszDest ) == 0 )
  661. {
  662. dwSize = lstrlen( GetResString( IDS_COLLISION ) )+ lstrlen(pszSource) + 10;
  663. szBuffer = malloc( dwSize*sizeof(WCHAR) );
  664. if( NULL == szBuffer )
  665. {
  666. DISPLAY_MESSAGE( stderr, GetResString(IDS_TAG_ERROR) );
  667. DISPLAY_MESSAGE( stderr, EMPTY_SPACE );
  668. SetLastError( ERROR_OUTOFMEMORY );
  669. SaveLastError();
  670. DISPLAY_MESSAGE( stderr, GetReason() );
  671. return( EXIT_FAILURE );
  672. }
  673. DISPLAY_MESSAGE1( stderr, szBuffer, GetResString( IDS_COLLISION ), pszSource );
  674. free( szBuffer );
  675. return FALSE;
  676. }
  677. // Display start message.
  678. switch (byteAlgorithm)
  679. {
  680. case LZX_ALG:
  681. dwSize = lstrlen( GetResString( IDS_COMPRESSING_LZX ) )+ lstrlen(pszSource) + lstrlen(pszDest)+10;
  682. szBuffer = malloc( dwSize*sizeof(WCHAR) );
  683. if( NULL == szBuffer )
  684. {
  685. DISPLAY_MESSAGE( stderr, GetResString(IDS_TAG_ERROR) );
  686. DISPLAY_MESSAGE( stderr, EMPTY_SPACE );
  687. SetLastError( ERROR_OUTOFMEMORY );
  688. SaveLastError();
  689. DISPLAY_MESSAGE( stderr, GetReason() );
  690. return( EXIT_FAILURE );
  691. }
  692. swprintf( szBuffer, GetResString( IDS_COMPRESSING_LZX ), pszSource, pszDest,
  693. CompressionMemoryFromTCOMP(DiamondCompressionType) );
  694. ShowMessage(stdout, _X(szBuffer) );
  695. free( szBuffer );
  696. break;
  697. case QUANTUM_ALG:
  698. dwSize = lstrlen( GetResString( IDS_COMPRESSING_QUANTUM ) )+ lstrlen(pszSource) + lstrlen(pszDest)+10;
  699. szBuffer = malloc( dwSize*sizeof(WCHAR) );
  700. if( NULL == szBuffer )
  701. {
  702. DISPLAY_MESSAGE( stderr, GetResString(IDS_TAG_ERROR) );
  703. DISPLAY_MESSAGE( stderr, EMPTY_SPACE );
  704. SetLastError( ERROR_OUTOFMEMORY );
  705. SaveLastError();
  706. DISPLAY_MESSAGE( stderr, GetReason() );
  707. return( EXIT_FAILURE );
  708. }
  709. swprintf( szBuffer, GetResString( IDS_COMPRESSING_QUANTUM ), pszSource, pszDest,
  710. CompressionLevelFromTCOMP(DiamondCompressionType),
  711. CompressionMemoryFromTCOMP(DiamondCompressionType)
  712. );
  713. ShowMessage( stdout, _X(szBuffer) );
  714. free( szBuffer );
  715. break;
  716. default:
  717. dwSize = lstrlen( GetResString( IDS_COMPRESSING_MSZIP ) )+ lstrlen(pszSource) + lstrlen(pszDest)+10;
  718. szBuffer = malloc( dwSize*sizeof(WCHAR) );
  719. if( NULL == szBuffer )
  720. {
  721. DISPLAY_MESSAGE( stderr, GetResString(IDS_TAG_ERROR) );
  722. DISPLAY_MESSAGE( stderr, EMPTY_SPACE );
  723. SetLastError( ERROR_OUTOFMEMORY );
  724. SaveLastError();
  725. DISPLAY_MESSAGE( stderr, GetReason() );
  726. return( EXIT_FAILURE );
  727. }
  728. swprintf(szBuffer,
  729. (byteAlgorithm == MSZIP_ALG) ? GetResString( IDS_COMPRESSING_MSZIP ) : GetResString( IDS_COMPRESSING ),
  730. pszSource,
  731. pszDest);
  732. ShowMessage( stdout, _X(szBuffer) );
  733. free( szBuffer );
  734. }
  735. }
  736. break;
  737. default:
  738. break;
  739. }
  740. return(TRUE);
  741. }
  742. INT CopyDateTimeStamp(HANDLE doshFrom, HANDLE doshTo)
  743. /*++
  744. Copy date and time stamp from one file to another.
  745. Arguments: doshFrom - date and time stamp source DOS file handle
  746. doshTo - target DOS file handle
  747. Returns: TRUE if successful. LZERROR_BADINHANDLE or
  748. LZERROR_BADOUTHANDLE if unsuccessful.
  749. Globals: none
  750. N.b., stream-style I/O routines like fopen() and fclose() may counter the
  751. intended effect of this function. fclose() writes the current date to any
  752. file it's called with which was opened in write "w" or append "a" mode.
  753. One way to get around this in order to modify the date of a file opened
  754. for writing or appending by fopen() is to fclose() the file and fopen() it
  755. again in read "r" mode. Then set its date and time stamp with
  756. CopyDateTimeStamp().
  757. --*/
  758. {
  759. FILETIME lpCreationTime, lpLastAccessTime, lpLastWriteTime;
  760. if(!GetFileTime((HANDLE) doshFrom, &lpCreationTime, &lpLastAccessTime,
  761. &lpLastWriteTime)){
  762. return(FALSE);
  763. }
  764. if(!SetFileTime((HANDLE) doshTo, &lpCreationTime, &lpLastAccessTime,
  765. &lpLastWriteTime)){
  766. return(FALSE);
  767. }
  768. return(TRUE);
  769. }