From c23aef47be68f7dbf9954b63b553d93b584f51a9 Mon Sep 17 00:00:00 2001 From: Nikolaj Schlej Date: Sat, 5 Jul 2014 14:56:56 +0200 Subject: [PATCH] UEFIPatch 0.2.0 / UEFITool 0.18.0 - updated EFI11/Tiano compression and decompression code to UDK2014 versions - UEFIPatch rewritten to support offset-based patches and patterns with placeholder symbols --- Tiano/EfiTianoCompress.c | 3136 +++++++++++++++------------------- Tiano/EfiTianoCompress.h | 27 +- Tiano/EfiTianoDecompress.c | 1115 ++++++------ Tiano/EfiTianoDecompress.h | 18 +- UEFIPatch/uefipatch.cpp | 120 +- UEFIPatch/uefipatch.h | 2 +- UEFIPatch/uefipatch_main.cpp | 35 +- basetypes.h | 24 +- ffsengine.cpp | 162 +- ffsengine.h | 15 +- uefitool.ui | 2 +- 11 files changed, 2227 insertions(+), 2429 deletions(-) diff --git a/Tiano/EfiTianoCompress.c b/Tiano/EfiTianoCompress.c index ee21c48..3c2b690 100644 --- a/Tiano/EfiTianoCompress.c +++ b/Tiano/EfiTianoCompress.c @@ -1,20 +1,4 @@ -/* 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: - -EfiTianoCompress.c - -Abstract: +/* EfiTianoCompress.c Compression routine. The compression algorithm is a mixture of LZ77 and Huffman coding. LZ77 transforms the source data into a @@ -22,298 +6,1402 @@ 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. All rights reserved.
+Copyright (c) 2007 - 2011, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php + +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ #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) +typedef INT16 NODE; +#ifndef UINT8_MAX +#define UINT8_MAX 0xff +#endif +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 13 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define BLKSIZ (1U << 14) // 16 * 1024U +#define PERC_FLAG 0x8000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(LoopVar7, LoopVar5) ((LoopVar7) + ((LoopVar5) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(LoopVar5) mCrc = mCrcTable[(mCrc ^ (LoopVar5)) & 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 +#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 - ); +/** +Put a dword to output stream -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[] +@param[in] Data The dword to put. +**/ +VOID +EFIAPI +PutDword( +IN UINT32 Data ); // // Global Variables // -STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; +STATIC UINT8 *mSrc; +STATIC UINT8 *mDst; +STATIC UINT8 *mSrcUpperLimit; +STATIC UINT8 *mDstUpperLimit; -STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; +STATIC UINT8 *mLevel; +STATIC UINT8 *mText; +STATIC UINT8 *mChildCount; +STATIC UINT8 *mBuf; +STATIC UINT8 mCLen[NC]; +STATIC UINT8 mPTLen[NPT]; +STATIC UINT8 *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 INT32 mRemainder; +STATIC INT32 mMatchLen; +STATIC INT32 mBitCount; +STATIC INT32 mHeapSize; +STATIC INT32 mTempInt32; +STATIC UINT32 mBufSiz = 0; +STATIC UINT32 mOutputPos; +STATIC UINT32 mOutputMask; +STATIC UINT32 mSubBitBuf; +STATIC UINT32 mCrc; +STATIC UINT32 mCompSize; +STATIC UINT32 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 UINT16 *mFreq; +STATIC UINT16 *mSortPtr; +STATIC UINT16 mLenCnt[17]; +STATIC UINT16 mLeft[2 * NC - 1]; +STATIC UINT16 mRight[2 * NC - 1]; +STATIC UINT16 mCrcTable[UINT8_MAX + 1]; +STATIC UINT16 mCFreq[2 * NC - 1]; +STATIC UINT16 mCCode[NC]; +STATIC UINT16 mPFreq[2 * NP - 1]; +STATIC UINT16 mPTCode[NPT]; +STATIC UINT16 mTFreq[2 * NT - 1]; -STATIC UINT8 mPbit; +STATIC NODE mPos; +STATIC NODE mMatchPos; +STATIC NODE mAvail; +STATIC NODE *mPosition; +STATIC NODE *mParent; +STATIC NODE *mPrev; +STATIC NODE *mNext = NULL; +INT32 mHuffmanDepth = 0; -STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; +STATIC UINT8 mPBit; -// -// functions -// -// -// functions -// -INT32 -EfiCompress( -UINT8 *SrcBuffer, -UINT32 SrcSize, -UINT8 *DstBuffer, -UINT32 *DstSize +VOID* SetMem(VOID* dst, size_t size, UINT8 value) { + return memset(dst, value, size); +} + +VOID* CopyMem(VOID* dst, CONST VOID* src, size_t size) { + return memcpy(dst, src, size); +} + +VOID* AllocateZeroPool(size_t size) { + if (!size) + return NULL; + + VOID* pool = malloc(size); + memset(pool, 0x00, size); + return pool; +} + +VOID FreePool(VOID* pool) { + if (pool != NULL) + free(pool); +} + +/** +Make a CRC table. + +**/ +VOID +EFIAPI +MakeCrcTable( +VOID ) -/*++ - -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; + UINT32 LoopVar1; + + UINT32 LoopVar2; + + UINT32 LoopVar4; + + for (LoopVar1 = 0; LoopVar1 <= UINT8_MAX; LoopVar1++) { + LoopVar4 = LoopVar1; + for (LoopVar2 = 0; LoopVar2 < UINT8_BIT; LoopVar2++) { + if ((LoopVar4 & 1) != 0) { + LoopVar4 = (LoopVar4 >> 1) ^ CRCPOLY; + } + else { + LoopVar4 >>= 1; + } + } + + mCrcTable[LoopVar1] = (UINT16)LoopVar4; + } +} + +/** +Put a dword to output stream + +@param[in] Data The dword to put. +**/ +VOID +EFIAPI +PutDword( +IN UINT32 Data +) +{ + 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); + } +} + +/** +Allocate memory spaces for data structures used in compression process. + +@retval EFI_SUCCESS Memory was allocated successfully. +@retval EFI_OUT_OF_RESOURCES A memory allocation failed. +**/ +EFI_STATUS +EFIAPI +AllocateMemory( +VOID +) +{ + mText = AllocateZeroPool(WNDSIZ * 2 + MAXMATCH); + mLevel = AllocateZeroPool((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel)); + mChildCount = AllocateZeroPool((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount)); + mPosition = AllocateZeroPool((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition)); + mParent = AllocateZeroPool(WNDSIZ * 2 * sizeof(*mParent)); + mPrev = AllocateZeroPool(WNDSIZ * 2 * sizeof(*mPrev)); + mNext = AllocateZeroPool((MAX_HASH_VAL + 1) * sizeof(*mNext)); + + mBufSiz = BLKSIZ; + mBuf = AllocateZeroPool(mBufSiz); + while (mBuf == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + + mBuf = AllocateZeroPool(mBufSiz); + } + + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** +Called when compression is completed to free memory previously allocated. + +**/ +VOID +EFIAPI +FreeMemory( +VOID +) +{ + FreePool(mText); + FreePool(mLevel); + FreePool(mChildCount); + FreePool(mPosition); + FreePool(mParent); + FreePool(mPrev); + FreePool(mNext); + FreePool(mBuf); +} + +/** +Initialize String Info Log data structures. +**/ +VOID +EFIAPI +InitSlide( +VOID +) +{ + NODE LoopVar1; + + SetMem(mLevel + WNDSIZ, (UINT8_MAX + 1) * sizeof(UINT8), 1); + SetMem(mPosition + WNDSIZ, (UINT8_MAX + 1) * sizeof(NODE), 0); + + SetMem(mParent + WNDSIZ, WNDSIZ * sizeof(NODE), 0); + + mAvail = 1; + for (LoopVar1 = 1; LoopVar1 < WNDSIZ - 1; LoopVar1++) { + mNext[LoopVar1] = (NODE)(LoopVar1 + 1); + } + + mNext[WNDSIZ - 1] = NIL; + SetMem(mNext + WNDSIZ * 2, (MAX_HASH_VAL - WNDSIZ * 2 + 1) * sizeof(NODE), 0); +} + +/** +Find child node given the parent node and the edge character + +@param[in] LoopVar6 The parent node. +@param[in] LoopVar5 The edge character. + +@return The child node. +@retval NIL(Zero) No child could be found. + +**/ +NODE +EFIAPI +Child( +IN NODE LoopVar6, +IN UINT8 LoopVar5 +) +{ + NODE LoopVar4; + + LoopVar4 = mNext[HASH(LoopVar6, LoopVar5)]; + mParent[NIL] = LoopVar6; /* sentinel */ + while (mParent[LoopVar4] != LoopVar6) { + LoopVar4 = mNext[LoopVar4]; + } + + return LoopVar4; +} + +/** +Create a new child for a given parent node. + +@param[in] LoopVar6 The parent node. +@param[in] LoopVar5 The edge character. +@param[in] LoopVar4 The child node. +**/ +VOID +EFIAPI +MakeChild( +IN NODE LoopVar6, +IN UINT8 LoopVar5, +IN NODE LoopVar4 +) +{ + NODE LoopVar12; + + NODE LoopVar10; + + LoopVar12 = (NODE)HASH(LoopVar6, LoopVar5); + LoopVar10 = mNext[LoopVar12]; + mNext[LoopVar12] = LoopVar4; + mNext[LoopVar4] = LoopVar10; + mPrev[LoopVar10] = LoopVar4; + mPrev[LoopVar4] = LoopVar12; + mParent[LoopVar4] = LoopVar6; + mChildCount[LoopVar6]++; +} + +/** +Split a node. + +@param[in] Old The node to split. +**/ +VOID +EFIAPI +Split( +IN NODE Old +) +{ + NODE New; + + NODE LoopVar10; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + LoopVar10 = mPrev[Old]; + mPrev[New] = LoopVar10; + mNext[LoopVar10] = New; + LoopVar10 = mNext[Old]; + mNext[New] = LoopVar10; + mPrev[LoopVar10] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8)mMatchLen; + mPosition[New] = mPos; + MakeChild(New, mText[mMatchPos + mMatchLen], Old); + MakeChild(New, mText[mPos + mMatchLen], mPos); +} + +/** +Insert string info for current position into the String Info Log. + +**/ +VOID +EFIAPI +InsertNode( +VOID +) +{ + NODE LoopVar6; + + NODE LoopVar4; + + NODE LoopVar2; + + NODE LoopVar10; + UINT8 LoopVar5; + UINT8 *TempString3; + UINT8 *TempString2; + + 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--; + LoopVar4 = (NODE)((mMatchPos + 1) | WNDSIZ); + LoopVar6 = mParent[LoopVar4]; + while (LoopVar6 == NIL) { + LoopVar4 = mNext[LoopVar4]; + LoopVar6 = mParent[LoopVar4]; + } + + while (mLevel[LoopVar6] >= mMatchLen) { + LoopVar4 = LoopVar6; + LoopVar6 = mParent[LoopVar6]; + } + + LoopVar10 = LoopVar6; + while (mPosition[LoopVar10] < 0) { + mPosition[LoopVar10] = mPos; + LoopVar10 = mParent[LoopVar10]; + } + + if (LoopVar10 < WNDSIZ) { + mPosition[LoopVar10] = (NODE)(mPos | PERC_FLAG); + } + } + else { + // + // Locate the target tree + // + LoopVar6 = (NODE)(mText[mPos] + WNDSIZ); + LoopVar5 = mText[mPos + 1]; + LoopVar4 = Child(LoopVar6, LoopVar5); + if (LoopVar4 == NIL) { + MakeChild(LoopVar6, LoopVar5, 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 (LoopVar4 >= WNDSIZ) { + LoopVar2 = MAXMATCH; + mMatchPos = LoopVar4; + } + else { + LoopVar2 = mLevel[LoopVar4]; + mMatchPos = (NODE)(mPosition[LoopVar4] & ~PERC_FLAG); + } + + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + + TempString3 = &mText[mPos + mMatchLen]; + TempString2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < LoopVar2) { + if (*TempString3 != *TempString2) { + Split(LoopVar4); + return; + } + + mMatchLen++; + TempString3++; + TempString2++; + } + + if (mMatchLen >= MAXMATCH) { + break; + } + + mPosition[LoopVar4] = mPos; + LoopVar6 = LoopVar4; + LoopVar4 = Child(LoopVar6, *TempString3); + if (LoopVar4 == NIL) { + MakeChild(LoopVar6, *TempString3, mPos); + return; + } + + mMatchLen++; + } + + LoopVar10 = mPrev[LoopVar4]; + mPrev[mPos] = LoopVar10; + mNext[LoopVar10] = mPos; + LoopVar10 = mNext[LoopVar4]; + mNext[mPos] = LoopVar10; + mPrev[LoopVar10] = mPos; + mParent[mPos] = LoopVar6; + mParent[LoopVar4] = NIL; + + // + // Special usage of 'next' + // + mNext[LoopVar4] = mPos; + +} + +/** +Delete outdated string info. (The Usage of PERC_FLAG +ensures a clean deletion). + +**/ +VOID +EFIAPI +DeleteNode( +VOID +) +{ + NODE LoopVar6; + + NODE LoopVar4; + + NODE LoopVar11; + + NODE LoopVar10; + + NODE LoopVar9; + + if (mParent[mPos] == NIL) { + return; + } + + LoopVar4 = mPrev[mPos]; + LoopVar11 = mNext[mPos]; + mNext[LoopVar4] = LoopVar11; + mPrev[LoopVar11] = LoopVar4; + LoopVar4 = mParent[mPos]; + mParent[mPos] = NIL; + if (LoopVar4 >= WNDSIZ) { + return; + } + + mChildCount[LoopVar4]--; + if (mChildCount[LoopVar4] > 1) { + return; + } + + LoopVar10 = (NODE)(mPosition[LoopVar4] & ~PERC_FLAG); + if (LoopVar10 >= mPos) { + LoopVar10 -= WNDSIZ; + } + + LoopVar11 = LoopVar10; + LoopVar6 = mParent[LoopVar4]; + LoopVar9 = mPosition[LoopVar6]; + while ((LoopVar9 & PERC_FLAG) != 0){ + LoopVar9 &= ~PERC_FLAG; + if (LoopVar9 >= mPos) { + LoopVar9 -= WNDSIZ; + } + + if (LoopVar9 > LoopVar11) { + LoopVar11 = LoopVar9; + } + + mPosition[LoopVar6] = (NODE)(LoopVar11 | WNDSIZ); + LoopVar6 = mParent[LoopVar6]; + LoopVar9 = mPosition[LoopVar6]; + } + + if (LoopVar6 < WNDSIZ) { + if (LoopVar9 >= mPos) { + LoopVar9 -= WNDSIZ; + } + + if (LoopVar9 > LoopVar11) { + LoopVar11 = LoopVar9; + } + + mPosition[LoopVar6] = (NODE)(LoopVar11 | WNDSIZ | PERC_FLAG); + } + + LoopVar11 = Child(LoopVar4, mText[LoopVar10 + mLevel[LoopVar4]]); + LoopVar10 = mPrev[LoopVar11]; + LoopVar9 = mNext[LoopVar11]; + mNext[LoopVar10] = LoopVar9; + mPrev[LoopVar9] = LoopVar10; + LoopVar10 = mPrev[LoopVar4]; + mNext[LoopVar10] = LoopVar11; + mPrev[LoopVar11] = LoopVar10; + LoopVar10 = mNext[LoopVar4]; + mPrev[LoopVar10] = LoopVar11; + mNext[LoopVar11] = LoopVar10; + mParent[LoopVar11] = mParent[LoopVar4]; + mParent[LoopVar4] = NIL; + mNext[LoopVar4] = mAvail; + mAvail = LoopVar4; +} + +/** +Read in source data + +@param[out] LoopVar7 The buffer to hold the data. +@param[in] LoopVar8 The number of bytes to read. + +@return The number of bytes actually read. +**/ +INT32 +EFIAPI +FreadCrc( +OUT UINT8 *LoopVar7, +IN INT32 LoopVar8 +) +{ + INT32 LoopVar1; + + for (LoopVar1 = 0; mSrc < mSrcUpperLimit && LoopVar1 < LoopVar8; LoopVar1++) { + *LoopVar7++ = *mSrc++; + } + + LoopVar8 = LoopVar1; + + LoopVar7 -= LoopVar8; + mOrigSize += LoopVar8; + LoopVar1--; + while (LoopVar1 >= 0) { + UPDATE_CRC(*LoopVar7++); + LoopVar1--; + } + + return LoopVar8; +} + +/** +Advance the current position (read in new data if needed). +Delete outdated string info. Find a match string for current position. + +@retval TRUE The operation was successful. +@retval FALSE The operation failed due to insufficient memory. +**/ +BOOLEAN +EFIAPI +GetNextMatch( +VOID +) +{ + INT32 LoopVar8; + VOID *Temp; + + mRemainder--; + mPos++; + if (mPos == WNDSIZ * 2) { + Temp = AllocateZeroPool(WNDSIZ + MAXMATCH); + if (Temp == NULL) { + return (FALSE); + } + CopyMem(Temp, &mText[WNDSIZ], WNDSIZ + MAXMATCH); + CopyMem(&mText[0], Temp, WNDSIZ + MAXMATCH); + FreePool(Temp); + LoopVar8 = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += LoopVar8; + mPos = WNDSIZ; + } + + DeleteNode(); + InsertNode(); + + return (TRUE); +} + +/** +Send entry LoopVar1 down the queue. + +@param[in] LoopVar1 The index of the item to move. +**/ +VOID +EFIAPI +DownHeap( +IN INT32 i +) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + + // + // priority queue: send i-th entry down heap + // + LoopVar2 = mHeap[i]; + LoopVar1 = 2 * i; + while (LoopVar1 <= mHeapSize) { + if (LoopVar1 < mHeapSize && mFreq[mHeap[LoopVar1]] > mFreq[mHeap[LoopVar1 + 1]]) { + LoopVar1++; + } + + if (mFreq[LoopVar2] <= mFreq[mHeap[LoopVar1]]) { + break; + } + + mHeap[i] = mHeap[LoopVar1]; + i = LoopVar1; + LoopVar1 = 2 * i; + } + + mHeap[i] = (INT16)LoopVar2; +} + +/** +Count the number of each code length for a Huffman tree. + +@param[in] LoopVar1 The top node. +**/ +VOID +EFIAPI +CountLen( +IN INT32 LoopVar1 +) +{ + if (LoopVar1 < mTempInt32) { + mLenCnt[(mHuffmanDepth < 16) ? mHuffmanDepth : 16]++; + } + else { + mHuffmanDepth++; + CountLen(mLeft[LoopVar1]); + CountLen(mRight[LoopVar1]); + mHuffmanDepth--; + } +} + +/** +Create code length array for a Huffman tree. + +@param[in] Root The root of the tree. +**/ +VOID +EFIAPI +MakeLen( +IN INT32 Root +) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + UINT32 Cum; + + for (LoopVar1 = 0; LoopVar1 <= 16; LoopVar1++) { + mLenCnt[LoopVar1] = 0; + } + + CountLen(Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + Cum = 0; + for (LoopVar1 = 16; LoopVar1 > 0; LoopVar1--) { + Cum += mLenCnt[LoopVar1] << (16 - LoopVar1); + } + + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (LoopVar1 = 15; LoopVar1 > 0; LoopVar1--) { + if (mLenCnt[LoopVar1] != 0) { + mLenCnt[LoopVar1]--; + mLenCnt[LoopVar1 + 1] += 2; + break; + } + } + + Cum--; + } + + for (LoopVar1 = 16; LoopVar1 > 0; LoopVar1--) { + LoopVar2 = mLenCnt[LoopVar1]; + LoopVar2--; + while (LoopVar2 >= 0) { + mLen[*mSortPtr++] = (UINT8)LoopVar1; + LoopVar2--; + } + } +} + +/** +Assign code to each symbol based on the code length array. + +@param[in] LoopVar8 The number of symbols. +@param[in] Len The code length array. +@param[out] Code The stores codes for each symbol. +**/ +VOID +EFIAPI +MakeCode( +IN INT32 LoopVar8, +IN UINT8 Len[], +OUT UINT16 Code[] +) +{ + INT32 LoopVar1; + UINT16 Start[18]; + + Start[1] = 0; + for (LoopVar1 = 1; LoopVar1 <= 16; LoopVar1++) { + Start[LoopVar1 + 1] = (UINT16)((Start[LoopVar1] + mLenCnt[LoopVar1]) << 1); + } + + for (LoopVar1 = 0; LoopVar1 < LoopVar8; LoopVar1++) { + Code[LoopVar1] = Start[Len[LoopVar1]]++; + } +} + +/** +Generates Huffman codes given a frequency distribution of symbols. + +@param[in] NParm The number of symbols. +@param[in] FreqParm The frequency of each symbol. +@param[out] LenParm The code length for each symbol. +@param[out] CodeParm The code for each symbol. + +@return The root of the Huffman tree. +**/ +INT32 +EFIAPI +MakeTree( +IN INT32 NParm, +IN UINT16 FreqParm[], +OUT UINT8 LenParm[], +OUT UINT16 CodeParm[] +) +{ + INT32 LoopVar1; + + INT32 LoopVar2; + + INT32 LoopVar3; + + INT32 Avail; + + // + // make tree, calculate len[], return root + // + mTempInt32 = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mTempInt32; + mHeapSize = 0; + mHeap[1] = 0; + for (LoopVar1 = 0; LoopVar1 < mTempInt32; LoopVar1++) { + mLen[LoopVar1] = 0; + if ((mFreq[LoopVar1]) != 0) { + mHeapSize++; + mHeap[mHeapSize] = (INT16)LoopVar1; + } + } + + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + + for (LoopVar1 = mHeapSize / 2; LoopVar1 >= 1; LoopVar1--) { + // + // make priority queue + // + DownHeap(LoopVar1); + } + + mSortPtr = CodeParm; + do { + LoopVar1 = mHeap[1]; + if (LoopVar1 < mTempInt32) { + *mSortPtr++ = (UINT16)LoopVar1; + } + + mHeap[1] = mHeap[mHeapSize--]; + DownHeap(1); + LoopVar2 = mHeap[1]; + if (LoopVar2 < mTempInt32) { + *mSortPtr++ = (UINT16)LoopVar2; + } + + LoopVar3 = Avail++; + mFreq[LoopVar3] = (UINT16)(mFreq[LoopVar1] + mFreq[LoopVar2]); + mHeap[1] = (INT16)LoopVar3; + DownHeap(1); + mLeft[LoopVar3] = (UINT16)LoopVar1; + mRight[LoopVar3] = (UINT16)LoopVar2; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen(LoopVar3); + MakeCode(NParm, LenParm, CodeParm); + + // + // return root + // + return LoopVar3; +} + +/** +Outputs rightmost LoopVar8 bits of x + +@param[in] LoopVar8 The rightmost LoopVar8 bits of the data is used. +@param[in] x The data. +**/ +VOID +EFIAPI +PutBits( +IN INT32 LoopVar8, +IN UINT32 x +) +{ + UINT8 Temp; + + if (LoopVar8 < mBitCount) { + mSubBitBuf |= x << (mBitCount -= LoopVar8); + } + else { + + Temp = (UINT8)(mSubBitBuf | (x >> (LoopVar8 -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + if (LoopVar8 < UINT8_BIT) { + mSubBitBuf = x << (mBitCount = UINT8_BIT - LoopVar8); + } + else { + + Temp = (UINT8)(x >> (LoopVar8 - UINT8_BIT)); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - LoopVar8); + } + } +} + +/** +Encode a signed 32 bit number. + +@param[in] LoopVar5 The number to encode. +**/ +VOID +EFIAPI +EncodeC( +IN INT32 LoopVar5 +) +{ + PutBits(mCLen[LoopVar5], mCCode[LoopVar5]); +} + +/** +Encode a unsigned 32 bit number. + +@param[in] LoopVar7 The number to encode. +**/ +VOID +EFIAPI +EncodeP( +IN UINT32 LoopVar7 +) +{ + UINT32 LoopVar5; + + UINT32 LoopVar6; + + LoopVar5 = 0; + LoopVar6 = LoopVar7; + while (LoopVar6 != 0) { + LoopVar6 >>= 1; + LoopVar5++; + } + + PutBits(mPTLen[LoopVar5], mPTCode[LoopVar5]); + if (LoopVar5 > 1) { + PutBits(LoopVar5 - 1, LoopVar7 & (0xFFFFU >> (17 - LoopVar5))); + } +} + +/** +Count the frequencies for the Extra Set. + +**/ +VOID +EFIAPI +CountTFreq( +VOID +) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + INT32 LoopVar8; + + INT32 Count; + + for (LoopVar1 = 0; LoopVar1 < NT; LoopVar1++) { + mTFreq[LoopVar1] = 0; + } + + LoopVar8 = NC; + while (LoopVar8 > 0 && mCLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mCLen[LoopVar1++]; + if (LoopVar3 == 0) { + Count = 1; + while (LoopVar1 < LoopVar8 && mCLen[LoopVar1] == 0) { + LoopVar1++; + 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 { + ASSERT((LoopVar3 + 2)<(2 * NT - 1)); + mTFreq[LoopVar3 + 2]++; + } + } +} + +/** +Outputs the code length array for the Extra Set or the Position Set. + +@param[in] LoopVar8 The number of symbols. +@param[in] nbit The number of bits needed to represent 'LoopVar8'. +@param[in] Special The special symbol that needs to be take care of. + +**/ +VOID +EFIAPI +WritePTLen( +IN INT32 LoopVar8, +IN INT32 nbit, +IN INT32 Special +) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + while (LoopVar8 > 0 && mPTLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + PutBits(nbit, LoopVar8); + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mPTLen[LoopVar1++]; + if (LoopVar3 <= 6) { + PutBits(3, LoopVar3); + } + else { + PutBits(LoopVar3 - 3, (1U << (LoopVar3 - 3)) - 2); + } + + if (LoopVar1 == Special) { + while (LoopVar1 < 6 && mPTLen[LoopVar1] == 0) { + LoopVar1++; + } + + PutBits(2, (LoopVar1 - 3) & 3); + } + } +} + +/** +Outputs the code length array for Char&Length Set. +**/ +VOID +EFIAPI +WriteCLen( +VOID +) +{ + INT32 LoopVar1; + + INT32 LoopVar3; + + INT32 LoopVar8; + + INT32 Count; + + LoopVar8 = NC; + while (LoopVar8 > 0 && mCLen[LoopVar8 - 1] == 0) { + LoopVar8--; + } + + PutBits(CBIT, LoopVar8); + LoopVar1 = 0; + while (LoopVar1 < LoopVar8) { + LoopVar3 = mCLen[LoopVar1++]; + if (LoopVar3 == 0) { + Count = 1; + while (LoopVar1 < LoopVar8 && mCLen[LoopVar1] == 0) { + LoopVar1++; + Count++; + } + + if (Count <= 2) { + for (LoopVar3 = 0; LoopVar3 < Count; LoopVar3++) { + 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 { + ASSERT((LoopVar3 + 2)= 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 (LoopVar1 = 0; LoopVar1 < Size; LoopVar1++) { + if (LoopVar1 % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } + else { + Flags <<= 1; + } + if ((Flags & (1U << (UINT8_BIT - 1))) != 0){ + EncodeC(mBuf[Pos++] + (1U << UINT8_BIT)); + LoopVar3 = mBuf[Pos++] << UINT8_BIT; + LoopVar3 += mBuf[Pos++]; + + EncodeP(LoopVar3); + } + else { + EncodeC(mBuf[Pos++]); + } + } + + SetMem(mCFreq, NC * sizeof(UINT16), 0); + SetMem(mPFreq, NP * sizeof(UINT16), 0); +} + +/** +Start the huffman encoding. + +**/ +VOID +EFIAPI +HufEncodeStart( +VOID +) +{ + SetMem(mCFreq, NC * sizeof(UINT16), 0); + SetMem(mPFreq, NP * sizeof(UINT16), 0); + + mOutputPos = mOutputMask = 0; + + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** +Outputs an Original Character or a Pointer. + +@param[in] LoopVar5 The original character or the 'String Length' element of +a Pointer. +@param[in] LoopVar7 The 'Position' field of a Pointer. +**/ +VOID +EFIAPI +CompressOutput( +IN UINT32 LoopVar5, +IN UINT32 LoopVar7 +) +{ + 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)LoopVar5; + mCFreq[LoopVar5]++; + if (LoopVar5 >= (1U << UINT8_BIT)) { + mBuf[CPos] = (UINT8)(mBuf[CPos] | mOutputMask); + mBuf[mOutputPos++] = (UINT8)(LoopVar7 >> UINT8_BIT); + mBuf[mOutputPos++] = (UINT8)LoopVar7; + LoopVar5 = 0; + while (LoopVar7 != 0) { + LoopVar7 >>= 1; + LoopVar5++; + } + mPFreq[LoopVar5]++; + } +} + +/** +End the huffman encoding. + +**/ +VOID +EFIAPI +HufEncodeEnd( +VOID +) +{ + SendBlock(); + + // + // Flush remaining bits + // + PutBits(UINT8_BIT - 1, 0); +} + +/** +The main controlling routine for compression process. + +@retval EFI_SUCCESS The compression is successful. +@retval EFI_OUT_0F_RESOURCES Not enough memory for compression process. +**/ +EFI_STATUS +EFIAPI +Encode( +VOID +) +{ + 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; + if (!GetNextMatch()) { + Status = EFI_OUT_OF_RESOURCES; + } + 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 + // + CompressOutput(mText[mPos - 1], 0); + } + else { + // + // Outputting a pointer is beneficial enough, do it. + // + + CompressOutput(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1)); + LastMatchLen--; + while (LastMatchLen > 0) { + if (!GetNextMatch()) { + Status = EFI_OUT_OF_RESOURCES; + } + LastMatchLen--; + } + + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd(); + FreeMemory(); + return (Status); +} + +/** +The compression routine. + +@param[in] SrcBuffer The buffer containing the source data. +@param[in] SrcSize The number of bytes in SrcBuffer. +@param[in] DstBuffer The buffer to put the compressed image in. +@param[in, out] DstSize On input the size (in bytes) of DstBuffer, on +return the number of bytes placed in DstBuffer. + +@retval EFI_SUCCESS The compression was successful. +@retval EFI_BUFFER_TOO_SMALL The buffer was too small. DstSize is required. +**/ +EFI_STATUS +EFIAPI +Compress( +IN VOID *SrcBuffer, +IN UINT64 SrcSize, +IN VOID *DstBuffer, +IN OUT UINT64 *DstSize +) +{ + EFI_STATUS Status; // // Initializations // - mPbit = 4; - mBufSiz = 0; mBuf = NULL; mText = NULL; @@ -341,8 +1429,8 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. // Compress it // Status = Encode(); - if (Status) { - return ERR_OUT_OF_RESOURCES; + if (EFI_ERROR(Status)) { + return EFI_OUT_OF_RESOURCES; } // // Null terminate the compressed data @@ -351,7 +1439,7 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. *mDst++ = 0; } // - // Fill compressed size and original size + // Fill in compressed size and original size // mDst = DstBuffer; PutDword(mCompSize + 1); @@ -362,1495 +1450,27 @@ EFI_INVALID_PARAMETER - Parameter supplied is wrong. // if (mCompSize + 1 + 8 > *DstSize) { *DstSize = mCompSize + 1 + 8; - return ERR_BUFFER_TOO_SMALL; + return EFI_BUFFER_TOO_SMALL; } else { *DstSize = mCompSize + 1 + 8; - return ERR_SUCCESS; + return EFI_SUCCESS; } } -INT32 - TianoCompress ( - UINT8 *SrcBuffer, - UINT32 SrcSize, - UINT8 *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. - - --*/ +UINT8 EfiCompress(CONST VOID* SrcBuffer, CONST UINT64 SrcSize, VOID* DstBuffer, UINT64* DstSize) { - INT32 Status; - - // - // Initializations - // - mPbit = 5; - - 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 (Status) { - return ERR_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 ERR_BUFFER_TOO_SMALL; - } else { - *DstSize = mCompSize + 1 + 8; - return ERR_SUCCESS; - } - + mPBit = 4; + VOID* buffer = (VOID*)SrcBuffer; + UINT64 size = SrcSize; + return Compress(buffer, size, DstBuffer, DstSize); } -STATIC - VOID - PutDword ( - UINT32 Data - ) - /*++ - - Routine Description: - - Put a DWORD to output stream - - Arguments: - - Data - the DWORD to put - - Returns: (VOID) - - --*/ +UINT8 TianoCompress(CONST VOID* SrcBuffer, CONST UINT64 SrcSize, VOID* DstBuffer, UINT64* DstSize) { - 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 ERR_OUT_OF_RESOURCES; - } - - mBuf = malloc (mBufSiz); - } - - mBuf[0] = 0; - - return ERR_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 ERR_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; -} + mPBit = 5; + VOID* buffer = (VOID*)SrcBuffer; + UINT64 size = SrcSize; + return Compress(buffer, size, DstBuffer, DstSize); +} \ No newline at end of file diff --git a/Tiano/EfiTianoCompress.h b/Tiano/EfiTianoCompress.h index c5e026a..f1b5356 100644 --- a/Tiano/EfiTianoCompress.h +++ b/Tiano/EfiTianoCompress.h @@ -1,13 +1,14 @@ -/* EFI/Tiano Compress Header +/* EfiTianoCompress.h -Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved. +Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
+Copyright (c) 2004 - 2008, 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: @@ -54,12 +55,12 @@ Returns: EFI_INVALID_PARAMETER - Parameter supplied is wrong. --*/ -INT32 +UINT8 TianoCompress ( - UINT8 *SrcBuffer, - UINT32 SrcSize, - UINT8 *DstBuffer, - UINT32 *DstSize + CONST VOID *SrcBuffer, + CONST UINT64 SrcSize, + VOID *DstBuffer, + UINT64 *DstSize ) ; @@ -86,12 +87,12 @@ Returns: EFI_INVALID_PARAMETER - Parameter supplied is wrong. --*/ -INT32 +UINT8 EfiCompress ( - UINT8 *SrcBuffer, - UINT32 SrcSize, - UINT8 *DstBuffer, - UINT32 *DstSize + CONST VOID *SrcBuffer, + CONST UINT64 SrcSize, + VOID *DstBuffer, + UINT64 *DstSize ) ; diff --git a/Tiano/EfiTianoDecompress.c b/Tiano/EfiTianoDecompress.c index 7fac2fe..9d2bef3 100644 --- a/Tiano/EfiTianoDecompress.c +++ b/Tiano/EfiTianoDecompress.c @@ -1,13 +1,14 @@ -/*++ +/*++ EfiTianoDecompress.c -Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php +Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: @@ -28,7 +29,9 @@ Decompressor. Algorithm Ported from OPSD code (Decomp.asm) #define MAXMATCH 256 #define THRESHOLD 3 #define CODE_BIT 16 -//#define UINT8_MAX 0xff +#ifndef UINT8_MAX +#define UINT8_MAX 0xff +#endif #define BAD_TABLE - 1 // @@ -47,46 +50,46 @@ Decompressor. Algorithm Ported from OPSD code (Decomp.asm) #endif typedef struct { -UINT8 *mSrcBase; // Starting address of compressed data -UINT8 *mDstBase; // Starting address of decompressed data -UINT32 mOutBuf; -UINT32 mInBuf; + UINT8 *mSrcBase; // Starting address of compressed data + UINT8 *mDstBase; // Starting address of decompressed data + UINT32 mOutBuf; + UINT32 mInBuf; -UINT16 mBitCount; -UINT32 mBitBuf; -UINT32 mSubBitBuf; -UINT16 mBlockSize; -UINT32 mCompSize; -UINT32 mOrigSize; + UINT16 mBitCount; + UINT32 mBitBuf; + UINT32 mSubBitBuf; + UINT16 mBlockSize; + UINT32 mCompSize; + UINT32 mOrigSize; -UINT16 mBadTableFlag; + UINT16 mBadTableFlag; -UINT16 mLeft[2 * NC - 1]; -UINT16 mRight[2 * NC - 1]; -UINT8 mCLen[NC]; -UINT8 mPTLen[NPT]; -UINT16 mCTable[4096]; -UINT16 mPTTable[256]; + UINT16 mLeft[2 * NC - 1]; + UINT16 mRight[2 * NC - 1]; + UINT8 mCLen[NC]; + UINT8 mPTLen[NPT]; + UINT16 mCTable[4096]; + UINT16 mPTTable[256]; -// -// The length of the field 'Position Set Code Length Array Size'Block Header. -// For EFI 1.1 de/compression algorithm, mPBit = 4 -// For Tiano de/compression algorithm, mPBit = 5 -// -UINT8 mPBit; + // + // The length of the field 'Position Set Code Length Array Size' in Block Header. + // For EFI 1.1 de/compression algorithm, mPBit = 4 + // For Tiano de/compression algorithm, mPBit = 5 + // + UINT8 mPBit; } SCRATCH_DATA; STATIC VOID -FillBuf ( -SCRATCH_DATA *Sd, -UINT16 NumOfBits +FillBuf( +IN SCRATCH_DATA *Sd, +IN UINT16 NumOfBits ) /*++ Routine Description: -Shift mBitBuf NumOfBits left. ReadNumOfBits of bits from source. +Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. Arguments: @@ -97,48 +100,49 @@ Returns: (VOID) --*/ { -Sd->mBitBuf = (UINT32) (Sd->mBitBuf << NumOfBits); + Sd->mBitBuf = (UINT32)(Sd->mBitBuf << NumOfBits); -while (NumOfBits > Sd->mBitCount) { + while (NumOfBits > Sd->mBitCount) { - Sd->mBitBuf |= (UINT32) (Sd->mSubBitBuf << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); + Sd->mBitBuf |= (UINT32)(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; + 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; + } + 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; + Sd->mBitCount = (UINT16)(Sd->mBitCount - NumOfBits); + Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; } STATIC UINT32 -GetBits ( -SCRATCH_DATA *Sd, -UINT16 NumOfBits +GetBits( +IN SCRATCH_DATA *Sd, +IN UINT16 NumOfBits ) /*++ Routine Description: -Get NumOfBits of bits from mBitBuf. Fill mBitBuf with subsequent -NumOfBits of bits from source. Returns NumOfBits of bits that are -popped. +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: @@ -147,27 +151,27 @@ NumOfBits - The number of bits to pop and read. Returns: -The bits that are popped. +The bits that are popped out. --*/ { -UINT32 Bits; + UINT32 OutBits; -Bits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); + OutBits = (UINT32)(Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); -FillBuf (Sd, NumOfBits); + FillBuf(Sd, NumOfBits); -return Bits; + return OutBits; } STATIC UINT16 -MakeTable ( -SCRATCH_DATA *Sd, -UINT16 NumOfChar, -UINT8 *BitLen, -UINT16 TableBits, -UINT16 *Table +MakeTable( +IN SCRATCH_DATA *Sd, +IN UINT16 NumOfChar, +IN UINT8 *BitLen, +IN UINT16 TableBits, +OUT UINT16 *Table ) /*++ @@ -190,119 +194,145 @@ 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 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; -for (Index = 1; Index <= 16; Index++) { - Count[Index] = 0; -} + // + // TableBits should not be greater than 16. + // + if (TableBits >= (sizeof(Count) / sizeof(UINT16))) { + return (UINT16)BAD_TABLE; + } -for (Index = 0; Index < NumOfChar; Index++) { - Count[BitLen[Index]]++; -} + // + // Initialize Count array starting from Index 0, as there is a possibility of Count array being uninitialized. + // + for (Index = 0; Index <= 16; Index++) { + Count[Index] = 0; + } -Start[1] = 0; + for (Index = 0; Index < NumOfChar; Index++) { + // + // Count array index should not be greater than or equal to its size. + // + if (BitLen[Index] < (sizeof(Count) / sizeof(UINT16))) { + Count[BitLen[Index]]++; + } + else { + return (UINT16)BAD_TABLE; + } + } -for (Index = 1; Index <= 16; Index++) { - Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index))); -} + Start[0] = 0; + Start[1] = 0; -if (Start[17] != 0) { - /*(1U << 16)*/ - return (UINT16) BAD_TABLE; -} + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16)(Start[Index] + (Count[Index] << (16 - Index))); + } -JuBits = (UINT16) (16 - TableBits); + if (Start[17] != 0) { + /*(1U << 16)*/ + return (UINT16)BAD_TABLE; + } -for (Index = 1; Index <= TableBits; Index++) { - Start[Index] >>= JuBits; - Weight[Index] = (UINT16) (1U << (TableBits - Index)); -} + JuBits = (UINT16)(16 - TableBits); -while (Index <= 16) { - Weight[Index] = (UINT16) (1U << (16 - Index)); - Index++; -} + for (Index = 1; Index <= TableBits; Index++) { + Start[Index] >>= JuBits; + Weight[Index] = (UINT16)(1U << (TableBits - Index)); + } -Index = (UINT16) (Start[TableBits + 1] >> JuBits); + while (Index <= 16) { + Weight[Index] = (UINT16)(1U << (16 - Index)); + Index++; + } -if (Index != 0) { - Index3 = (UINT16) (1U << TableBits); - while (Index != Index3) { - Table[Index++] = 0; - } -} + Index = (UINT16)(Start[TableBits + 1] >> JuBits); -Avail = NumOfChar; -Mask = (UINT16) (1U << (15 - TableBits)); + if (Index != 0) { + Index3 = (UINT16)(1U << TableBits); + while (Index != Index3) { + Table[Index++] = 0; + } + } -for (Char = 0; Char < NumOfChar; Char++) { + Avail = NumOfChar; + Mask = (UINT16)(1U << (15 - TableBits)); - Len = BitLen[Char]; - if (Len == 0) { - continue; - } + for (Char = 0; Char < NumOfChar; Char++) { - NextCode = (UINT16) (Start[Len] + Weight[Len]); + Len = BitLen[Char]; + if (Len == 0 || Len >= 17) { + continue; + } - if (Len <= TableBits) { + NextCode = (UINT16)(Start[Len] + Weight[Len]); - for (Index = Start[Len]; Index < NextCode; Index++) { - // Check to prevent possible heap corruption - if (Index >= (UINT16) (1U << TableBits)) - return (UINT16)BAD_TABLE; + if (Len <= TableBits) { - Table[Index] = Char; - } + for (Index = Start[Len]; Index < NextCode; Index++) { + // Check to prevent possible heap corruption + if (Index >= (UINT16)(1U << TableBits)) + return (UINT16)BAD_TABLE; + Table[Index] = Char; + } - } else { + } + else { - Index3 = Start[Len]; - Pointer = &Table[Index3 >> JuBits]; - Index = (UINT16) (Len - TableBits); + 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++; - } + while (Index != 0) { + // + // Avail should be lesser than size of mRight and mLeft to prevent buffer overflow. + // + if ((*Pointer == 0) && (Avail < sizeof(Sd->mRight) / sizeof(UINT16)) && (Avail < sizeof(Sd->mLeft) / sizeof(UINT16))) { + Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; + *Pointer = Avail++; + } - if (Index3 & Mask) { - Pointer = &Sd->mRight[*Pointer]; - } else { - Pointer = &Sd->mLeft[*Pointer]; - } + // + // *Pointer should be lesser than size of mRight and mLeft to prevent buffer overflow. + // + if ((Index3 & Mask) && (*Pointer < (sizeof(Sd->mRight) / sizeof(UINT16)))) { + Pointer = &Sd->mRight[*Pointer]; + } + else if (*Pointer < (sizeof(Sd->mLeft) / sizeof(UINT16))) { + Pointer = &Sd->mLeft[*Pointer]; + } - Index3 <<= 1; - Index--; - } + Index3 <<= 1; + Index--; + } - *Pointer = Char; + *Pointer = Char; - } + } - Start[Len] = NextCode; -} -// -// Succeeds -// -return 0; + Start[Len] = NextCode; + } + // + // Succeeds + // + return 0; } STATIC UINT32 -DecodeP ( -SCRATCH_DATA *Sd +DecodeP( +IN SCRATCH_DATA *Sd ) /*++ @@ -320,46 +350,47 @@ The position value decoded. --*/ { -UINT16 Val; -UINT32 Mask; -UINT32 Pos; + UINT16 Val; + UINT32 Mask; + UINT32 Pos; -Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; -if (Val >= MAXNP) { - Mask = 1U << (BITBUFSIZ - 1 - 8); + if (Val >= MAXNP) { + Mask = 1U << (BITBUFSIZ - 1 - 8); - do { + do { - if (Sd->mBitBuf & Mask) { - Val = Sd->mRight[Val]; - } else { - Val = Sd->mLeft[Val]; - } + 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]); + 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))); -} + Pos = Val; + if (Val > 1) { + Pos = (UINT32)((1U << (Val - 1)) + GetBits(Sd, (UINT16)(Val - 1))); + } -return Pos; + return Pos; } STATIC UINT16 -ReadPTLen ( -SCRATCH_DATA *Sd, -UINT16 nn, -UINT16 nbit, -UINT16 Special +ReadPTLen( +IN SCRATCH_DATA *Sd, +IN UINT16 nn, +IN UINT16 nbit, +IN UINT16 Special ) /*++ @@ -372,7 +403,7 @@ 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 +Special - The special symbol that needs to be taken care of Returns: @@ -381,63 +412,76 @@ BAD_TABLE - Table is corrupted. --*/ { -UINT16 Number; -UINT16 CharC; -UINT16 Index; -UINT32 Mask; + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; -Number = (UINT16) GetBits (Sd, nbit); + Number = (UINT16)GetBits(Sd, nbit); -if (Number == 0) { - CharC = (UINT16) GetBits (Sd, nbit); + if ((Number > sizeof(Sd->mPTLen)) || (nn > sizeof(Sd->mPTLen))) { + // + // Fail if Number or nn is greater than size of mPTLen + // + return (UINT16)BAD_TABLE; + } - for (Index = 0; Index < 256; Index++) { - Sd->mPTTable[Index] = CharC; - } + if (Number == 0) { + CharC = (UINT16)GetBits(Sd, nbit); - for (Index = 0; Index < nn; Index++) { - Sd->mPTLen[Index] = 0; - } + for (Index = 0; Index < 256; Index++) { + Sd->mPTTable[Index] = CharC; + } - return 0; -} + for (Index = 0; Index < nn; Index++) { + Sd->mPTLen[Index] = 0; + } -Index = 0; + return 0; + } -while (Index < Number) { + Index = 0; - CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); + while (Index < Number) { - if (CharC == 7) { - Mask = 1U << (BITBUFSIZ - 1 - 3); - while (Mask & Sd->mBitBuf) { - Mask >>= 1; - CharC += 1; - } - } + CharC = (UINT16)(Sd->mBitBuf >> (BITBUFSIZ - 3)); - FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); + if (CharC == 7) { + Mask = 1U << (BITBUFSIZ - 1 - 3); + while (Mask & Sd->mBitBuf) { + Mask >>= 1; + CharC += 1; + } + } - Sd->mPTLen[Index++] = (UINT8) CharC; + FillBuf(Sd, (UINT16)((CharC < 7) ? 3 : CharC - 3)); - if (Index == Special) { - CharC = (UINT16) GetBits (Sd, 2); - while ((INT16) (--CharC) >= 0) { - Sd->mPTLen[Index++] = 0; - } - } -} + Sd->mPTLen[Index++] = (UINT8)CharC; -while (Index < nn) { - Sd->mPTLen[Index++] = 0; -} + if (Index == Special) { + CharC = (UINT16)GetBits(Sd, 2); + while ((INT16)(--CharC) >= 0) { + if (Index >= sizeof(Sd->mPTLen)) { + // + // Fail if Index is greater than or equal to mPTLen + // + return (UINT16)BAD_TABLE; + } + Sd->mPTLen[Index++] = 0; + } + } + } -return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); + while (Index < nn) { + Sd->mPTLen[Index++] = 0; + } + + return MakeTable(Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); } STATIC VOID -ReadCLen ( +ReadCLen( SCRATCH_DATA *Sd ) /*++ @@ -454,84 +498,88 @@ Returns: (VOID) --*/ { -UINT16 Number; -UINT16 CharC; -UINT16 Index; -UINT32 Mask; + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; -Number = (UINT16) GetBits (Sd, CBIT); + Number = (UINT16)GetBits(Sd, CBIT); -if (Number == 0) { - CharC = (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 < NC; Index++) { + Sd->mCLen[Index] = 0; + } - for (Index = 0; Index < 4096; Index++) { - Sd->mCTable[Index] = CharC; - } + for (Index = 0; Index < 4096; Index++) { + Sd->mCTable[Index] = CharC; + } - return ; -} + return; + } -Index = 0; -while (Index < Number) { + Index = 0; + while (Index < Number) { - CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; - if (CharC >= NT) { - Mask = 1U << (BITBUFSIZ - 1 - 8); + CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + if (CharC >= NT) { + Mask = 1U << (BITBUFSIZ - 1 - 8); - do { + do { - if (Mask & Sd->mBitBuf) { - CharC = Sd->mRight[CharC]; - } else { - CharC = Sd->mLeft[CharC]; - } + if (Mask & Sd->mBitBuf) { + CharC = Sd->mRight[CharC]; + } + else { + CharC = Sd->mLeft[CharC]; + } - Mask >>= 1; + Mask >>= 1; - } while (CharC >= NT); - } - // - // Advance what we have read - // - FillBuf (Sd, Sd->mPTLen[CharC]); + } while (CharC >= NT); + } + // + // Advance what we have read + // + FillBuf(Sd, Sd->mPTLen[CharC]); - if (CharC <= 2) { + 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); - } + 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; - } + while ((INT16)(--CharC) >= 0) { + Sd->mCLen[Index++] = 0; + } - } else { + } + else { - Sd->mCLen[Index++] = (UINT8) (CharC - 2); + Sd->mCLen[Index++] = (UINT8)(CharC - 2); - } -} + } + } -while (Index < NC) { - Sd->mCLen[Index++] = 0; -} + while (Index < NC) { + Sd->mCLen[Index++] = 0; + } -MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); + MakeTable(Sd, NC, Sd->mCLen, 12, Sd->mCTable); -return ; + return; } STATIC UINT16 -DecodeC ( +DecodeC( SCRATCH_DATA *Sd ) /*++ @@ -550,54 +598,55 @@ The value decoded. --*/ { -UINT16 Index2; -UINT32 Mask; + 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; - } + 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); + ReadCLen(Sd); - Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1)); - if (Sd->mBadTableFlag != 0) { - return 0; - } -} + Sd->mBadTableFlag = ReadPTLen(Sd, MAXNP, Sd->mPBit, (UINT16)(-1)); + if (Sd->mBadTableFlag != 0) { + return 0; + } + } -Sd->mBlockSize--; -Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; + Sd->mBlockSize--; + Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; -if (Index2 >= NC) { - Mask = 1U << (BITBUFSIZ - 1 - 12); + if (Index2 >= NC) { + Mask = 1U << (BITBUFSIZ - 1 - 12); - do { - if (Sd->mBitBuf & Mask) { - Index2 = Sd->mRight[Index2]; - } else { - Index2 = Sd->mLeft[Index2]; - } + 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]); + Mask >>= 1; + } while (Index2 >= NC); + } + // + // Advance what we have read + // + FillBuf(Sd, Sd->mCLen[Index2]); -return Index2; + return Index2; } STATIC VOID -Decode ( +Decode( SCRATCH_DATA *Sd ) /*++ @@ -614,65 +663,61 @@ Returns: (VOID) --*/ { -UINT16 BytesRemain; -UINT32 DataIdx; -UINT16 CharC; + UINT16 BytesRemain; + UINT32 DataIdx; + UINT16 CharC; -BytesRemain = (UINT16) (-1); + BytesRemain = (UINT16)(-1); -DataIdx = 0; + DataIdx = 0; -for (;;) { - CharC = DecodeC (Sd); - if (Sd->mBadTableFlag != 0) { - return ; - } - - if (CharC < 256) { - // - // Process an Original character - // - if (Sd->mOutBuf >= Sd->mOrigSize) { - return ; - } 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; - if (DataIdx >= Sd->mOrigSize) { - Sd->mBadTableFlag = 1; + for (;;) { + CharC = DecodeC(Sd); + if (Sd->mBadTableFlag != 0) { return; } - - BytesRemain--; - while ((INT16) (BytesRemain) >= 0) { - Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; - if (Sd->mOutBuf >= Sd->mOrigSize) { - return ; - } - BytesRemain--; - } - } + if (CharC < 256) { + // + // Process an Original character + // + if (Sd->mOutBuf >= Sd->mOrigSize) { + return; + } + 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) { + Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; + if (Sd->mOutBuf >= Sd->mOrigSize) { + return; + } + + BytesRemain--; + } + } + } } -return ; -} - -UINT32 -EfiTianoGetInfo ( -VOID *Source, -UINT32 SrcSize, -UINT32 *DstSize, -UINT32 *ScratchSize +EFI_STATUS +GetInfo( +IN VOID *Source, +IN UINT32 SrcSize, +OUT UINT32 *DstSize, +OUT UINT32 *ScratchSize ) /*++ @@ -689,33 +734,33 @@ ScratchSize - The size of scratch buffer. Returns: -EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. +EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successull retrieved. EFI_INVALID_PARAMETER - The source data is corrupted --*/ { -UINT8 *Src; + UINT8 *Src; -*ScratchSize = sizeof (SCRATCH_DATA); + *ScratchSize = sizeof(SCRATCH_DATA); -Src = Source; -if (SrcSize < 8) { - return ERR_INVALID_PARAMETER; + Src = Source; + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + return EFI_SUCCESS; } -*DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); -return ERR_SUCCESS; -} - -UINT32 -Decompress ( -VOID *Source, -UINT32 SrcSize, -VOID *Destination, -UINT32 DstSize, -VOID *Scratch, -UINT32 ScratchSize, -UINT8 Version +EFI_STATUS +Decompress( +IN VOID *Source, +IN UINT32 SrcSize, +IN OUT VOID *Destination, +IN UINT32 DstSize, +IN OUT VOID *Scratch, +IN UINT32 ScratchSize, +IN UINT8 Version ) /*++ @@ -742,112 +787,149 @@ EFI_INVALID_PARAMETER - The source data is corrupted --*/ { -UINT32 Index; -UINT32 CompSize; -UINT32 OrigSize; -UINT32 Status; -SCRATCH_DATA *Sd; -UINT8 *Src; -UINT8 *Dst; + UINT32 Index; + UINT32 CompSize; + UINT32 OrigSize; + EFI_STATUS Status; + SCRATCH_DATA *Sd; + UINT8 *Src; + UINT8 *Dst; -Status = ERR_SUCCESS; -Src = Source; -Dst = Destination; + Status = EFI_SUCCESS; + Src = Source; + Dst = Destination; -if (ScratchSize < sizeof (SCRATCH_DATA)) { - return ERR_INVALID_PARAMETER; + if (ScratchSize < sizeof(SCRATCH_DATA)) { + return EFI_INVALID_PARAMETER; + } + + Sd = (SCRATCH_DATA *)Scratch; + + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + 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 Status; + } + + if (SrcSize < CompSize + 8) { + return EFI_INVALID_PARAMETER; + } + + if (DstSize != OrigSize) { + return EFI_INVALID_PARAMETER; + } + + 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: + // + // Currently, only have 2 versions + // + return EFI_INVALID_PARAMETER; + } + + Sd->mSrcBase = 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 + // + Status = EFI_INVALID_PARAMETER; + } + + return Status; } -Sd = (SCRATCH_DATA *) Scratch; - -if (SrcSize < 8) { - return ERR_INVALID_PARAMETER; -} - -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 Status; -} - -if (SrcSize < CompSize + 8) { - return ERR_INVALID_PARAMETER; -} - -if (DstSize != OrigSize) { - return ERR_INVALID_PARAMETER; -} - -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'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: - // - // Currently, only have 2 versions - // - return ERR_INVALID_PARAMETER; -} - -Sd->mSrcBase = 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 - // - Status = ERR_INVALID_PARAMETER; -} - -return Status; -} - -UINT32 +EFI_STATUS EFIAPI -EfiDecompress ( -VOID *Source, -UINT32 SrcSize, -VOID *Destination, -UINT32 DstSize, -VOID *Scratch, -UINT32 ScratchSize +EfiTianoGetInfo( +IN VOID *Source, +IN UINT32 SrcSize, +OUT UINT32 *DstSize, +OUT UINT32 *ScratchSize ) /*++ Routine Description: -The implementation is same as that of EFI_DECOMPRESS_PROTOCOL.Decompress(). +The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo(). + +Arguments: + +This - The protocol instance pointer +Source - The source buffer containing the compressed data. +SrcSize - The size of source buffer +DstSize - The size of destination buffer. +ScratchSize - The size of scratch buffer. + +Returns: + +EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successful retrieved. +EFI_INVALID_PARAMETER - The source data is corrupted + +--*/ +{ + return GetInfo( + Source, + SrcSize, + DstSize, + ScratchSize + ); +} + +EFI_STATUS +EFIAPI +EfiDecompress( +IN VOID *Source, +IN UINT32 SrcSize, +IN OUT VOID *Destination, +IN UINT32 DstSize, +IN OUT VOID *Scratch, +IN UINT32 ScratchSize +) +/*++ + +Routine Description: + +The implementation of EFI_DECOMPRESS_PROTOCOL.Decompress(). Arguments: @@ -866,35 +948,35 @@ EFI_INVALID_PARAMETER - The source data is corrupted --*/ { -// -// For EFI 1.1 de/compression algorithm, the version is 1. -// -return Decompress ( - Source, - SrcSize, - Destination, - DstSize, - Scratch, - ScratchSize, - 1 - ); + // + // For EFI 1.1 de/compression algorithm, the version is 1. + // + return Decompress( + Source, + SrcSize, + Destination, + DstSize, + Scratch, + ScratchSize, + 1 + ); } -UINT32 +EFI_STATUS EFIAPI -TianoDecompress ( -VOID *Source, -UINT32 SrcSize, -VOID *Destination, -UINT32 DstSize, -VOID *Scratch, -UINT32 ScratchSize +TianoDecompress( +IN VOID *Source, +IN UINT32 SrcSize, +IN OUT VOID *Destination, +IN UINT32 DstSize, +IN OUT VOID *Scratch, +IN UINT32 ScratchSize ) /*++ Routine Description: -The implementation is same as that of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress(). +The implementation of EFI_TIANO_DECOMPRESS_PROTOCOL.Decompress(). Arguments: @@ -913,17 +995,16 @@ EFI_INVALID_PARAMETER - The source data is corrupted --*/ { -// -// For Tiano de/compression algorithm, the version is 2. -// -return Decompress ( - Source, - SrcSize, - Destination, - DstSize, - Scratch, - ScratchSize, - 2 - ); + // + // For Tiano de/compression algorithm, the version is 2. + // + return Decompress( + Source, + SrcSize, + Destination, + DstSize, + Scratch, + ScratchSize, + 2 + ); } - diff --git a/Tiano/EfiTianoDecompress.h b/Tiano/EfiTianoDecompress.h index 177c901..54c0fa1 100644 --- a/Tiano/EfiTianoDecompress.h +++ b/Tiano/EfiTianoDecompress.h @@ -1,6 +1,7 @@ -/*++ +/* EfiTianoDecompress.h -Copyright (c) 2004 - 2006, Intel Corporation. All rights reserved.
+Copyright (c) 2014, Nikolaj Schlej. All rights reserved.
+Copyright (c) 2004 - 2008, 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 @@ -11,12 +12,12 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. Module Name: -Decompress.h + Decompress.h Abstract: -Header file for decompression routine. -Providing both EFI and Tiano decompress algorithms. + Header file for decompression routine. + Providing both EFI and Tiano decompress algorithms. --*/ @@ -30,12 +31,13 @@ Providing both EFI and Tiano decompress algorithms. #ifdef __cplusplus extern "C" { #endif + typedef struct { UINT32 CompSize; UINT32 OrigSize; } EFI_TIANO_HEADER; -UINT32 +EFI_STATUS EFIAPI EfiTianoGetInfo ( VOID *Source, @@ -65,7 +67,7 @@ EFI_INVALID_PARAMETER - The source data is corrupted --*/ ; -UINT32 +EFI_STATUS EFIAPI EfiDecompress ( VOID *Source, @@ -99,7 +101,7 @@ EFI_INVALID_PARAMETER - The source data is corrupted --*/ ; -UINT32 +EFI_STATUS EFIAPI TianoDecompress ( VOID *Source, diff --git a/UEFIPatch/uefipatch.cpp b/UEFIPatch/uefipatch.cpp index fc0b711..3d2576e 100644 --- a/UEFIPatch/uefipatch.cpp +++ b/UEFIPatch/uefipatch.cpp @@ -56,6 +56,7 @@ UINT8 UEFIPatch::patchFromFile(QString path) if (result) return result; + UINT8 counter = 0; while (!file.atEnd()) { QByteArray line = file.readLine(); // Use sharp sign as commentary @@ -68,20 +69,46 @@ UINT8 UEFIPatch::patchFromFile(QString path) QUuid uuid = QUuid(list.at(0)); QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID)); - result = patchFile(model->index(0, 0), guid, QByteArray::fromHex(list.at(1)), QByteArray::fromHex(list.at(2))); - if (result) + bool converted; + UINT8 sectionType = (UINT8)list.at(1).toUShort(&converted, 16); + if (!converted) + return ERR_INVALID_PARAMETER; + + QVector patches; + + for (int i = 2; i < list.count(); i++) { + QList patchList = list.at(i).split(':'); + PatchData patch; + patch.type = *(UINT8*)patchList.at(0).constData(); + if (patch.type == PATCH_TYPE_PATTERN) { + patch.offset = 0xFFFFFFFF; + patch.hexFindPattern = patchList.at(1); + patch.hexReplacePattern = patchList.at(2); + patches.append(patch); + } + else if (patch.type == PATCH_TYPE_OFFSET) { + patch.offset = patchList.at(1).toUInt(NULL, 16); + patch.hexReplacePattern = patchList.at(2); + patches.append(patch); + } + else { + // Ignore unknown patch type + continue; + } + } + result = patchFile(model->index(0, 0), guid, sectionType, patches); + if (result && result != ERR_NOTHING_TO_PATCH) return result; + counter++; } QByteArray reconstructed; result = ffsEngine->reconstructImageFile(reconstructed); if (result) return result; - - if (reconstructed == buffer) { - return ERR_ITEM_NOT_FOUND; - } - + if (reconstructed == buffer) + return ERR_NOTHING_TO_PATCH; + QFile outputFile; outputFile.setFileName(path.append(".patched")); if (!outputFile.open(QFile::WriteOnly)) @@ -94,72 +121,29 @@ UINT8 UEFIPatch::patchFromFile(QString path) return ERR_SUCCESS; } -UINT8 UEFIPatch::patch(QString path, QString fileGuid, QString findPattern, QString replacePattern) -{ - QFileInfo fileInfo = QFileInfo(path); - - if (!fileInfo.exists()) - return ERR_FILE_OPEN; - - QFile inputFile; - inputFile.setFileName(path); - - if (!inputFile.open(QFile::ReadOnly)) - return ERR_FILE_READ; - - QByteArray buffer = inputFile.readAll(); - inputFile.close(); - - UINT8 result = ffsEngine->parseImageFile(buffer); - if (result) - return result; - - - QUuid uuid = QUuid(fileGuid); - QByteArray guid = QByteArray::fromRawData((const char*)&uuid.data1, sizeof(EFI_GUID)); - result = patchFile(model->index(0, 0), guid, QByteArray::fromHex(findPattern.toLatin1()), QByteArray::fromHex(replacePattern.toLatin1())); - if (result) - return result; - - QByteArray reconstructed; - result = ffsEngine->reconstructImageFile(reconstructed); - if (result) - return result; - - if (reconstructed == buffer) { - return ERR_ITEM_NOT_FOUND; - } - - QFile outputFile; - outputFile.setFileName(path.append(".patched")); - if (!outputFile.open(QFile::WriteOnly)) - return ERR_FILE_WRITE; - - outputFile.resize(0); - outputFile.write(reconstructed); - outputFile.close(); - - return ERR_SUCCESS; -} - -UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const QByteArray & findPattern, const QByteArray & replacePattern) +UINT8 UEFIPatch::patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector & patches) { + if (!model || !index.isValid()) return ERR_INVALID_PARAMETER; - - if (model->type(index) == Types::File && model->header(index).left(sizeof(EFI_GUID)) == fileGuid) { - return ffsEngine->patch(index, findPattern, replacePattern, PATCH_MODE_BODY); + if (model->type(index) == Types::Section && model->subtype(index) == sectionType) { + QModelIndex fileIndex = model->findParentOfType(index, Types::File); + if (model->type(fileIndex) == Types::File && + model->header(fileIndex).left(sizeof(EFI_GUID)) == fileGuid) + { + return ffsEngine->patch(index, patches); + } } - int childCount = model->rowCount(index); - if (childCount > 0) { - UINT8 result; - for (int i = 0; i < childCount; i++) { - result = patchFile(index.child(i, 0), fileGuid, findPattern, replacePattern); - if (result) + if (model->rowCount(index) > 0) { + for (int i = 0; i < model->rowCount(index); i++) { + UINT8 result = patchFile(index.child(i, 0), fileGuid, sectionType, patches); + if (!result) + break; + else if (result != ERR_NOTHING_TO_PATCH) return result; } } - - return ERR_SUCCESS; -} \ No newline at end of file + + return ERR_NOTHING_TO_PATCH; +} diff --git a/UEFIPatch/uefipatch.h b/UEFIPatch/uefipatch.h index 44c4562..3d94ca2 100644 --- a/UEFIPatch/uefipatch.h +++ b/UEFIPatch/uefipatch.h @@ -37,7 +37,7 @@ public: UINT8 patch(QString path, QString fileGuid, QString findPattern, QString replacePattern); private: - UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const QByteArray & findPattern, const QByteArray & replacePattern); + UINT8 patchFile(const QModelIndex & index, const QByteArray & fileGuid, const UINT8 sectionType, const QVector & patches); FfsEngine* ffsEngine; TreeModel* model; }; diff --git a/UEFIPatch/uefipatch_main.cpp b/UEFIPatch/uefipatch_main.cpp index f15f79d..050eb0b 100644 --- a/UEFIPatch/uefipatch_main.cpp +++ b/UEFIPatch/uefipatch_main.cpp @@ -27,31 +27,34 @@ int main(int argc, char *argv[]) UINT8 result = ERR_SUCCESS; UINT32 argumentsCount = a.arguments().length(); - if (argumentsCount == 2) { result = w.patchFromFile(a.arguments().at(1)); } - else if (argumentsCount == 5) { - result = w.patch(a.arguments().at(1), a.arguments().at(2), a.arguments().at(3), a.arguments().at(4)); + else { + std::cout << "UEFIPatch 0.2.0 - UEFI image file patching utility" << std::endl << std::endl << + "Usage: UEFIPatch image_file" << std::endl << std::endl << + "Patches will be read from patches.txt file\n"; + return ERR_SUCCESS; } - else - result = ERR_INVALID_PARAMETER; switch (result) { - case ERR_INVALID_PARAMETER: - std::cout << "UEFIPatch 0.1.0 - UEFI image file patching utility" << std::endl << std::endl << - "Usage: UEFIPatch image_file [ffs_file_guid search_pattern replace_pattern]" << std::endl << std::endl << - "image_file - full or relative path to UEFI image file" << std::endl << - "ffs_file_guid - GUID of FFS file to be patched" << std::endl << - "search_pattern - pattern to search" << std::endl << - "replace_pattern - pattern to replace" << std::endl << std::endl << - "If only image_file parameter is specified, patches will be read from patches.txt file"; - break; case ERR_SUCCESS: std::cout << "Image patched" << std::endl; break; - case ERR_ITEM_NOT_FOUND: - std::cout << "FFS file or search pattern not found in input file" << std::endl; + case ERR_INVALID_PARAMETER: + std::cout << "Function called with invalid parameter" << std::endl; + break; + case ERR_NOTHING_TO_PATCH: + std::cout << "No patches can be applied to input file" << std::endl; + break; + case ERR_UNKNOWN_PATCH_TYPE: + std::cout << "Unknown patch type" << std::endl; + break; + case ERR_PATCH_OFFSET_OUT_OF_BOUNDS: + std::cout << "Patch offset out of bounds" << std::endl; + break; + case ERR_INVALID_SYMBOL: + std::cout << "Pattern format mismatch" << std::endl; break; case ERR_INVALID_FILE: std::cout << "patches.txt file not found or can't be read" << std::endl; diff --git a/basetypes.h b/basetypes.h index c910adb..9f34a47 100644 --- a/basetypes.h +++ b/basetypes.h @@ -45,8 +45,6 @@ typedef uint16_t CHAR16; #define NULL ((VOID *) 0) #endif -#define EFIAPI - #define ERR_SUCCESS 0 #define ERR_INVALID_PARAMETER 1 #define ERR_BUFFER_TOO_SMALL 2 @@ -85,9 +83,23 @@ typedef uint16_t CHAR16; #define ERR_COMPLEX_BLOCK_MAP 35 #define ERR_DIR_ALREADY_EXIST 36 #define ERR_DIR_CREATE 37 -#define ERR_UNKNOWN_PATCH_MODE 38 +#define ERR_UNKNOWN_PATCH_TYPE 38 +#define ERR_PATCH_OFFSET_OUT_OF_BOUNDS 39 +#define ERR_INVALID_SYMBOL 40 +#define ERR_NOTHING_TO_PATCH 41 #define ERR_NOT_IMPLEMENTED 0xFF +// UDK porting definitions +#define IN +#define OUT +#define EFIAPI +#define EFI_STATUS UINT8 +#define EFI_SUCCESS ERR_SUCCESS +#define EFI_INVALID_PARAMETER ERR_INVALID_PARAMETER +#define EFI_OUT_OF_RESOURCES ERR_OUT_OF_RESOURCES +#define EFI_BUFFER_TOO_SMALL ERR_BUFFER_TOO_SMALL +#define EFI_ERROR(X) X + // Compression algorithms #define COMPRESSION_ALGORITHM_UNKNOWN 0 #define COMPRESSION_ALGORITHM_NONE 1 @@ -114,6 +126,10 @@ typedef uint16_t CHAR16; #define PATCH_MODE_HEADER 0 #define PATCH_MODE_BODY 1 +// Patch types +#define PATCH_TYPE_OFFSET 'O' +#define PATCH_TYPE_PATTERN 'P' + // Erase polarity types #define ERASE_POLARITY_FALSE 0 #define ERASE_POLARITY_TRUE 1 @@ -124,8 +140,6 @@ typedef uint16_t CHAR16; #define SEARCH_MODE_BODY 2 #define SEARCH_MODE_ALL 3 - - // EFI GUID typedef struct { UINT8 Data[16]; diff --git a/ffsengine.cpp b/ffsengine.cpp index b11cd6c..5c99281 100644 --- a/ffsengine.cpp +++ b/ffsengine.cpp @@ -1797,8 +1797,7 @@ UINT8 FfsEngine::decompress(const QByteArray & compressedData, const UINT8 compr UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteArray & compressedData) { UINT8* compressed; - UINT32 compressedSize = 0; - + switch (algorithm) { case COMPRESSION_ALGORITHM_NONE: { @@ -1808,10 +1807,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA break; case COMPRESSION_ALGORITHM_EFI11: { - if (EfiCompress((UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) + UINT64 compressedSize = 0; + if (EfiCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) return ERR_STANDARD_COMPRESSION_FAILED; compressed = new UINT8[compressedSize]; - if (EfiCompress((UINT8*)data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { + if (EfiCompress(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { delete[] compressed; return ERR_STANDARD_COMPRESSION_FAILED; } @@ -1822,10 +1822,11 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA break; case COMPRESSION_ALGORITHM_TIANO: { - if (TianoCompress((UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) + UINT64 compressedSize = 0; + if (TianoCompress(data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) return ERR_STANDARD_COMPRESSION_FAILED; compressed = new UINT8[compressedSize]; - if (TianoCompress((UINT8*)data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { + if (TianoCompress(data.constData(), data.size(), compressed, &compressedSize) != ERR_SUCCESS) { delete[] compressed; return ERR_STANDARD_COMPRESSION_FAILED; } @@ -1836,6 +1837,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA break; case COMPRESSION_ALGORITHM_LZMA: { + UINT32 compressedSize = 0; if (LzmaCompress((const UINT8*)data.constData(), data.size(), NULL, &compressedSize) != ERR_BUFFER_TOO_SMALL) return ERR_CUSTOMIZED_COMPRESSION_FAILED; compressed = new UINT8[compressedSize]; @@ -1850,6 +1852,7 @@ UINT8 FfsEngine::compress(const QByteArray & data, const UINT8 algorithm, QByteA break; case COMPRESSION_ALGORITHM_IMLZMA: { + UINT32 compressedSize = 0; QByteArray header = data.left(sizeof(EFI_COMMON_SECTION_HEADER)); EFI_COMMON_SECTION_HEADER* sectionHeader = (EFI_COMMON_SECTION_HEADER*)header.constData(); UINT32 headerSize = sizeOfSectionHeader(sectionHeader); @@ -2645,6 +2648,7 @@ UINT8 FfsEngine::reconstructSection(const QModelIndex& index, const UINT32 base, // Reconstruction successful reconstructed = header.append(reconstructed); + return ERR_SUCCESS; } @@ -3198,48 +3202,126 @@ UINT8 FfsEngine::dump(const QModelIndex & index, const QString path) return ERR_SUCCESS; } -UINT8 FfsEngine::patch(const QModelIndex & index, const QByteArray & findPattern, const QByteArray & replacePattern, const UINT8 mode) +UINT8 FfsEngine::patch(const QModelIndex & index, const QVector & patches) { - if (!index.isValid() || findPattern.isEmpty()) + if (!index.isValid() || patches.isEmpty() || model->rowCount(index)) return ERR_INVALID_PARAMETER; - // Skip removed files + // Skip removed items if (model->action(index) == Actions::Remove) - return ERR_SUCCESS; + return ERR_NOTHING_TO_PATCH; - // Patch header - if (mode == PATCH_MODE_HEADER && model->header(index).contains(findPattern)) { + UINT8 result; + + // Apply patches to item's body + QByteArray body = model->body(index); + PatchData current; + Q_FOREACH(current, patches) + { + if (current.type == PATCH_TYPE_OFFSET) { + result = patchViaOffset(body, current.offset, current.hexReplacePattern); + if (result) + return result; + } + else if (current.type == PATCH_TYPE_PATTERN) { + result = patchViaPattern(body, current.hexFindPattern, current.hexReplacePattern); + if (result) + return result; + } + else + return ERR_UNKNOWN_PATCH_TYPE; + } + + if (body != model->body(index)) { QByteArray patched = model->header(index); - patched.replace(findPattern, replacePattern).append(model->body(index)); - msg(tr("Header of %1 patched, %2 -> %3") - .arg(model->nameString(index)) - .arg(QString(findPattern.toHex())) - .arg(QString(replacePattern.toHex())), index); + patched.append(body); return replace(index, patched, REPLACE_MODE_AS_IS); } - // Patch body - else if (mode == PATCH_MODE_BODY) { - if (model->rowCount(index)) { - UINT8 result; - for (int i = 0; i < model->rowCount(index); i++) { - result = patch(index.child(i, 0), findPattern, replacePattern, PATCH_MODE_BODY); - if (result) - return result; - } - } - else if (model->body(index).contains(findPattern)){ - QByteArray patched = model->body(index); - patched.replace(findPattern, replacePattern); - patched.prepend(model->header(index)); - msg(tr("Body of %1 patched, %2 -> %3") - .arg(model->nameString(index)) - .arg(QString(findPattern.toHex())) - .arg(QString(replacePattern.toHex())), index); - return replace(index, patched, REPLACE_MODE_AS_IS); - } - } - else - return ERR_UNKNOWN_PATCH_MODE; + + return ERR_NOTHING_TO_PATCH; +} +UINT8 FfsEngine::patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern) +{ + QByteArray body = data; + + // Skip patterns with odd length + if (hexReplacePattern.length() % 2 > 0) + return ERR_INVALID_PARAMETER; + + // Check offset bounds + if (offset > body.length() - hexReplacePattern.length() / 2) + return ERR_PATCH_OFFSET_OUT_OF_BOUNDS; + + // Parse replace pattern + QByteArray replacePattern; + bool converted; + for (int i = 0; i < hexReplacePattern.length() / 2; i++) { + QByteArray hex = hexReplacePattern.mid(2 * i, 2); + UINT8 value = 0; + + if (!hex.contains('.')) { // Normal byte pattern + value = (UINT8)hex.toUShort(&converted, 16); + if (!converted) + return ERR_INVALID_SYMBOL; + } + else { // Placeholder byte pattern + if (hex[0] == '.' && hex[1] == '.') { // Full byte placeholder + value = body.at(offset + i); + } + else if (hex[0] == '.') {// Upper byte part placeholder + hex[0] = '0'; + value = (UINT8)(body.at(offset + i) & 0xF0); + value += (UINT8)hex.toUShort(&converted, 16); + if (!converted) + return ERR_INVALID_SYMBOL; + } + else if (hex[1] == '.') { // Lower byte part placeholder + hex[1] = '0'; + value = (UINT8)(body.at(offset + i) & 0x0F); + value += (UINT8)hex.toUShort(&converted, 16); + if (!converted) + return ERR_INVALID_SYMBOL; + } + else + return ERR_INVALID_SYMBOL; + } + + // Append calculated value to real pattern + replacePattern.append(value); + } + + body.replace(offset, replacePattern.length(), replacePattern); + msg(tr("patch: replaced %1 bytes at offset 0x%2 %3 -> %4") + .arg(replacePattern.length()) + .arg(offset, 8, 16, QChar('0')) + .arg(QString(data.mid(offset, replacePattern.length()).toHex())) + .arg(QString(replacePattern.toHex()))); + data = body; + return ERR_SUCCESS; +} + +UINT8 FfsEngine::patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern) +{ + QByteArray body = data; + + // Skip patterns with odd length + if (hexFindPattern.length() % 2 > 0 || hexReplacePattern.length() % 2 > 0) + return ERR_INVALID_PARAMETER; + + // Convert file body to hex; + QString hexBody = QString(body.toHex()); + QRegExp regexp = QRegExp(QString(hexFindPattern), Qt::CaseInsensitive); + INT64 offset = regexp.indexIn(hexBody); + while (offset >= 0) { + if (offset % 2 == 0) { + UINT8 result = patchViaOffset(body, offset/2, hexReplacePattern); + if (result) + return result; + } + offset = regexp.indexIn(hexBody, offset + 1); + } + + data = body; return ERR_SUCCESS; } \ No newline at end of file diff --git a/ffsengine.h b/ffsengine.h index de8f2d6..a44cb38 100644 --- a/ffsengine.h +++ b/ffsengine.h @@ -32,6 +32,13 @@ WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. class TreeModel; +struct PatchData { + UINT8 type; + UINT32 offset; + QByteArray hexFindPattern; + QByteArray hexReplacePattern; +}; + class FfsEngine : public QObject { Q_OBJECT @@ -86,7 +93,7 @@ public: UINT8 remove(const QModelIndex & index); UINT8 rebuild(const QModelIndex & index); UINT8 dump(const QModelIndex & index, const QString path); - UINT8 patch(const QModelIndex & index, const QByteArray & findPattern, const QByteArray & replacePattern, const UINT8 mode); + UINT8 patch(const QModelIndex & index, const QVector & patches); // Search routines UINT8 findHexPattern(const QByteArray & pattern, const UINT8 mode); @@ -120,12 +127,16 @@ private: // Patch routines UINT8 patchVtf(QByteArray &vtf); + // Patch helpers + UINT8 patchViaOffset(QByteArray & data, const UINT32 offset, const QByteArray & hexReplacePattern); + UINT8 patchViaPattern(QByteArray & data, const QByteArray hexFindPattern, const QByteArray & hexReplacePattern); + #ifndef _CONSOLE QQueue messageItems; #endif // Message helper void msg(const QString & message, const QModelIndex &index = QModelIndex()); - + // Internal operations bool hasIntersection(const UINT32 begin1, const UINT32 end1, const UINT32 begin2, const UINT32 end2); UINT32 crc32(UINT32 initial, const UINT8* buffer, UINT32 length); diff --git a/uefitool.ui b/uefitool.ui index b404910..988157c 100644 --- a/uefitool.ui +++ b/uefitool.ui @@ -20,7 +20,7 @@ true - UEFITool 0.17.10 + UEFITool 0.18.0