mirror of
				https://github.com/acidanthera/audk.git
				synced 2025-10-25 17:23:53 +02:00 
			
		
		
		
	https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
		
			
				
	
	
		
			2796 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2796 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
| Compression routine. The compression algorithm is a mixture of LZ77 and Huffman
 | |
| coding. LZ77 transforms the source data into a sequence of Original Characters
 | |
| and Pointers to repeated strings.
 | |
| This sequence is further divided into Blocks and Huffman codings are applied to
 | |
| each Block.
 | |
| 
 | |
| Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "Compress.h"
 | |
| #include "Decompress.h"
 | |
| #include "TianoCompress.h"
 | |
| #include "EfiUtilityMsgs.h"
 | |
| #include "ParseInf.h"
 | |
| #include <stdio.h>
 | |
| #include "assert.h"
 | |
| 
 | |
| //
 | |
| // Macro Definitions
 | |
| //
 | |
| static BOOLEAN VerboseMode = FALSE;
 | |
| static BOOLEAN QuietMode = FALSE;
 | |
| #undef UINT8_MAX
 | |
| #define UINT8_MAX     0xff
 | |
| #define UINT8_BIT     8
 | |
| #define THRESHOLD     3
 | |
| #define INIT_CRC      0
 | |
| #define WNDBIT        19
 | |
| #define WNDSIZ        (1U << WNDBIT)
 | |
| #define MAXMATCH      256
 | |
| #define BLKSIZ        (1U << 14)  // 16 * 1024U
 | |
| #define PERC_FLAG     0x80000000U
 | |
| #define CODE_BIT      16
 | |
| #define NIL           0
 | |
| #define MAX_HASH_VAL  (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
 | |
| #define HASH(p, c)    ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
 | |
| #define CRCPOLY       0xA001
 | |
| #define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
 | |
| 
 | |
| //
 | |
| // C: the Char&Len Set; P: the Position Set; T: the exTra Set
 | |
| //
 | |
| //#define NC    (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
 | |
| #define CBIT  9
 | |
| #define NP    (WNDBIT + 1)
 | |
| #define PBIT  5
 | |
| //#define NT    (CODE_BIT + 3)
 | |
| //#define TBIT  5
 | |
| //#if NT > NP
 | |
| //#define NPT NT
 | |
| //#else
 | |
| //#define NPT NP
 | |
| //#endif
 | |
| 
 | |
| //
 | |
| //  Global Variables
 | |
| //
 | |
| STATIC BOOLEAN ENCODE = FALSE;
 | |
| STATIC BOOLEAN DECODE = FALSE;
 | |
| STATIC BOOLEAN UEFIMODE = FALSE;
 | |
| STATIC UINT8  *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit;
 | |
| STATIC UINT8  *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen;
 | |
| STATIC INT16  mHeap[NC + 1];
 | |
| STATIC INT32  mRemainder, mMatchLen, mBitCount, mHeapSize, mN;
 | |
| STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc;
 | |
| STATIC UINT32 mCompSize, mOrigSize;
 | |
| 
 | |
| STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], mCrcTable[UINT8_MAX + 1],
 | |
|   mCFreq[2 * NC - 1], mCCode[NC], mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];
 | |
| 
 | |
| STATIC NODE   mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;
 | |
| 
 | |
| static  UINT64     DebugLevel;
 | |
| static  BOOLEAN    DebugMode;
 | |
| //
 | |
| // functions
 | |
| //
 | |
| EFI_STATUS
 | |
| TianoCompress (
 | |
|   IN      UINT8   *SrcBuffer,
 | |
|   IN      UINT32  SrcSize,
 | |
|   IN      UINT8   *DstBuffer,
 | |
|   IN OUT  UINT32  *DstSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   The internal implementation of [Efi/Tiano]Compress().
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   SrcBuffer   - The buffer storing the source data
 | |
|   SrcSize     - The size of source data
 | |
|   DstBuffer   - The buffer to store the compressed data
 | |
| 
 | |
|   Version     - The version of de/compression algorithm.
 | |
|                 Version 1 for EFI 1.1 de/compression algorithm.
 | |
|                 Version 2 for Tiano de/compression algorithm.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_BUFFER_TOO_SMALL  - The DstBuffer is too small. In this case,
 | |
|                 DstSize contains the size needed.
 | |
|   EFI_SUCCESS           - Compression is successful.
 | |
|   EFI_OUT_OF_RESOURCES  - No resource to complete function.
 | |
|   EFI_INVALID_PARAMETER - Parameter supplied is wrong.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   //
 | |
|   // Initializations
 | |
|   //
 | |
|   mBufSiz         = 0;
 | |
|   mBuf            = NULL;
 | |
|   mText           = NULL;
 | |
|   mLevel          = NULL;
 | |
|   mChildCount     = NULL;
 | |
|   mPosition       = NULL;
 | |
|   mParent         = NULL;
 | |
|   mPrev           = NULL;
 | |
|   mNext           = NULL;
 | |
| 
 | |
| 
 | |
|   mSrc            = SrcBuffer;
 | |
|   mSrcUpperLimit  = mSrc + SrcSize;
 | |
|   mDst            = DstBuffer;
 | |
|   mDstUpperLimit  = mDst +*DstSize;
 | |
| 
 | |
|   PutDword (0L);
 | |
|   PutDword (0L);
 | |
| 
 | |
|   MakeCrcTable ();
 | |
| 
 | |
|   mOrigSize             = mCompSize = 0;
 | |
|   mCrc                  = INIT_CRC;
 | |
| 
 | |
|   //
 | |
|   // Compress it
 | |
|   //
 | |
|   Status = Encode ();
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Null terminate the compressed data
 | |
|   //
 | |
| 
 | |
|   if (mDst < mDstUpperLimit) {
 | |
|     *mDst++ = 0;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Fill in compressed size and original size
 | |
|   //
 | |
|   mDst = DstBuffer;
 | |
| 
 | |
|   PutDword (mCompSize + 1);
 | |
|   PutDword (mOrigSize);
 | |
|   //
 | |
|   // Return
 | |
|   //
 | |
| 
 | |
|   if (mCompSize + 1 + 8 > *DstSize) {
 | |
|     *DstSize = mCompSize + 1 + 8;
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   } else {
 | |
|     *DstSize = mCompSize + 1 + 8;
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| PutDword (
 | |
|   IN UINT32 Data
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Put a dword to output stream
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Data    - the dword to put
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   if (mDst < mDstUpperLimit) {
 | |
|     *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff);
 | |
|   }
 | |
| 
 | |
|   if (mDst < mDstUpperLimit) {
 | |
|     *mDst++ = (UINT8) (((UINT8) (Data >> 0x08)) & 0xff);
 | |
|   }
 | |
| 
 | |
|   if (mDst < mDstUpperLimit) {
 | |
|     *mDst++ = (UINT8) (((UINT8) (Data >> 0x10)) & 0xff);
 | |
|   }
 | |
| 
 | |
|   if (mDst < mDstUpperLimit) {
 | |
|     *mDst++ = (UINT8) (((UINT8) (Data >> 0x18)) & 0xff);
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| AllocateMemory (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Allocate memory spaces for data structures used in compression process
 | |
| 
 | |
| Arguments:
 | |
|   VOID
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS           - Memory is allocated successfully
 | |
|   EFI_OUT_OF_RESOURCES  - Allocation fails
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32  Index;
 | |
| 
 | |
|   mText = malloc (WNDSIZ * 2 + MAXMATCH);
 | |
|   if (mText == NULL) {
 | |
|     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
|   for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) {
 | |
|     mText[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   mLevel      = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel));
 | |
|   mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount));
 | |
|   mPosition   = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition));
 | |
|   mParent     = malloc (WNDSIZ * 2 * sizeof (*mParent));
 | |
|   mPrev       = malloc (WNDSIZ * 2 * sizeof (*mPrev));
 | |
|   mNext       = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext));
 | |
