Index: utility/eficompress.c |
diff --git a/utility/eficompress.c b/utility/eficompress.c |
new file mode 100644 |
index 0000000000000000000000000000000000000000..b0cf4fb38f15d885522cac852bad512c9470c3f1 |
--- /dev/null |
+++ b/utility/eficompress.c |
@@ -0,0 +1,1609 @@ |
+/* Copyright (c) 2010 The Chromium OS Authors. All rights reserved. |
+ * Use of this source code is governed by a BSD-style license that can be |
+ * found in the LICENSE file. |
+ */ |
+ |
+/*++ |
+ |
+Copyright (c) 2006, Intel Corporation |
+All rights reserved. This program and the accompanying materials |
+are licensed and made available under the terms and conditions of the BSD License |
+which accompanies this distribution. The full text of the license may be found at |
+http://opensource.org/licenses/bsd-license.php |
+ |
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, |
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. |
+ |
+Module Name: |
+ |
+ EfiCompress.c |
+ |
+Abstract: |
+ |
+ Compression routine. The compression algorithm is a mixture of |
+ LZ77 and Huffman coding. LZ77 transforms the source data into a |
+ sequence of Original Characters and Pointers to repeated strings. |
+ This sequence is further divided into Blocks and Huffman codings |
+ are applied to each Block. |
+ |
+--*/ |
+ |
+#include <errno.h> |
+#include <stdint.h> |
+#include <stdio.h> |
+#include <stdlib.h> |
+#include <string.h> |
+#include <sys/types.h> |
+#include <sys/stat.h> |
+#include <unistd.h> |
+ |
+#include "eficompress.h" |
+ |
+ |
+// |
+// Macro Definitions |
+// |
+ |
+typedef INT16 NODE; |
+#define UINT8_BIT 8 |
+#define THRESHOLD 3 |
+#define INIT_CRC 0 |
+#define WNDBIT 13 |
+#define WNDSIZ (1U << WNDBIT) |
+#define MAXMATCH 256 |
+#define PERC_FLAG 0x8000U |
+#define CODE_BIT 16 |
+#define NIL 0 |
+#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) |
+#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2) |
+#define CRCPOLY 0xA001 |
+#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT) |
+ |
+// |
+// C: the Char&Len Set; P: the Position Set; T: the exTra Set |
+// |
+ |
+#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) |
+#define CBIT 9 |
+#define NP (WNDBIT + 1) |
+#define PBIT 4 |
+#define NT (CODE_BIT + 3) |
+#define TBIT 5 |
+#if NT > NP |
+ #define NPT NT |
+#else |
+ #define NPT NP |
+#endif |
+ |
+// |
+// Function Prototypes |
+// |
+ |
+STATIC |
+VOID |
+PutDword( |
+ IN UINT32 Data |
+ ); |
+ |
+STATIC |
+EFI_STATUS |
+AllocateMemory ( |
+ ); |
+ |
+STATIC |
+VOID |
+FreeMemory ( |
+ ); |
+ |
+STATIC |
+VOID |
+InitSlide ( |
+ ); |
+ |
+STATIC |
+NODE |
+Child ( |
+ IN NODE q, |
+ IN UINT8 c |
+ ); |
+ |
+STATIC |
+VOID |
+MakeChild ( |
+ IN NODE q, |
+ IN UINT8 c, |
+ IN NODE r |
+ ); |
+ |
+STATIC |
+VOID |
+Split ( |
+ IN NODE Old |
+ ); |
+ |
+STATIC |
+VOID |
+InsertNode ( |
+ ); |
+ |
+STATIC |
+VOID |
+DeleteNode ( |
+ ); |
+ |
+STATIC |
+VOID |
+GetNextMatch ( |
+ ); |
+ |
+STATIC |
+EFI_STATUS |
+Encode ( |
+ ); |
+ |
+STATIC |
+VOID |
+CountTFreq ( |
+ ); |
+ |
+STATIC |
+VOID |
+WritePTLen ( |
+ IN INT32 n, |
+ IN INT32 nbit, |
+ IN INT32 Special |
+ ); |
+ |
+STATIC |
+VOID |
+WriteCLen ( |
+ ); |
+ |
+STATIC |
+VOID |
+EncodeC ( |
+ IN INT32 c |
+ ); |
+ |
+STATIC |
+VOID |
+EncodeP ( |
+ IN UINT32 p |
+ ); |
+ |
+STATIC |
+VOID |
+SendBlock ( |
+ ); |
+ |
+STATIC |
+VOID |
+Output ( |
+ IN UINT32 c, |
+ IN UINT32 p |
+ ); |
+ |
+STATIC |
+VOID |
+HufEncodeStart ( |
+ ); |
+ |
+STATIC |
+VOID |
+HufEncodeEnd ( |
+ ); |
+ |
+STATIC |
+VOID |
+MakeCrcTable ( |
+ ); |
+ |
+STATIC |
+VOID |
+PutBits ( |
+ IN INT32 n, |
+ IN UINT32 x |
+ ); |
+ |
+STATIC |
+INT32 |
+FreadCrc ( |
+ OUT UINT8 *p, |
+ IN INT32 n |
+ ); |
+ |
+STATIC |
+VOID |
+InitPutBits ( |
+ ); |
+ |
+STATIC |
+VOID |
+CountLen ( |
+ IN INT32 i |
+ ); |
+ |
+STATIC |
+VOID |
+MakeLen ( |
+ IN INT32 Root |
+ ); |
+ |
+STATIC |
+VOID |
+DownHeap ( |
+ IN INT32 i |
+ ); |
+ |
+STATIC |
+VOID |
+MakeCode ( |
+ IN INT32 n, |
+ IN UINT8 Len[], |
+ OUT UINT16 Code[] |
+ ); |
+ |
+STATIC |
+INT32 |
+MakeTree ( |
+ IN INT32 NParm, |
+ IN UINT16 FreqParm[], |
+ OUT UINT8 LenParm[], |
+ OUT UINT16 CodeParm[] |
+ ); |
+ |
+ |
+// |
+// Global Variables |
+// |
+ |
+STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; |
+ |
+STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; |
+STATIC INT16 mHeap[NC + 1]; |
+STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN; |
+STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc; |
+STATIC UINT32 mCompSize, mOrigSize; |
+ |
+STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], |
+ mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1], mCCode[NC], |
+ mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1]; |
+ |
+STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; |
+ |
+ |
+// |
+// functions |
+// |
+ |
+EFI_STATUS |
+EfiCompress ( |
+ IN UINT8 *SrcBuffer, |
+ IN UINT32 SrcSize, |
+ IN UINT8 *DstBuffer, |
+ IN OUT UINT32 *DstSize |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ The main compression routine. |
+ |
+Arguments: |
+ |
+ SrcBuffer - The buffer storing the source data |
+ SrcSize - The size of source data |
+ DstBuffer - The buffer to store the compressed data |
+ DstSize - On input, the size of DstBuffer; On output, |
+ the size of the actual compressed data. |
+ |
+Returns: |
+ |
+ EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case, |
+ DstSize contains the size needed. |
+ EFI_SUCCESS - Compression is successful. |
+ |
+--*/ |
+{ |
+ EFI_STATUS Status = EFI_SUCCESS; |
+ |
+ // |
+ // Initializations |
+ // |
+ mBufSiz = 0; |
+ mBuf = NULL; |
+ mText = NULL; |
+ mLevel = NULL; |
+ mChildCount = NULL; |
+ mPosition = NULL; |
+ mParent = NULL; |
+ mPrev = NULL; |
+ mNext = NULL; |
+ |
+ |
+ mSrc = SrcBuffer; |
+ mSrcUpperLimit = mSrc + SrcSize; |
+ mDst = DstBuffer; |
+ mDstUpperLimit = mDst + *DstSize; |
+ |
+ PutDword(0L); |
+ PutDword(0L); |
+ |
+ MakeCrcTable (); |
+ |
+ mOrigSize = mCompSize = 0; |
+ mCrc = INIT_CRC; |
+ |
+ // |
+ // Compress it |
+ // |
+ |
+ Status = Encode(); |
+ if (EFI_ERROR (Status)) { |
+ return EFI_OUT_OF_RESOURCES; |
+ } |
+ |
+ // |
+ // Null terminate the compressed data |
+ // |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = 0; |
+ } |
+ |
+ // |
+ // Fill in compressed size and original size |
+ // |
+ mDst = DstBuffer; |
+ PutDword(mCompSize+1); |
+ PutDword(mOrigSize); |
+ |
+ // |
+ // Return |
+ // |
+ |
+ if (mCompSize + 1 + 8 > *DstSize) { |
+ *DstSize = mCompSize + 1 + 8; |
+ return EFI_BUFFER_TOO_SMALL; |
+ } else { |
+ *DstSize = mCompSize + 1 + 8; |
+ return EFI_SUCCESS; |
+ } |
+ |
+} |
+ |
+STATIC |
+VOID |
+PutDword( |
+ IN UINT32 Data |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Put a dword to output stream |
+ |
+Arguments: |
+ |
+ Data - the dword to put |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff); |
+ } |
+ |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff); |
+ } |
+ |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff); |
+ } |
+ |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff); |
+ } |
+} |
+ |
+STATIC |
+EFI_STATUS |
+AllocateMemory () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Allocate memory spaces for data structures used in compression process |
+ |
+Argements: (VOID) |
+ |
+Returns: |
+ |
+ EFI_SUCCESS - Memory is allocated successfully |
+ EFI_OUT_OF_RESOURCES - Allocation fails |
+ |
+--*/ |
+{ |
+ UINT32 i; |
+ |
+ mText = malloc (WNDSIZ * 2 + MAXMATCH); |
+ for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) { |
+ mText[i] = 0; |
+ } |
+ |
+ mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel)); |
+ mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount)); |
+ mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition)); |
+ mParent = malloc (WNDSIZ * 2 * sizeof(*mParent)); |
+ mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev)); |
+ mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext)); |
+ |
+ mBufSiz = 16 * 1024U; |
+ while ((mBuf = malloc(mBufSiz)) == NULL) { |
+ mBufSiz = (mBufSiz / 10U) * 9U; |
+ if (mBufSiz < 4 * 1024U) { |
+ return EFI_OUT_OF_RESOURCES; |
+ } |
+ } |
+ mBuf[0] = 0; |
+ |
+ return EFI_SUCCESS; |
+} |
+ |
+VOID |
+FreeMemory () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Called when compression is completed to free memory previously allocated. |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ if (mText) { |
+ free (mText); |
+ } |
+ |
+ if (mLevel) { |
+ free (mLevel); |
+ } |
+ |
+ if (mChildCount) { |
+ free (mChildCount); |
+ } |
+ |
+ if (mPosition) { |
+ free (mPosition); |
+ } |
+ |
+ if (mParent) { |
+ free (mParent); |
+ } |
+ |
+ if (mPrev) { |
+ free (mPrev); |
+ } |
+ |
+ if (mNext) { |
+ free (mNext); |
+ } |
+ |
+ if (mBuf) { |
+ free (mBuf); |
+ } |
+ |
+ return; |
+} |
+ |
+ |
+STATIC |
+VOID |
+InitSlide () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Initialize String Info Log data structures |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ NODE i; |
+ |
+ for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) { |
+ mLevel[i] = 1; |
+ mPosition[i] = NIL; /* sentinel */ |
+ } |
+ for (i = WNDSIZ; i < WNDSIZ * 2; i++) { |
+ mParent[i] = NIL; |
+ } |
+ mAvail = 1; |
+ for (i = 1; i < WNDSIZ - 1; i++) { |
+ mNext[i] = (NODE)(i + 1); |
+ } |
+ |
+ mNext[WNDSIZ - 1] = NIL; |
+ for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) { |
+ mNext[i] = NIL; |
+ } |
+} |
+ |
+ |
+STATIC |
+NODE |
+Child ( |
+ IN NODE q, |
+ IN UINT8 c |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Find child node given the parent node and the edge character |
+ |
+Arguments: |
+ |
+ q - the parent node |
+ c - the edge character |
+ |
+Returns: |
+ |
+ The child node (NIL if not found) |
+ |
+--*/ |
+{ |
+ NODE r; |
+ |
+ r = mNext[HASH(q, c)]; |
+ mParent[NIL] = q; /* sentinel */ |
+ while (mParent[r] != q) { |
+ r = mNext[r]; |
+ } |
+ |
+ return r; |
+} |
+ |
+STATIC |
+VOID |
+MakeChild ( |
+ IN NODE q, |
+ IN UINT8 c, |
+ IN NODE r |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Create a new child for a given parent node. |
+ |
+Arguments: |
+ |
+ q - the parent node |
+ c - the edge character |
+ r - the child node |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ NODE h, t; |
+ |
+ h = (NODE)HASH(q, c); |
+ t = mNext[h]; |
+ mNext[h] = r; |
+ mNext[r] = t; |
+ mPrev[t] = r; |
+ mPrev[r] = h; |
+ mParent[r] = q; |
+ mChildCount[q]++; |
+} |
+ |
+STATIC |
+VOID |
+Split ( |
+ NODE Old |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Split a node. |
+ |
+Arguments: |
+ |
+ Old - the node to split |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ NODE New, t; |
+ |
+ New = mAvail; |
+ mAvail = mNext[New]; |
+ mChildCount[New] = 0; |
+ t = mPrev[Old]; |
+ mPrev[New] = t; |
+ mNext[t] = New; |
+ t = mNext[Old]; |
+ mNext[New] = t; |
+ mPrev[t] = New; |
+ mParent[New] = mParent[Old]; |
+ mLevel[New] = (UINT8)mMatchLen; |
+ mPosition[New] = mPos; |
+ MakeChild(New, mText[mMatchPos + mMatchLen], Old); |
+ MakeChild(New, mText[mPos + mMatchLen], mPos); |
+} |
+ |
+STATIC |
+VOID |
+InsertNode () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Insert string info for current position into the String Info Log |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ NODE q, r, j, t; |
+ UINT8 c, *t1, *t2; |
+ |
+ if (mMatchLen >= 4) { |
+ |
+ // |
+ // We have just got a long match, the target tree |
+ // can be located by MatchPos + 1. Travese the tree |
+ // from bottom up to get to a proper starting point. |
+ // The usage of PERC_FLAG ensures proper node deletion |
+ // in DeleteNode() later. |
+ // |
+ |
+ mMatchLen--; |
+ r = (INT16)((mMatchPos + 1) | WNDSIZ); |
+ while ((q = mParent[r]) == NIL) { |
+ r = mNext[r]; |
+ } |
+ while (mLevel[q] >= mMatchLen) { |
+ r = q; q = mParent[q]; |
+ } |
+ t = q; |
+ while (mPosition[t] < 0) { |
+ mPosition[t] = mPos; |
+ t = mParent[t]; |
+ } |
+ if (t < WNDSIZ) { |
+ mPosition[t] = (NODE)(mPos | PERC_FLAG); |
+ } |
+ } else { |
+ |
+ // |
+ // Locate the target tree |
+ // |
+ |
+ q = (INT16)(mText[mPos] + WNDSIZ); |
+ c = mText[mPos + 1]; |
+ if ((r = Child(q, c)) == NIL) { |
+ MakeChild(q, c, mPos); |
+ mMatchLen = 1; |
+ return; |
+ } |
+ mMatchLen = 2; |
+ } |
+ |
+ // |
+ // Traverse down the tree to find a match. |
+ // Update Position value along the route. |
+ // Node split or creation is involved. |
+ // |
+ |
+ for ( ; ; ) { |
+ if (r >= WNDSIZ) { |
+ j = MAXMATCH; |
+ mMatchPos = r; |
+ } else { |
+ j = mLevel[r]; |
+ mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG); |
+ } |
+ if (mMatchPos >= mPos) { |
+ mMatchPos -= WNDSIZ; |
+ } |
+ t1 = &mText[mPos + mMatchLen]; |
+ t2 = &mText[mMatchPos + mMatchLen]; |
+ while (mMatchLen < j) { |
+ if (*t1 != *t2) { |
+ Split(r); |
+ return; |
+ } |
+ mMatchLen++; |
+ t1++; |
+ t2++; |
+ } |
+ if (mMatchLen >= MAXMATCH) { |
+ break; |
+ } |
+ mPosition[r] = mPos; |
+ q = r; |
+ if ((r = Child(q, *t1)) == NIL) { |
+ MakeChild(q, *t1, mPos); |
+ return; |
+ } |
+ mMatchLen++; |
+ } |
+ t = mPrev[r]; |
+ mPrev[mPos] = t; |
+ mNext[t] = mPos; |
+ t = mNext[r]; |
+ mNext[mPos] = t; |
+ mPrev[t] = mPos; |
+ mParent[mPos] = q; |
+ mParent[r] = NIL; |
+ |
+ // |
+ // Special usage of 'next' |
+ // |
+ mNext[r] = mPos; |
+ |
+} |
+ |
+STATIC |
+VOID |
+DeleteNode () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Delete outdated string info. (The Usage of PERC_FLAG |
+ ensures a clean deletion) |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ NODE q, r, s, t, u; |
+ |
+ if (mParent[mPos] == NIL) { |
+ return; |
+ } |
+ |
+ r = mPrev[mPos]; |
+ s = mNext[mPos]; |
+ mNext[r] = s; |
+ mPrev[s] = r; |
+ r = mParent[mPos]; |
+ mParent[mPos] = NIL; |
+ if (r >= WNDSIZ || --mChildCount[r] > 1) { |
+ return; |
+ } |
+ t = (NODE)(mPosition[r] & ~PERC_FLAG); |
+ if (t >= mPos) { |
+ t -= WNDSIZ; |
+ } |
+ s = t; |
+ q = mParent[r]; |
+ while ((u = mPosition[q]) & PERC_FLAG) { |
+ u &= ~PERC_FLAG; |
+ if (u >= mPos) { |
+ u -= WNDSIZ; |
+ } |
+ if (u > s) { |
+ s = u; |
+ } |
+ mPosition[q] = (INT16)(s | WNDSIZ); |
+ q = mParent[q]; |
+ } |
+ if (q < WNDSIZ) { |
+ if (u >= mPos) { |
+ u -= WNDSIZ; |
+ } |
+ if (u > s) { |
+ s = u; |
+ } |
+ mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG); |
+ } |
+ s = Child(r, mText[t + mLevel[r]]); |
+ t = mPrev[s]; |
+ u = mNext[s]; |
+ mNext[t] = u; |
+ mPrev[u] = t; |
+ t = mPrev[r]; |
+ mNext[t] = s; |
+ mPrev[s] = t; |
+ t = mNext[r]; |
+ mPrev[t] = s; |
+ mNext[s] = t; |
+ mParent[s] = mParent[r]; |
+ mParent[r] = NIL; |
+ mNext[r] = mAvail; |
+ mAvail = r; |
+} |
+ |
+STATIC |
+VOID |
+GetNextMatch () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Advance the current position (read in new data if needed). |
+ Delete outdated string info. Find a match string for current position. |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ INT32 n; |
+ |
+ mRemainder--; |
+ if (++mPos == WNDSIZ * 2) { |
+ memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); |
+ n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ); |
+ mRemainder += n; |
+ mPos = WNDSIZ; |
+ } |
+ DeleteNode(); |
+ InsertNode(); |
+} |
+ |
+STATIC |
+EFI_STATUS |
+Encode () |
+/*++ |
+ |
+Routine Description: |
+ |
+ The main controlling routine for compression process. |
+ |
+Arguments: (VOID) |
+ |
+Returns: |
+ |
+ EFI_SUCCESS - The compression is successful |
+ EFI_OUT_0F_RESOURCES - Not enough memory for compression process |
+ |
+--*/ |
+{ |
+ EFI_STATUS Status; |
+ INT32 LastMatchLen; |
+ NODE LastMatchPos; |
+ |
+ Status = AllocateMemory(); |
+ if (EFI_ERROR(Status)) { |
+ FreeMemory(); |
+ return Status; |
+ } |
+ |
+ InitSlide(); |
+ |
+ HufEncodeStart(); |
+ |
+ mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH); |
+ |
+ mMatchLen = 0; |
+ mPos = WNDSIZ; |
+ InsertNode(); |
+ if (mMatchLen > mRemainder) { |
+ mMatchLen = mRemainder; |
+ } |
+ while (mRemainder > 0) { |
+ LastMatchLen = mMatchLen; |
+ LastMatchPos = mMatchPos; |
+ GetNextMatch(); |
+ if (mMatchLen > mRemainder) { |
+ mMatchLen = mRemainder; |
+ } |
+ |
+ if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { |
+ |
+ // |
+ // Not enough benefits are gained by outputting a pointer, |
+ // so just output the original character |
+ // |
+ |
+ Output(mText[mPos - 1], 0); |
+ } else { |
+ |
+ // |
+ // Outputting a pointer is beneficial enough, do it. |
+ // |
+ |
+ Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), |
+ (mPos - LastMatchPos - 2) & (WNDSIZ - 1)); |
+ while (--LastMatchLen > 0) { |
+ GetNextMatch(); |
+ } |
+ if (mMatchLen > mRemainder) { |
+ mMatchLen = mRemainder; |
+ } |
+ } |
+ } |
+ |
+ HufEncodeEnd(); |
+ FreeMemory(); |
+ return EFI_SUCCESS; |
+} |
+ |
+STATIC |
+VOID |
+CountTFreq () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Count the frequencies for the Extra Set |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ INT32 i, k, n, Count; |
+ |
+ for (i = 0; i < NT; i++) { |
+ mTFreq[i] = 0; |
+ } |
+ n = NC; |
+ while (n > 0 && mCLen[n - 1] == 0) { |
+ n--; |
+ } |
+ i = 0; |
+ while (i < n) { |
+ k = mCLen[i++]; |
+ if (k == 0) { |
+ Count = 1; |
+ while (i < n && mCLen[i] == 0) { |
+ i++; |
+ Count++; |
+ } |
+ if (Count <= 2) { |
+ mTFreq[0] = (UINT16)(mTFreq[0] + Count); |
+ } else if (Count <= 18) { |
+ mTFreq[1]++; |
+ } else if (Count == 19) { |
+ mTFreq[0]++; |
+ mTFreq[1]++; |
+ } else { |
+ mTFreq[2]++; |
+ } |
+ } else { |
+ mTFreq[k + 2]++; |
+ } |
+ } |
+} |
+ |
+STATIC |
+VOID |
+WritePTLen ( |
+ IN INT32 n, |
+ IN INT32 nbit, |
+ IN INT32 Special |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Outputs the code length array for the Extra Set or the Position Set. |
+ |
+Arguments: |
+ |
+ n - the number of symbols |
+ nbit - the number of bits needed to represent 'n' |
+ Special - the special symbol that needs to be take care of |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ INT32 i, k; |
+ |
+ while (n > 0 && mPTLen[n - 1] == 0) { |
+ n--; |
+ } |
+ PutBits(nbit, n); |
+ i = 0; |
+ while (i < n) { |
+ k = mPTLen[i++]; |
+ if (k <= 6) { |
+ PutBits(3, k); |
+ } else { |
+ PutBits(k - 3, (1U << (k - 3)) - 2); |
+ } |
+ if (i == Special) { |
+ while (i < 6 && mPTLen[i] == 0) { |
+ i++; |
+ } |
+ PutBits(2, (i - 3) & 3); |
+ } |
+ } |
+} |
+ |
+STATIC |
+VOID |
+WriteCLen () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Outputs the code length array for Char&Length Set |
+ |
+Arguments: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ INT32 i, k, n, Count; |
+ |
+ n = NC; |
+ while (n > 0 && mCLen[n - 1] == 0) { |
+ n--; |
+ } |
+ PutBits(CBIT, n); |
+ i = 0; |
+ while (i < n) { |
+ k = mCLen[i++]; |
+ if (k == 0) { |
+ Count = 1; |
+ while (i < n && mCLen[i] == 0) { |
+ i++; |
+ Count++; |
+ } |
+ if (Count <= 2) { |
+ for (k = 0; k < Count; k++) { |
+ PutBits(mPTLen[0], mPTCode[0]); |
+ } |
+ } else if (Count <= 18) { |
+ PutBits(mPTLen[1], mPTCode[1]); |
+ PutBits(4, Count - 3); |
+ } else if (Count == 19) { |
+ PutBits(mPTLen[0], mPTCode[0]); |
+ PutBits(mPTLen[1], mPTCode[1]); |
+ PutBits(4, 15); |
+ } else { |
+ PutBits(mPTLen[2], mPTCode[2]); |
+ PutBits(CBIT, Count - 20); |
+ } |
+ } else { |
+ PutBits(mPTLen[k + 2], mPTCode[k + 2]); |
+ } |
+ } |
+} |
+ |
+STATIC |
+VOID |
+EncodeC ( |
+ IN INT32 c |
+ ) |
+{ |
+ PutBits(mCLen[c], mCCode[c]); |
+} |
+ |
+STATIC |
+VOID |
+EncodeP ( |
+ IN UINT32 p |
+ ) |
+{ |
+ UINT32 c, q; |
+ |
+ c = 0; |
+ q = p; |
+ while (q) { |
+ q >>= 1; |
+ c++; |
+ } |
+ PutBits(mPTLen[c], mPTCode[c]); |
+ if (c > 1) { |
+ PutBits(c - 1, p & (0xFFFFU >> (17 - c))); |
+ } |
+} |
+ |
+STATIC |
+VOID |
+SendBlock () |
+/*++ |
+ |
+Routine Description: |
+ |
+ Huffman code the block and output it. |
+ |
+Argument: (VOID) |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ UINT32 i, k, Flags, Root, Pos, Size; |
+ Flags = 0; |
+ |
+ Root = MakeTree(NC, mCFreq, mCLen, mCCode); |
+ Size = mCFreq[Root]; |
+ PutBits(16, Size); |
+ if (Root >= NC) { |
+ CountTFreq(); |
+ Root = MakeTree(NT, mTFreq, mPTLen, mPTCode); |
+ if (Root >= NT) { |
+ WritePTLen(NT, TBIT, 3); |
+ } else { |
+ PutBits(TBIT, 0); |
+ PutBits(TBIT, Root); |
+ } |
+ WriteCLen(); |
+ } else { |
+ PutBits(TBIT, 0); |
+ PutBits(TBIT, 0); |
+ PutBits(CBIT, 0); |
+ PutBits(CBIT, Root); |
+ } |
+ Root = MakeTree(NP, mPFreq, mPTLen, mPTCode); |
+ if (Root >= NP) { |
+ WritePTLen(NP, PBIT, -1); |
+ } else { |
+ PutBits(PBIT, 0); |
+ PutBits(PBIT, Root); |
+ } |
+ Pos = 0; |
+ for (i = 0; i < Size; i++) { |
+ if (i % UINT8_BIT == 0) { |
+ Flags = mBuf[Pos++]; |
+ } else { |
+ Flags <<= 1; |
+ } |
+ if (Flags & (1U << (UINT8_BIT - 1))) { |
+ EncodeC(mBuf[Pos++] + (1U << UINT8_BIT)); |
+ k = mBuf[Pos++] << UINT8_BIT; |
+ k += mBuf[Pos++]; |
+ EncodeP(k); |
+ } else { |
+ EncodeC(mBuf[Pos++]); |
+ } |
+ } |
+ for (i = 0; i < NC; i++) { |
+ mCFreq[i] = 0; |
+ } |
+ for (i = 0; i < NP; i++) { |
+ mPFreq[i] = 0; |
+ } |
+} |
+ |
+ |
+STATIC |
+VOID |
+Output ( |
+ IN UINT32 c, |
+ IN UINT32 p |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Outputs an Original Character or a Pointer |
+ |
+Arguments: |
+ |
+ c - The original character or the 'String Length' element of a Pointer |
+ p - The 'Position' field of a Pointer |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ STATIC UINT32 CPos; |
+ |
+ if ((mOutputMask >>= 1) == 0) { |
+ mOutputMask = 1U << (UINT8_BIT - 1); |
+ if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) { |
+ SendBlock(); |
+ mOutputPos = 0; |
+ } |
+ CPos = mOutputPos++; |
+ mBuf[CPos] = 0; |
+ } |
+ mBuf[mOutputPos++] = (UINT8) c; |
+ mCFreq[c]++; |
+ if (c >= (1U << UINT8_BIT)) { |
+ mBuf[CPos] |= mOutputMask; |
+ mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT); |
+ mBuf[mOutputPos++] = (UINT8) p; |
+ c = 0; |
+ while (p) { |
+ p >>= 1; |
+ c++; |
+ } |
+ mPFreq[c]++; |
+ } |
+} |
+ |
+STATIC |
+VOID |
+HufEncodeStart () |
+{ |
+ INT32 i; |
+ |
+ for (i = 0; i < NC; i++) { |
+ mCFreq[i] = 0; |
+ } |
+ for (i = 0; i < NP; i++) { |
+ mPFreq[i] = 0; |
+ } |
+ mOutputPos = mOutputMask = 0; |
+ InitPutBits(); |
+ return; |
+} |
+ |
+STATIC |
+VOID |
+HufEncodeEnd () |
+{ |
+ SendBlock(); |
+ |
+ // |
+ // Flush remaining bits |
+ // |
+ PutBits(UINT8_BIT - 1, 0); |
+ |
+ return; |
+} |
+ |
+ |
+STATIC |
+VOID |
+MakeCrcTable () |
+{ |
+ UINT32 i, j, r; |
+ |
+ for (i = 0; i <= UINT8_MAX; i++) { |
+ r = i; |
+ for (j = 0; j < UINT8_BIT; j++) { |
+ if (r & 1) { |
+ r = (r >> 1) ^ CRCPOLY; |
+ } else { |
+ r >>= 1; |
+ } |
+ } |
+ mCrcTable[i] = (UINT16)r; |
+ } |
+} |
+ |
+STATIC |
+VOID |
+PutBits ( |
+ IN INT32 n, |
+ IN UINT32 x |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Outputs rightmost n bits of x |
+ |
+Argments: |
+ |
+ n - the rightmost n bits of the data is used |
+ x - the data |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ UINT8 Temp; |
+ |
+ if (n < mBitCount) { |
+ mSubBitBuf |= x << (mBitCount -= n); |
+ } else { |
+ |
+ Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount))); |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = Temp; |
+ } |
+ mCompSize++; |
+ |
+ if (n < UINT8_BIT) { |
+ mSubBitBuf = x << (mBitCount = UINT8_BIT - n); |
+ } else { |
+ |
+ Temp = (UINT8)(x >> (n - UINT8_BIT)); |
+ if (mDst < mDstUpperLimit) { |
+ *mDst++ = Temp; |
+ } |
+ mCompSize++; |
+ |
+ mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n); |
+ } |
+ } |
+} |
+ |
+STATIC |
+INT32 |
+FreadCrc ( |
+ OUT UINT8 *p, |
+ IN INT32 n |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Read in source data |
+ |
+Arguments: |
+ |
+ p - the buffer to hold the data |
+ n - number of bytes to read |
+ |
+Returns: |
+ |
+ number of bytes actually read |
+ |
+--*/ |
+{ |
+ INT32 i; |
+ |
+ for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) { |
+ *p++ = *mSrc++; |
+ } |
+ n = i; |
+ |
+ p -= n; |
+ mOrigSize += n; |
+ while (--i >= 0) { |
+ UPDATE_CRC(*p++); |
+ } |
+ return n; |
+} |
+ |
+ |
+STATIC |
+VOID |
+InitPutBits () |
+{ |
+ mBitCount = UINT8_BIT; |
+ mSubBitBuf = 0; |
+} |
+ |
+STATIC |
+VOID |
+CountLen ( |
+ IN INT32 i |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Count the number of each code length for a Huffman tree. |
+ |
+Arguments: |
+ |
+ i - the top node |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ STATIC INT32 Depth = 0; |
+ |
+ if (i < mN) { |
+ mLenCnt[(Depth < 16) ? Depth : 16]++; |
+ } else { |
+ Depth++; |
+ CountLen(mLeft [i]); |
+ CountLen(mRight[i]); |
+ Depth--; |
+ } |
+} |
+ |
+STATIC |
+VOID |
+MakeLen ( |
+ IN INT32 Root |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Create code length array for a Huffman tree |
+ |
+Arguments: |
+ |
+ Root - the root of the tree |
+ |
+--*/ |
+{ |
+ INT32 i, k; |
+ UINT32 Cum; |
+ |
+ for (i = 0; i <= 16; i++) { |
+ mLenCnt[i] = 0; |
+ } |
+ CountLen(Root); |
+ |
+ // |
+ // Adjust the length count array so that |
+ // no code will be generated longer than its designated length |
+ // |
+ |
+ Cum = 0; |
+ for (i = 16; i > 0; i--) { |
+ Cum += mLenCnt[i] << (16 - i); |
+ } |
+ while (Cum != (1U << 16)) { |
+ mLenCnt[16]--; |
+ for (i = 15; i > 0; i--) { |
+ if (mLenCnt[i] != 0) { |
+ mLenCnt[i]--; |
+ mLenCnt[i+1] += 2; |
+ break; |
+ } |
+ } |
+ Cum--; |
+ } |
+ for (i = 16; i > 0; i--) { |
+ k = mLenCnt[i]; |
+ while (--k >= 0) { |
+ mLen[*mSortPtr++] = (UINT8)i; |
+ } |
+ } |
+} |
+ |
+STATIC |
+VOID |
+DownHeap ( |
+ IN INT32 i |
+ ) |
+{ |
+ INT32 j, k; |
+ |
+ // |
+ // priority queue: send i-th entry down heap |
+ // |
+ |
+ k = mHeap[i]; |
+ while ((j = 2 * i) <= mHeapSize) { |
+ if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) { |
+ j++; |
+ } |
+ if (mFreq[k] <= mFreq[mHeap[j]]) { |
+ break; |
+ } |
+ mHeap[i] = mHeap[j]; |
+ i = j; |
+ } |
+ mHeap[i] = (INT16)k; |
+} |
+ |
+STATIC |
+VOID |
+MakeCode ( |
+ IN INT32 n, |
+ IN UINT8 Len[], |
+ OUT UINT16 Code[] |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Assign code to each symbol based on the code length array |
+ |
+Arguments: |
+ |
+ n - number of symbols |
+ Len - the code length array |
+ Code - stores codes for each symbol |
+ |
+Returns: (VOID) |
+ |
+--*/ |
+{ |
+ INT32 i; |
+ UINT16 Start[18]; |
+ |
+ Start[1] = 0; |
+ for (i = 1; i <= 16; i++) { |
+ Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1); |
+ } |
+ for (i = 0; i < n; i++) { |
+ Code[i] = Start[Len[i]]++; |
+ } |
+} |
+ |
+STATIC |
+INT32 |
+MakeTree ( |
+ IN INT32 NParm, |
+ IN UINT16 FreqParm[], |
+ OUT UINT8 LenParm[], |
+ OUT UINT16 CodeParm[] |
+ ) |
+/*++ |
+ |
+Routine Description: |
+ |
+ Generates Huffman codes given a frequency distribution of symbols |
+ |
+Arguments: |
+ |
+ NParm - number of symbols |
+ FreqParm - frequency of each symbol |
+ LenParm - code length for each symbol |
+ CodeParm - code for each symbol |
+ |
+Returns: |
+ |
+ Root of the Huffman tree. |
+ |
+--*/ |
+{ |
+ INT32 i, j, k, Avail; |
+ |
+ // |
+ // make tree, calculate len[], return root |
+ // |
+ |
+ mN = NParm; |
+ mFreq = FreqParm; |
+ mLen = LenParm; |
+ Avail = mN; |
+ mHeapSize = 0; |
+ mHeap[1] = 0; |
+ for (i = 0; i < mN; i++) { |
+ mLen[i] = 0; |
+ if (mFreq[i]) { |
+ mHeap[++mHeapSize] = (INT16)i; |
+ } |
+ } |
+ if (mHeapSize < 2) { |
+ CodeParm[mHeap[1]] = 0; |
+ return mHeap[1]; |
+ } |
+ for (i = mHeapSize / 2; i >= 1; i--) { |
+ |
+ // |
+ // make priority queue |
+ // |
+ DownHeap(i); |
+ } |
+ mSortPtr = CodeParm; |
+ do { |
+ i = mHeap[1]; |
+ if (i < mN) { |
+ *mSortPtr++ = (UINT16)i; |
+ } |
+ mHeap[1] = mHeap[mHeapSize--]; |
+ DownHeap(1); |
+ j = mHeap[1]; |
+ if (j < mN) { |
+ *mSortPtr++ = (UINT16)j; |
+ } |
+ k = Avail++; |
+ mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]); |
+ mHeap[1] = (INT16)k; |
+ DownHeap(1); |
+ mLeft[k] = (UINT16)i; |
+ mRight[k] = (UINT16)j; |
+ } while (mHeapSize > 1); |
+ |
+ mSortPtr = CodeParm; |
+ MakeLen(k); |
+ MakeCode(NParm, LenParm, CodeParm); |
+ |
+ // |
+ // return root |
+ // |
+ return k; |
+} |