From d89aac244c8a9d895d0148b363de42a05e3c2de0 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Mon, 10 Nov 2014 17:48:59 +0100 Subject: [PATCH] UEFITool 0.19.2 - correct a bug with legacy EFI1.1/Tiano compression routines, which lead to possible image corruption --- Tiano/EfiTianoCompress.c | 3027 +++++++++++++++----------------- Tiano/EfiTianoCompress.h | 28 +- Tiano/EfiTianoCompressLegacy.c | 1858 ++++++++++++++++++++ ffsengine.cpp | 52 +- uefitool.cpp | 2 +- uefitool.pro | 5 +- 6 files changed, 3364 insertions(+), 1608 deletions(-) create mode 100644 Tiano/EfiTianoCompressLegacy.c diff --git a/Tiano/EfiTianoCompress.c b/Tiano/EfiTianoCompress.c index d13864c..334e791 100644 --- a/Tiano/EfiTianoCompress.c +++ b/Tiano/EfiTianoCompress.c @@ -1,260 +1,244 @@ -/* EFI11/Tiano Compress Implementation +/** @file +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. Copyright (c) 2014, Nikolaj Schlej -Copyright (c) 2006 - 2008, Intel Corporation +Copyright (c) 2006 - 2014, 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, -WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. -Module Name: - -EfiTianoCompress.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 "EfiTianoCompress.h" + // // Macro Definitions // -#undef UINT8_MAX -typedef INT32 NODE; -#define UINT8_MAX 0xff -#define UINT8_BIT 8 -#define THRESHOLD 3 -#define INIT_CRC 0 -#define WNDBIT 19 -#define WNDSIZ (1U << WNDBIT) -#define MAXMATCH 256 -#define BLKSIZ (1U << 14) // 16 * 1024U -#define PERC_FLAG 0x80000000U -#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) + +#undef UINT8_MAX +typedef INT16 NODE; +#define UINT8_MAX 0xff +#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 5 -#define NT (CODE_BIT + 3) -#define TBIT 5 + +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +//#define PBIT 4 +UINT8 gPBIT = 4; +#define NT (CODE_BIT + 3) +#define TBIT 5 #if NT > NP -#define NPT NT + #define NPT NT #else -#define NPT NP + #define NPT NP #endif + // // Function Prototypes // STATIC - VOID - PutDword( - UINT32 Data - ); +VOID +PutDword( + IN UINT32 Data + ); STATIC - INT32 - AllocateMemory ( - VOID - ); +EFI_STATUS +AllocateMemory ( + ); STATIC - VOID - FreeMemory ( - VOID - ); +VOID +FreeMemory ( + ); -STATIC - VOID - InitSlide ( - VOID - ); +STATIC +VOID +InitSlide ( + ); -STATIC - NODE - Child ( - NODE NodeQ, - UINT8 CharC - ); +STATIC +NODE +Child ( + IN NODE q, + IN UINT8 c + ); -STATIC - VOID - MakeChild ( - NODE NodeQ, - UINT8 CharC, - NODE NodeR - ); +STATIC +VOID +MakeChild ( + IN NODE q, + IN UINT8 c, + IN NODE r + ); + +STATIC +VOID +Split ( + IN NODE Old + ); -STATIC - VOID - Split ( - NODE Old - ); +STATIC +VOID +InsertNode ( + ); + +STATIC +VOID +DeleteNode ( + ); -STATIC - VOID - InsertNode ( - VOID - ); +STATIC +VOID +GetNextMatch ( + ); + +STATIC +EFI_STATUS +Encode ( + ); -STATIC - VOID - DeleteNode ( - VOID - ); +STATIC +VOID +CountTFreq ( + ); -STATIC - VOID - GetNextMatch ( - VOID - ); +STATIC +VOID +WritePTLen ( + IN INT32 n, + IN INT32 nbit, + IN INT32 Special + ); -STATIC - INT32 - Encode ( - VOID - ); +STATIC +VOID +WriteCLen ( + ); + +STATIC +VOID +EncodeC ( + IN INT32 c + ); -STATIC - VOID - CountTFreq ( - VOID - ); +STATIC +VOID +EncodeP ( + IN UINT32 p + ); -STATIC - VOID - WritePTLen ( - INT32 Number, - INT32 nbit, - INT32 Special - ); +STATIC +VOID +SendBlock ( + ); + +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ); -STATIC - VOID - WriteCLen ( - VOID - ); +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 - EncodeC ( - INT32 Value - ); +STATIC +VOID +MakeLen ( + IN INT32 Root + ); + +STATIC +VOID +DownHeap ( + IN INT32 i + ); -STATIC - VOID - EncodeP ( - UINT32 Value - ); +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[] + ); -STATIC - VOID - SendBlock ( - VOID - ); - -STATIC - VOID - Output ( - UINT32 c, - UINT32 p - ); - -STATIC - VOID - HufEncodeStart ( - VOID - ); - -STATIC - VOID - HufEncodeEnd ( - VOID - ); - -STATIC - VOID - MakeCrcTable ( - VOID - ); - -STATIC - VOID - PutBits ( - INT32 Number, - UINT32 Value - ); - -STATIC - INT32 - FreadCrc ( - UINT8 *Pointer, - INT32 Number - ); - -STATIC - VOID - InitPutBits ( - VOID - ); - -STATIC - VOID - CountLen ( - INT32 Index - ); - -STATIC - VOID - MakeLen ( - INT32 Root - ); - -STATIC - VOID - DownHeap ( - INT32 Index - ); - -STATIC - VOID - MakeCode ( - INT32 Number, - UINT8 Len[ ], - UINT16 Code[] -); - -STATIC - INT32 - MakeTree ( - INT32 NParm, - UINT16 FreqParm[], - UINT8 LenParm[ ], - UINT16 CodeParm[] -); // // Global Variables // + STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; @@ -263,28 +247,124 @@ 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 UINT8 mPbit; +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 // -UINT8 -EfiCompress( -CONST VOID *SrcBuffer, -CONST UINT64 SrcSize, -VOID *DstBuffer, -UINT64 *DstSize + +EFI_STATUS +EfiCompress ( + IN VOID *SrcBuffer, + IN UINT32 SrcSize, + IN VOID *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; + gPBIT = 4; + + 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; + } + +} + +EFI_STATUS +TianoCompress( +IN VOID *SrcBuffer, +IN UINT32 SrcSize, +IN VOID *DstBuffer, +IN OUT UINT32 *DstSize ) /*++ Routine Description: -The internal implementation of [Efi/Tiano]Compress(). +The main compression routine. Arguments: @@ -296,21 +376,17 @@ the size of the actual compressed data. Returns: -EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case, +EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case, DstSize contains the size needed. EFI_SUCCESS - Compression is successful. -EFI_OUT_OF_RESOURCES - No resource to complete function. -EFI_INVALID_PARAMETER - Parameter supplied is wrong. --*/ { - INT32 Status; + EFI_STATUS Status = EFI_SUCCESS; // // Initializations // - mPbit = 4; - mBufSiz = 0; mBuf = NULL; mText = NULL; @@ -320,8 +396,9 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. mParent = NULL; mPrev = NULL; mNext = NULL; + gPBIT = 5; - mSrc = (UINT8*) SrcBuffer; + mSrc = SrcBuffer; mSrcUpperLimit = mSrc + SrcSize; mDst = DstBuffer; mDstUpperLimit = mDst + *DstSize; @@ -337,18 +414,21 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. // // Compress it // + Status = Encode(); - if (Status) { + if (EFI_ERROR(Status)) { return EFI_OUT_OF_RESOURCES; } + // // Null terminate the compressed data // if (mDst < mDstUpperLimit) { *mDst++ = 0; } + // - // Fill compressed size and original size + // Fill in compressed size and original size // mDst = DstBuffer; PutDword(mCompSize + 1); @@ -357,6 +437,7 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. // // Return // + if (mCompSize + 1 + 8 > *DstSize) { *DstSize = mCompSize + 1 + 8; return EFI_BUFFER_TOO_SMALL; @@ -368,1486 +449,1240 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. } -UINT8 -TianoCompress ( -CONST VOID *SrcBuffer, -CONST UINT64 SrcSize, -VOID *DstBuffer, -UINT64 *DstSize -) - /*++ +STATIC +VOID +PutDword( + IN UINT32 Data + ) +/*++ - Routine Description: +Routine Description: - The internal implementation of [Efi/Tiano]Compress(). + Put a dword to output stream + +Arguments: - 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. - Version - The version of de/compression algorithm. - Version 1 for UEFI 2.0 de/compression algorithm. - Version 2 for Tiano de/compression algorithm. - - Returns: - - EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case, - DstSize contains the size needed. - EFI_SUCCESS - Compression is successful. - EFI_OUT_OF_RESOURCES - No resource to complete function. - EFI_INVALID_PARAMETER - Parameter supplied is wrong. - - --*/ + Data - the dword to put + +Returns: (VOID) + +--*/ { - INT32 Status; + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff); + } - // - // Initializations - // - mPbit = 5; + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff); + } - mBufSiz = 0; - mBuf = NULL; - mText = NULL; - mLevel = NULL; - mChildCount = NULL; - mPosition = NULL; - mParent = NULL; - mPrev = NULL; - mNext = NULL; - - mSrc = (UINT8*) 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 (Status) { - return EFI_OUT_OF_RESOURCES; - } - // - // Null terminate the compressed data - // - if (mDst < mDstUpperLimit) { - *mDst++ = 0; - } - // - // Fill 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; - } + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff); + } + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff); + } } STATIC - VOID - PutDword ( - UINT32 Data - ) - /*++ +EFI_STATUS +AllocateMemory () +/*++ - Routine Description: +Routine Description: - Put a DWORD to output stream + Allocate memory spaces for data structures used in compression process + +Argements: (VOID) - Arguments: +Returns: - Data - the DWORD to put + EFI_SUCCESS - Memory is allocated successfully + EFI_OUT_OF_RESOURCES - Allocation fails - Returns: (VOID) - - --*/ +--*/ { - if (mDst < mDstUpperLimit) { - *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff); - } + UINT32 i; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) { + mText[i] = 0; + } - 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 - INT32 - AllocateMemory ( - VOID - ) - /*++ - - Routine Description: - - Allocate memory spaces for data structures used compression process - - Arguments: - VOID - - Returns: - - EFI_SUCCESS - Memory is allocated successfully - EFI_OUT_OF_RESOURCES - Allocation fails - - --*/ -{ - UINT32 Index; - - mText = malloc (WNDSIZ * 2 + MAXMATCH); - for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) { - mText[Index] = 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 = BLKSIZ; - mBuf = malloc (mBufSiz); - while (mBuf == NULL) { - mBufSiz = (mBufSiz / 10U) * 9U; - if (mBufSiz < 4 * 1024U) { - return EFI_OUT_OF_RESOURCES; - } - - mBuf = malloc (mBufSiz); - } - - mBuf[0] = 0; - - return EFI_SUCCESS; + 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 ( - VOID - ) - /*++ +FreeMemory () +/*++ - Routine Description: +Routine Description: - Called when compression is completed to free memory previously allocated. + Called when compression is completed to free memory previously allocated. + +Arguments: (VOID) - Arguments: (VOID) +Returns: (VOID) - Returns: (VOID) - - --*/ +--*/ { - if (mText != NULL) { - free (mText); - } + 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); + } - if (mLevel != NULL) { - free (mLevel); - } + return; +} - if (mChildCount != NULL) { - free (mChildCount); - } - if (mPosition != NULL) { - free (mPosition); - } +STATIC +VOID +InitSlide () +/*++ - if (mParent != NULL) { - free (mParent); - } +Routine Description: - if (mPrev != NULL) { - free (mPrev); - } + Initialize String Info Log data structures + +Arguments: (VOID) - if (mNext != NULL) { - free (mNext); - } +Returns: (VOID) - if (mBuf != NULL) { - free (mBuf); - } +--*/ +{ + NODE i; - return ; + 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 - VOID - InitSlide ( - VOID - ) - /*++ +EFI_STATUS +Encode () +/*++ - Routine Description: +Routine Description: - Initialize String Info Log data structures + The main controlling routine for compression process. - Arguments: (VOID) +Arguments: (VOID) - Returns: (VOID) +Returns: + + EFI_SUCCESS - The compression is successful + EFI_OUT_0F_RESOURCES - Not enough memory for compression process - --*/ +--*/ { - NODE Index; + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; - for (Index = (NODE) WNDSIZ; Index <= (NODE) WNDSIZ + UINT8_MAX; Index++) { - mLevel[Index] = 1; - mPosition[Index] = NIL; // sentinel - } + Status = AllocateMemory(); + if (EFI_ERROR(Status)) { + FreeMemory(); + return Status; + } - for (Index = (NODE) WNDSIZ; Index < (NODE) WNDSIZ * 2; Index++) { - mParent[Index] = NIL; - } + InitSlide(); + + HufEncodeStart(); - mAvail = 1; - for (Index = 1; Index < (NODE) WNDSIZ - 1; Index++) { - mNext[Index] = (NODE) (Index + 1); - } + 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; +} - mNext[WNDSIZ - 1] = NIL; - for (Index = (NODE) WNDSIZ * 2; Index <= (NODE) MAX_HASH_VAL; Index++) { - mNext[Index] = NIL; - } +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, gPBIT, -1); + } else { + PutBits(gPBIT, 0); + PutBits(gPBIT, 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 - NODE - Child ( - NODE NodeQ, - UINT8 CharC - ) - /*++ - - Routine Description: - - Find child node given the parent node and the edge character - - Arguments: - - NodeQ - the parent node - CharC - the edge character - - Returns: - - The child node (NIL if not found) - - --*/ +VOID +HufEncodeStart () { - NODE NodeR; + INT32 i; - NodeR = mNext[HASH (NodeQ, CharC)]; - // - // sentinel - // - mParent[NIL] = NodeQ; - while (mParent[NodeR] != NodeQ) { - NodeR = mNext[NodeR]; - } - - return NodeR; + 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 - MakeChild ( - NODE Parent, - UINT8 CharC, - NODE Child - ) - /*++ - - Routine Description: - - Create a new child for a given parent node. - - Arguments: - - Parent - the parent node - CharC - the edge character - Child - the child node - - Returns: (VOID) - - --*/ +STATIC +VOID +HufEncodeEnd () { - NODE Node1; - NODE Node2; - - Node1 = (NODE) HASH (Parent, CharC); - Node2 = mNext[Node1]; - mNext[Node1] = Child; - mNext[Child] = Node2; - mPrev[Node2] = Child; - mPrev[Child] = Node1; - mParent[Child] = Parent; - mChildCount[Parent]++; + SendBlock(); + + // + // Flush remaining bits + // + PutBits(UINT8_BIT - 1, 0); + + return; } -STATIC - VOID - Split ( - NODE Old - ) - /*++ - Routine Description: - - Split a node. - - Arguments: - - Old - the node to split - - Returns: (VOID) - - --*/ +STATIC +VOID +MakeCrcTable () { - NODE New; - NODE TempNode; + UINT32 i, j, r; - New = mAvail; - mAvail = mNext[New]; - mChildCount[New] = 0; - TempNode = mPrev[Old]; - mPrev[New] = TempNode; - mNext[TempNode] = New; - TempNode = mNext[Old]; - mNext[New] = TempNode; - mPrev[TempNode] = New; - mParent[New] = mParent[Old]; - mLevel[New] = (UINT8) mMatchLen; - mPosition[New] = mPos; - MakeChild (New, mText[mMatchPos + mMatchLen], Old); - MakeChild (New, mText[mPos + mMatchLen], mPos); + 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 - InsertNode ( - VOID - ) - /*++ +STATIC +VOID +PutBits ( + IN INT32 n, + IN UINT32 x + ) +/*++ - Routine Description: +Routine Description: - Insert string info for current position into the String Info Log + Outputs rightmost n bits of x - Arguments: (VOID) +Argments: - Returns: (VOID) + n - the rightmost n bits of the data is used + x - the data - --*/ +Returns: (VOID) + +--*/ { - NODE NodeQ; - NODE NodeR; - NODE Index2; - NODE NodeT; - UINT8 CharC; - UINT8 *t1; - UINT8 *t2; - - if (mMatchLen >= 4) { - // - // We have just got a long match, the target tree - // can be located by MatchPos + 1. Traverse the tree - // from bottom up to get to a proper starting point. - // The usage of PERC_FLAG ensures proper node deletion - // DeleteNode() later. - // - mMatchLen--; - NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ); - NodeQ = mParent[NodeR]; - while (NodeQ == NIL) { - NodeR = mNext[NodeR]; - NodeQ = mParent[NodeR]; - } - - while (mLevel[NodeQ] >= mMatchLen) { - NodeR = NodeQ; - NodeQ = mParent[NodeQ]; - } - - NodeT = NodeQ; - while (mPosition[NodeT] < 0) { - mPosition[NodeT] = mPos; - NodeT = mParent[NodeT]; - } - - if (NodeT < (NODE) WNDSIZ) { - mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG); - } - } else { - // - // Locate the target tree - // - NodeQ = (NODE) (mText[mPos] + WNDSIZ); - CharC = mText[mPos + 1]; - NodeR = Child (NodeQ, CharC); - if (NodeR == NIL) { - MakeChild (NodeQ, CharC, 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 (NodeR >= (NODE) WNDSIZ) { - Index2 = MAXMATCH; - mMatchPos = NodeR; - } else { - Index2 = mLevel[NodeR]; - mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); - } - - if (mMatchPos >= mPos) { - mMatchPos -= WNDSIZ; - } - - t1 = &mText[mPos + mMatchLen]; - t2 = &mText[mMatchPos + mMatchLen]; - while (mMatchLen < Index2) { - if (*t1 != *t2) { - Split (NodeR); - return ; - } - - mMatchLen++; - t1++; - t2++; - } - - if (mMatchLen >= MAXMATCH) { - break; - } - - mPosition[NodeR] = mPos; - NodeQ = NodeR; - NodeR = Child (NodeQ, *t1); - if (NodeR == NIL) { - MakeChild (NodeQ, *t1, mPos); - return ; - } - - mMatchLen++; - } - - NodeT = mPrev[NodeR]; - mPrev[mPos] = NodeT; - mNext[NodeT] = mPos; - NodeT = mNext[NodeR]; - mNext[mPos] = NodeT; - mPrev[NodeT] = mPos; - mParent[mPos] = NodeQ; - mParent[NodeR] = NIL; - - // - // Special usage of 'next' - // - mNext[NodeR] = mPos; + 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 - VOID - DeleteNode ( - VOID - ) - /*++ +STATIC +INT32 +FreadCrc ( + OUT UINT8 *p, + IN INT32 n + ) +/*++ - Routine Description: +Routine Description: - Delete outdated string info. (The Usage of PERC_FLAG - ensures a clean deletion) + Read in source data + +Arguments: - Arguments: (VOID) + p - the buffer to hold the data + n - number of bytes to read - Returns: (VOID) +Returns: - --*/ + number of bytes actually read + +--*/ { - NODE NodeQ; - NODE NodeR; - NODE NodeS; - NODE NodeT; - NODE NodeU; + INT32 i; - if (mParent[mPos] == NIL) { - return ; - } + for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) { + *p++ = *mSrc++; + } + n = i; - NodeR = mPrev[mPos]; - NodeS = mNext[mPos]; - mNext[NodeR] = NodeS; - mPrev[NodeS] = NodeR; - NodeR = mParent[mPos]; - mParent[mPos] = NIL; - if (NodeR >= (NODE) WNDSIZ) { - return ; - } - - mChildCount[NodeR]--; - if (mChildCount[NodeR] > 1) { - return ; - } - - NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); - if (NodeT >= mPos) { - NodeT -= WNDSIZ; - } - - NodeS = NodeT; - NodeQ = mParent[NodeR]; - NodeU = mPosition[NodeQ]; - while (NodeU & (UINT32) PERC_FLAG) { - NodeU &= (UINT32)~PERC_FLAG; - if (NodeU >= mPos) { - NodeU -= WNDSIZ; - } - - if (NodeU > NodeS) { - NodeS = NodeU; - } - - mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ); - NodeQ = mParent[NodeQ]; - NodeU = mPosition[NodeQ]; - } - - if (NodeQ < (NODE) WNDSIZ) { - if (NodeU >= mPos) { - NodeU -= WNDSIZ; - } - - if (NodeU > NodeS) { - NodeS = NodeU; - } - - mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG); - } - - NodeS = Child (NodeR, mText[NodeT + mLevel[NodeR]]); - NodeT = mPrev[NodeS]; - NodeU = mNext[NodeS]; - mNext[NodeT] = NodeU; - mPrev[NodeU] = NodeT; - NodeT = mPrev[NodeR]; - mNext[NodeT] = NodeS; - mPrev[NodeS] = NodeT; - NodeT = mNext[NodeR]; - mPrev[NodeT] = NodeS; - mNext[NodeS] = NodeT; - mParent[NodeS] = mParent[NodeR]; - mParent[NodeR] = NIL; - mNext[NodeR] = mAvail; - mAvail = NodeR; + p -= n; + mOrigSize += n; + while (--i >= 0) { + UPDATE_CRC(*p++); + } + return n; } -STATIC - VOID - GetNextMatch ( - VOID - ) - /*++ - Routine Description: - - Advance the current position (read new data if needed). - Delete outdated string info. Find a match string for current position. - - Arguments: (VOID) - - Returns: (VOID) - - --*/ +STATIC +VOID +InitPutBits () { - INT32 Number; - - mRemainder--; - mPos++; - if (mPos == WNDSIZ * 2) { - memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); - Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ); - mRemainder += Number; - mPos = WNDSIZ; - } - - DeleteNode (); - InsertNode (); + mBitCount = UINT8_BIT; + mSubBitBuf = 0; } -STATIC - INT32 - Encode ( - VOID - ) - /*++ +STATIC +VOID +CountLen ( + IN INT32 i + ) +/*++ - Routine Description: +Routine Description: - The mac controlling routine for compression process. + Count the number of each code length for a Huffman tree. + +Arguments: - Arguments: (VOID) + i - the top node + +Returns: (VOID) - Returns: - - EFI_SUCCESS - The compression is successful - EFI_OUT_0F_RESOURCES - Not enough memory for compression process - - --*/ +--*/ { - INT32 Status; - INT32 LastMatchLen; - NODE LastMatchPos; + STATIC INT32 Depth = 0; - Status = AllocateMemory (); - if (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 { - - if (LastMatchLen == THRESHOLD) { - if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) { - Output (mText[mPos - 1], 0); - continue; - } - } - // - // Outputting a pointer is beneficial enough, do it. - // - Output ( - LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), - (mPos - LastMatchPos - 2) & (WNDSIZ - 1) - ); - LastMatchLen--; - while (LastMatchLen > 0) { - GetNextMatch (); - LastMatchLen--; - } - - if (mMatchLen > mRemainder) { - mMatchLen = mRemainder; - } - } - } - - HufEncodeEnd (); - FreeMemory (); - return EFI_SUCCESS; + if (i < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen(mLeft [i]); + CountLen(mRight[i]); + Depth--; + } } -STATIC - VOID - CountTFreq ( - VOID - ) - /*++ +STATIC +VOID +MakeLen ( + IN INT32 Root + ) +/*++ - Routine Description: +Routine Description: - Count the frequencies for the Extra Set + Create code length array for a Huffman tree + +Arguments: - Arguments: (VOID) + Root - the root of the tree - Returns: (VOID) - - --*/ +--*/ { - INT32 Index; - INT32 Index3; - INT32 Number; - INT32 Count; + INT32 i, k; + UINT32 Cum; - for (Index = 0; Index < NT; Index++) { - mTFreq[Index] = 0; - } - - Number = NC; - while (Number > 0 && mCLen[Number - 1] == 0) { - Number--; - } - - Index = 0; - while (Index < Number) { - Index3 = mCLen[Index++]; - if (Index3 == 0) { - Count = 1; - while (Index < Number && mCLen[Index] == 0) { - Index++; - 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[Index3 + 2]++; - } - } + 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 - WritePTLen ( - INT32 Number, - INT32 nbit, - INT32 Special - ) - /*++ - - Routine Description: - - Outputs the code length array for the Extra Set or the Position Set. - - Arguments: - - Number - 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) - - --*/ +STATIC +VOID +DownHeap ( + IN INT32 i + ) { - INT32 Index; - INT32 Index3; + INT32 j, k; - while (Number > 0 && mPTLen[Number - 1] == 0) { - Number--; - } - - PutBits (nbit, Number); - Index = 0; - while (Index < Number) { - Index3 = mPTLen[Index++]; - if (Index3 <= 6) { - PutBits (3, Index3); - } else { - PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2); - } - - if (Index == Special) { - while (Index < 6 && mPTLen[Index] == 0) { - Index++; - } - - PutBits (2, (Index - 3) & 3); - } - } + // + // 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 - WriteCLen ( - VOID - ) - /*++ +STATIC +VOID +MakeCode ( + IN INT32 n, + IN UINT8 Len[], + OUT UINT16 Code[] + ) +/*++ - Routine Description: +Routine Description: - Outputs the code length array for Char&Length Set + Assign code to each symbol based on the code length array + +Arguments: - Arguments: (VOID) + n - number of symbols + Len - the code length array + Code - stores codes for each symbol - Returns: (VOID) +Returns: (VOID) - --*/ +--*/ { - INT32 Index; - INT32 Index3; - INT32 Number; - INT32 Count; + INT32 i; + UINT16 Start[18]; - Number = NC; - while (Number > 0 && mCLen[Number - 1] == 0) { - Number--; - } - - PutBits (CBIT, Number); - Index = 0; - while (Index < Number) { - Index3 = mCLen[Index++]; - if (Index3 == 0) { - Count = 1; - while (Index < Number && mCLen[Index] == 0) { - Index++; - Count++; - } - - if (Count <= 2) { - for (Index3 = 0; Index3 < Count; Index3++) { - 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[Index3 + 2], mPTCode[Index3 + 2]); - } - } + 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 - VOID - EncodeC ( - INT32 Value - ) +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. + +--*/ { - PutBits (mCLen[Value], mCCode[Value]); + 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; } -STATIC - VOID - EncodeP ( - UINT32 Value - ) -{ - UINT32 Index; - UINT32 NodeQ; - - Index = 0; - NodeQ = Value; - while (NodeQ) { - NodeQ >>= 1; - Index++; - } - - PutBits (mPTLen[Index], mPTCode[Index]); - if (Index > 1) { - PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1))); - } -} - -STATIC - VOID - SendBlock ( - VOID - ) - /*++ - - Routine Description: - - Huffman code the block and output it. - - Arguments: - (VOID) - - Returns: - (VOID) - - --*/ -{ - UINT32 Index; - UINT32 Index2; - UINT32 Index3; - UINT32 Flags; - UINT32 Root; - UINT32 Pos; - UINT32 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, mPbit, -1); - } else { - PutBits (mPbit, 0); - PutBits (mPbit, Root); - } - - Pos = 0; - for (Index = 0; Index < Size; Index++) { - if (Index % UINT8_BIT == 0) { - Flags = mBuf[Pos++]; - } else { - Flags <<= 1; - } - - if (Flags & (1U << (UINT8_BIT - 1))) { - EncodeC (mBuf[Pos++] + (1U << UINT8_BIT)); - Index3 = mBuf[Pos++]; - for (Index2 = 0; Index2 < 3; Index2++) { - Index3 <<= UINT8_BIT; - Index3 += mBuf[Pos++]; - } - - EncodeP (Index3); - } else { - EncodeC (mBuf[Pos++]); - } - } - - for (Index = 0; Index < NC; Index++) { - mCFreq[Index] = 0; - } - - for (Index = 0; Index < NP; Index++) { - mPFreq[Index] = 0; - } -} - -STATIC - VOID - Output ( - UINT32 CharC, - UINT32 Pos - ) - /*++ - - Routine Description: - - Outputs an Original Character or a Pointer - - Arguments: - - CharC - The original character or the 'String Length' element of a Pointer - Pos - The 'Position' field of a Pointer - - Returns: (VOID) - - --*/ -{ - STATIC UINT32 CPos; - - if ((mOutputMask >>= 1) == 0) { - mOutputMask = 1U << (UINT8_BIT - 1); - // - // Check the buffer overflow per outputting UINT8_BIT symbols - // which is an Original Character or a Pointer. The biggest - // symbol is a Pointer which occupies 5 bytes. - // - if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) { - SendBlock (); - mOutputPos = 0; - } - - CPos = mOutputPos++; - mBuf[CPos] = 0; - } - - mBuf[mOutputPos++] = (UINT8) CharC; - mCFreq[CharC]++; - if (CharC >= (1U << UINT8_BIT)) { - mBuf[CPos] |= mOutputMask; - mBuf[mOutputPos++] = (UINT8) (Pos >> 24); - mBuf[mOutputPos++] = (UINT8) (Pos >> 16); - mBuf[mOutputPos++] = (UINT8) (Pos >> (UINT8_BIT)); - mBuf[mOutputPos++] = (UINT8) Pos; - CharC = 0; - while (Pos) { - Pos >>= 1; - CharC++; - } - - mPFreq[CharC]++; - } -} - -STATIC - VOID - HufEncodeStart ( - VOID - ) -{ - INT32 Index; - - for (Index = 0; Index < NC; Index++) { - mCFreq[Index] = 0; - } - - for (Index = 0; Index < NP; Index++) { - mPFreq[Index] = 0; - } - - mOutputPos = mOutputMask = 0; - InitPutBits (); - return ; -} - -STATIC - VOID - HufEncodeEnd ( - VOID - ) -{ - SendBlock (); - - // - // Flush remaining bits - // - PutBits (UINT8_BIT - 1, 0); - - return ; -} - -STATIC - VOID - MakeCrcTable ( - VOID - ) -{ - UINT32 Index; - UINT32 Index2; - UINT32 Temp; - - for (Index = 0; Index <= UINT8_MAX; Index++) { - Temp = Index; - for (Index2 = 0; Index2 < UINT8_BIT; Index2++) { - if (Temp & 1) { - Temp = (Temp >> 1) ^ CRCPOLY; - } else { - Temp >>= 1; - } - } - - mCrcTable[Index] = (UINT16) Temp; - } -} - -STATIC - VOID - PutBits ( - INT32 Number, - UINT32 Value - ) - /*++ - - Routine Description: - - Outputs rightmost n bits of x - - Arguments: - - Number - the rightmost n bits of the data is used - x - the data - - Returns: (VOID) - - --*/ -{ - UINT8 Temp; - - while (Number >= mBitCount) { - // - // Number -= mBitCount should never equal to 32 - // - Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount))); - if (mDst < mDstUpperLimit) { - *mDst++ = Temp; - } - - mCompSize++; - mSubBitBuf = 0; - mBitCount = UINT8_BIT; - } - - mSubBitBuf |= Value << (mBitCount -= Number); -} - -STATIC - INT32 - FreadCrc ( - UINT8 *Pointer, - INT32 Number - ) - /*++ - - Routine Description: - - Read source data - - Arguments: - - Pointer - the buffer to hold the data - Number - number of bytes to read - - Returns: - - number of bytes actually read - - --*/ -{ - INT32 Index; - - for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) { - *Pointer++ = *mSrc++; - } - - Number = Index; - - Pointer -= Number; - mOrigSize += Number; - Index--; - while (Index >= 0) { - UPDATE_CRC (*Pointer++); - Index--; - } - - return Number; -} - -STATIC - VOID - InitPutBits ( - VOID - ) -{ - mBitCount = UINT8_BIT; - mSubBitBuf = 0; -} - -STATIC - VOID - CountLen ( - INT32 Index - ) - /*++ - - Routine Description: - - Count the number of each code length for a Huffman tree. - - Arguments: - - Index - the top node - - Returns: (VOID) - - --*/ -{ - STATIC INT32 Depth = 0; - - if (Index < mN) { - mLenCnt[(Depth < 16) ? Depth : 16]++; - } else { - Depth++; - CountLen (mLeft[Index]); - CountLen (mRight[Index]); - Depth--; - } -} - -STATIC - VOID - MakeLen ( - INT32 Root - ) - /*++ - - Routine Description: - - Create code length array for a Huffman tree - - Arguments: - - Root - the root of the tree - - Returns: - - VOID - - --*/ -{ - INT32 Index; - INT32 Index3; - UINT32 Cum; - - for (Index = 0; Index <= 16; Index++) { - mLenCnt[Index] = 0; - } - - CountLen (Root); - - // - // Adjust the length count array so that - // no code will be generated longer than its designated length - // - Cum = 0; - for (Index = 16; Index > 0; Index--) { - Cum += mLenCnt[Index] << (16 - Index); - } - - while (Cum != (1U << 16)) { - mLenCnt[16]--; - for (Index = 15; Index > 0; Index--) { - if (mLenCnt[Index] != 0) { - mLenCnt[Index]--; - mLenCnt[Index + 1] += 2; - break; - } - } - - Cum--; - } - - for (Index = 16; Index > 0; Index--) { - Index3 = mLenCnt[Index]; - Index3--; - while (Index3 >= 0) { - mLen[*mSortPtr++] = (UINT8) Index; - Index3--; - } - } -} - -STATIC - VOID - DownHeap ( - INT32 Index - ) -{ - INT32 Index2; - INT32 Index3; - - // - // priority queue: send Index-th entry down heap - // - Index3 = mHeap[Index]; - Index2 = 2 * Index; - while (Index2 <= mHeapSize) { - if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) { - Index2++; - } - - if (mFreq[Index3] <= mFreq[mHeap[Index2]]) { - break; - } - - mHeap[Index] = mHeap[Index2]; - Index = Index2; - Index2 = 2 * Index; - } - - mHeap[Index] = (INT16) Index3; -} - -STATIC - VOID - MakeCode ( - INT32 Number, - UINT8 Len[ ], - UINT16 Code[] -) - /*++ - - Routine Description: - - Assign code to each symbol based on the code length array - - Arguments: - - Number - number of symbols - Len - the code length array - Code - stores codes for each symbol - - Returns: (VOID) - - --*/ -{ - INT32 Index; - UINT16 Start[18]; - - Start[1] = 0; - for (Index = 1; Index <= 16; Index++) { - Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1); - } - - for (Index = 0; Index < Number; Index++) { - Code[Index] = Start[Len[Index]]++; - } -} - -STATIC - INT32 - MakeTree ( - INT32 NParm, - UINT16 FreqParm[], - UINT8 LenParm[ ], - 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 Index; - INT32 Index2; - INT32 Index3; - INT32 Avail; - - // - // make tree, calculate len[], return root - // - mN = NParm; - mFreq = FreqParm; - mLen = LenParm; - Avail = mN; - mHeapSize = 0; - mHeap[1] = 0; - for (Index = 0; Index < mN; Index++) { - mLen[Index] = 0; - if (mFreq[Index]) { - mHeapSize++; - mHeap[mHeapSize] = (INT16) Index; - } - } - - if (mHeapSize < 2) { - CodeParm[mHeap[1]] = 0; - return mHeap[1]; - } - - for (Index = mHeapSize / 2; Index >= 1; Index--) { - // - // make priority queue - // - DownHeap (Index); - } - - mSortPtr = CodeParm; - do { - Index = mHeap[1]; - if (Index < mN) { - *mSortPtr++ = (UINT16) Index; - } - - mHeap[1] = mHeap[mHeapSize--]; - DownHeap (1); - Index2 = mHeap[1]; - if (Index2 < mN) { - *mSortPtr++ = (UINT16) Index2; - } - - Index3 = Avail++; - mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]); - mHeap[1] = (INT16) Index3; - DownHeap (1); - mLeft[Index3] = (UINT16) Index; - mRight[Index3] = (UINT16) Index2; - } while (mHeapSize > 1); - - mSortPtr = CodeParm; - MakeLen (Index3); - MakeCode (NParm, LenParm, CodeParm); - - // - // return root - // - return Index3; -} diff --git a/Tiano/EfiTianoCompress.h b/Tiano/EfiTianoCompress.h index a0e38af..e5c2fb9 100644 --- a/Tiano/EfiTianoCompress.h +++ b/Tiano/EfiTianoCompress.h @@ -55,15 +55,23 @@ extern "C" { EFI_INVALID_PARAMETER - Parameter supplied is wrong. --*/ - UINT8 + EFI_STATUS TianoCompress( CONST VOID *SrcBuffer, - CONST UINT64 SrcSize, + UINT32 SrcSize, VOID *DstBuffer, - UINT64 *DstSize + UINT32 *DstSize ) ; + EFI_STATUS + TianoCompressLegacy( + CONST VOID *SrcBuffer, + UINT32 SrcSize, + VOID *DstBuffer, + UINT32 *DstSize + ) + ; /*++ Routine Description: @@ -87,12 +95,20 @@ extern "C" { EFI_INVALID_PARAMETER - Parameter supplied is wrong. --*/ - UINT8 + EFI_STATUS EfiCompress( CONST VOID *SrcBuffer, - CONST UINT64 SrcSize, + UINT32 SrcSize, VOID *DstBuffer, - UINT64 *DstSize + UINT32 *DstSize + ) + ; + EFI_STATUS + EfiCompressLegacy( + CONST VOID *SrcBuffer, + UINT32 SrcSize, + VOID *DstBuffer, + UINT32 *DstSize ) ; diff --git a/Tiano/EfiTianoCompressLegacy.c b/Tiano/EfiTianoCompressLegacy.c new file mode 100644 index 0000000..9711c1b --- /dev/null +++ b/Tiano/EfiTianoCompressLegacy.c @@ -0,0 +1,1858 @@ +/* EFI11/Tiano Compress Implementation + +Copyright (c) 2014, Nikolaj Schlej +Copyright (c) 2006 - 2008, Intel Corporation +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, +WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +Module Name: + +EfiTianoCompressLegacy.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. + +Notes: + +This legacy compression code can produce incorrect output, +but has better compression ratio as newer releases + +*/ + +#include "EfiTianoCompress.h" + +// +// Macro Definitions +// +#undef UINT8_MAX +typedef INT32 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 19 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define BLKSIZ (1U << 14) // 16 * 1024U +#define PERC_FLAG 0x80000000U +#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 5 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP +#define NPT NT +#else +#define NPT NP +#endif +// +// Function Prototypes +// + +STATIC + VOID + PutDword( + UINT32 Data + ); + +STATIC + INT32 + AllocateMemory ( + VOID + ); + +STATIC + VOID + FreeMemory ( + VOID + ); + +STATIC + VOID + InitSlide ( + VOID + ); + +STATIC + NODE + Child ( + NODE NodeQ, + UINT8 CharC + ); + +STATIC + VOID + MakeChild ( + NODE NodeQ, + UINT8 CharC, + NODE NodeR + ); + +STATIC + VOID + Split ( + NODE Old + ); + +STATIC + VOID + InsertNode ( + VOID + ); + +STATIC + VOID + DeleteNode ( + VOID + ); + +STATIC + VOID + GetNextMatch ( + VOID + ); + +STATIC + INT32 + Encode ( + VOID + ); + +STATIC + VOID + CountTFreq ( + VOID + ); + +STATIC + VOID + WritePTLen ( + INT32 Number, + INT32 nbit, + INT32 Special + ); + +STATIC + VOID + WriteCLen ( + VOID + ); + +STATIC + VOID + EncodeC ( + INT32 Value + ); + +STATIC + VOID + EncodeP ( + UINT32 Value + ); + +STATIC + VOID + SendBlock ( + VOID + ); + +STATIC + VOID + Output ( + UINT32 c, + UINT32 p + ); + +STATIC + VOID + HufEncodeStart ( + VOID + ); + +STATIC + VOID + HufEncodeEnd ( + VOID + ); + +STATIC + VOID + MakeCrcTable ( + VOID + ); + +STATIC + VOID + PutBits ( + INT32 Number, + UINT32 Value + ); + +STATIC + INT32 + FreadCrc ( + UINT8 *Pointer, + INT32 Number + ); + +STATIC + VOID + InitPutBits ( + VOID + ); + +STATIC + VOID + CountLen ( + INT32 Index + ); + +STATIC + VOID + MakeLen ( + INT32 Root + ); + +STATIC + VOID + DownHeap ( + INT32 Index + ); + +STATIC + VOID + MakeCode ( + INT32 Number, + UINT8 Len[ ], + UINT16 Code[] +); + +STATIC + INT32 + MakeTree ( + INT32 NParm, + UINT16 FreqParm[], + UINT8 LenParm[ ], + 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 UINT8 mPbit; + +STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; + +// +// functions +// +UINT8 +EfiCompressLegacy( +CONST VOID *SrcBuffer, +UINT32 SrcSize, +VOID *DstBuffer, +UINT32 *DstSize +) +/*++ + +Routine Description: + +The internal implementation of [Efi/Tiano]Compress(). + +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. this case, +DstSize contains the size needed. +EFI_SUCCESS - Compression is successful. +EFI_OUT_OF_RESOURCES - No resource to complete function. +EFI_INVALID_PARAMETER - Parameter supplied is wrong. + +--*/ +{ + INT32 Status; + + // + // Initializations + // + mPbit = 4; + + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + mSrc = (UINT8*) 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 (Status) { + return EFI_OUT_OF_RESOURCES; + } + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + // + // Fill 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; + } + +} + +UINT8 +TianoCompressLegacy ( +CONST VOID *SrcBuffer, +UINT32 SrcSize, +VOID *DstBuffer, +UINT32 *DstSize +) + /*++ + + Routine Description: + + The internal implementation of [Efi/Tiano]Compress(). + + 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. + Version - The version of de/compression algorithm. + Version 1 for UEFI 2.0 de/compression algorithm. + Version 2 for Tiano de/compression algorithm. + + Returns: + + EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case, + DstSize contains the size needed. + EFI_SUCCESS - Compression is successful. + EFI_OUT_OF_RESOURCES - No resource to complete function. + EFI_INVALID_PARAMETER - Parameter supplied is wrong. + + --*/ +{ + INT32 Status; + + // + // Initializations + // + mPbit = 5; + + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + mSrc = (UINT8*) 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 (Status) { + return EFI_OUT_OF_RESOURCES; + } + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + // + // Fill 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 ( + 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 + INT32 + AllocateMemory ( + VOID + ) + /*++ + + Routine Description: + + Allocate memory spaces for data structures used compression process + + Arguments: + VOID + + Returns: + + EFI_SUCCESS - Memory is allocated successfully + EFI_OUT_OF_RESOURCES - Allocation fails + + --*/ +{ + UINT32 Index; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) { + mText[Index] = 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 = BLKSIZ; + mBuf = malloc (mBufSiz); + while (mBuf == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + + mBuf = malloc (mBufSiz); + } + + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +VOID + FreeMemory ( + VOID + ) + /*++ + + Routine Description: + + Called when compression is completed to free memory previously allocated. + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + if (mText != NULL) { + free (mText); + } + + if (mLevel != NULL) { + free (mLevel); + } + + if (mChildCount != NULL) { + free (mChildCount); + } + + if (mPosition != NULL) { + free (mPosition); + } + + if (mParent != NULL) { + free (mParent); + } + + if (mPrev != NULL) { + free (mPrev); + } + + if (mNext != NULL) { + free (mNext); + } + + if (mBuf != NULL) { + free (mBuf); + } + + return ; +} + +STATIC + VOID + InitSlide ( + VOID + ) + /*++ + + Routine Description: + + Initialize String Info Log data structures + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + NODE Index; + + for (Index = (NODE) WNDSIZ; Index <= (NODE) WNDSIZ + UINT8_MAX; Index++) { + mLevel[Index] = 1; + mPosition[Index] = NIL; // sentinel + } + + for (Index = (NODE) WNDSIZ; Index < (NODE) WNDSIZ * 2; Index++) { + mParent[Index] = NIL; + } + + mAvail = 1; + for (Index = 1; Index < (NODE) WNDSIZ - 1; Index++) { + mNext[Index] = (NODE) (Index + 1); + } + + mNext[WNDSIZ - 1] = NIL; + for (Index = (NODE) WNDSIZ * 2; Index <= (NODE) MAX_HASH_VAL; Index++) { + mNext[Index] = NIL; + } +} + +STATIC + NODE + Child ( + NODE NodeQ, + UINT8 CharC + ) + /*++ + + Routine Description: + + Find child node given the parent node and the edge character + + Arguments: + + NodeQ - the parent node + CharC - the edge character + + Returns: + + The child node (NIL if not found) + + --*/ +{ + NODE NodeR; + + NodeR = mNext[HASH (NodeQ, CharC)]; + // + // sentinel + // + mParent[NIL] = NodeQ; + while (mParent[NodeR] != NodeQ) { + NodeR = mNext[NodeR]; + } + + return NodeR; +} + +STATIC + VOID + MakeChild ( + NODE Parent, + UINT8 CharC, + NODE Child + ) + /*++ + + Routine Description: + + Create a new child for a given parent node. + + Arguments: + + Parent - the parent node + CharC - the edge character + Child - the child node + + Returns: (VOID) + + --*/ +{ + NODE Node1; + NODE Node2; + + Node1 = (NODE) HASH (Parent, CharC); + Node2 = mNext[Node1]; + mNext[Node1] = Child; + mNext[Child] = Node2; + mPrev[Node2] = Child; + mPrev[Child] = Node1; + mParent[Child] = Parent; + mChildCount[Parent]++; +} + +STATIC + VOID + Split ( + NODE Old + ) + /*++ + + Routine Description: + + Split a node. + + Arguments: + + Old - the node to split + + Returns: (VOID) + + --*/ +{ + NODE New; + NODE TempNode; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + TempNode = mPrev[Old]; + mPrev[New] = TempNode; + mNext[TempNode] = New; + TempNode = mNext[Old]; + mNext[New] = TempNode; + mPrev[TempNode] = 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 ( + VOID + ) + /*++ + + Routine Description: + + Insert string info for current position into the String Info Log + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + NODE NodeQ; + NODE NodeR; + NODE Index2; + NODE NodeT; + UINT8 CharC; + UINT8 *t1; + UINT8 *t2; + + if (mMatchLen >= 4) { + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Traverse the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // DeleteNode() later. + // + mMatchLen--; + NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ); + NodeQ = mParent[NodeR]; + while (NodeQ == NIL) { + NodeR = mNext[NodeR]; + NodeQ = mParent[NodeR]; + } + + while (mLevel[NodeQ] >= mMatchLen) { + NodeR = NodeQ; + NodeQ = mParent[NodeQ]; + } + + NodeT = NodeQ; + while (mPosition[NodeT] < 0) { + mPosition[NodeT] = mPos; + NodeT = mParent[NodeT]; + } + + if (NodeT < (NODE) WNDSIZ) { + mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG); + } + } else { + // + // Locate the target tree + // + NodeQ = (NODE) (mText[mPos] + WNDSIZ); + CharC = mText[mPos + 1]; + NodeR = Child (NodeQ, CharC); + if (NodeR == NIL) { + MakeChild (NodeQ, CharC, 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 (NodeR >= (NODE) WNDSIZ) { + Index2 = MAXMATCH; + mMatchPos = NodeR; + } else { + Index2 = mLevel[NodeR]; + mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + } + + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + + t1 = &mText[mPos + mMatchLen]; + t2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < Index2) { + if (*t1 != *t2) { + Split (NodeR); + return ; + } + + mMatchLen++; + t1++; + t2++; + } + + if (mMatchLen >= MAXMATCH) { + break; + } + + mPosition[NodeR] = mPos; + NodeQ = NodeR; + NodeR = Child (NodeQ, *t1); + if (NodeR == NIL) { + MakeChild (NodeQ, *t1, mPos); + return ; + } + + mMatchLen++; + } + + NodeT = mPrev[NodeR]; + mPrev[mPos] = NodeT; + mNext[NodeT] = mPos; + NodeT = mNext[NodeR]; + mNext[mPos] = NodeT; + mPrev[NodeT] = mPos; + mParent[mPos] = NodeQ; + mParent[NodeR] = NIL; + + // + // Special usage of 'next' + // + mNext[NodeR] = mPos; + +} + +STATIC + VOID + DeleteNode ( + VOID + ) + /*++ + + Routine Description: + + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion) + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + NODE NodeQ; + NODE NodeR; + NODE NodeS; + NODE NodeT; + NODE NodeU; + + if (mParent[mPos] == NIL) { + return ; + } + + NodeR = mPrev[mPos]; + NodeS = mNext[mPos]; + mNext[NodeR] = NodeS; + mPrev[NodeS] = NodeR; + NodeR = mParent[mPos]; + mParent[mPos] = NIL; + if (NodeR >= (NODE) WNDSIZ) { + return ; + } + + mChildCount[NodeR]--; + if (mChildCount[NodeR] > 1) { + return ; + } + + NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + if (NodeT >= mPos) { + NodeT -= WNDSIZ; + } + + NodeS = NodeT; + NodeQ = mParent[NodeR]; + NodeU = mPosition[NodeQ]; + while (NodeU & (UINT32) PERC_FLAG) { + NodeU &= (UINT32)~PERC_FLAG; + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ); + NodeQ = mParent[NodeQ]; + NodeU = mPosition[NodeQ]; + } + + if (NodeQ < (NODE) WNDSIZ) { + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG); + } + + NodeS = Child (NodeR, mText[NodeT + mLevel[NodeR]]); + NodeT = mPrev[NodeS]; + NodeU = mNext[NodeS]; + mNext[NodeT] = NodeU; + mPrev[NodeU] = NodeT; + NodeT = mPrev[NodeR]; + mNext[NodeT] = NodeS; + mPrev[NodeS] = NodeT; + NodeT = mNext[NodeR]; + mPrev[NodeT] = NodeS; + mNext[NodeS] = NodeT; + mParent[NodeS] = mParent[NodeR]; + mParent[NodeR] = NIL; + mNext[NodeR] = mAvail; + mAvail = NodeR; +} + +STATIC + VOID + GetNextMatch ( + VOID + ) + /*++ + + Routine Description: + + Advance the current position (read new data if needed). + Delete outdated string info. Find a match string for current position. + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + INT32 Number; + + mRemainder--; + mPos++; + if (mPos == WNDSIZ * 2) { + memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); + Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += Number; + mPos = WNDSIZ; + } + + DeleteNode (); + InsertNode (); +} + +STATIC + INT32 + Encode ( + VOID + ) + /*++ + + Routine Description: + + The mac controlling routine for compression process. + + Arguments: (VOID) + + Returns: + + EFI_SUCCESS - The compression is successful + EFI_OUT_0F_RESOURCES - Not enough memory for compression process + + --*/ +{ + INT32 Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory (); + if (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 { + + if (LastMatchLen == THRESHOLD) { + if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) { + Output (mText[mPos - 1], 0); + continue; + } + } + // + // Outputting a pointer is beneficial enough, do it. + // + Output ( + LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1) + ); + LastMatchLen--; + while (LastMatchLen > 0) { + GetNextMatch (); + LastMatchLen--; + } + + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd (); + FreeMemory (); + return EFI_SUCCESS; +} + +STATIC + VOID + CountTFreq ( + VOID + ) + /*++ + + Routine Description: + + Count the frequencies for the Extra Set + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + for (Index = 0; Index < NT; Index++) { + mTFreq[Index] = 0; + } + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + 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[Index3 + 2]++; + } + } +} + +STATIC + VOID + WritePTLen ( + INT32 Number, + INT32 nbit, + INT32 Special + ) + /*++ + + Routine Description: + + Outputs the code length array for the Extra Set or the Position Set. + + Arguments: + + Number - 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 Index; + INT32 Index3; + + while (Number > 0 && mPTLen[Number - 1] == 0) { + Number--; + } + + PutBits (nbit, Number); + Index = 0; + while (Index < Number) { + Index3 = mPTLen[Index++]; + if (Index3 <= 6) { + PutBits (3, Index3); + } else { + PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2); + } + + if (Index == Special) { + while (Index < 6 && mPTLen[Index] == 0) { + Index++; + } + + PutBits (2, (Index - 3) & 3); + } + } +} + +STATIC + VOID + WriteCLen ( + VOID + ) + /*++ + + Routine Description: + + Outputs the code length array for Char&Length Set + + Arguments: (VOID) + + Returns: (VOID) + + --*/ +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + PutBits (CBIT, Number); + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + Count++; + } + + if (Count <= 2) { + for (Index3 = 0; Index3 < Count; Index3++) { + 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[Index3 + 2], mPTCode[Index3 + 2]); + } + } +} + +STATIC + VOID + EncodeC ( + INT32 Value + ) +{ + PutBits (mCLen[Value], mCCode[Value]); +} + +STATIC + VOID + EncodeP ( + UINT32 Value + ) +{ + UINT32 Index; + UINT32 NodeQ; + + Index = 0; + NodeQ = Value; + while (NodeQ) { + NodeQ >>= 1; + Index++; + } + + PutBits (mPTLen[Index], mPTCode[Index]); + if (Index > 1) { + PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1))); + } +} + +STATIC + VOID + SendBlock ( + VOID + ) + /*++ + + Routine Description: + + Huffman code the block and output it. + + Arguments: + (VOID) + + Returns: + (VOID) + + --*/ +{ + UINT32 Index; + UINT32 Index2; + UINT32 Index3; + UINT32 Flags; + UINT32 Root; + UINT32 Pos; + UINT32 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, mPbit, -1); + } else { + PutBits (mPbit, 0); + PutBits (mPbit, Root); + } + + Pos = 0; + for (Index = 0; Index < Size; Index++) { + if (Index % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + + if (Flags & (1U << (UINT8_BIT - 1))) { + EncodeC (mBuf[Pos++] + (1U << UINT8_BIT)); + Index3 = mBuf[Pos++]; + for (Index2 = 0; Index2 < 3; Index2++) { + Index3 <<= UINT8_BIT; + Index3 += mBuf[Pos++]; + } + + EncodeP (Index3); + } else { + EncodeC (mBuf[Pos++]); + } + } + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } +} + +STATIC + VOID + Output ( + UINT32 CharC, + UINT32 Pos + ) + /*++ + + Routine Description: + + Outputs an Original Character or a Pointer + + Arguments: + + CharC - The original character or the 'String Length' element of a Pointer + Pos - The 'Position' field of a Pointer + + Returns: (VOID) + + --*/ +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + // + // Check the buffer overflow per outputting UINT8_BIT symbols + // which is an Original Character or a Pointer. The biggest + // symbol is a Pointer which occupies 5 bytes. + // + if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) { + SendBlock (); + mOutputPos = 0; + } + + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + + mBuf[mOutputPos++] = (UINT8) CharC; + mCFreq[CharC]++; + if (CharC >= (1U << UINT8_BIT)) { + mBuf[CPos] |= mOutputMask; + mBuf[mOutputPos++] = (UINT8) (Pos >> 24); + mBuf[mOutputPos++] = (UINT8) (Pos >> 16); + mBuf[mOutputPos++] = (UINT8) (Pos >> (UINT8_BIT)); + mBuf[mOutputPos++] = (UINT8) Pos; + CharC = 0; + while (Pos) { + Pos >>= 1; + CharC++; + } + + mPFreq[CharC]++; + } +} + +STATIC + VOID + HufEncodeStart ( + VOID + ) +{ + INT32 Index; + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } + + mOutputPos = mOutputMask = 0; + InitPutBits (); + return ; +} + +STATIC + VOID + HufEncodeEnd ( + VOID + ) +{ + SendBlock (); + + // + // Flush remaining bits + // + PutBits (UINT8_BIT - 1, 0); + + return ; +} + +STATIC + VOID + MakeCrcTable ( + VOID + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 Temp; + + for (Index = 0; Index <= UINT8_MAX; Index++) { + Temp = Index; + for (Index2 = 0; Index2 < UINT8_BIT; Index2++) { + if (Temp & 1) { + Temp = (Temp >> 1) ^ CRCPOLY; + } else { + Temp >>= 1; + } + } + + mCrcTable[Index] = (UINT16) Temp; + } +} + +STATIC + VOID + PutBits ( + INT32 Number, + UINT32 Value + ) + /*++ + + Routine Description: + + Outputs rightmost n bits of x + + Arguments: + + Number - the rightmost n bits of the data is used + x - the data + + Returns: (VOID) + + --*/ +{ + UINT8 Temp; + + while (Number >= mBitCount) { + // + // Number -= mBitCount should never equal to 32 + // + Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + + mCompSize++; + mSubBitBuf = 0; + mBitCount = UINT8_BIT; + } + + mSubBitBuf |= Value << (mBitCount -= Number); +} + +STATIC + INT32 + FreadCrc ( + UINT8 *Pointer, + INT32 Number + ) + /*++ + + Routine Description: + + Read source data + + Arguments: + + Pointer - the buffer to hold the data + Number - number of bytes to read + + Returns: + + number of bytes actually read + + --*/ +{ + INT32 Index; + + for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) { + *Pointer++ = *mSrc++; + } + + Number = Index; + + Pointer -= Number; + mOrigSize += Number; + Index--; + while (Index >= 0) { + UPDATE_CRC (*Pointer++); + Index--; + } + + return Number; +} + +STATIC + VOID + InitPutBits ( + VOID + ) +{ + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +STATIC + VOID + CountLen ( + INT32 Index + ) + /*++ + + Routine Description: + + Count the number of each code length for a Huffman tree. + + Arguments: + + Index - the top node + + Returns: (VOID) + + --*/ +{ + STATIC INT32 Depth = 0; + + if (Index < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen (mLeft[Index]); + CountLen (mRight[Index]); + Depth--; + } +} + +STATIC + VOID + MakeLen ( + INT32 Root + ) + /*++ + + Routine Description: + + Create code length array for a Huffman tree + + Arguments: + + Root - the root of the tree + + Returns: + + VOID + + --*/ +{ + INT32 Index; + INT32 Index3; + UINT32 Cum; + + for (Index = 0; Index <= 16; Index++) { + mLenCnt[Index] = 0; + } + + CountLen (Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + Cum = 0; + for (Index = 16; Index > 0; Index--) { + Cum += mLenCnt[Index] << (16 - Index); + } + + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (Index = 15; Index > 0; Index--) { + if (mLenCnt[Index] != 0) { + mLenCnt[Index]--; + mLenCnt[Index + 1] += 2; + break; + } + } + + Cum--; + } + + for (Index = 16; Index > 0; Index--) { + Index3 = mLenCnt[Index]; + Index3--; + while (Index3 >= 0) { + mLen[*mSortPtr++] = (UINT8) Index; + Index3--; + } + } +} + +STATIC + VOID + DownHeap ( + INT32 Index + ) +{ + INT32 Index2; + INT32 Index3; + + // + // priority queue: send Index-th entry down heap + // + Index3 = mHeap[Index]; + Index2 = 2 * Index; + while (Index2 <= mHeapSize) { + if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) { + Index2++; + } + + if (mFreq[Index3] <= mFreq[mHeap[Index2]]) { + break; + } + + mHeap[Index] = mHeap[Index2]; + Index = Index2; + Index2 = 2 * Index; + } + + mHeap[Index] = (INT16) Index3; +} + +STATIC + VOID + MakeCode ( + INT32 Number, + UINT8 Len[ ], + UINT16 Code[] +) + /*++ + + Routine Description: + + Assign code to each symbol based on the code length array + + Arguments: + + Number - number of symbols + Len - the code length array + Code - stores codes for each symbol + + Returns: (VOID) + + --*/ +{ + INT32 Index; + UINT16 Start[18]; + + Start[1] = 0; + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1); + } + + for (Index = 0; Index < Number; Index++) { + Code[Index] = Start[Len[Index]]++; + } +} + +STATIC + INT32 + MakeTree ( + INT32 NParm, + UINT16 FreqParm[], + UINT8 LenParm[ ], + 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 Index; + INT32 Index2; + INT32 Index3; + INT32 Avail; + + // + // make tree, calculate len[], return root + // + mN = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mN; + mHeapSize = 0; + mHeap[1] = 0; + for (Index = 0; Index < mN; Index++) { + mLen[Index] = 0; + if (mFreq[Index]) { + mHeapSize++; + mHeap[mHeapSize] = (INT16) Index; + } + } + + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + + for (Index = mHeapSize / 2; Index >= 1; Index--) { + // + // make priority queue + // + DownHeap (Index); + } + + mSortPtr = CodeParm; + do { + Index = mHeap[1]; + if (Index < mN) { + *mSortPtr++ = (UINT16) Index; + } + + mHeap[1] = mHeap[mHeapSize--]; + DownHeap (1); + Index2 = mHeap[1]; + if (Index2 < mN) { + *mSortPtr++ = (UINT16) Index2; + } + + Index3 = Avail++; + mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]); + mHeap[1] = (INT16) Index3; + DownHeap (1); + mLeft[Index3] = (UINT16) Index; + mRight[Index3] = (UINT16) Index2; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen (Index3); + MakeCode (NParm, LenParm, CodeParm); + + // + // return root + // + return Index3; +} diff --git a/ffsengine.cpp b/ffsengine.cpp index bd0bf95..6d1e2c9 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -895,7 +895,7 @@ UINT8 FfsEngine::parseVolume(const QByteArray & volume, QModelIndex & index, co .arg(volumeHeader->Revision) .hexarg(volumeHeader->Attributes, 8) .arg(empty ? "1" : "0") - .hexarg(headerSize, 4); + .hexarg(headerSize, 8); // Extended header present if (volumeHeader->Revision > 1 && volumeHeader->ExtHeaderOffset) { EFI_FIRMWARE_VOLUME_EXT_HEADER* extendedHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER*)(volume.constData() + volumeHeader->ExtHeaderOffset); @@ -2242,7 +2242,28 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA break; case COMPRESSION_ALGORITHM_EFI11: { - UINT64 compressedSize = 0; + // Try legacy function first + UINT32 compressedSize = 0; + if (EfiCompressLegacy(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) + return ERR_STANDARD_COMPRESSION_FAILED; + compressed = new UINT8[compressedSize]; + if (EfiCompressLegacy(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { + delete[] compressed; + return ERR_STANDARD_COMPRESSION_FAILED; + } + compressedData = QByteArray((const char*)compressed, compressedSize); + + // Check that compressed data can be decompressed normally + QByteArray decompressed; + if (decompress(compressedData, EFI_STANDARD_COMPRESSION, decompressed, NULL) == ERR_SUCCESS + && decompressed == data) { + delete[] compressed; + return ERR_SUCCESS; + } + delete[] compressed; + + // Legacy function failed, use current one + compressedSize = 0; if (EfiCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) return ERR_STANDARD_COMPRESSION_FAILED; compressed = new UINT8[compressedSize]; @@ -2251,13 +2272,36 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA return ERR_STANDARD_COMPRESSION_FAILED; } compressedData = QByteArray((const char*)compressed, compressedSize); + + // New functions will be trusted here, because another check will reduce performance delete[] compressed; return ERR_SUCCESS; } break; case COMPRESSION_ALGORITHM_TIANO: { - UINT64 compressedSize = 0; + // Try legacy function first + UINT32 compressedSize = 0; + if (TianoCompressLegacy(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) + return ERR_STANDARD_COMPRESSION_FAILED; + compressed = new UINT8[compressedSize]; + if (TianoCompressLegacy(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { + delete[] compressed; + return ERR_STANDARD_COMPRESSION_FAILED; + } + compressedData = QByteArray((const char*)compressed, compressedSize); + + // Check that compressed data can be decompressed normally + QByteArray decompressed; + if (decompress(compressedData, EFI_STANDARD_COMPRESSION, decompressed, NULL) == ERR_SUCCESS + && decompressed == data) { + delete[] compressed; + return ERR_SUCCESS; + } + delete[] compressed; + + // Legacy function failed, use current one + compressedSize = 0; if (TianoCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) return ERR_STANDARD_COMPRESSION_FAILED; compressed = new UINT8[compressedSize]; @@ -2266,6 +2310,8 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA return ERR_STANDARD_COMPRESSION_FAILED; } compressedData = QByteArray((const char*)compressed, compressedSize); + + // New functions will be trusted here, because another check will reduce performance delete[] compressed; return ERR_SUCCESS; } diff --git a/uefitool.cpp b/uefitool.cpp index 7fcdaf1..f156204 100644 --- a/uefitool.cpp +++ b/uefitool.cpp @@ -17,7 +17,7 @@ UEFITool::UEFITool(QWidget *parent) : QMainWindow(parent), ui(new Ui::UEFITool), -version(tr("0.19.1.1")) +version(tr("0.19.2")) { clipboard = QApplication::clipboard(); diff --git a/uefitool.pro b/uefitool.pro index 73e258c..5d97cc8 100644 --- a/uefitool.pro +++ b/uefitool.pro @@ -21,8 +21,9 @@ SOURCES += uefitool_main.cpp \ LZMA/SDK/C/LzmaDec.c \ LZMA/SDK/C/LzmaEnc.c \ Tiano/EfiTianoDecompress.c \ - Tiano/EfiTianoCompress.c - + Tiano/EfiTianoCompress.c \ + Tiano/EfiTianoCompressLegacy.c + HEADERS += uefitool.h \ searchdialog.h \ basetypes.h \