UEFITool/Tiano/EfiTianoCompressLegacy.c

1882 lines
28 KiB
C
Raw Normal View History

/* EFI11/Tiano Compress Implementation
Copyright (c) 2015, Nikolaj Schlej
Copyright (c) 2006 - 2008, Intel Corporation
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
which accompanies this distribution. The full text of the license may be found at
http://opensource.org/licenses/bsd-license.php
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
WITHWARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
Module Name:
EfiTianoCompressLegacy.c
Abstract:
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.
Notes:
This legacy compression code can produce incorrect output,
but has better compression ratio as newer releases
*/
#include "EfiTianoCompress.h"
//
// Macro Definitions
//
#undef UINT8_MAX
typedef INT32 NODE;
#define UINT8_MAX 0xff
#define UINT8_BIT 8
#define THRESHOLD 3
#define INIT_CRC 0
#define WNDBIT 19
#define WNDSIZ (1U << WNDBIT)
#define MAXMATCH 256
#define BLKSIZ (1U << 14) // 16 * 1024U
#define PERC_FLAG 0x80000000U
#define CODE_BIT 16
#define NIL 0
#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
#define CRCPOLY 0xA001
#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
//
// 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
//
// Function Prototypes
//
STATIC
2018-04-30 13:38:54 +08:00
VOID
PutDword(
UINT32 Data
);
STATIC
2018-04-30 13:38:54 +08:00
INT32
AllocateMemory(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
FreeMemory(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
InitSlide(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
NODE
Child(
NODE NodeQ,
UINT8 CharC
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeChild(
NODE NodeQ,
UINT8 CharC,
NODE NodeR
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
Split(
NODE Old
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
InsertNode(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
DeleteNode(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
GetNextMatch(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
INT32
Encode(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
CountTFreq(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
WritePTLen(
INT32 Number,
INT32 nbit,
INT32 Special
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
WriteCLen(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
EncodeC(
INT32 Value
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
EncodeP(
UINT32 Value
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
SendBlock(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
Output(
UINT32 c,
UINT32 p
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
HufEncodeStart(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
HufEncodeEnd(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeCrcTable(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
PutBits(
INT32 Number,
UINT32 Value
);
STATIC
2018-04-30 13:38:54 +08:00
INT32
FreadCrc(
UINT8 *Pointer,
INT32 Number
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
InitPutBits(
VOID
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
CountLen(
INT32 Index
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeLen(
INT32 Root
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
DownHeap(
INT32 Index
);
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeCode(
INT32 Number,
UINT8 Len[],
UINT16 Code[]
);
STATIC
2018-04-30 13:38:54 +08:00
INT32
MakeTree(
INT32 NParm,
UINT16 FreqParm[],
UINT8 LenParm[],
UINT16 CodeParm[]
);
//
// Global Variables
//
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],
2018-04-30 13:38:54 +08:00
mCFreq[2 * NC - 1], mCCode[NC], mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];
STATIC UINT8 mPbit;
STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;
//
// functions
//
EFI_STATUS
EfiCompressLegacy(
2018-04-30 13:38:54 +08:00
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
/*++
Routine Description:
The internal implementation of [Efi/Tiano]Compress().
Arguments:
SrcBuffer - The buffer storing the source data
SrcSize - The size of source data
DstBuffer - The buffer to store the compressed data
DstSize - On input, the size of DstBuffer; On output,
the size of the actual compressed data.
Returns:
EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case,
DstSize contains the size needed.
EFI_SUCCESS - Compression is successful.
EFI_OUT_OF_RESOURCES - No resource to complete function.
EFI_INVALID_PARAMETER - Parameter supplied is wrong.
--*/
{
2018-04-30 13:38:54 +08:00
INT32 Status;
//
// Initializations
//
mPbit = 4;
mBufSiz = 0;
mBuf = NULL;
mText = NULL;
mLevel = NULL;
mChildCount = NULL;
mPosition = NULL;
mParent = NULL;
mPrev = NULL;
mNext = NULL;
mSrc = (UINT8*)SrcBuffer;
mSrcUpperLimit = mSrc + SrcSize;
mDst = DstBuffer;
mDstUpperLimit = mDst + *DstSize;
PutDword(0L);
PutDword(0L);
MakeCrcTable();
mOrigSize = mCompSize = 0;
mCrc = INIT_CRC;
//
// Compress it
//
Status = Encode();
if (Status) {
return EFI_OUT_OF_RESOURCES;
}
//
// Null terminate the compressed data
//
if (mDst < mDstUpperLimit) {
*mDst++ = 0;
}
//
// Fill compressed size and original size
//
mDst = DstBuffer;
PutDword(mCompSize + 1);
PutDword(mOrigSize);
//
// Return
//
if (mCompSize + 1 + 8 > *DstSize) {
*DstSize = mCompSize + 1 + 8;
return EFI_BUFFER_TOO_SMALL;
}
else {
*DstSize = mCompSize + 1 + 8;
return EFI_SUCCESS;
}
}
EFI_STATUS
2018-04-30 13:38:54 +08:00
TianoCompressLegacy(
CONST VOID *SrcBuffer,
UINT32 SrcSize,
VOID *DstBuffer,
UINT32 *DstSize
)
2018-04-30 13:38:54 +08:00
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
The internal implementation of [Efi/Tiano]Compress().
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
SrcBuffer - The buffer storing the source data
SrcSize - The size of source data
DstBuffer - The buffer to store the compressed data
DstSize - On input, the size of DstBuffer; On output,
the size of the actual compressed data.
Version - The version of de/compression algorithm.
Version 1 for UEFI 2.0 de/compression algorithm.
Version 2 for Tiano de/compression algorithm.
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. this case,
DstSize contains the size needed.
EFI_SUCCESS - Compression is successful.
EFI_OUT_OF_RESOURCES - No resource to complete function.
EFI_INVALID_PARAMETER - Parameter supplied is wrong.
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
INT32 Status;
//
// Initializations
//
mPbit = 5;
mBufSiz = 0;
mBuf = NULL;
mText = NULL;
mLevel = NULL;
mChildCount = NULL;
mPosition = NULL;
mParent = NULL;
mPrev = NULL;
mNext = NULL;
mSrc = (UINT8*)SrcBuffer;
mSrcUpperLimit = mSrc + SrcSize;
mDst = DstBuffer;
mDstUpperLimit = mDst + *DstSize;
PutDword(0L);
PutDword(0L);
MakeCrcTable();
mOrigSize = mCompSize = 0;
mCrc = INIT_CRC;
//
// Compress it
//
Status = Encode();
if (Status) {
return EFI_OUT_OF_RESOURCES;
}
//
// Null terminate the compressed data
//
if (mDst < mDstUpperLimit) {
*mDst++ = 0;
}
//
// Fill compressed size and original size
//
mDst = DstBuffer;
PutDword(mCompSize + 1);
PutDword(mOrigSize);
//
// Return
//
if (mCompSize + 1 + 8 > *DstSize) {
*DstSize = mCompSize + 1 + 8;
return EFI_BUFFER_TOO_SMALL;
}
else {
*DstSize = mCompSize + 1 + 8;
return EFI_SUCCESS;
}
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
PutDword(
UINT32 Data
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Put a DWORD to output stream
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Data - the DWORD to put
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
if (mDst < mDstUpperLimit) {
*mDst++ = (UINT8)(((UINT8)(Data)) & 0xff);
}
2018-04-30 13:38:54 +08:00
if (mDst < mDstUpperLimit) {
*mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff);
}
2018-04-30 13:38:54 +08:00
if (mDst < mDstUpperLimit) {
*mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff);
}
2018-04-30 13:38:54 +08:00
if (mDst < mDstUpperLimit) {
*mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff);
}
}
STATIC
2018-04-30 13:38:54 +08:00
INT32
AllocateMemory(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Allocate memory spaces for data structures used compression process
2018-04-30 13:38:54 +08:00
Arguments:
VOID
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
EFI_SUCCESS - Memory is allocated successfully
EFI_OUT_OF_RESOURCES - Allocation fails
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
UINT32 Index;
mText = malloc(WNDSIZ * 2 + MAXMATCH);
if (NULL == mText)
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));
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
2018-04-30 13:38:54 +08:00
FreeMemory(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Called when compression is completed to free memory previously allocated.
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
if (mText != NULL) {
free(mText);
}
2018-04-30 13:38:54 +08:00
if (mLevel != NULL) {
free(mLevel);
}
2018-04-30 13:38:54 +08:00
if (mChildCount != NULL) {
free(mChildCount);
}
2018-04-30 13:38:54 +08:00
if (mPosition != NULL) {
free(mPosition);
}
2018-04-30 13:38:54 +08:00
if (mParent != NULL) {
free(mParent);
}
2018-04-30 13:38:54 +08:00
if (mPrev != NULL) {
free(mPrev);
}
2018-04-30 13:38:54 +08:00
if (mNext != NULL) {
free(mNext);
}
2018-04-30 13:38:54 +08:00
if (mBuf != NULL) {
free(mBuf);
}
2018-04-30 13:38:54 +08:00
return;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
InitSlide(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Initialize String Info Log data structures
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
NODE Index;
for (Index = (NODE)WNDSIZ; Index <= (NODE)WNDSIZ + UINT8_MAX; Index++) {
mLevel[Index] = 1;
mPosition[Index] = NIL; // sentinel
}
for (Index = (NODE)WNDSIZ; Index < (NODE)WNDSIZ * 2; Index++) {
mParent[Index] = NIL;
}
mAvail = 1;
for (Index = 1; Index < (NODE)WNDSIZ - 1; Index++) {
mNext[Index] = (NODE)(Index + 1);
}
mNext[WNDSIZ - 1] = NIL;
for (Index = (NODE)WNDSIZ * 2; Index <= (NODE)MAX_HASH_VAL; Index++) {
mNext[Index] = NIL;
}
}
STATIC
2018-04-30 13:38:54 +08:00
NODE
Child(
NODE NodeQ,
UINT8 CharC
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Find child node given the parent node and the edge character
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
NodeQ - the parent node
CharC - the edge character
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
The child node (NIL if not found)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
NODE NodeR;
NodeR = mNext[HASH(NodeQ, CharC)];
//
// sentinel
//
mParent[NIL] = NodeQ;
while (mParent[NodeR] != NodeQ) {
NodeR = mNext[NodeR];
}
return NodeR;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeChild(
NODE Parent,
UINT8 CharC,
NODE Child
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Create a new child for a given parent node.
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Parent - the parent node
CharC - the edge character
Child - the child node
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
Split(
NODE Old
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Split a node.
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Old - the node to split
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
InsertNode(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Insert string info for current position into the String Info Log
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
NODE NodeQ;
NODE NodeR;
NODE Index2;
NODE NodeT;
UINT8 CharC;
UINT8 *t1;
UINT8 *t2;
if (mMatchLen >= 4) {
//
// We have just got a long match, the target tree
// can be located by MatchPos + 1. Traverse the tree
// from bottom up to get to a proper starting point.
// The usage of PERC_FLAG ensures proper node deletion
// DeleteNode() later.
//
mMatchLen--;
NodeR = (NODE)((mMatchPos + 1) | WNDSIZ);
NodeQ = mParent[NodeR];
while (NodeQ == NIL) {
NodeR = mNext[NodeR];
NodeQ = mParent[NodeR];
}
while (mLevel[NodeQ] >= mMatchLen) {
NodeR = NodeQ;
NodeQ = mParent[NodeQ];
}
NodeT = NodeQ;
while (mPosition[NodeT] < 0) {
mPosition[NodeT] = mPos;
NodeT = mParent[NodeT];
}
if (NodeT < (NODE)WNDSIZ) {
mPosition[NodeT] = (NODE)(mPos | (UINT32)PERC_FLAG);
}
}
else {
//
// Locate the target tree
//
NodeQ = (NODE)(mText[mPos] + WNDSIZ);
CharC = mText[mPos + 1];
NodeR = Child(NodeQ, CharC);
if (NodeR == NIL) {
MakeChild(NodeQ, CharC, mPos);
mMatchLen = 1;
return;
}
mMatchLen = 2;
}
//
// Traverse down the tree to find a match.
// Update Position value along the route.
// Node split or creation is involved.
//
for (;;) {
if (NodeR >= (NODE)WNDSIZ) {
Index2 = MAXMATCH;
mMatchPos = NodeR;
}
else {
Index2 = mLevel[NodeR];
mMatchPos = (NODE)(mPosition[NodeR] & (UINT32)~PERC_FLAG);
}
if (mMatchPos >= mPos) {
mMatchPos -= WNDSIZ;
}
t1 = &mText[mPos + mMatchLen];
t2 = &mText[mMatchPos + mMatchLen];
while (mMatchLen < Index2) {
if (*t1 != *t2) {
Split(NodeR);
return;
}
mMatchLen++;
t1++;
t2++;
}
if (mMatchLen >= MAXMATCH) {
break;
}
mPosition[NodeR] = mPos;
NodeQ = NodeR;
NodeR = Child(NodeQ, *t1);
if (NodeR == NIL) {
MakeChild(NodeQ, *t1, mPos);
return;
}
mMatchLen++;
}
NodeT = mPrev[NodeR];
mPrev[mPos] = NodeT;
mNext[NodeT] = mPos;
NodeT = mNext[NodeR];
mNext[mPos] = NodeT;
mPrev[NodeT] = mPos;
mParent[mPos] = NodeQ;
mParent[NodeR] = NIL;
//
// Special usage of 'next'
//
mNext[NodeR] = mPos;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
DeleteNode(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Delete outdated string info. (The Usage of PERC_FLAG
ensures a clean deletion)
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
NODE NodeQ;
NODE NodeR;
NODE NodeS;
NODE NodeT;
NODE NodeU;
if (mParent[mPos] == NIL) {
return;
}
NodeR = mPrev[mPos];
NodeS = mNext[mPos];
mNext[NodeR] = NodeS;
mPrev[NodeS] = NodeR;
NodeR = mParent[mPos];
mParent[mPos] = NIL;
if (NodeR >= (NODE)WNDSIZ) {
return;
}
mChildCount[NodeR]--;
if (mChildCount[NodeR] > 1) {
return;
}
NodeT = (NODE)(mPosition[NodeR] & (UINT32)~PERC_FLAG);
if (NodeT >= mPos) {
NodeT -= WNDSIZ;
}
NodeS = NodeT;
NodeQ = mParent[NodeR];
NodeU = mPosition[NodeQ];
while (NodeU & (UINT32)PERC_FLAG) {
NodeU &= (UINT32)~PERC_FLAG;
if (NodeU >= mPos) {
NodeU -= WNDSIZ;
}
if (NodeU > NodeS) {
NodeS = NodeU;
}
mPosition[NodeQ] = (NODE)(NodeS | WNDSIZ);
NodeQ = mParent[NodeQ];
NodeU = mPosition[NodeQ];
}
if (NodeQ < (NODE)WNDSIZ) {
if (NodeU >= mPos) {
NodeU -= WNDSIZ;
}
if (NodeU > NodeS) {
NodeS = NodeU;
}
mPosition[NodeQ] = (NODE)(NodeS | WNDSIZ | (UINT32)PERC_FLAG);
}
NodeS = Child(NodeR, mText[NodeT + mLevel[NodeR]]);
NodeT = mPrev[NodeS];
NodeU = mNext[NodeS];
mNext[NodeT] = NodeU;
mPrev[NodeU] = NodeT;
NodeT = mPrev[NodeR];
mNext[NodeT] = NodeS;
mPrev[NodeS] = NodeT;
NodeT = mNext[NodeR];
mPrev[NodeT] = NodeS;
mNext[NodeS] = NodeT;
mParent[NodeS] = mParent[NodeR];
mParent[NodeR] = NIL;
mNext[NodeR] = mAvail;
mAvail = NodeR;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
GetNextMatch(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Advance the current position (read new data if needed).
Delete outdated string info. Find a match string for current position.
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
INT32
Encode(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
The mac controlling routine for compression process.
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
EFI_SUCCESS - The compression is successful
EFI_OUT_0F_RESOURCES - Not enough memory for compression process
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
INT32 Status;
INT32 LastMatchLen;
NODE LastMatchPos;
Status = AllocateMemory();
if (Status) {
FreeMemory();
return Status;
}
InitSlide();
HufEncodeStart();
mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH);
mMatchLen = 0;
mPos = WNDSIZ;
InsertNode();
if (mMatchLen > mRemainder) {
mMatchLen = mRemainder;
}
while (mRemainder > 0) {
LastMatchLen = mMatchLen;
LastMatchPos = mMatchPos;
GetNextMatch();
if (mMatchLen > mRemainder) {
mMatchLen = mRemainder;
}
if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {
//
// Not enough benefits are gained by outputting a pointer,
// so just output the original character
//
Output(mText[mPos - 1], 0);
}
else {
if (LastMatchLen == THRESHOLD) {
if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) {
Output(mText[mPos - 1], 0);
continue;
}
}
//
// Outputting a pointer is beneficial enough, do it.
//
Output(
LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),
(mPos - LastMatchPos - 2) & (WNDSIZ - 1)
);
LastMatchLen--;
while (LastMatchLen > 0) {
GetNextMatch();
LastMatchLen--;
}
if (mMatchLen > mRemainder) {
mMatchLen = mRemainder;
}
}
}
HufEncodeEnd();
FreeMemory();
return EFI_SUCCESS;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
CountTFreq(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Count the frequencies for the Extra Set
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
WritePTLen(
INT32 Number,
INT32 nbit,
INT32 Special
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Outputs the code length array for the Extra Set or the Position Set.
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
WriteCLen(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Outputs the code length array for Char&Length Set
2018-04-30 13:38:54 +08:00
Arguments: (VOID)
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
EncodeC(
INT32 Value
)
{
2018-04-30 13:38:54 +08:00
PutBits(mCLen[Value], mCCode[Value]);
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
EncodeP(
UINT32 Value
)
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
SendBlock(
VOID
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Huffman code the block and output it.
2018-04-30 13:38:54 +08:00
Arguments:
(VOID)
2018-04-30 13:38:54 +08:00
Returns:
(VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
UINT32 Index;
UINT32 Index2;
UINT32 Index3;
UINT32 Flags;
UINT32 Root;
UINT32 Pos;
UINT32 Size;
Flags = 0;
Root = MakeTree(NC, mCFreq, mCLen, mCCode);
Size = mCFreq[Root];
PutBits(16, Size);
if (Root >= NC) {
CountTFreq();
Root = MakeTree(NT, mTFreq, mPTLen, mPTCode);
if (Root >= NT) {
WritePTLen(NT, TBIT, 3);
}
else {
PutBits(TBIT, 0);
PutBits(TBIT, Root);
}
WriteCLen();
}
else {
PutBits(TBIT, 0);
PutBits(TBIT, 0);
PutBits(CBIT, 0);
PutBits(CBIT, Root);
}
Root = MakeTree(NP, mPFreq, mPTLen, mPTCode);
if (Root >= NP) {
WritePTLen(NP, mPbit, -1);
}
else {
PutBits(mPbit, 0);
PutBits(mPbit, Root);
}
Pos = 0;
for (Index = 0; Index < Size; Index++) {
if (Index % UINT8_BIT == 0) {
Flags = mBuf[Pos++];
}
else {
Flags <<= 1;
}
if (Flags & (1U << (UINT8_BIT - 1))) {
EncodeC(mBuf[Pos++] + (1U << UINT8_BIT));
Index3 = mBuf[Pos++];
for (Index2 = 0; Index2 < 3; Index2++) {
Index3 <<= UINT8_BIT;
Index3 += mBuf[Pos++];
}
EncodeP(Index3);
}
else {
EncodeC(mBuf[Pos++]);
}
}
for (Index = 0; Index < NC; Index++) {
mCFreq[Index] = 0;
}
for (Index = 0; Index < NP; Index++) {
mPFreq[Index] = 0;
}
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
Output(
UINT32 CharC,
UINT32 Pos
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Outputs an Original Character or a Pointer
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
CharC - The original character or the 'String Length' element of a Pointer
Pos - The 'Position' field of a Pointer
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
STATIC UINT32 CPos;
if ((mOutputMask >>= 1) == 0) {
mOutputMask = 1U << (UINT8_BIT - 1);
//
// Check the buffer overflow per outputting UINT8_BIT symbols
// which is an Original Character or a Pointer. The biggest
// symbol is a Pointer which occupies 5 bytes.
//
if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) {
SendBlock();
mOutputPos = 0;
}
CPos = mOutputPos++;
mBuf[CPos] = 0;
}
mBuf[mOutputPos++] = (UINT8)CharC;
mCFreq[CharC]++;
if (CharC >= (1U << UINT8_BIT)) {
mBuf[CPos] |= mOutputMask;
mBuf[mOutputPos++] = (UINT8)(Pos >> 24);
mBuf[mOutputPos++] = (UINT8)(Pos >> 16);
mBuf[mOutputPos++] = (UINT8)(Pos >> (UINT8_BIT));
mBuf[mOutputPos++] = (UINT8)Pos;
CharC = 0;
while (Pos) {
Pos >>= 1;
CharC++;
}
mPFreq[CharC]++;
}
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
HufEncodeStart(
VOID
)
{
2018-04-30 13:38:54 +08:00
INT32 Index;
2018-04-30 13:38:54 +08:00
for (Index = 0; Index < NC; Index++) {
mCFreq[Index] = 0;
}
2018-04-30 13:38:54 +08:00
for (Index = 0; Index < NP; Index++) {
mPFreq[Index] = 0;
}
2018-04-30 13:38:54 +08:00
mOutputPos = mOutputMask = 0;
InitPutBits();
return;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
HufEncodeEnd(
VOID
)
{
2018-04-30 13:38:54 +08:00
SendBlock();
2018-04-30 13:38:54 +08:00
//
// Flush remaining bits
//
PutBits(UINT8_BIT - 1, 0);
2018-04-30 13:38:54 +08:00
return;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeCrcTable(
VOID
)
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
PutBits(
INT32 Number,
UINT32 Value
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Outputs rightmost n bits of x
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Number - the rightmost n bits of the data is used
x - the data
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
INT32
FreadCrc(
UINT8 *Pointer,
INT32 Number
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Read source data
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Pointer - the buffer to hold the data
Number - number of bytes to read
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
number of bytes actually read
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
INT32 Index;
2018-04-30 13:38:54 +08:00
for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) {
*Pointer++ = *mSrc++;
}
2018-04-30 13:38:54 +08:00
Number = Index;
2018-04-30 13:38:54 +08:00
Pointer -= Number;
mOrigSize += Number;
Index--;
while (Index >= 0) {
UPDATE_CRC(*Pointer++);
Index--;
}
2018-04-30 13:38:54 +08:00
return Number;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
InitPutBits(
VOID
)
{
2018-04-30 13:38:54 +08:00
mBitCount = UINT8_BIT;
mSubBitBuf = 0;
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
CountLen(
INT32 Index
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Count the number of each code length for a Huffman tree.
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Index - the top node
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
STATIC INT32 Depth = 0;
if (Index < mN) {
mLenCnt[(Depth < 16) ? Depth : 16]++;
}
else {
Depth++;
CountLen(mLeft[Index]);
CountLen(mRight[Index]);
Depth--;
}
}
STATIC
2018-04-30 13:38:54 +08:00
VOID
MakeLen(
INT32 Root
)
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Create code length array for a Huffman tree
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Root - the root of the tree
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
VOID
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
DownHeap(
INT32 Index
)
{
2018-04-30 13:38:54 +08:00
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
2018-04-30 13:38:54 +08:00
VOID
MakeCode(
INT32 Number,
UINT8 Len[],
UINT16 Code[]
)
2018-04-30 13:38:54 +08:00
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Assign code to each symbol based on the code length array
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
Number - number of symbols
Len - the code length array
Code - stores codes for each symbol
2018-04-30 13:38:54 +08:00
Returns: (VOID)
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
INT32 Index;
UINT16 Start[18];
2018-04-30 13:38:54 +08:00
Start[1] = 0;
for (Index = 1; Index <= 16; Index++) {
Start[Index + 1] = (UINT16)((Start[Index] + mLenCnt[Index]) << 1);
}
2018-04-30 13:38:54 +08:00
for (Index = 0; Index < Number; Index++) {
Code[Index] = Start[Len[Index]]++;
}
}
STATIC
2018-04-30 13:38:54 +08:00
INT32
MakeTree(
INT32 NParm,
UINT16 FreqParm[],
UINT8 LenParm[],
UINT16 CodeParm[]
)
2018-04-30 13:38:54 +08:00
/*++
2018-04-30 13:38:54 +08:00
Routine Description:
2018-04-30 13:38:54 +08:00
Generates Huffman codes given a frequency distribution of symbols
2018-04-30 13:38:54 +08:00
Arguments:
2018-04-30 13:38:54 +08:00
NParm - number of symbols
FreqParm - frequency of each symbol
LenParm - code length for each symbol
CodeParm - code for each symbol
2018-04-30 13:38:54 +08:00
Returns:
2018-04-30 13:38:54 +08:00
Root of the Huffman tree.
2018-04-30 13:38:54 +08:00
--*/
{
2018-04-30 13:38:54 +08:00
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;
}