Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Ruiyu Ni <ruiyu.ni@intel.com> Reviewed-by: Jaben Carsey <jaben.carsey@intel.com>
		
			
				
	
	
		
			1387 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1387 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   Main file for compression routine.
 | |
| 
 | |
|   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 - 2016, Intel Corporation. All rights reserved.<BR>
 | |
|   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 <Uefi.h>
 | |
| #include <Library/MemoryAllocationLib.h>
 | |
| #include <Library/BaseMemoryLib.h>
 | |
| #include <Library/DebugLib.h>
 | |
| #include <Library/ShellLib.h>
 | |
| 
 | |
| //
 | |
| // Macro Definitions
 | |
| //
 | |
| typedef INT16             NODE;
 | |
| #define UINT8_MAX         0xff
 | |
| #define UINT8_BIT         8
 | |
| #define THRESHOLD         3
 | |
| #define INIT_CRC          0
 | |
| #define WNDBIT            13
 | |
| #define WNDSIZ            (1U << WNDBIT)
 | |
| #define MAXMATCH          256
 | |
| #define 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              4
 | |
| #define NT                (CODE_BIT + 3)
 | |
| #define TBIT              5
 | |
| #if NT > NP
 | |
|   #define                 NPT NT
 | |
| #else
 | |
|   #define                 NPT NP
 | |
| #endif
 | |
| //
 | |
| // Function Prototypes
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Put a dword to output stream
 | |
| 
 | |
|   @param[in] Data    The dword to put.
 | |
| **/
 | |
| VOID
 | |
| PutDword(
 | |
|   IN UINT32 Data
 | |
|   );
 | |
| 
 | |
| //
 | |
| //  Global Variables
 | |
| //
 | |
| STATIC UINT8  *mSrc;
 | |
| STATIC UINT8  *mDst;
 | |
| STATIC UINT8  *mSrcUpperLimit;
 | |
| STATIC UINT8  *mDstUpperLimit;
 | |
| 
 | |
| 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;
 | |
| 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;
 | |
| 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 NODE   mPos;
 | |
| STATIC NODE   mMatchPos;
 | |
| STATIC NODE   mAvail;
 | |
| STATIC NODE   *mPosition;
 | |
| STATIC NODE   *mParent;
 | |
| STATIC NODE   *mPrev;
 | |
| STATIC NODE   *mNext = NULL;
 | |
| INT32         mHuffmanDepth = 0;
 | |
| 
 | |
| /**
 | |
|   Make a CRC table.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| MakeCrcTable (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   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
 | |
| 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
 | |
| 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
 | |
| FreeMemory (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   SHELL_FREE_NON_NULL (mText);
 | |
|   SHELL_FREE_NON_NULL (mLevel);
 | |
|   SHELL_FREE_NON_NULL (mChildCount);
 | |
|   SHELL_FREE_NON_NULL (mPosition);
 | |
|   SHELL_FREE_NON_NULL (mParent);
 | |
|   SHELL_FREE_NON_NULL (mPrev);
 | |
|   SHELL_FREE_NON_NULL (mNext);
 | |
|   SHELL_FREE_NON_NULL (mBuf);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize String Info Log data structures.
 | |
| **/
 | |
| VOID
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| EncodeC (
 | |
|   IN INT32 LoopVar5
 | |
|   )
 | |
| {
 | |
|   PutBits (mCLen[LoopVar5], mCCode[LoopVar5]);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Encode a unsigned 32 bit number.
 | |
| 
 | |
|   @param[in] LoopVar7     The number to encode.
 | |
| **/
 | |
| VOID
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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)<NPT);
 | |
|       PutBits (mPTLen[LoopVar3 + 2], mPTCode[LoopVar3 + 2]);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Huffman code the block and output it.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SendBlock (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   UINT32  LoopVar1;
 | |
| 
 | |
|   UINT32  LoopVar3;
 | |
| 
 | |
|   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 (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
 | |
| 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
 | |
| 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
 | |
| 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
 | |
| 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 sucessful.
 | |
|   @retval EFI_BUFFER_TOO_SMALL  The buffer was too small.  DstSize is required.
 | |
| **/
 | |
| EFI_STATUS
 | |
| Compress (
 | |
|   IN       VOID   *SrcBuffer,
 | |
|   IN       UINT64 SrcSize,
 | |
|   IN       VOID   *DstBuffer,
 | |
|   IN OUT   UINT64 *DstSize
 | |
|   )
 | |
| {
 | |
|   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;
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 |