/** @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) 2007 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "Compress.h" #include "Decompress.h" #include "TianoCompress.h" #include "EfiUtilityMsgs.h" #include "ParseInf.h" #include #include "assert.h" // // Macro Definitions // static BOOLEAN VerboseMode = FALSE; static BOOLEAN QuietMode = FALSE; #undef UINT8_MAX #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 // // Global Variables // STATIC BOOLEAN ENCODE = FALSE; STATIC BOOLEAN DECODE = FALSE; STATIC BOOLEAN UEFIMODE = FALSE; 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; static UINT64 DebugLevel; static BOOLEAN DebugMode; // // functions // EFI_STATUS TianoCompress ( IN UINT8 *SrcBuffer, IN UINT32 SrcSize, IN UINT8 *DstBuffer, IN OUT 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 Version - The version of de/compression algorithm. Version 1 for EFI 1.1 de/compression algorithm. Version 2 for Tiano de/compression algorithm. Returns: 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. --*/ { EFI_STATUS Status; // // 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 ( VOID ) /*++ Routine Description: Allocate memory spaces for data structures used in compression process Arguments: VOID Returns: EFI_SUCCESS - Memory is allocated successfully EFI_OUT_OF_RESOURCES - Allocation fails --*/ { UINT32 Index; mText = malloc (WNDSIZ * 2 + MAXMATCH); if (mText == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } 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)); if (mLevel == NULL || mChildCount == NULL || mPosition == NULL || mParent == NULL || mPrev == NULL || mNext == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } 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 = WNDSIZ; Index <= WNDSIZ + UINT8_MAX; Index++) { mLevel[Index] = 1; mPosition[Index] = NIL; // sentinel } for (Index = WNDSIZ; Index < WNDSIZ * 2; Index++) { mParent[Index] = NIL; } mAvail = 1; for (Index = 1; Index < WNDSIZ - 1; Index++) { mNext[Index] = (NODE) (Index + 1); } mNext[WNDSIZ - 1] = NIL; for (Index = WNDSIZ * 2; Index <= MAX_HASH_VAL; Index++) { mNext[Index] = NIL; } } STATIC NODE Child ( IN NODE NodeQ, IN 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 ( IN NODE Parent, IN UINT8 CharC, IN 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 // in 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 < 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 >= 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 >= 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 < 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 in 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 EFI_STATUS Encode ( VOID ) /*++ 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 { 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 ( IN INT32 Number, IN INT32 nbit, IN 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 ( IN INT32 Value ) { PutBits (mCLen[Value], mCCode[Value]); } STATIC VOID EncodeP ( IN 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, PBIT, -1); } else { PutBits (PBIT, 0); PutBits (PBIT, 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 ( IN UINT32 CharC, IN 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 outputing 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 ( IN INT32 Number, IN 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 ( OUT UINT8 *Pointer, IN INT32 Number ) /*++ Routine Description: Read in 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 ( IN 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 ( IN 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 ( IN 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 ( IN INT32 Number, IN UINT8 Len[ ], OUT 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 ( 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 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; } EFI_STATUS GetFileContents ( IN char *InputFileName, OUT UINT8 *FileBuffer, OUT UINT32 *BufferLength ) /*++ Routine Description: Get the contents of file specified in InputFileName into FileBuffer. Arguments: InputFileName - Name of the input file. FileBuffer - Output buffer to contain data BufferLength - Actual length of the data Returns: EFI_SUCCESS on successful return EFI_ABORTED if unable to open input file. --*/ { UINTN Size; UINTN FileSize; FILE *InputFile; Size = 0; // // Copy the file contents to the output buffer. // InputFile = fopen (LongFilePath (InputFileName), "rb"); if (InputFile == NULL) { Error (NULL, 0, 0001, "Error opening file: %s", InputFileName); return EFI_ABORTED; } fseek (InputFile, 0, SEEK_END); FileSize = ftell (InputFile); fseek (InputFile, 0, SEEK_SET); // // Now read the contents of the file into the buffer // if (FileSize > 0 && FileBuffer != NULL) { if (fread (FileBuffer, FileSize, 1, InputFile) != 1) { Error (NULL, 0, 0004, "Error reading contents of input file: %s", InputFileName); fclose (InputFile); return EFI_ABORTED; } } fclose (InputFile); Size += (UINTN) FileSize; *BufferLength = Size; if (FileBuffer != NULL) { return EFI_SUCCESS; } else { return EFI_BUFFER_TOO_SMALL; } } VOID Version ( VOID ) /*++ Routine Description: Displays the standard utility information to SDTOUT Arguments: None Returns: None --*/ { fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); } VOID Usage ( VOID ) /*++ Routine Description: Displays the utility usage syntax to STDOUT Arguments: None Returns: None --*/ { // // Summary usage // fprintf (stdout, "Usage: %s -e|-d [options] \n\n", UTILITY_NAME); // // Copyright declaration // fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n"); // // Details Option // fprintf (stdout, "Options:\n"); fprintf (stdout, " --uefi\n\ Enable UefiCompress, use TianoCompress when without this option\n"); fprintf (stdout, " -o FileName, --output FileName\n\ File will be created to store the output content.\n"); fprintf (stdout, " -v, --verbose\n\ Turn on verbose output with informational messages.\n"); fprintf (stdout, " -q, --quiet\n\ Disable all messages except key message and fatal error\n"); fprintf (stdout, " --debug [0-9]\n\ Enable debug messages, at input debug level.\n"); fprintf (stdout, " --version\n\ Show program's version number and exit.\n"); fprintf (stdout, " -h, --help\n\ Show this help message and exit.\n"); } int main ( int argc, char *argv[] ) /*++ Routine Description: Main Arguments: command line parameters Returns: EFI_SUCCESS Section header successfully generated and section concatenated. EFI_ABORTED Could not generate the section EFI_OUT_OF_RESOURCES No resource to complete the operation. --*/ { FILE *OutputFile; char *OutputFileName; char *InputFileName; FILE *InputFile; EFI_STATUS Status; UINT8 *FileBuffer; UINT8 *OutBuffer; UINT32 InputLength; UINT32 DstSize; SCRATCH_DATA *Scratch; UINT8 *Src; UINT32 OrigSize; UINT32 CompSize; SetUtilityName(UTILITY_NAME); FileBuffer = NULL; Src = NULL; OutBuffer = NULL; Scratch = NULL; OrigSize = 0; CompSize = 0; InputLength = 0; InputFileName = NULL; OutputFileName = NULL; InputFile = NULL; OutputFile = NULL; DstSize=0; DebugLevel = 0; DebugMode = FALSE; // // Verify the correct number of arguments // if (argc == 1) { Error (NULL, 0, 1001, "Missing options", "No input options specified."); Usage(); return 0; } if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) { Usage(); return 0; } if ((strcmp(argv[1], "--version") == 0)) { Version(); return 0; } argc--; argv++; if (strcmp(argv[0],"-e") == 0) { // // encode the input file // ENCODE = TRUE; argc--; argv++; } else if (strcmp(argv[0], "-d") == 0) { // // decode the input file // DECODE = TRUE; argc--; argv++; } else { // // Error command line // Error (NULL, 0, 1003, "Invalid option value", "the options specified are not recognized."); Usage(); return 1; } while (argc > 0) { if ((strcmp(argv[0], "-v") == 0) || (stricmp(argv[0], "--verbose") == 0)) { VerboseMode = TRUE; argc--; argv++; continue; } if (stricmp(argv[0], "--uefi") == 0) { UEFIMODE = TRUE; argc--; argv++; continue; } if (stricmp (argv[0], "--debug") == 0) { argc-=2; argv++; Status = AsciiStringToUint64(argv[0], FALSE, &DebugLevel); if (DebugLevel > 9) { Error (NULL, 0 ,2000, "Invalid parameter", "Unrecognized argument %s", argv[0]); goto ERROR; } if (DebugLevel>=5 && DebugLevel <=9){ DebugMode = TRUE; } else { DebugMode = FALSE; } argv++; continue; } if ((strcmp(argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { QuietMode = TRUE; argc--; argv++; continue; } if ((strcmp(argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) { if (argv[1] == NULL || argv[1][0] == '-') { Error (NULL, 0, 1003, "Invalid option value", "Output File name is missing for -o option"); goto ERROR; } OutputFileName = argv[1]; argc -=2; argv +=2; continue; } if (argv[0][0]!='-') { InputFileName = argv[0]; argc--; argv++; continue; } Error (NULL, 0, 1000, "Unknown option", argv[0]); goto ERROR; } if (InputFileName == NULL) { Error (NULL, 0, 1001, "Missing options", "No input files specified."); goto ERROR; } // // All Parameters has been parsed, now set the message print level // if (QuietMode) { SetPrintLevel(40); } else if (VerboseMode) { SetPrintLevel(15); } else if (DebugMode) { SetPrintLevel(DebugLevel); } if (VerboseMode) { VerboseMsg("%s tool start.\n", UTILITY_NAME); } Scratch = (SCRATCH_DATA *)malloc(sizeof(SCRATCH_DATA)); if (Scratch == NULL) { Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!"); goto ERROR; } InputFile = fopen (LongFilePath (InputFileName), "rb"); if (InputFile == NULL) { Error (NULL, 0, 0001, "Error opening input file", InputFileName); goto ERROR; } Status = GetFileContents( InputFileName, FileBuffer, &InputLength); if (Status == EFI_BUFFER_TOO_SMALL) { FileBuffer = (UINT8 *) malloc (InputLength); if (FileBuffer == NULL) { Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!"); goto ERROR; } Status = GetFileContents ( InputFileName, FileBuffer, &InputLength ); } if (EFI_ERROR(Status)) { Error (NULL, 0, 0004, "Error getting contents of file: %s", InputFileName); goto ERROR; } if (OutputFileName == NULL) { OutputFileName = DEFAULT_OUTPUT_FILE; } OutputFile = fopen (LongFilePath (OutputFileName), "wb"); if (OutputFile == NULL) { Error (NULL, 0, 0001, "Error opening output file for writing", OutputFileName); goto ERROR; } if (ENCODE) { // // First call TianoCompress to get DstSize // if (DebugMode) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding", NULL); } if (UEFIMODE) { Status = EfiCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize); } else { Status = TianoCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize); } if (Status == EFI_BUFFER_TOO_SMALL) { OutBuffer = (UINT8 *) malloc (DstSize); if (OutBuffer == NULL) { Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!"); goto ERROR; } } if (UEFIMODE) { Status = EfiCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize); } else { Status = TianoCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize); } if (Status != EFI_SUCCESS) { Error (NULL, 0, 0007, "Error compressing file", NULL); goto ERROR; } if (OutBuffer == NULL) { Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!"); goto ERROR; } fwrite(OutBuffer,(size_t)DstSize, 1, OutputFile); fclose(OutputFile); fclose(InputFile); free(Scratch); free(FileBuffer); free(OutBuffer); if (DebugMode) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding Successful!\n", NULL); } if (VerboseMode) { VerboseMsg("Encoding successful\n"); } return 0; } else if (DECODE) { if (DebugMode) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Decoding\n", NULL); } if (UEFIMODE) { Status = Extract((VOID *)FileBuffer, InputLength, (VOID *)&OutBuffer, &DstSize, 1); if (Status != EFI_SUCCESS) { goto ERROR; } fwrite(OutBuffer, (size_t)(DstSize), 1, OutputFile); } else { if (InputLength < 8){ Error (NULL, 0, 3000, "Invalid", "The input file %s is too small.", InputFileName); goto ERROR; } // // Get Compressed file original size // Src = (UINT8 *)FileBuffer; OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); CompSize = Src[0] + (Src[1] << 8) + (Src[2] <<16) + (Src[3] <<24); // // Allocate OutputBuffer // if (InputLength < CompSize + 8 || (CompSize + 8) < 8) { Error (NULL, 0, 3000, "Invalid", "The input file %s data is invalid.", InputFileName); goto ERROR; } OutBuffer = (UINT8 *)malloc(OrigSize); if (OutBuffer == NULL) { Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!"); goto ERROR; } Status = TDecompress((VOID *)FileBuffer, (VOID *)OutBuffer, (VOID *)Scratch, 2); if (Status != EFI_SUCCESS) { goto ERROR; } fwrite(OutBuffer, (size_t)(Scratch->mOrigSize), 1, OutputFile); } fclose(OutputFile); fclose(InputFile); if (Scratch != NULL) { free(Scratch); } if (FileBuffer != NULL) { free(FileBuffer); } if (OutBuffer != NULL) { free(OutBuffer); } if (DebugMode) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding successful!\n", NULL); } if (VerboseMode) { VerboseMsg("Decoding successful\n"); } return 0; } ERROR: if (DebugMode) { if (ENCODE) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding Error\n", NULL); } else if (DECODE) { DebugMsg(UTILITY_NAME, 0, DebugLevel, "Decoding Error\n", NULL); } } if (OutputFile != NULL) { fclose(OutputFile); } if (InputFile != NULL) { fclose (InputFile); } if (Scratch != NULL) { free(Scratch); } if (FileBuffer != NULL) { free(FileBuffer); } if (OutBuffer != NULL) { free(OutBuffer); } if (VerboseMode) { VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ()); } return GetUtilityStatus (); } VOID FillBuf ( IN SCRATCH_DATA *Sd, IN UINT16 NumOfBits ) /*++ Routine Description: Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. Arguments: Sd - The global scratch data NumOfBits - The number of bits to shift and read. Returns: (VOID) --*/ { Sd->mBitBuf = (UINT32) (((UINT64)Sd->mBitBuf) << NumOfBits); while (NumOfBits > Sd->mBitCount) { Sd->mBitBuf |= (UINT32) (((UINT64)Sd->mSubBitBuf) << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); if (Sd->mCompSize > 0) { // // Get 1 byte into SubBitBuf // Sd->mCompSize--; Sd->mSubBitBuf = 0; Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; Sd->mBitCount = 8; } else { // // No more bits from the source, just pad zero bit. // Sd->mSubBitBuf = 0; Sd->mBitCount = 8; } } Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits); Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; } UINT32 GetBits ( IN SCRATCH_DATA *Sd, IN UINT16 NumOfBits ) /*++ Routine Description: Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent NumOfBits of bits from source. Returns NumOfBits of bits that are popped out. Arguments: Sd - The global scratch data. NumOfBits - The number of bits to pop and read. Returns: The bits that are popped out. --*/ { UINT32 OutBits; OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); FillBuf (Sd, NumOfBits); return OutBits; } UINT16 MakeTable ( IN SCRATCH_DATA *Sd, IN UINT16 NumOfChar, IN UINT8 *BitLen, IN UINT16 TableBits, OUT UINT16 *Table ) /*++ Routine Description: Creates Huffman Code mapping table according to code length array. Arguments: Sd - The global scratch data NumOfChar - Number of symbols in the symbol set BitLen - Code length array TableBits - The width of the mapping table Table - The table Returns: 0 - OK. BAD_TABLE - The table is corrupted. --*/ { UINT16 Count[17]; UINT16 Weight[17]; UINT16 Start[18]; UINT16 *Pointer; UINT16 Index3; UINT16 Index; UINT16 Len; UINT16 Char; UINT16 JuBits; UINT16 Avail; UINT16 NextCode; UINT16 Mask; UINT16 WordOfStart; UINT16 WordOfCount; UINT16 MaxTableLength; for (Index = 0; Index <= 16; Index++) { Count[Index] = 0; } for (Index = 0; Index < NumOfChar; Index++) { if (BitLen[Index] > 16) { return (UINT16) BAD_TABLE; } Count[BitLen[Index]]++; } Start[0] = 0; Start[1] = 0; for (Index = 1; Index <= 16; Index++) { WordOfStart = Start[Index]; WordOfCount = Count[Index]; Start[Index + 1] = (UINT16) (WordOfStart + (WordOfCount << (16 - Index))); } if (Start[17] != 0) { // //(1U << 16) // return (UINT16) BAD_TABLE; } JuBits = (UINT16) (16 - TableBits); Weight[0] = 0; for (Index = 1; Index <= TableBits; Index++) { Start[Index] >>= JuBits; Weight[Index] = (UINT16) (1U << (TableBits - Index)); } while (Index <= 16) { Weight[Index] = (UINT16) (1U << (16 - Index)); Index++; } Index = (UINT16) (Start[TableBits + 1] >> JuBits); if (Index != 0) { Index3 = (UINT16) (1U << TableBits); while (Index != Index3) { Table[Index++] = 0; } } Avail = NumOfChar; Mask = (UINT16) (1U << (15 - TableBits)); MaxTableLength = (UINT16) (1U << TableBits); for (Char = 0; Char < NumOfChar; Char++) { Len = BitLen[Char]; if (Len == 0 || Len >= 17) { continue; } NextCode = (UINT16) (Start[Len] + Weight[Len]); if (Len <= TableBits) { if (Start[Len] >= NextCode || NextCode > MaxTableLength){ return (UINT16) BAD_TABLE; } for (Index = Start[Len]; Index < NextCode; Index++) { Table[Index] = Char; } } else { Index3 = Start[Len]; Pointer = &Table[Index3 >> JuBits]; Index = (UINT16) (Len - TableBits); while (Index != 0) { if (*Pointer == 0) { Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; *Pointer = Avail++; } if (Index3 & Mask) { Pointer = &Sd->mRight[*Pointer]; } else { Pointer = &Sd->mLeft[*Pointer]; } Index3 <<= 1; Index--; } *Pointer = Char; } Start[Len] = NextCode; } // // Succeeds // return 0; } UINT32 DecodeP ( IN SCRATCH_DATA *Sd ) /*++ Routine Description: Decodes a position value. Arguments: Sd - the global scratch data Returns: The position value decoded. --*/ { UINT16 Val; UINT32 Mask; UINT32 Pos; Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; if (Val >= MAXNP) { Mask = 1U << (BITBUFSIZ - 1 - 8); do { if (Sd->mBitBuf & Mask) { Val = Sd->mRight[Val]; } else { Val = Sd->mLeft[Val]; } Mask >>= 1; } while (Val >= MAXNP); } // // Advance what we have read // FillBuf (Sd, Sd->mPTLen[Val]); Pos = Val; if (Val > 1) { Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1))); } return Pos; } UINT16 ReadPTLen ( IN SCRATCH_DATA *Sd, IN UINT16 nn, IN UINT16 nbit, IN UINT16 Special ) /*++ Routine Description: Reads code lengths for the Extra Set or the Position Set Arguments: Sd - The global scratch data nn - Number of symbols nbit - Number of bits needed to represent nn Special - The special symbol that needs to be taken care of Returns: 0 - OK. BAD_TABLE - Table is corrupted. --*/ { UINT16 Number; UINT16 CharC; volatile UINT16 Index; UINT32 Mask; assert (nn <= NPT); Number = (UINT16) GetBits (Sd, nbit); if (Number == 0) { CharC = (UINT16) GetBits (Sd, nbit); for (Index = 0; Index < 256; Index++) { Sd->mPTTable[Index] = CharC; } for (Index = 0; Index < nn; Index++) { Sd->mPTLen[Index] = 0; } return 0; } Index = 0; while (Index < Number) { CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); if (CharC == 7) { Mask = 1U << (BITBUFSIZ - 1 - 3); while (Mask & Sd->mBitBuf) { Mask >>= 1; CharC += 1; } } FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); Sd->mPTLen[Index++] = (UINT8) CharC; if (Index == Special) { CharC = (UINT16) GetBits (Sd, 2); while ((INT16) (--CharC) >= 0) { Sd->mPTLen[Index++] = 0; } } } while (Index < nn) { Sd->mPTLen[Index++] = 0; } return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); } VOID ReadCLen ( SCRATCH_DATA *Sd ) /*++ Routine Description: Reads code lengths for Char&Len Set. Arguments: Sd - the global scratch data Returns: (VOID) --*/ { UINT16 Number; UINT16 CharC; volatile UINT16 Index; UINT32 Mask; Number = (UINT16) GetBits (Sd, CBIT); if (Number == 0) { CharC = (UINT16) GetBits (Sd, CBIT); for (Index = 0; Index < NC; Index++) { Sd->mCLen[Index] = 0; } for (Index = 0; Index < 4096; Index++) { Sd->mCTable[Index] = CharC; } return ; } Index = 0; while (Index < Number) { CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; if (CharC >= NT) { Mask = 1U << (BITBUFSIZ - 1 - 8); do { if (Mask & Sd->mBitBuf) { CharC = Sd->mRight[CharC]; } else { CharC = Sd->mLeft[CharC]; } Mask >>= 1; } while (CharC >= NT); } // // Advance what we have read // FillBuf (Sd, Sd->mPTLen[CharC]); if (CharC <= 2) { if (CharC == 0) { CharC = 1; } else if (CharC == 1) { CharC = (UINT16) (GetBits (Sd, 4) + 3); } else if (CharC == 2) { CharC = (UINT16) (GetBits (Sd, CBIT) + 20); } while ((INT16) (--CharC) >= 0) { Sd->mCLen[Index++] = 0; } } else { Sd->mCLen[Index++] = (UINT8) (CharC - 2); } } while (Index < NC) { Sd->mCLen[Index++] = 0; } MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); return ; } UINT16 DecodeC ( SCRATCH_DATA *Sd ) /*++ Routine Description: Decode a character/length value. Arguments: Sd - The global scratch data. Returns: The value decoded. --*/ { UINT16 Index2; UINT32 Mask; if (Sd->mBlockSize == 0) { // // Starting a new block // Sd->mBlockSize = (UINT16) GetBits (Sd, 16); Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3); if (Sd->mBadTableFlag != 0) { return 0; } ReadCLen (Sd); Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1)); if (Sd->mBadTableFlag != 0) { return 0; } } Sd->mBlockSize--; Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; if (Index2 >= NC) { Mask = 1U << (BITBUFSIZ - 1 - 12); do { if (Sd->mBitBuf & Mask) { Index2 = Sd->mRight[Index2]; } else { Index2 = Sd->mLeft[Index2]; } Mask >>= 1; } while (Index2 >= NC); } // // Advance what we have read // FillBuf (Sd, Sd->mCLen[Index2]); return Index2; } VOID Decode ( SCRATCH_DATA *Sd ) /*++ Routine Description: Decode the source data and put the resulting data into the destination buffer. Arguments: Sd - The global scratch data Returns: (VOID) --*/ { UINT16 BytesRemain; UINT32 DataIdx; UINT16 CharC; BytesRemain = (UINT16) (-1); DataIdx = 0; for (;;) { CharC = DecodeC (Sd); if (Sd->mBadTableFlag != 0) { goto Done ; } if (CharC < 256) { // // Process an Original character // if (Sd->mOutBuf >= Sd->mOrigSize) { goto Done ; } else { Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC; } } else { // // Process a Pointer // CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD)); BytesRemain = CharC; DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1; BytesRemain--; while ((INT16) (BytesRemain) >= 0) { if (Sd->mOutBuf >= Sd->mOrigSize) { goto Done ; } if (DataIdx >= Sd->mOrigSize) { Sd->mBadTableFlag = (UINT16) BAD_TABLE; goto Done ; } Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; BytesRemain--; } // // Once mOutBuf is fully filled, directly return // if (Sd->mOutBuf >= Sd->mOrigSize) { goto Done ; } } } Done: return ; } RETURN_STATUS EFIAPI TDecompress ( IN VOID *Source, IN OUT VOID *Destination, IN OUT VOID *Scratch, IN UINT32 Version ) /*++ Routine Description: The internal implementation of Decompress(). Arguments: Source - The source buffer containing the compressed data. Destination - The destination buffer to store the decompressed data Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. Version - 1 for EFI1.1 Decompress algorithm, 2 for Tiano Decompress algorithm Returns: RETURN_SUCCESS - Decompression is successful RETURN_INVALID_PARAMETER - The source data is corrupted --*/ { volatile UINT32 Index; UINT32 CompSize; UINT32 OrigSize; SCRATCH_DATA *Sd; CONST UINT8 *Src; UINT8 *Dst; // // Verify input is not NULL // assert(Source); // assert(Destination); assert(Scratch); Src = (UINT8 *)Source; Dst = (UINT8 *)Destination; Sd = (SCRATCH_DATA *) Scratch; CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); // // If compressed file size is 0, return // if (OrigSize == 0) { return RETURN_SUCCESS; } Src = Src + 8; for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) { ((UINT8 *) Sd)[Index] = 0; } // // The length of the field 'Position Set Code Length Array Size' in Block Header. // For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4 // For Tiano de/compression algorithm(Version 2), mPBit = 5 // switch (Version) { case 1 : Sd->mPBit = 4; break; case 2 : Sd->mPBit = 5; break; default: assert(FALSE); } Sd->mSrcBase = (UINT8 *)Src; Sd->mDstBase = Dst; Sd->mCompSize = CompSize; Sd->mOrigSize = OrigSize; // // Fill the first BITBUFSIZ bits // FillBuf (Sd, BITBUFSIZ); // // Decompress it // Decode (Sd); if (Sd->mBadTableFlag != 0) { // // Something wrong with the source // return RETURN_INVALID_PARAMETER; } return RETURN_SUCCESS; }