This reverts commit 6693f359b3c213513c5096a06c6f67244a44dc52.. 678f85131238622e576705117e299d81cff755c9. Python3 migration is the fundamental change. It requires every developer to install Python3. Before this migration, the well communication and wide verification must be done. But now, most people is not aware of this change, and not try it. So, Python3 migration is reverted and be moved to edk2-staging Python3 branch for the edk2 user evaluation. Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Liming Gao <liming.gao@intel.com>
2738 lines
52 KiB
C
2738 lines
52 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>
|
|
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 "Compress.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 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
|
|
|
|
Argements:
|
|
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. 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--;
|
|
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, " -o FileName, --output FileName\n\
|
|
File will be created to store the ouput 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;
|
|
|
|
SetUtilityName(UTILITY_NAME);
|
|
|
|
FileBuffer = NULL;
|
|
Src = NULL;
|
|
OutBuffer = NULL;
|
|
Scratch = NULL;
|
|
OrigSize = 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], "--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);
|
|
}
|
|
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;
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
//
|
|
// Get Compressed file original size
|
|
//
|
|
Src = (UINT8 *)FileBuffer;
|
|
OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
|
|
|
|
//
|
|
// Allocate OutputBuffer
|
|
//
|
|
OutBuffer = (UINT8 *)malloc(OrigSize);
|
|
if (OutBuffer == NULL) {
|
|
Error (NULL, 0, 4001, "Resource:", "Memory cannot be allocated!");
|
|
goto ERROR;
|
|
}
|
|
|
|
Status = Decompress((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);
|
|
free(Scratch);
|
|
free(FileBuffer);
|
|
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;
|
|
|
|
for (Index = 0; Index <= 16; Index++) {
|
|
Count[Index] = 0;
|
|
}
|
|
|
|
for (Index = 0; Index < NumOfChar; Index++) {
|
|
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));
|
|
|
|
for (Char = 0; Char < NumOfChar; Char++) {
|
|
|
|
Len = BitLen[Char];
|
|
if (Len == 0 || Len >= 17) {
|
|
continue;
|
|
}
|
|
|
|
NextCode = (UINT16) (Start[Len] + Weight[Len]);
|
|
|
|
if (Len <= TableBits) {
|
|
|
|
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) {
|
|
Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
|
|
if (Sd->mOutBuf >= Sd->mOrigSize) {
|
|
goto Done ;
|
|
}
|
|
|
|
BytesRemain--;
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
return ;
|
|
}
|
|
|
|
RETURN_STATUS
|
|
EFIAPI
|
|
Decompress (
|
|
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 algoruthm, 2 for Tiano Decompress algorithm
|
|
|
|
Returns:
|
|
|
|
RETURN_SUCCESS - Decompression is successfull
|
|
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;
|
|
}
|
|
|
|
|