|   if (mLevel == NULL || mChildCount == NULL || mPosition == NULL ||
 | |
|     mParent == NULL || mPrev == NULL || mNext == NULL) {
 | |
|     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   mBufSiz     = BLKSIZ;
 | |
|   mBuf        = malloc (mBufSiz);
 | |
|   while (mBuf == NULL) {
 | |
|     mBufSiz = (mBufSiz / 10U) * 9U;
 | |
|     if (mBufSiz < 4 * 1024U) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     mBuf = malloc (mBufSiz);
 | |
|   }
 | |
| 
 | |
|   mBuf[0] = 0;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| FreeMemory (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Called when compression is completed to free memory previously allocated.
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   if (mText != NULL) {
 | |
|     free (mText);
 | |
|   }
 | |
| 
 | |
|   if (mLevel != NULL) {
 | |
|     free (mLevel);
 | |
|   }
 | |
| 
 | |
|   if (mChildCount != NULL) {
 | |
|     free (mChildCount);
 | |
|   }
 | |
| 
 | |
|   if (mPosition != NULL) {
 | |
|     free (mPosition);
 | |
|   }
 | |
| 
 | |
|   if (mParent != NULL) {
 | |
|     free (mParent);
 | |
|   }
 | |
| 
 | |
|   if (mPrev != NULL) {
 | |
|     free (mPrev);
 | |
|   }
 | |
| 
 | |
|   if (mNext != NULL) {
 | |
|     free (mNext);
 | |
|   }
 | |
| 
 | |
|   if (mBuf != NULL) {
 | |
|     free (mBuf);
 | |
|   }
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| InitSlide (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Initialize String Info Log data structures
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  Index;
 | |
| 
 | |
|   for (Index = WNDSIZ; Index <= WNDSIZ + UINT8_MAX; Index++) {
 | |
|     mLevel[Index]     = 1;
 | |
|     mPosition[Index]  = NIL;  // sentinel
 | |
|   }
 | |
| 
 | |
|   for (Index = WNDSIZ; Index < WNDSIZ * 2; Index++) {
 | |
|     mParent[Index] = NIL;
 | |
|   }
 | |
| 
 | |
|   mAvail = 1;
 | |
|   for (Index = 1; Index < WNDSIZ - 1; Index++) {
 | |
|     mNext[Index] = (NODE) (Index + 1);
 | |
|   }
 | |
| 
 | |
|   mNext[WNDSIZ - 1] = NIL;
 | |
|   for (Index = WNDSIZ * 2; Index <= MAX_HASH_VAL; Index++) {
 | |
|     mNext[Index] = NIL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| NODE
 | |
| Child (
 | |
|   IN NODE  NodeQ,
 | |
|   IN UINT8 CharC
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Find child node given the parent node and the edge character
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   NodeQ       - the parent node
 | |
|   CharC       - the edge character
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The child node (NIL if not found)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  NodeR;
 | |
| 
 | |
|   NodeR = mNext[HASH (NodeQ, CharC)];
 | |
|   //
 | |
|   // sentinel
 | |
|   //
 | |
|   mParent[NIL] = NodeQ;
 | |
|   while (mParent[NodeR] != NodeQ) {
 | |
|     NodeR = mNext[NodeR];
 | |
|   }
 | |
| 
 | |
|   return NodeR;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| MakeChild (
 | |
|   IN NODE  Parent,
 | |
|   IN UINT8 CharC,
 | |
|   IN NODE  Child
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Create a new child for a given parent node.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Parent       - the parent node
 | |
|   CharC   - the edge character
 | |
|   Child       - the child node
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  Node1;
 | |
|   NODE  Node2;
 | |
| 
 | |
|   Node1           = (NODE) HASH (Parent, CharC);
 | |
|   Node2           = mNext[Node1];
 | |
|   mNext[Node1]    = Child;
 | |
|   mNext[Child]    = Node2;
 | |
|   mPrev[Node2]    = Child;
 | |
|   mPrev[Child]    = Node1;
 | |
|   mParent[Child]  = Parent;
 | |
|   mChildCount[Parent]++;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| Split (
 | |
|   NODE Old
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Split a node.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Old     - the node to split
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  New;
 | |
|   NODE  TempNode;
 | |
| 
 | |
|   New               = mAvail;
 | |
|   mAvail            = mNext[New];
 | |
|   mChildCount[New]  = 0;
 | |
|   TempNode          = mPrev[Old];
 | |
|   mPrev[New]        = TempNode;
 | |
|   mNext[TempNode]   = New;
 | |
|   TempNode          = mNext[Old];
 | |
|   mNext[New]        = TempNode;
 | |
|   mPrev[TempNode]   = New;
 | |
|   mParent[New]      = mParent[Old];
 | |
|   mLevel[New]       = (UINT8) mMatchLen;
 | |
|   mPosition[New]    = mPos;
 | |
|   MakeChild (New, mText[mMatchPos + mMatchLen], Old);
 | |
|   MakeChild (New, mText[mPos + mMatchLen], mPos);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| InsertNode (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Insert string info for current position into the String Info Log
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  NodeQ;
 | |
|   NODE  NodeR;
 | |
|   NODE  Index2;
 | |
|   NODE  NodeT;
 | |
|   UINT8 CharC;
 | |
|   UINT8 *t1;
 | |
|   UINT8 *t2;
 | |
| 
 | |
|   if (mMatchLen >= 4) {
 | |
|     //
 | |
|     // We have just got a long match, the target tree
 | |
|     // can be located by MatchPos + 1. Traverse the tree
 | |
|     // from bottom up to get to a proper starting point.
 | |
|     // The usage of PERC_FLAG ensures proper node deletion
 | |
|     // in DeleteNode() later.
 | |
|     //
 | |
|     mMatchLen--;
 | |
|     NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ);
 | |
|     NodeQ = mParent[NodeR];
 | |
|     while (NodeQ == NIL) {
 | |
|       NodeR = mNext[NodeR];
 | |
|       NodeQ = mParent[NodeR];
 | |
|     }
 | |
| 
 | |
|     while (mLevel[NodeQ] >= mMatchLen) {
 | |
|       NodeR = NodeQ;
 | |
|       NodeQ = mParent[NodeQ];
 | |
|     }
 | |
| 
 | |
|     NodeT = NodeQ;
 | |
|     while (mPosition[NodeT] < 0) {
 | |
|       mPosition[NodeT]  = mPos;
 | |
|       NodeT             = mParent[NodeT];
 | |
|     }
 | |
| 
 | |
|     if (NodeT < WNDSIZ) {
 | |
|       mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG);
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Locate the target tree
 | |
|     //
 | |
|     NodeQ = (NODE) (mText[mPos] + WNDSIZ);
 | |
|     CharC = mText[mPos + 1];
 | |
|     NodeR = Child (NodeQ, CharC);
 | |
|     if (NodeR == NIL) {
 | |
|       MakeChild (NodeQ, CharC, mPos);
 | |
|       mMatchLen = 1;
 | |
|       return ;
 | |
|     }
 | |
| 
 | |
|     mMatchLen = 2;
 | |
|   }
 | |
|   //
 | |
|   // Traverse down the tree to find a match.
 | |
|   // Update Position value along the route.
 | |
|   // Node split or creation is involved.
 | |
|   //
 | |
|   for (;;) {
 | |
|     if (NodeR >= WNDSIZ) {
 | |
|       Index2    = MAXMATCH;
 | |
|       mMatchPos = NodeR;
 | |
|     } else {
 | |
|       Index2    = mLevel[NodeR];
 | |
|       mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG);
 | |
|     }
 | |
| 
 | |
|     if (mMatchPos >= mPos) {
 | |
|       mMatchPos -= WNDSIZ;
 | |
|     }
 | |
| 
 | |
|     t1  = &mText[mPos + mMatchLen];
 | |
|     t2  = &mText[mMatchPos + mMatchLen];
 | |
|     while (mMatchLen < Index2) {
 | |
|       if (*t1 != *t2) {
 | |
|         Split (NodeR);
 | |
|         return ;
 | |
|       }
 | |
| 
 | |
|       mMatchLen++;
 | |
|       t1++;
 | |
|       t2++;
 | |
|     }
 | |
| 
 | |
|     if (mMatchLen >= MAXMATCH) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     mPosition[NodeR]  = mPos;
 | |
|     NodeQ             = NodeR;
 | |
|     NodeR             = Child (NodeQ, *t1);
 | |
|     if (NodeR == NIL) {
 | |
|       MakeChild (NodeQ, *t1, mPos);
 | |
|       return ;
 | |
|     }
 | |
| 
 | |
|     mMatchLen++;
 | |
|   }
 | |
| 
 | |
|   NodeT           = mPrev[NodeR];
 | |
|   mPrev[mPos]     = NodeT;
 | |
|   mNext[NodeT]    = mPos;
 | |
|   NodeT           = mNext[NodeR];
 | |
|   mNext[mPos]     = NodeT;
 | |
|   mPrev[NodeT]    = mPos;
 | |
|   mParent[mPos]   = NodeQ;
 | |
|   mParent[NodeR]  = NIL;
 | |
| 
 | |
|   //
 | |
|   // Special usage of 'next'
 | |
|   //
 | |
|   mNext[NodeR] = mPos;
 | |
| 
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| DeleteNode (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Delete outdated string info. (The Usage of PERC_FLAG
 | |
|   ensures a clean deletion)
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   NODE  NodeQ;
 | |
|   NODE  NodeR;
 | |
|   NODE  NodeS;
 | |
|   NODE  NodeT;
 | |
|   NODE  NodeU;
 | |
| 
 | |
|   if (mParent[mPos] == NIL) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   NodeR         = mPrev[mPos];
 | |
|   NodeS         = mNext[mPos];
 | |
|   mNext[NodeR]  = NodeS;
 | |
|   mPrev[NodeS]  = NodeR;
 | |
|   NodeR         = mParent[mPos];
 | |
|   mParent[mPos] = NIL;
 | |
|   if (NodeR >= WNDSIZ) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   mChildCount[NodeR]--;
 | |
|   if (mChildCount[NodeR] > 1) {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG);
 | |
|   if (NodeT >= mPos) {
 | |
|     NodeT -= WNDSIZ;
 | |
|   }
 | |
| 
 | |
|   NodeS = NodeT;
 | |
|   NodeQ = mParent[NodeR];
 | |
|   NodeU = mPosition[NodeQ];
 | |
|   while (NodeU & (UINT32) PERC_FLAG) {
 | |
|     NodeU &= (UINT32)~PERC_FLAG;
 | |
|     if (NodeU >= mPos) {
 | |
|       NodeU -= WNDSIZ;
 | |
|     }
 | |
| 
 | |
|     if (NodeU > NodeS) {
 | |
|       NodeS = NodeU;
 | |
|     }
 | |
| 
 | |
|     mPosition[NodeQ]  = (NODE) (NodeS | WNDSIZ);
 | |
|     NodeQ             = mParent[NodeQ];
 | |
|     NodeU             = mPosition[NodeQ];
 | |
|   }
 | |
| 
 | |
|   if (NodeQ < WNDSIZ) {
 | |
|     if (NodeU >= mPos) {
 | |
|       NodeU -= WNDSIZ;
 | |
|     }
 | |
| 
 | |
|     if (NodeU > NodeS) {
 | |
|       NodeS = NodeU;
 | |
|     }
 | |
| 
 | |
|     mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG);
 | |
|   }
 | |
| 
 | |
|   NodeS           = Child (NodeR, mText[NodeT + mLevel[NodeR]]);
 | |
|   NodeT           = mPrev[NodeS];
 | |
|   NodeU           = mNext[NodeS];
 | |
|   mNext[NodeT]    = NodeU;
 | |
|   mPrev[NodeU]    = NodeT;
 | |
|   NodeT           = mPrev[NodeR];
 | |
|   mNext[NodeT]    = NodeS;
 | |
|   mPrev[NodeS]    = NodeT;
 | |
|   NodeT           = mNext[NodeR];
 | |
|   mPrev[NodeT]    = NodeS;
 | |
|   mNext[NodeS]    = NodeT;
 | |
|   mParent[NodeS]  = mParent[NodeR];
 | |
|   mParent[NodeR]  = NIL;
 | |
|   mNext[NodeR]    = mAvail;
 | |
|   mAvail          = NodeR;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| GetNextMatch (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Advance the current position (read in new data if needed).
 | |
|   Delete outdated string info. Find a match string for current position.
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Number;
 | |
| 
 | |
|   mRemainder--;
 | |
|   mPos++;
 | |
|   if (mPos == WNDSIZ * 2) {
 | |
|     memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH);
 | |
|     Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ);
 | |
|     mRemainder += Number;
 | |
|     mPos = WNDSIZ;
 | |
|   }
 | |
| 
 | |
|   DeleteNode ();
 | |
|   InsertNode ();
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| EFI_STATUS
 | |
| Encode (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   The main controlling routine for compression process.
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS           - The compression is successful
 | |
|   EFI_OUT_0F_RESOURCES  - Not enough memory for compression process
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   INT32       LastMatchLen;
 | |
|   NODE        LastMatchPos;
 | |
| 
 | |
|   Status = AllocateMemory ();
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FreeMemory ();
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   InitSlide ();
 | |
| 
 | |
|   HufEncodeStart ();
 | |
| 
 | |
|   mRemainder  = FreadCrc (&mText[WNDSIZ], WNDSIZ + MAXMATCH);
 | |
| 
 | |
|   mMatchLen   = 0;
 | |
|   mPos        = WNDSIZ;
 | |
|   InsertNode ();
 | |
|   if (mMatchLen > mRemainder) {
 | |
|     mMatchLen = mRemainder;
 | |
|   }
 | |
| 
 | |
|   while (mRemainder > 0) {
 | |
|     LastMatchLen  = mMatchLen;
 | |
|     LastMatchPos  = mMatchPos;
 | |
|     GetNextMatch ();
 | |
|     if (mMatchLen > mRemainder) {
 | |
|       mMatchLen = mRemainder;
 | |
|     }
 | |
| 
 | |
|     if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {
 | |
|       //
 | |
|       // Not enough benefits are gained by outputting a pointer,
 | |
|       // so just output the original character
 | |
|       //
 | |
|       Output (mText[mPos - 1], 0);
 | |
| 
 | |
|     } else {
 | |
| 
 | |
|       if (LastMatchLen == THRESHOLD) {
 | |
|         if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) {
 | |
|           Output (mText[mPos - 1], 0);
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // Outputting a pointer is beneficial enough, do it.
 | |
|       //
 | |
|       Output (
 | |
|         LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),
 | |
|         (mPos - LastMatchPos - 2) & (WNDSIZ - 1)
 | |
|         );
 | |
|       LastMatchLen--;
 | |
|       while (LastMatchLen > 0) {
 | |
|         GetNextMatch ();
 | |
|         LastMatchLen--;
 | |
|       }
 | |
| 
 | |
|       if (mMatchLen > mRemainder) {
 | |
|         mMatchLen = mRemainder;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   HufEncodeEnd ();
 | |
|   FreeMemory ();
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| CountTFreq (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Count the frequencies for the Extra Set
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 Index3;
 | |
|   INT32 Number;
 | |
|   INT32 Count;
 | |
| 
 | |
|   for (Index = 0; Index < NT; Index++) {
 | |
|     mTFreq[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   Number = NC;
 | |
|   while (Number > 0 && mCLen[Number - 1] == 0) {
 | |
|     Number--;
 | |
|   }
 | |
| 
 | |
|   Index = 0;
 | |
|   while (Index < Number) {
 | |
|     Index3 = mCLen[Index++];
 | |
|     if (Index3 == 0) {
 | |
|       Count = 1;
 | |
|       while (Index < Number && mCLen[Index] == 0) {
 | |
|         Index++;
 | |
|         Count++;
 | |
|       }
 | |
| 
 | |
|       if (Count <= 2) {
 | |
|         mTFreq[0] = (UINT16) (mTFreq[0] + Count);
 | |
|       } else if (Count <= 18) {
 | |
|         mTFreq[1]++;
 | |
|       } else if (Count == 19) {
 | |
|         mTFreq[0]++;
 | |
|         mTFreq[1]++;
 | |
|       } else {
 | |
|         mTFreq[2]++;
 | |
|       }
 | |
|     } else {
 | |
|       mTFreq[Index3 + 2]++;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| WritePTLen (
 | |
|   IN INT32 Number,
 | |
|   IN INT32 nbit,
 | |
|   IN INT32 Special
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Outputs the code length array for the Extra Set or the Position Set.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Number       - the number of symbols
 | |
|   nbit    - the number of bits needed to represent 'n'
 | |
|   Special - the special symbol that needs to be take care of
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 Index3;
 | |
| 
 | |
|   while (Number > 0 && mPTLen[Number - 1] == 0) {
 | |
|     Number--;
 | |
|   }
 | |
| 
 | |
|   PutBits (nbit, Number);
 | |
|   Index = 0;
 | |
|   while (Index < Number) {
 | |
|     Index3 = mPTLen[Index++];
 | |
|     if (Index3 <= 6) {
 | |
|       PutBits (3, Index3);
 | |
|     } else {
 | |
|       PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2);
 | |
|     }
 | |
| 
 | |
|     if (Index == Special) {
 | |
|       while (Index < 6 && mPTLen[Index] == 0) {
 | |
|         Index++;
 | |
|       }
 | |
| 
 | |
|       PutBits (2, (Index - 3) & 3);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| WriteCLen (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Outputs the code length array for Char&Length Set
 | |
| 
 | |
| Arguments: (VOID)
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 Index3;
 | |
|   INT32 Number;
 | |
|   INT32 Count;
 | |
| 
 | |
|   Number = NC;
 | |
|   while (Number > 0 && mCLen[Number - 1] == 0) {
 | |
|     Number--;
 | |
|   }
 | |
| 
 | |
|   PutBits (CBIT, Number);
 | |
|   Index = 0;
 | |
|   while (Index < Number) {
 | |
|     Index3 = mCLen[Index++];
 | |
|     if (Index3 == 0) {
 | |
|       Count = 1;
 | |
|       while (Index < Number && mCLen[Index] == 0) {
 | |
|         Index++;
 | |
|         Count++;
 | |
|       }
 | |
| 
 | |
|       if (Count <= 2) {
 | |
|         for (Index3 = 0; Index3 < Count; Index3++) {
 | |
|           PutBits (mPTLen[0], mPTCode[0]);
 | |
|         }
 | |
|       } else if (Count <= 18) {
 | |
|         PutBits (mPTLen[1], mPTCode[1]);
 | |
|         PutBits (4, Count - 3);
 | |
|       } else if (Count == 19) {
 | |
|         PutBits (mPTLen[0], mPTCode[0]);
 | |
|         PutBits (mPTLen[1], mPTCode[1]);
 | |
|         PutBits (4, 15);
 | |
|       } else {
 | |
|         PutBits (mPTLen[2], mPTCode[2]);
 | |
|         PutBits (CBIT, Count - 20);
 | |
|       }
 | |
|     } else {
 | |
|       PutBits (mPTLen[Index3 + 2], mPTCode[Index3 + 2]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| EncodeC (
 | |
|   IN INT32 Value
 | |
|   )
 | |
| {
 | |
|   PutBits (mCLen[Value], mCCode[Value]);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| EncodeP (
 | |
|   IN UINT32 Value
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  NodeQ;
 | |
| 
 | |
|   Index = 0;
 | |
|   NodeQ = Value;
 | |
|   while (NodeQ) {
 | |
|     NodeQ >>= 1;
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   PutBits (mPTLen[Index], mPTCode[Index]);
 | |
|   if (Index > 1) {
 | |
|     PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1)));
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| SendBlock (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Huffman code the block and output it.
 | |
| 
 | |
| Arguments:
 | |
|   (VOID)
 | |
| 
 | |
| Returns:
 | |
|   (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Index2;
 | |
|   UINT32  Index3;
 | |
|   UINT32  Flags;
 | |
|   UINT32  Root;
 | |
|   UINT32  Pos;
 | |
|   UINT32  Size;
 | |
|   Flags = 0;
 | |
| 
 | |
|   Root  = MakeTree (NC, mCFreq, mCLen, mCCode);
 | |
|   Size  = mCFreq[Root];
 | |
| 
 | |
|   PutBits (16, Size);
 | |
|   if (Root >= NC) {
 | |
|     CountTFreq ();
 | |
|     Root = MakeTree (NT, mTFreq, mPTLen, mPTCode);
 | |
|     if (Root >= NT) {
 | |
|       WritePTLen (NT, TBIT, 3);
 | |
|     } else {
 | |
|       PutBits (TBIT, 0);
 | |
|       PutBits (TBIT, Root);
 | |
|     }
 | |
| 
 | |
|     WriteCLen ();
 | |
|   } else {
 | |
|     PutBits (TBIT, 0);
 | |
|     PutBits (TBIT, 0);
 | |
|     PutBits (CBIT, 0);
 | |
|     PutBits (CBIT, Root);
 | |
|   }
 | |
| 
 | |
|   Root = MakeTree (NP, mPFreq, mPTLen, mPTCode);
 | |
|   if (Root >= NP) {
 | |
|     WritePTLen (NP, PBIT, -1);
 | |
|   } else {
 | |
|     PutBits (PBIT, 0);
 | |
|     PutBits (PBIT, Root);
 | |
|   }
 | |
| 
 | |
|   Pos = 0;
 | |
|   for (Index = 0; Index < Size; Index++) {
 | |
|     if (Index % UINT8_BIT == 0) {
 | |
|       Flags = mBuf[Pos++];
 | |
|     } else {
 | |
|       Flags <<= 1;
 | |
|     }
 | |
| 
 | |
|     if (Flags & (1U << (UINT8_BIT - 1))) {
 | |
|       EncodeC (mBuf[Pos++] + (1U << UINT8_BIT));
 | |
|       Index3 = mBuf[Pos++];
 | |
|       for (Index2 = 0; Index2 < 3; Index2++) {
 | |
|         Index3 <<= UINT8_BIT;
 | |
|         Index3 += mBuf[Pos++];
 | |
|       }
 | |
| 
 | |
|       EncodeP (Index3);
 | |
|     } else {
 | |
|       EncodeC (mBuf[Pos++]);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NC; Index++) {
 | |
|     mCFreq[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NP; Index++) {
 | |
|     mPFreq[Index] = 0;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| Output (
 | |
|   IN UINT32 CharC,
 | |
|   IN UINT32 Pos
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Outputs an Original Character or a Pointer
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   CharC     - The original character or the 'String Length' element of a Pointer
 | |
|   Pos     - The 'Position' field of a Pointer
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   STATIC UINT32 CPos;
 | |
| 
 | |
|   if ((mOutputMask >>= 1) == 0) {
 | |
|     mOutputMask = 1U << (UINT8_BIT - 1);
 | |
|     //
 | |
|     // Check the buffer overflow per outputing UINT8_BIT symbols
 | |
|     // which is an Original Character or a Pointer. The biggest
 | |
|     // symbol is a Pointer which occupies 5 bytes.
 | |
|     //
 | |
|     if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) {
 | |
|       SendBlock ();
 | |
|       mOutputPos = 0;
 | |
|     }
 | |
| 
 | |
|     CPos        = mOutputPos++;
 | |
|     mBuf[CPos]  = 0;
 | |
|   }
 | |
| 
 | |
|   mBuf[mOutputPos++] = (UINT8) CharC;
 | |
|   mCFreq[CharC]++;
 | |
|   if (CharC >= (1U << UINT8_BIT)) {
 | |
|     mBuf[CPos] |= mOutputMask;
 | |
|     mBuf[mOutputPos++]  = (UINT8) (Pos >> 24);
 | |
|     mBuf[mOutputPos++]  = (UINT8) (Pos >> 16);
 | |
|     mBuf[mOutputPos++]  = (UINT8) (Pos >> (UINT8_BIT));
 | |
|     mBuf[mOutputPos++]  = (UINT8) Pos;
 | |
|     CharC               = 0;
 | |
|     while (Pos) {
 | |
|       Pos >>= 1;
 | |
|       CharC++;
 | |
|     }
 | |
| 
 | |
|     mPFreq[CharC]++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| HufEncodeStart (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   INT32 Index;
 | |
| 
 | |
|   for (Index = 0; Index < NC; Index++) {
 | |
|     mCFreq[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NP; Index++) {
 | |
|     mPFreq[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   mOutputPos = mOutputMask = 0;
 | |
|   InitPutBits ();
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| HufEncodeEnd (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   SendBlock ();
 | |
| 
 | |
|   //
 | |
|   // Flush remaining bits
 | |
|   //
 | |
|   PutBits (UINT8_BIT - 1, 0);
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| MakeCrcTable (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Index2;
 | |
|   UINT32  Temp;
 | |
| 
 | |
|   for (Index = 0; Index <= UINT8_MAX; Index++) {
 | |
|     Temp = Index;
 | |
|     for (Index2 = 0; Index2 < UINT8_BIT; Index2++) {
 | |
|       if (Temp & 1) {
 | |
|         Temp = (Temp >> 1) ^ CRCPOLY;
 | |
|       } else {
 | |
|         Temp >>= 1;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     mCrcTable[Index] = (UINT16) Temp;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| PutBits (
 | |
|   IN INT32  Number,
 | |
|   IN UINT32 Value
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Outputs rightmost n bits of x
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Number   - the rightmost n bits of the data is used
 | |
|   x   - the data
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT8 Temp;
 | |
| 
 | |
|   while (Number >= mBitCount) {
 | |
|     //
 | |
|     // Number -= mBitCount should never equal to 32
 | |
|     //
 | |
|     Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount)));
 | |
| 
 | |
|     if (mDst < mDstUpperLimit) {
 | |
|       *mDst++ = Temp;
 | |
|     }
 | |
| 
 | |
|     mCompSize++;
 | |
|     mSubBitBuf  = 0;
 | |
|     mBitCount   = UINT8_BIT;
 | |
|   }
 | |
| 
 | |
|   mSubBitBuf |= Value << (mBitCount -= Number);
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| INT32
 | |
| FreadCrc (
 | |
|   OUT UINT8 *Pointer,
 | |
|   IN  INT32 Number
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Read in source data
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Pointer   - the buffer to hold the data
 | |
|   Number   - number of bytes to read
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   number of bytes actually read
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
| 
 | |
|   for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) {
 | |
|     *Pointer++ = *mSrc++;
 | |
|   }
 | |
| 
 | |
|   Number = Index;
 | |
| 
 | |
|   Pointer -= Number;
 | |
|   mOrigSize += Number;
 | |
| 
 | |
|   Index--;
 | |
|   while (Index >= 0) {
 | |
|     UPDATE_CRC (*Pointer++);
 | |
|     Index--;
 | |
|   }
 | |
| 
 | |
|   return Number;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| InitPutBits (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   mBitCount   = UINT8_BIT;
 | |
|   mSubBitBuf  = 0;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| CountLen (
 | |
|   IN INT32 Index
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Count the number of each code length for a Huffman tree.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Index   - the top node
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   STATIC INT32  Depth = 0;
 | |
| 
 | |
|   if (Index < mN) {
 | |
|     mLenCnt[(Depth < 16) ? Depth : 16]++;
 | |
|   } else {
 | |
|     Depth++;
 | |
|     CountLen (mLeft[Index]);
 | |
|     CountLen (mRight[Index]);
 | |
|     Depth--;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| MakeLen (
 | |
|   IN INT32 Root
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Create code length array for a Huffman tree
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Root   - the root of the tree
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   VOID
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32   Index;
 | |
|   INT32   Index3;
 | |
|   UINT32  Cum;
 | |
| 
 | |
|   for (Index = 0; Index <= 16; Index++) {
 | |
|     mLenCnt[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   CountLen (Root);
 | |
| 
 | |
|   //
 | |
|   // Adjust the length count array so that
 | |
|   // no code will be generated longer than its designated length
 | |
|   //
 | |
|   Cum = 0;
 | |
|   for (Index = 16; Index > 0; Index--) {
 | |
|     Cum += mLenCnt[Index] << (16 - Index);
 | |
|   }
 | |
| 
 | |
|   while (Cum != (1U << 16)) {
 | |
|     mLenCnt[16]--;
 | |
|     for (Index = 15; Index > 0; Index--) {
 | |
|       if (mLenCnt[Index] != 0) {
 | |
|         mLenCnt[Index]--;
 | |
|         mLenCnt[Index + 1] += 2;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     Cum--;
 | |
|   }
 | |
| 
 | |
|   for (Index = 16; Index > 0; Index--) {
 | |
|     Index3 = mLenCnt[Index];
 | |
|     Index3--;
 | |
|     while (Index3 >= 0) {
 | |
|       mLen[*mSortPtr++] = (UINT8) Index;
 | |
|       Index3--;
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| DownHeap (
 | |
|   IN INT32 Index
 | |
|   )
 | |
| {
 | |
|   INT32 Index2;
 | |
|   INT32 Index3;
 | |
| 
 | |
|   //
 | |
|   // priority queue: send Index-th entry down heap
 | |
|   //
 | |
|   Index3  = mHeap[Index];
 | |
|   Index2  = 2 * Index;
 | |
|   while (Index2 <= mHeapSize) {
 | |
|     if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) {
 | |
|       Index2++;
 | |
|     }
 | |
| 
 | |
|     if (mFreq[Index3] <= mFreq[mHeap[Index2]]) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     mHeap[Index]  = mHeap[Index2];
 | |
|     Index         = Index2;
 | |
|     Index2        = 2 * Index;
 | |
|   }
 | |
| 
 | |
|   mHeap[Index] = (INT16) Index3;
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| VOID
 | |
| MakeCode (
 | |
|   IN  INT32       Number,
 | |
|   IN  UINT8 Len[  ],
 | |
|   OUT UINT16 Code[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Assign code to each symbol based on the code length array
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Number     - number of symbols
 | |
|   Len   - the code length array
 | |
|   Code  - stores codes for each symbol
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32   Index;
 | |
|   UINT16  Start[18];
 | |
| 
 | |
|   Start[1] = 0;
 | |
|   for (Index = 1; Index <= 16; Index++) {
 | |
|     Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1);
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < Number; Index++) {
 | |
|     Code[Index] = Start[Len[Index]]++;
 | |
|   }
 | |
| }
 | |
| 
 | |
| STATIC
 | |
| INT32
 | |
| MakeTree (
 | |
|   IN  INT32            NParm,
 | |
|   IN  UINT16  FreqParm[],
 | |
|   OUT UINT8   LenParm[ ],
 | |
|   OUT UINT16  CodeParm[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Generates Huffman codes given a frequency distribution of symbols
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   NParm    - number of symbols
 | |
|   FreqParm - frequency of each symbol
 | |
|   LenParm  - code length for each symbol
 | |
|   CodeParm - code for each symbol
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   Root of the Huffman tree.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 Index2;
 | |
|   INT32 Index3;
 | |
|   INT32 Avail;
 | |
| 
 | |
|   //
 | |
|   // make tree, calculate len[], return root
 | |
|   //
 | |
|   mN        = NParm;
 | |
|   mFreq     = FreqParm;
 | |
|   mLen      = LenParm;
 | |
|   Avail     = mN;
 | |
|   mHeapSize = 0;
 | |
|   mHeap[1]  = 0;
 | |
|   for (Index = 0; Index < mN; Index++) {
 | |
|     mLen[Index] = 0;
 | |
|     if (mFreq[Index]) {
 | |
|       mHeapSize++;
 | |
|       mHeap[mHeapSize] = (INT16) Index;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (mHeapSize < 2) {
 | |
|     CodeParm[mHeap[1]] = 0;
 | |
|     return mHeap[1];
 | |
|   }
 | |
| 
 | |
|   for (Index = mHeapSize / 2; Index >= 1; Index--) {
 | |
|     //
 | |
|     // make priority queue
 | |
|     //
 | |
|     DownHeap (Index);
 | |
|   }
 | |
| 
 | |
|   mSortPtr = CodeParm;
 | |
|   do {
 | |
|     Index = mHeap[1];
 | |
|     if (Index < mN) {
 | |
|       *mSortPtr++ = (UINT16) Index;
 | |
|     }
 | |
| 
 | |
|     mHeap[1] = mHeap[mHeapSize--];
 | |
|     DownHeap (1);
 | |
|     Index2 = mHeap[1];
 | |
|     if (Index2 < mN) {
 | |
|       *mSortPtr++ = (UINT16) Index2;
 | |
|     }
 | |
| 
 | |
|     Index3        = Avail++;
 | |
|     mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]);
 | |
|     mHeap[1]      = (INT16) Index3;
 | |
|     DownHeap (1);
 | |
|     mLeft[Index3]   = (UINT16) Index;
 | |
|     mRight[Index3]  = (UINT16) Index2;
 | |
|   } while (mHeapSize > 1);
 | |
| 
 | |
|   mSortPtr = CodeParm;
 | |
|   MakeLen (Index3);
 | |
|   MakeCode (NParm, LenParm, CodeParm);
 | |
| 
 | |
|   //
 | |
|   // return root
 | |
|   //
 | |
|   return Index3;
 | |
| }
 | |
| 
 | |
| EFI_STATUS
 | |
| GetFileContents (
 | |
|   IN char    *InputFileName,
 | |
|   OUT UINT8   *FileBuffer,
 | |
|   OUT UINT32  *BufferLength
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Get the contents of file specified in InputFileName
 | |
|   into FileBuffer.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   InputFileName  - Name of the input file.
 | |
| 
 | |
|   FileBuffer     - Output buffer to contain data
 | |
| 
 | |
|   BufferLength   - Actual length of the data
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS on successful return
 | |
|   EFI_ABORTED if unable to open input file.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN   Size;
 | |
|   UINTN   FileSize;
 | |
|   FILE    *InputFile;
 | |
| 
 | |
|   Size = 0;
 | |
|   //
 | |
|   // Copy the file contents to the output buffer.
 | |
|   //
 | |
|   InputFile = fopen (LongFilePath (InputFileName), "rb");
 | |
|     if (InputFile == NULL) {
 | |
|       Error (NULL, 0, 0001, "Error opening file: %s", InputFileName);
 | |
|       return EFI_ABORTED;
 | |
|     }
 | |
| 
 | |
|   fseek (InputFile, 0, SEEK_END);
 | |
|   FileSize = ftell (InputFile);
 | |
|   fseek (InputFile, 0, SEEK_SET);
 | |
|     //
 | |
|     // Now read the contents of the file into the buffer
 | |
|     //
 | |
|     if (FileSize > 0 && FileBuffer != NULL) {
 | |
|       if (fread (FileBuffer, FileSize, 1, InputFile) != 1) {
 | |
|         Error (NULL, 0, 0004, "Error reading contents of input file: %s", InputFileName);
 | |
|         fclose (InputFile);
 | |
|         return EFI_ABORTED;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   fclose (InputFile);
 | |
|   Size += (UINTN) FileSize;
 | |
|   *BufferLength = Size;
 | |
| 
 | |
|   if (FileBuffer != NULL) {
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
| }
 | |
| 
 | |
| VOID
 | |
| Version (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Displays the standard utility information to SDTOUT
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| Usage (
 | |
|   VOID
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Displays the utility usage syntax to STDOUT
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // Summary usage
 | |
|   //
 | |
|   fprintf (stdout, "Usage: %s -e|-d [options] <input_file>\n\n", UTILITY_NAME);
 | |
| 
 | |
|   //
 | |
|   // Copyright declaration
 | |
|   //
 | |
|   fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");
 | |
| 
 | |
|   //
 | |
|   // Details Option
 | |
|   //
 | |
|   fprintf (stdout, "Options:\n");
 | |
|   fprintf (stdout, "  --uefi\n\
 | |
|             Enable UefiCompress, use TianoCompress when without this option\n");
 | |
|   fprintf (stdout, "  -o FileName, --output FileName\n\
 | |
|             File will be created to store the output content.\n");
 | |
|   fprintf (stdout, "  -v, --verbose\n\
 | |
|            Turn on verbose output with informational messages.\n");
 | |
|   fprintf (stdout, "  -q, --quiet\n\
 | |
|            Disable all messages except key message and fatal error\n");
 | |
|   fprintf (stdout, "  --debug [0-9]\n\
 | |
|            Enable debug messages, at input debug level.\n");
 | |
|   fprintf (stdout, "  --version\n\
 | |
|            Show program's version number and exit.\n");
 | |
|   fprintf (stdout, "  -h, --help\n\
 | |
|            Show this help message and exit.\n");
 | |
| }
 | |
| 
 | |
| 
 | |
| int
 | |
| main (
 | |
|   int  argc,
 | |
|   char *argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Main
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   command line parameters
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS    Section header successfully generated and section concatenated.
 | |
|   EFI_ABORTED    Could not generate the section
 | |
|   EFI_OUT_OF_RESOURCES  No resource to complete the operation.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   FILE       *OutputFile;
 | |
|   char       *OutputFileName;
 | |
|   char       *InputFileName;
 | |
|   FILE       *InputFile;
 | |
|   EFI_STATUS Status;
 | |
|   UINT8      *FileBuffer;
 | |
|   UINT8      *OutBuffer;
 | |
|   UINT32     InputLength;
 | |
|   UINT32     DstSize;
 | |
|   SCRATCH_DATA      *Scratch;
 | |
|   UINT8      *Src;
 | |
|   UINT32     OrigSize;
 | |
|   UINT32     CompSize;
 | |
| 
 | |
|   SetUtilityName(UTILITY_NAME);
 | |
| 
 | |
|   FileBuffer = NULL;
 | |
|   Src = NULL;
 | |
|   OutBuffer = NULL;
 | |
|   Scratch   = NULL;
 | |
|   OrigSize = 0;
 | |
|   CompSize = 0;
 | |
|   InputLength = 0;
 | |
|   InputFileName = NULL;
 | |
|   OutputFileName = NULL;
 | |
|   InputFile = NULL;
 | |
|   OutputFile = NULL;
 | |
|   DstSize=0;
 | |
|   DebugLevel = 0;
 | |
|   DebugMode = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Verify the correct number of arguments
 | |
|   //
 | |
|   if (argc == 1) {
 | |
|     Error (NULL, 0, 1001, "Missing options", "No input options specified.");
 | |
|     Usage();
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if ((strcmp(argv[1], "-h") == 0) || (strcmp(argv[1], "--help") == 0)) {
 | |
|     Usage();
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   if ((strcmp(argv[1], "--version") == 0)) {
 | |
|     Version();
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   argc--;
 | |
|   argv++;
 | |
|   if (strcmp(argv[0],"-e") == 0) {
 | |
|     //
 | |
|     // encode the input file
 | |
|     //
 | |
|     ENCODE = TRUE;
 | |
|     argc--;
 | |
|     argv++;
 | |
|   } else if (strcmp(argv[0], "-d") == 0) {
 | |
|     //
 | |
|     // decode the input file
 | |
|     //
 | |
|     DECODE = TRUE;
 | |
|     argc--;
 | |
|     argv++;
 | |
|   } else {
 | |
|     //
 | |
|     // Error command line
 | |
|     //
 | |
|     Error (NULL, 0, 1003, "Invalid option value", "the options specified are not recognized.");
 | |
|     Usage();
 | |
|     return 1;
 | |
|   }
 | |
| 
 | |
|   while (argc > 0) {
 | |
|     if ((strcmp(argv[0], "-v") == 0) || (stricmp(argv[0], "--verbose") == 0)) {
 | |
|       VerboseMode = TRUE;
 | |
|       argc--;
 | |
|       argv++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (stricmp(argv[0], "--uefi") == 0) {
 | |
|       UEFIMODE = TRUE;
 | |
|       argc--;
 | |
|       argv++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (stricmp (argv[0], "--debug") == 0) {
 | |
|       argc-=2;
 | |
|       argv++;
 | |
|       Status = AsciiStringToUint64(argv[0], FALSE, &DebugLevel);
 | |
|       if (DebugLevel > 9) {
 | |
|         Error (NULL, 0 ,2000, "Invalid parameter", "Unrecognized argument %s", argv[0]);
 | |
|         goto ERROR;
 | |
|       }
 | |
|       if (DebugLevel>=5 && DebugLevel <=9){
 | |
|         DebugMode = TRUE;
 | |
|       } else {
 | |
|         DebugMode = FALSE;
 | |
|       }
 | |
|       argv++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((strcmp(argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {
 | |
|       QuietMode = TRUE;
 | |
|       argc--;
 | |
|       argv++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if ((strcmp(argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
 | |
|       if (argv[1] == NULL || argv[1][0] == '-') {
 | |
|         Error (NULL, 0, 1003, "Invalid option value", "Output File name is missing for -o option");
 | |
|         goto ERROR;
 | |
|       }
 | |
|       OutputFileName = argv[1];
 | |
|       argc -=2;
 | |
|       argv +=2;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (argv[0][0]!='-') {
 | |
|       InputFileName = argv[0];
 | |
|       argc--;
 | |
|       argv++;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Error (NULL, 0, 1000, "Unknown option", argv[0]);
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   if (InputFileName == NULL) {
 | |
|     Error (NULL, 0, 1001, "Missing options", "No input files specified.");
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
| //
 | |
| // All Parameters has been parsed, now set the message print level
 | |
| //
 | |
|   if (QuietMode) {
 | |
|     SetPrintLevel(40);
 | |
|   } else if (VerboseMode) {
 | |
|     SetPrintLevel(15);
 | |
|   } else if (DebugMode) {
 | |
|     SetPrintLevel(DebugLevel);
 | |
|   }
 | |
| 
 | |
|   if (VerboseMode) {
 | |
|     VerboseMsg("%s tool start.\n", UTILITY_NAME);
 | |
|    }
 | |
|   Scratch = (SCRATCH_DATA *)malloc(sizeof(SCRATCH_DATA));
 | |
|   if (Scratch == NULL) {
 | |
|     Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   InputFile = fopen (LongFilePath (InputFileName), "rb");
 | |
|   if (InputFile == NULL) {
 | |
|     Error (NULL, 0, 0001, "Error opening input file", InputFileName);
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   Status = GetFileContents(
 | |
|             InputFileName,
 | |
|             FileBuffer,
 | |
|             &InputLength);
 | |
| 
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     FileBuffer = (UINT8 *) malloc (InputLength);
 | |
|     if (FileBuffer == NULL) {
 | |
|       Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
 | |
|       goto ERROR;
 | |
|     }
 | |
| 
 | |
|     Status = GetFileContents (
 | |
|               InputFileName,
 | |
|               FileBuffer,
 | |
|               &InputLength
 | |
|               );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     Error (NULL, 0, 0004, "Error getting contents of file: %s", InputFileName);
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   if (OutputFileName == NULL) {
 | |
|     OutputFileName = DEFAULT_OUTPUT_FILE;
 | |
|   }
 | |
|   OutputFile = fopen (LongFilePath (OutputFileName), "wb");
 | |
|   if (OutputFile == NULL) {
 | |
|     Error (NULL, 0, 0001, "Error opening output file for writing", OutputFileName);
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   if (ENCODE) {
 | |
|   //
 | |
|   // First call TianoCompress to get DstSize
 | |
|   //
 | |
|   if (DebugMode) {
 | |
|     DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding", NULL);
 | |
|   }
 | |
|   if (UEFIMODE) {
 | |
|     Status = EfiCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize);
 | |
|   } else {
 | |
|     Status = TianoCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize);
 | |
|   }
 | |
| 
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     OutBuffer = (UINT8 *) malloc (DstSize);
 | |
|     if (OutBuffer == NULL) {
 | |
|       Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
 | |
|       goto ERROR;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (UEFIMODE) {
 | |
|     Status = EfiCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize);
 | |
|   } else {
 | |
|     Status = TianoCompress ((UINT8 *)FileBuffer, InputLength, OutBuffer, &DstSize);
 | |
|   }
 | |
|   if (Status != EFI_SUCCESS) {
 | |
|     Error (NULL, 0, 0007, "Error compressing file", NULL);
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   if (OutBuffer == NULL) {
 | |
|     Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
 | |
|     goto ERROR;
 | |
|   }
 | |
| 
 | |
|   fwrite(OutBuffer,(size_t)DstSize, 1, OutputFile);
 | |
|   fclose(OutputFile);
 | |
|   fclose(InputFile);
 | |
|   free(Scratch);
 | |
|   free(FileBuffer);
 | |
|   free(OutBuffer);
 | |
| 
 | |
|   if (DebugMode) {
 | |
|     DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding Successful!\n", NULL);
 | |
|   }
 | |
|   if (VerboseMode) {
 | |
|     VerboseMsg("Encoding successful\n");
 | |
|   }
 | |
|   return 0;
 | |
|   }
 | |
|   else if (DECODE) {
 | |
|   if (DebugMode) {
 | |
|     DebugMsg(UTILITY_NAME, 0, DebugLevel, "Decoding\n", NULL);
 | |
|   }
 | |
| 
 | |
|   if (UEFIMODE) {
 | |
|     Status = Extract((VOID *)FileBuffer, InputLength, (VOID *)&OutBuffer, &DstSize, 1);
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       goto ERROR;
 | |
|     }
 | |
|     fwrite(OutBuffer, (size_t)(DstSize), 1, OutputFile);
 | |
|   } else {
 | |
|     if (InputLength < 8){
 | |
|       Error (NULL, 0, 3000, "Invalid", "The input file %s is too small.", InputFileName);
 | |
|       goto ERROR;
 | |
|     }
 | |
|     //
 | |
|     // Get Compressed file original size
 | |
|     //
 | |
|     Src     = (UINT8 *)FileBuffer;
 | |
|     OrigSize  = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
 | |
|     CompSize  = Src[0] + (Src[1] << 8) + (Src[2] <<16) + (Src[3] <<24);
 | |
| 
 | |
|     //
 | |
|     // Allocate OutputBuffer
 | |
|     //
 | |
|     if (InputLength < CompSize + 8 || (CompSize + 8) < 8) {
 | |
|       Error (NULL, 0, 3000, "Invalid", "The input file %s data is invalid.", InputFileName);
 | |
|       goto ERROR;
 | |
|     }
 | |
|     OutBuffer = (UINT8 *)malloc(OrigSize);
 | |
|     if (OutBuffer == NULL) {
 | |
|       Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
 | |
|       goto ERROR;
 | |
|      }
 | |
| 
 | |
|     Status = TDecompress((VOID *)FileBuffer, (VOID *)OutBuffer, (VOID *)Scratch, 2);
 | |
|     if (Status != EFI_SUCCESS) {
 | |
|       goto ERROR;
 | |
|     }
 | |
|     fwrite(OutBuffer, (size_t)(Scratch->mOrigSize), 1, OutputFile);
 | |
|   }
 | |
|   fclose(OutputFile);
 | |
|   fclose(InputFile);
 | |
|   if (Scratch != NULL) {
 | |
|     free(Scratch);
 | |
|   }
 | |
|   if (FileBuffer != NULL) {
 | |
|     free(FileBuffer);
 | |
|   }
 | |
|   if (OutBuffer != NULL) {
 | |
|     free(OutBuffer);
 | |
|   }
 | |
| 
 | |
|   if (DebugMode) {
 | |
|     DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding successful!\n", NULL);
 | |
|   }
 | |
| 
 | |
|   if (VerboseMode) {
 | |
|     VerboseMsg("Decoding successful\n");
 | |
|   }
 | |
|   return 0;
 | |
|   }
 | |
| 
 | |
| ERROR:
 | |
|   if (DebugMode) {
 | |
|     if (ENCODE) {
 | |
|       DebugMsg(UTILITY_NAME, 0, DebugLevel, "Encoding Error\n", NULL);
 | |
|     } else if (DECODE) {
 | |
|       DebugMsg(UTILITY_NAME, 0, DebugLevel, "Decoding Error\n", NULL);
 | |
|     }
 | |
|   }
 | |
|   if (OutputFile != NULL) {
 | |
|     fclose(OutputFile);
 | |
|   }
 | |
|   if (InputFile != NULL) {
 | |
|     fclose (InputFile);
 | |
|   }
 | |
|   if (Scratch != NULL) {
 | |
|     free(Scratch);
 | |
|   }
 | |
|   if (FileBuffer != NULL) {
 | |
|     free(FileBuffer);
 | |
|   }
 | |
|   if (OutBuffer != NULL) {
 | |
|     free(OutBuffer);
 | |
|   }
 | |
| 
 | |
|   if (VerboseMode) {
 | |
|     VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());
 | |
|   }
 | |
|   return GetUtilityStatus ();
 | |
| }
 | |
| 
 | |
| VOID
 | |
| FillBuf (
 | |
|   IN  SCRATCH_DATA  *Sd,
 | |
|   IN  UINT16        NumOfBits
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd        - The global scratch data
 | |
|   NumOfBits  - The number of bits to shift and read.
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   Sd->mBitBuf = (UINT32) (((UINT64)Sd->mBitBuf) << NumOfBits);
 | |
| 
 | |
|   while (NumOfBits > Sd->mBitCount) {
 | |
| 
 | |
|     Sd->mBitBuf |= (UINT32) (((UINT64)Sd->mSubBitBuf) << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount)));
 | |
| 
 | |
|     if (Sd->mCompSize > 0) {
 | |
|       //
 | |
|       // Get 1 byte into SubBitBuf
 | |
|       //
 | |
|       Sd->mCompSize--;
 | |
|       Sd->mSubBitBuf  = 0;
 | |
|       Sd->mSubBitBuf  = Sd->mSrcBase[Sd->mInBuf++];
 | |
|       Sd->mBitCount   = 8;
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // No more bits from the source, just pad zero bit.
 | |
|       //
 | |
|       Sd->mSubBitBuf  = 0;
 | |
|       Sd->mBitCount   = 8;
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits);
 | |
|   Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| GetBits (
 | |
|   IN  SCRATCH_DATA  *Sd,
 | |
|   IN  UINT16        NumOfBits
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
 | |
|   NumOfBits of bits from source. Returns NumOfBits of bits that are
 | |
|   popped out.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd            - The global scratch data.
 | |
|   NumOfBits     - The number of bits to pop and read.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The bits that are popped out.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32  OutBits;
 | |
| 
 | |
|   OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
 | |
| 
 | |
|   FillBuf (Sd, NumOfBits);
 | |
| 
 | |
|   return OutBits;
 | |
| }
 | |
| 
 | |
| UINT16
 | |
| MakeTable (
 | |
|   IN  SCRATCH_DATA  *Sd,
 | |
|   IN  UINT16        NumOfChar,
 | |
|   IN  UINT8         *BitLen,
 | |
|   IN  UINT16        TableBits,
 | |
|   OUT UINT16        *Table
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Creates Huffman Code mapping table according to code length array.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd        - The global scratch data
 | |
|   NumOfChar - Number of symbols in the symbol set
 | |
|   BitLen    - Code length array
 | |
|   TableBits - The width of the mapping table
 | |
|   Table     - The table
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   0         - OK.
 | |
|   BAD_TABLE - The table is corrupted.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Count[17];
 | |
|   UINT16  Weight[17];
 | |
|   UINT16  Start[18];
 | |
|   UINT16  *Pointer;
 | |
|   UINT16  Index3;
 | |
|   UINT16  Index;
 | |
|   UINT16  Len;
 | |
|   UINT16  Char;
 | |
|   UINT16  JuBits;
 | |
|   UINT16  Avail;
 | |
|   UINT16  NextCode;
 | |
|   UINT16  Mask;
 | |
|   UINT16  WordOfStart;
 | |
|   UINT16  WordOfCount;
 | |
|   UINT16  MaxTableLength;
 | |
| 
 | |
|   for (Index = 0; Index <= 16; Index++) {
 | |
|     Count[Index] = 0;
 | |
|   }
 | |
| 
 | |
|   for (Index = 0; Index < NumOfChar; Index++) {
 | |
|     if (BitLen[Index] > 16) {
 | |
|       return (UINT16) BAD_TABLE;
 | |
|     }
 | |
|     Count[BitLen[Index]]++;
 | |
|   }
 | |
| 
 | |
|   Start[0] = 0;
 | |
|   Start[1] = 0;
 | |
| 
 | |
|   for (Index = 1; Index <= 16; Index++) {
 | |
|     WordOfStart = Start[Index];
 | |
|     WordOfCount = Count[Index];
 | |
|     Start[Index + 1] = (UINT16) (WordOfStart + (WordOfCount << (16 - Index)));
 | |
|   }
 | |
| 
 | |
|   if (Start[17] != 0) {
 | |
|     //
 | |
|     //(1U << 16)
 | |
|     //
 | |
|     return (UINT16) BAD_TABLE;
 | |
|   }
 | |
| 
 | |
|   JuBits = (UINT16) (16 - TableBits);
 | |
| 
 | |
|   Weight[0] = 0;
 | |
|   for (Index = 1; Index <= TableBits; Index++) {
 | |
|     Start[Index] >>= JuBits;
 | |
|     Weight[Index] = (UINT16) (1U << (TableBits - Index));
 | |
|   }
 | |
| 
 | |
|   while (Index <= 16) {
 | |
|     Weight[Index] = (UINT16) (1U << (16 - Index));
 | |
|     Index++;
 | |
|   }
 | |
| 
 | |
|   Index = (UINT16) (Start[TableBits + 1] >> JuBits);
 | |
| 
 | |
|   if (Index != 0) {
 | |
|     Index3 = (UINT16) (1U << TableBits);
 | |
|     while (Index != Index3) {
 | |
|       Table[Index++] = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Avail = NumOfChar;
 | |
|   Mask  = (UINT16) (1U << (15 - TableBits));
 | |
|   MaxTableLength = (UINT16) (1U << TableBits);
 | |
| 
 | |
|   for (Char = 0; Char < NumOfChar; Char++) {
 | |
| 
 | |
|     Len = BitLen[Char];
 | |
|     if (Len == 0 || Len >= 17) {
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     NextCode = (UINT16) (Start[Len] + Weight[Len]);
 | |
| 
 | |
|     if (Len <= TableBits) {
 | |
| 
 | |
|       if (Start[Len] >= NextCode || NextCode > MaxTableLength){
 | |
|         return (UINT16) BAD_TABLE;
 | |
|       }
 | |
| 
 | |
|       for (Index = Start[Len]; Index < NextCode; Index++) {
 | |
|         Table[Index] = Char;
 | |
|       }
 | |
| 
 | |
|     } else {
 | |
| 
 | |
|       Index3  = Start[Len];
 | |
|       Pointer = &Table[Index3 >> JuBits];
 | |
|       Index   = (UINT16) (Len - TableBits);
 | |
| 
 | |
|       while (Index != 0) {
 | |
|         if (*Pointer == 0) {
 | |
|           Sd->mRight[Avail]                     = Sd->mLeft[Avail] = 0;
 | |
|           *Pointer = Avail++;
 | |
|         }
 | |
| 
 | |
|         if (Index3 & Mask) {
 | |
|           Pointer = &Sd->mRight[*Pointer];
 | |
|         } else {
 | |
|           Pointer = &Sd->mLeft[*Pointer];
 | |
|         }
 | |
| 
 | |
|         Index3 <<= 1;
 | |
|         Index--;
 | |
|       }
 | |
| 
 | |
|       *Pointer = Char;
 | |
| 
 | |
|     }
 | |
| 
 | |
|     Start[Len] = NextCode;
 | |
|   }
 | |
|   //
 | |
|   // Succeeds
 | |
|   //
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| UINT32
 | |
| DecodeP (
 | |
|   IN  SCRATCH_DATA  *Sd
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Decodes a position value.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd      - the global scratch data
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The position value decoded.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Val;
 | |
|   UINT32  Mask;
 | |
|   UINT32  Pos;
 | |
| 
 | |
|   Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
 | |
| 
 | |
|   if (Val >= MAXNP) {
 | |
|     Mask = 1U << (BITBUFSIZ - 1 - 8);
 | |
| 
 | |
|     do {
 | |
| 
 | |
|       if (Sd->mBitBuf & Mask) {
 | |
|         Val = Sd->mRight[Val];
 | |
|       } else {
 | |
|         Val = Sd->mLeft[Val];
 | |
|       }
 | |
| 
 | |
|       Mask >>= 1;
 | |
|     } while (Val >= MAXNP);
 | |
|   }
 | |
|   //
 | |
|   // Advance what we have read
 | |
|   //
 | |
|   FillBuf (Sd, Sd->mPTLen[Val]);
 | |
| 
 | |
|   Pos = Val;
 | |
|   if (Val > 1) {
 | |
|     Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1)));
 | |
|   }
 | |
| 
 | |
|   return Pos;
 | |
| }
 | |
| 
 | |
| UINT16
 | |
| ReadPTLen (
 | |
|   IN  SCRATCH_DATA  *Sd,
 | |
|   IN  UINT16        nn,
 | |
|   IN  UINT16        nbit,
 | |
|   IN  UINT16        Special
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Reads code lengths for the Extra Set or the Position Set
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd        - The global scratch data
 | |
|   nn        - Number of symbols
 | |
|   nbit      - Number of bits needed to represent nn
 | |
|   Special   - The special symbol that needs to be taken care of
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   0         - OK.
 | |
|   BAD_TABLE - Table is corrupted.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Number;
 | |
|   UINT16  CharC;
 | |
|   volatile UINT16  Index;
 | |
|   UINT32  Mask;
 | |
| 
 | |
|   assert (nn <= NPT);
 | |
| 
 | |
|   Number = (UINT16) GetBits (Sd, nbit);
 | |
| 
 | |
|   if (Number == 0) {
 | |
|     CharC = (UINT16) GetBits (Sd, nbit);
 | |
| 
 | |
|     for (Index = 0; Index < 256; Index++) {
 | |
|       Sd->mPTTable[Index] = CharC;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < nn; Index++) {
 | |
|       Sd->mPTLen[Index] = 0;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   Index = 0;
 | |
| 
 | |
|   while (Index < Number) {
 | |
| 
 | |
|     CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3));
 | |
| 
 | |
|     if (CharC == 7) {
 | |
|       Mask = 1U << (BITBUFSIZ - 1 - 3);
 | |
|       while (Mask & Sd->mBitBuf) {
 | |
|         Mask >>= 1;
 | |
|         CharC += 1;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3));
 | |
| 
 | |
|     Sd->mPTLen[Index++] = (UINT8) CharC;
 | |
| 
 | |
|     if (Index == Special) {
 | |
|       CharC = (UINT16) GetBits (Sd, 2);
 | |
|       while ((INT16) (--CharC) >= 0) {
 | |
|         Sd->mPTLen[Index++] = 0;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   while (Index < nn) {
 | |
|     Sd->mPTLen[Index++] = 0;
 | |
|   }
 | |
| 
 | |
|   return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable);
 | |
| }
 | |
| 
 | |
| VOID
 | |
| ReadCLen (
 | |
|   SCRATCH_DATA  *Sd
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Reads code lengths for Char&Len Set.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd    - the global scratch data
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Number;
 | |
|   UINT16  CharC;
 | |
|   volatile UINT16  Index;
 | |
|   UINT32  Mask;
 | |
| 
 | |
|   Number = (UINT16) GetBits (Sd, CBIT);
 | |
| 
 | |
|   if (Number == 0) {
 | |
|     CharC = (UINT16) GetBits (Sd, CBIT);
 | |
| 
 | |
|     for (Index = 0; Index < NC; Index++) {
 | |
|       Sd->mCLen[Index] = 0;
 | |
|     }
 | |
| 
 | |
|     for (Index = 0; Index < 4096; Index++) {
 | |
|       Sd->mCTable[Index] = CharC;
 | |
|     }
 | |
| 
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   Index = 0;
 | |
|   while (Index < Number) {
 | |
| 
 | |
|     CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
 | |
|     if (CharC >= NT) {
 | |
|       Mask = 1U << (BITBUFSIZ - 1 - 8);
 | |
| 
 | |
|       do {
 | |
| 
 | |
|         if (Mask & Sd->mBitBuf) {
 | |
|           CharC = Sd->mRight[CharC];
 | |
|         } else {
 | |
|           CharC = Sd->mLeft[CharC];
 | |
|         }
 | |
| 
 | |
|         Mask >>= 1;
 | |
| 
 | |
|       } while (CharC >= NT);
 | |
|     }
 | |
|     //
 | |
|     // Advance what we have read
 | |
|     //
 | |
|     FillBuf (Sd, Sd->mPTLen[CharC]);
 | |
| 
 | |
|     if (CharC <= 2) {
 | |
| 
 | |
|       if (CharC == 0) {
 | |
|         CharC = 1;
 | |
|       } else if (CharC == 1) {
 | |
|         CharC = (UINT16) (GetBits (Sd, 4) + 3);
 | |
|       } else if (CharC == 2) {
 | |
|         CharC = (UINT16) (GetBits (Sd, CBIT) + 20);
 | |
|       }
 | |
| 
 | |
|       while ((INT16) (--CharC) >= 0) {
 | |
|         Sd->mCLen[Index++] = 0;
 | |
|       }
 | |
| 
 | |
|     } else {
 | |
| 
 | |
|       Sd->mCLen[Index++] = (UINT8) (CharC - 2);
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   while (Index < NC) {
 | |
|     Sd->mCLen[Index++] = 0;
 | |
|   }
 | |
| 
 | |
|   MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable);
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| UINT16
 | |
| DecodeC (
 | |
|   SCRATCH_DATA  *Sd
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Decode a character/length value.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd    - The global scratch data.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   The value decoded.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT16  Index2;
 | |
|   UINT32  Mask;
 | |
| 
 | |
|   if (Sd->mBlockSize == 0) {
 | |
|     //
 | |
|     // Starting a new block
 | |
|     //
 | |
|     Sd->mBlockSize    = (UINT16) GetBits (Sd, 16);
 | |
|     Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3);
 | |
|     if (Sd->mBadTableFlag != 0) {
 | |
|       return 0;
 | |
|     }
 | |
| 
 | |
|     ReadCLen (Sd);
 | |
| 
 | |
|     Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1));
 | |
|     if (Sd->mBadTableFlag != 0) {
 | |
|       return 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   Sd->mBlockSize--;
 | |
|   Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)];
 | |
| 
 | |
|   if (Index2 >= NC) {
 | |
|     Mask = 1U << (BITBUFSIZ - 1 - 12);
 | |
| 
 | |
|     do {
 | |
|       if (Sd->mBitBuf & Mask) {
 | |
|         Index2 = Sd->mRight[Index2];
 | |
|       } else {
 | |
|         Index2 = Sd->mLeft[Index2];
 | |
|       }
 | |
| 
 | |
|       Mask >>= 1;
 | |
|     } while (Index2 >= NC);
 | |
|   }
 | |
|   //
 | |
|   // Advance what we have read
 | |
|   //
 | |
|   FillBuf (Sd, Sd->mCLen[Index2]);
 | |
| 
 | |
|   return Index2;
 | |
| }
 | |
| 
 | |
| VOID
 | |
| Decode (
 | |
|   SCRATCH_DATA  *Sd
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Decode the source data and put the resulting data into the destination buffer.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Sd            - The global scratch data
 | |
| 
 | |
| Returns: (VOID)
 | |
| 
 | |
|  --*/
 | |
| {
 | |
|   UINT16  BytesRemain;
 | |
|   UINT32  DataIdx;
 | |
|   UINT16  CharC;
 | |
| 
 | |
|   BytesRemain = (UINT16) (-1);
 | |
| 
 | |
|   DataIdx     = 0;
 | |
| 
 | |
|   for (;;) {
 | |
|     CharC = DecodeC (Sd);
 | |
|     if (Sd->mBadTableFlag != 0) {
 | |
|       goto Done ;
 | |
|     }
 | |
| 
 | |
|     if (CharC < 256) {
 | |
|       //
 | |
|       // Process an Original character
 | |
|       //
 | |
|       if (Sd->mOutBuf >= Sd->mOrigSize) {
 | |
|         goto Done ;
 | |
|       } else {
 | |
|         Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC;
 | |
|       }
 | |
| 
 | |
|     } else {
 | |
|       //
 | |
|       // Process a Pointer
 | |
|       //
 | |
|       CharC       = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD));
 | |
| 
 | |
|       BytesRemain = CharC;
 | |
| 
 | |
|       DataIdx     = Sd->mOutBuf - DecodeP (Sd) - 1;
 | |
| 
 | |
|       BytesRemain--;
 | |
| 
 | |
|       while ((INT16) (BytesRemain) >= 0) {
 | |
|         if (Sd->mOutBuf >= Sd->mOrigSize) {
 | |
|           goto Done ;
 | |
|         }
 | |
|         if (DataIdx >= Sd->mOrigSize) {
 | |
|           Sd->mBadTableFlag = (UINT16) BAD_TABLE;
 | |
|           goto Done ;
 | |
|         }
 | |
|         Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
 | |
| 
 | |
|         BytesRemain--;
 | |
|       }
 | |
|       //
 | |
|       // Once mOutBuf is fully filled, directly return
 | |
|       //
 | |
|       if (Sd->mOutBuf >= Sd->mOrigSize) {
 | |
|         goto Done ;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| RETURN_STATUS
 | |
| EFIAPI
 | |
| TDecompress (
 | |
|   IN VOID  *Source,
 | |
|   IN OUT VOID    *Destination,
 | |
|   IN OUT VOID    *Scratch,
 | |
|   IN UINT32      Version
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   The internal implementation of Decompress().
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Source          - The source buffer containing the compressed data.
 | |
|   Destination     - The destination buffer to store the decompressed data
 | |
|   Scratch         - The buffer used internally by the decompress routine. This  buffer is needed to store intermediate data.
 | |
|   Version         - 1 for EFI1.1 Decompress algorithm, 2 for Tiano Decompress algorithm
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   RETURN_SUCCESS           - Decompression is successful
 | |
|   RETURN_INVALID_PARAMETER - The source data is corrupted
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   volatile UINT32  Index;
 | |
|   UINT32           CompSize;
 | |
|   UINT32           OrigSize;
 | |
|   SCRATCH_DATA     *Sd;
 | |
|   CONST UINT8      *Src;
 | |
|   UINT8            *Dst;
 | |
| 
 | |
|   //
 | |
|   // Verify input is not NULL
 | |
|   //
 | |
|   assert(Source);
 | |
| //  assert(Destination);
 | |
|   assert(Scratch);
 | |
| 
 | |
|   Src     = (UINT8 *)Source;
 | |
|   Dst     = (UINT8 *)Destination;
 | |
| 
 | |
|   Sd      = (SCRATCH_DATA *) Scratch;
 | |
|   CompSize  = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
 | |
|   OrigSize  = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
 | |
| 
 | |
|   //
 | |
|   // If compressed file size is 0, return
 | |
|   //
 | |
|   if (OrigSize == 0) {
 | |
|     return RETURN_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   Src = Src + 8;
 | |
| 
 | |
|   for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) {
 | |
|     ((UINT8 *) Sd)[Index] = 0;
 | |
|   }
 | |
|   //
 | |
|   // The length of the field 'Position Set Code Length Array Size' in Block Header.
 | |
|   // For EFI 1.1 de/compression algorithm(Version 1), mPBit = 4
 | |
|   // For Tiano de/compression algorithm(Version 2), mPBit = 5
 | |
|   //
 | |
|   switch (Version) {
 | |
|     case 1 :
 | |
|       Sd->mPBit = 4;
 | |
|       break;
 | |
|     case 2 :
 | |
|       Sd->mPBit = 5;
 | |
|       break;
 | |
|     default:
 | |
|       assert(FALSE);
 | |
|   }
 | |
|   Sd->mSrcBase  = (UINT8 *)Src;
 | |
|   Sd->mDstBase  = Dst;
 | |
|   Sd->mCompSize = CompSize;
 | |
|   Sd->mOrigSize = OrigSize;
 | |
| 
 | |
|   //
 | |
|   // Fill the first BITBUFSIZ bits
 | |
|   //
 | |
|   FillBuf (Sd, BITBUFSIZ);
 | |
| 
 | |
|   //
 | |
|   // Decompress it
 | |
|   //
 | |
| 
 | |
|   Decode (Sd);
 | |
| 
 | |
|   if (Sd->mBadTableFlag != 0) {
 | |
|     //
 | |
|     // Something wrong with the source
 | |
|     //
 | |
|     return RETURN_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   return RETURN_SUCCESS;
 | |
| }
 | |
| 
 | |
| 
 |