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.

174 lines
4.7 KiB

  1. /*
  2. * LZEXP.C
  3. *
  4. * Routines used in Lempel-Ziv expansion.
  5. *
  6. */
  7. #include "kernel.h"
  8. #if ROM //--------------------------------------------------------------
  9. #define API _far _pascal _loadds
  10. #define RING_BUF_LEN 4096 // size of ring buffer
  11. #define MAX_RING_BUF_LEN 4224 // size of ring buffer - from LZFile
  12. // struct declaration in lzexpand.h
  13. #define BUF_CLEAR_BYTE ((BYTE) ' ') // rgbyteRingBuf[] initializer
  14. #define MAX_LITERAL_LEN 2 // encode string into position and
  15. // length if match length greater than
  16. // this value (== # of bytes required
  17. // to encode position and length)
  18. #define LZ_MAX_MATCH_LEN (0x10 + MAX_LITERAL_LEN)
  19. // upper limit for match length
  20. // (n.b., assume length field implies
  21. // length += 3)
  22. #define END_OF_INPUT 500 // EOF flag for input file
  23. #define FOREVER for(;;)
  24. #define ReadByte(byte) ((byte = (BYTE)(cbSrc ? *pSrc++ : 0)), \
  25. (cbSrc ? (cbSrc--, TRUE) : END_OF_INPUT))
  26. #define WriteByte(byte) ((*pDst++ = byte), cblOutSize++)
  27. typedef struct COMPHEAD _far * LPCOMPHEAD;
  28. struct COMPHEAD { // Compressed segment/resource header
  29. BYTE Sig; // signature
  30. BYTE Method; // compression method
  31. DWORD cbSize; // # compressed bytes following
  32. };
  33. #define CMP_SIG ('C')
  34. #define CMP_LZ ('L')
  35. /*
  36. * LZDecode
  37. *
  38. * Parameters:
  39. * selDst Selector pointing to destination buffer
  40. * selSrc Selector pointing to compressed data
  41. * lpBuf Pointer to optional ring buffer
  42. *
  43. * Returns:
  44. * count (in bytes) of uncompressed data written to selDst buffer
  45. *
  46. * Note: This routine does not use any static or external data.
  47. * This allows it to be used to uncompress Kernel's own
  48. * data segment.
  49. */
  50. DWORD FAR API
  51. LZDecode(WORD selDst, WORD selSrc, LPSTR lpBuf) {
  52. int i,
  53. cb, // number of bytes to unpack
  54. f; // holds ReadByte() return values
  55. int oStart; // buffer offset for unpacking
  56. BYTE byte1, byte2; // input byte holders
  57. unsigned uFlags; // LZ decoding description byte
  58. int iCurRingBufPos; // ring buffer offset
  59. int cbMaxMatchLen;
  60. LPSTR rgbyteRingBuf;
  61. HANDLE hRingBuf;
  62. LPCOMPHEAD lpHead;
  63. DWORD cblOutSize, cbSrc;
  64. char _based((_segment)selDst) *pDst = NULL;
  65. char _based((_segment)selSrc) *pSrc = NULL;
  66. struct COMPHEAD _based((_segment)selSrc) *pHead = NULL;
  67. pSrc += sizeof(struct COMPHEAD);
  68. cblOutSize = 0;
  69. cbSrc = pHead->cbSize;
  70. cbMaxMatchLen = LZ_MAX_MATCH_LEN;
  71. // Make sure we know how to expand this object
  72. if (pHead->Sig != CMP_SIG || pHead->Method != CMP_LZ)
  73. return(0);
  74. // Set up a fresh buffer state.
  75. if (lpBuf) {
  76. hRingBuf = NULL;
  77. rgbyteRingBuf = lpBuf;
  78. } else {
  79. if (!(hRingBuf = GlobalAlloc(GMEM_MOVEABLE,MAX_RING_BUF_LEN)))
  80. return(0);
  81. rgbyteRingBuf = GlobalLock(hRingBuf);
  82. }
  83. // Initialize ring buffer.
  84. for (i = 0; i < RING_BUF_LEN - cbMaxMatchLen; i++)
  85. rgbyteRingBuf[i] = BUF_CLEAR_BYTE;
  86. // Initialize decoding globals.
  87. uFlags = 0U;
  88. iCurRingBufPos = RING_BUF_LEN - cbMaxMatchLen;
  89. f = ReadByte(byte1);
  90. // Decode one encoded unit at a time.
  91. FOREVER
  92. {
  93. if (f == END_OF_INPUT) // EOF reached
  94. break;
  95. // High order byte counts the number of bits used in the low order
  96. // byte.
  97. if (((uFlags >>= 1) & 0x100) == 0)
  98. {
  99. // Set bit mask describing the next 8 bytes.
  100. uFlags = ((unsigned)byte1) | 0xff00;
  101. if ((f = ReadByte(byte1)) != TRUE)
  102. break;
  103. }
  104. if (uFlags & 1)
  105. {
  106. // Just store the literal byte in the buffer.
  107. WriteByte(byte1);
  108. rgbyteRingBuf[iCurRingBufPos++] = byte1;
  109. iCurRingBufPos &= RING_BUF_LEN - 1;
  110. }
  111. else
  112. {
  113. // Extract the offset and count to copy from the ring buffer.
  114. if ((f = ReadByte(byte2)) != TRUE)
  115. break;
  116. cb = (int)byte2;
  117. oStart = (cb & 0xf0) << 4 | (int)byte1;
  118. cb = (cb & 0x0f) + MAX_LITERAL_LEN;
  119. for (i = 0; i <= cb; i++)
  120. {
  121. byte1 = rgbyteRingBuf[(oStart + i) & (RING_BUF_LEN - 1)];
  122. WriteByte(byte1);
  123. rgbyteRingBuf[iCurRingBufPos++] = byte1;
  124. iCurRingBufPos &= RING_BUF_LEN - 1;
  125. }
  126. }
  127. f = ReadByte(byte1);
  128. }
  129. if (hRingBuf) {
  130. GlobalUnlock(hRingBuf);
  131. GlobalFree(hRingBuf);
  132. }
  133. return(cblOutSize);
  134. }
  135. #endif //ROM -------------------------------------------------------