]>
git.proxmox.com Git - mirror_edk2.git/blob - EdkCompatibilityPkg/Sample/Tools/Source/Common/EfiCompress.c
3 Copyright (c) 2006, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 Compression routine. The compression algorithm is a mixture of
19 LZ77 and Huffman coding. LZ77 transforms the source data into a
20 sequence of Original Characters and Pointers to repeated strings.
21 This sequence is further divided into Blocks and Huffman codings
22 are applied to each Block.
28 #include "TianoCommon.h"
37 #define UINT8_MAX 0xff
42 #define WNDSIZ (1U << WNDBIT)
44 #define PERC_FLAG 0x8000U
47 #define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
48 #define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
49 #define CRCPOLY 0xA001
50 #define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
53 // C: the Char&Len Set; P: the Position Set; T: the exTra Set
56 #define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
58 #define NP (WNDBIT + 1)
60 #define NT (CODE_BIT + 3)
69 // Function Prototypes
240 IN UINT16 FreqParm
[],
242 OUT UINT16 CodeParm
[]
250 STATIC UINT8
*mSrc
, *mDst
, *mSrcUpperLimit
, *mDstUpperLimit
;
252 STATIC UINT8
*mLevel
, *mText
, *mChildCount
, *mBuf
, mCLen
[NC
], mPTLen
[NPT
], *mLen
;
253 STATIC INT16 mHeap
[NC
+ 1];
254 STATIC INT32 mRemainder
, mMatchLen
, mBitCount
, mHeapSize
, mN
;
255 STATIC UINT32 mBufSiz
= 0, mOutputPos
, mOutputMask
, mSubBitBuf
, mCrc
;
256 STATIC UINT32 mCompSize
, mOrigSize
;
258 STATIC UINT16
*mFreq
, *mSortPtr
, mLenCnt
[17], mLeft
[2 * NC
- 1], mRight
[2 * NC
- 1],
259 mCrcTable
[UINT8_MAX
+ 1], mCFreq
[2 * NC
- 1], mCTable
[4096], mCCode
[NC
],
260 mPFreq
[2 * NP
- 1], mPTCode
[NPT
], mTFreq
[2 * NT
- 1];
262 STATIC NODE mPos
, mMatchPos
, mAvail
, *mPosition
, *mParent
, *mPrev
, *mNext
= NULL
;
274 IN OUT UINT32
*DstSize
280 The main compression routine.
284 SrcBuffer - The buffer storing the source data
285 SrcSize - The size of source data
286 DstBuffer - The buffer to store the compressed data
287 DstSize - On input, the size of DstBuffer; On output,
288 the size of the actual compressed data.
292 EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case,
293 DstSize contains the size needed.
294 EFI_SUCCESS - Compression is successful.
298 EFI_STATUS Status
= EFI_SUCCESS
;
315 mSrcUpperLimit
= mSrc
+ SrcSize
;
317 mDstUpperLimit
= mDst
+ *DstSize
;
324 mOrigSize
= mCompSize
= 0;
332 if (EFI_ERROR (Status
)) {
333 return EFI_OUT_OF_RESOURCES
;
337 // Null terminate the compressed data
339 if (mDst
< mDstUpperLimit
) {
344 // Fill in compressed size and original size
347 PutDword(mCompSize
+1);
354 if (mCompSize
+ 1 + 8 > *DstSize
) {
355 *DstSize
= mCompSize
+ 1 + 8;
356 return EFI_BUFFER_TOO_SMALL
;
358 *DstSize
= mCompSize
+ 1 + 8;
373 Put a dword to output stream
377 Data - the dword to put
383 if (mDst
< mDstUpperLimit
) {
384 *mDst
++ = (UINT8
)(((UINT8
)(Data
)) & 0xff);
387 if (mDst
< mDstUpperLimit
) {
388 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x08)) & 0xff);
391 if (mDst
< mDstUpperLimit
) {
392 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x10)) & 0xff);
395 if (mDst
< mDstUpperLimit
) {
396 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x18)) & 0xff);
407 Allocate memory spaces for data structures used in compression process
413 EFI_SUCCESS - Memory is allocated successfully
414 EFI_OUT_OF_RESOURCES - Allocation fails
420 mText
= malloc (WNDSIZ
* 2 + MAXMATCH
);
421 for (i
= 0 ; i
< WNDSIZ
* 2 + MAXMATCH
; i
++) {
425 mLevel
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mLevel
));
426 mChildCount
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mChildCount
));
427 mPosition
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mPosition
));
428 mParent
= malloc (WNDSIZ
* 2 * sizeof(*mParent
));
429 mPrev
= malloc (WNDSIZ
* 2 * sizeof(*mPrev
));
430 mNext
= malloc ((MAX_HASH_VAL
+ 1) * sizeof(*mNext
));
432 mBufSiz
= 16 * 1024U;
433 while ((mBuf
= malloc(mBufSiz
)) == NULL
) {
434 mBufSiz
= (mBufSiz
/ 10U) * 9U;
435 if (mBufSiz
< 4 * 1024U) {
436 return EFI_OUT_OF_RESOURCES
;
450 Called when compression is completed to free memory previously allocated.
501 Initialize String Info Log data structures
511 for (i
= WNDSIZ
; i
<= WNDSIZ
+ UINT8_MAX
; i
++) {
513 mPosition
[i
] = NIL
; /* sentinel */
515 for (i
= WNDSIZ
; i
< WNDSIZ
* 2; i
++) {
519 for (i
= 1; i
< WNDSIZ
- 1; i
++) {
520 mNext
[i
] = (NODE
)(i
+ 1);
523 mNext
[WNDSIZ
- 1] = NIL
;
524 for (i
= WNDSIZ
* 2; i
<= MAX_HASH_VAL
; i
++) {
540 Find child node given the parent node and the edge character
545 c - the edge character
549 The child node (NIL if not found)
555 r
= mNext
[HASH(q
, c
)];
556 mParent
[NIL
] = q
; /* sentinel */
557 while (mParent
[r
] != q
) {
575 Create a new child for a given parent node.
580 c - the edge character
589 h
= (NODE
)HASH(q
, c
);
612 Old - the node to split
622 mChildCount
[New
] = 0;
629 mParent
[New
] = mParent
[Old
];
630 mLevel
[New
] = (UINT8
)mMatchLen
;
631 mPosition
[New
] = mPos
;
632 MakeChild(New
, mText
[mMatchPos
+ mMatchLen
], Old
);
633 MakeChild(New
, mText
[mPos
+ mMatchLen
], mPos
);
643 Insert string info for current position into the String Info Log
654 if (mMatchLen
>= 4) {
657 // We have just got a long match, the target tree
658 // can be located by MatchPos + 1. Travese the tree
659 // from bottom up to get to a proper starting point.
660 // The usage of PERC_FLAG ensures proper node deletion
661 // in DeleteNode() later.
665 r
= (INT16
)((mMatchPos
+ 1) | WNDSIZ
);
666 while ((q
= mParent
[r
]) == NIL
) {
669 while (mLevel
[q
] >= mMatchLen
) {
670 r
= q
; q
= mParent
[q
];
673 while (mPosition
[t
] < 0) {
678 mPosition
[t
] = (NODE
)(mPos
| PERC_FLAG
);
683 // Locate the target tree
686 q
= (INT16
)(mText
[mPos
] + WNDSIZ
);
688 if ((r
= Child(q
, c
)) == NIL
) {
689 MakeChild(q
, c
, mPos
);
697 // Traverse down the tree to find a match.
698 // Update Position value along the route.
699 // Node split or creation is involved.
708 mMatchPos
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
710 if (mMatchPos
>= mPos
) {
713 t1
= &mText
[mPos
+ mMatchLen
];
714 t2
= &mText
[mMatchPos
+ mMatchLen
];
715 while (mMatchLen
< j
) {
724 if (mMatchLen
>= MAXMATCH
) {
729 if ((r
= Child(q
, *t1
)) == NIL
) {
730 MakeChild(q
, *t1
, mPos
);
745 // Special usage of 'next'
758 Delete outdated string info. (The Usage of PERC_FLAG
759 ensures a clean deletion)
769 if (mParent
[mPos
] == NIL
) {
779 if (r
>= WNDSIZ
|| --mChildCount
[r
] > 1) {
782 t
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
788 while ((u
= mPosition
[q
]) & PERC_FLAG
) {
796 mPosition
[q
] = (INT16
)(s
| WNDSIZ
);
806 mPosition
[q
] = (INT16
)(s
| WNDSIZ
| PERC_FLAG
);
808 s
= Child(r
, mText
[t
+ mLevel
[r
]]);
819 mParent
[s
] = mParent
[r
];
832 Advance the current position (read in new data if needed).
833 Delete outdated string info. Find a match string for current position.
844 if (++mPos
== WNDSIZ
* 2) {
845 memmove(&mText
[0], &mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
846 n
= FreadCrc(&mText
[WNDSIZ
+ MAXMATCH
], WNDSIZ
);
861 The main controlling routine for compression process.
867 EFI_SUCCESS - The compression is successful
868 EFI_OUT_0F_RESOURCES - Not enough memory for compression process
876 Status
= AllocateMemory();
877 if (EFI_ERROR(Status
)) {
886 mRemainder
= FreadCrc(&mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
891 if (mMatchLen
> mRemainder
) {
892 mMatchLen
= mRemainder
;
894 while (mRemainder
> 0) {
895 LastMatchLen
= mMatchLen
;
896 LastMatchPos
= mMatchPos
;
898 if (mMatchLen
> mRemainder
) {
899 mMatchLen
= mRemainder
;
902 if (mMatchLen
> LastMatchLen
|| LastMatchLen
< THRESHOLD
) {
905 // Not enough benefits are gained by outputting a pointer,
906 // so just output the original character
909 Output(mText
[mPos
- 1], 0);
913 // Outputting a pointer is beneficial enough, do it.
916 Output(LastMatchLen
+ (UINT8_MAX
+ 1 - THRESHOLD
),
917 (mPos
- LastMatchPos
- 2) & (WNDSIZ
- 1));
918 while (--LastMatchLen
> 0) {
921 if (mMatchLen
> mRemainder
) {
922 mMatchLen
= mRemainder
;
939 Count the frequencies for the Extra Set
947 INT32 i
, k
, n
, Count
;
949 for (i
= 0; i
< NT
; i
++) {
953 while (n
> 0 && mCLen
[n
- 1] == 0) {
961 while (i
< n
&& mCLen
[i
] == 0) {
966 mTFreq
[0] = (UINT16
)(mTFreq
[0] + Count
);
967 } else if (Count
<= 18) {
969 } else if (Count
== 19) {
992 Outputs the code length array for the Extra Set or the Position Set.
996 n - the number of symbols
997 nbit - the number of bits needed to represent 'n'
998 Special - the special symbol that needs to be take care of
1006 while (n
> 0 && mPTLen
[n
- 1] == 0) {
1016 PutBits(k
- 3, (1U << (k
- 3)) - 2);
1019 while (i
< 6 && mPTLen
[i
] == 0) {
1022 PutBits(2, (i
- 3) & 3);
1032 Routine Description:
1034 Outputs the code length array for Char&Length Set
1042 INT32 i
, k
, n
, Count
;
1045 while (n
> 0 && mCLen
[n
- 1] == 0) {
1054 while (i
< n
&& mCLen
[i
] == 0) {
1059 for (k
= 0; k
< Count
; k
++) {
1060 PutBits(mPTLen
[0], mPTCode
[0]);
1062 } else if (Count
<= 18) {
1063 PutBits(mPTLen
[1], mPTCode
[1]);
1064 PutBits(4, Count
- 3);
1065 } else if (Count
== 19) {
1066 PutBits(mPTLen
[0], mPTCode
[0]);
1067 PutBits(mPTLen
[1], mPTCode
[1]);
1070 PutBits(mPTLen
[2], mPTCode
[2]);
1071 PutBits(CBIT
, Count
- 20);
1074 PutBits(mPTLen
[k
+ 2], mPTCode
[k
+ 2]);
1085 PutBits(mCLen
[c
], mCCode
[c
]);
1102 PutBits(mPTLen
[c
], mPTCode
[c
]);
1104 PutBits(c
- 1, p
& (0xFFFFU
>> (17 - c
)));
1113 Routine Description:
1115 Huffman code the block and output it.
1123 UINT32 i
, k
, Flags
, Root
, Pos
, Size
;
1126 Root
= MakeTree(NC
, mCFreq
, mCLen
, mCCode
);
1127 Size
= mCFreq
[Root
];
1131 Root
= MakeTree(NT
, mTFreq
, mPTLen
, mPTCode
);
1133 WritePTLen(NT
, TBIT
, 3);
1136 PutBits(TBIT
, Root
);
1143 PutBits(CBIT
, Root
);
1145 Root
= MakeTree(NP
, mPFreq
, mPTLen
, mPTCode
);
1147 WritePTLen(NP
, PBIT
, -1);
1150 PutBits(PBIT
, Root
);
1153 for (i
= 0; i
< Size
; i
++) {
1154 if (i
% UINT8_BIT
== 0) {
1155 Flags
= mBuf
[Pos
++];
1159 if (Flags
& (1U << (UINT8_BIT
- 1))) {
1160 EncodeC(mBuf
[Pos
++] + (1U << UINT8_BIT
));
1161 k
= mBuf
[Pos
++] << UINT8_BIT
;
1165 EncodeC(mBuf
[Pos
++]);
1168 for (i
= 0; i
< NC
; i
++) {
1171 for (i
= 0; i
< NP
; i
++) {
1185 Routine Description:
1187 Outputs an Original Character or a Pointer
1191 c - The original character or the 'String Length' element of a Pointer
1192 p - The 'Position' field of a Pointer
1200 if ((mOutputMask
>>= 1) == 0) {
1201 mOutputMask
= 1U << (UINT8_BIT
- 1);
1202 if (mOutputPos
>= mBufSiz
- 3 * UINT8_BIT
) {
1206 CPos
= mOutputPos
++;
1209 mBuf
[mOutputPos
++] = (UINT8
) c
;
1211 if (c
>= (1U << UINT8_BIT
)) {
1212 mBuf
[CPos
] |= mOutputMask
;
1213 mBuf
[mOutputPos
++] = (UINT8
)(p
>> UINT8_BIT
);
1214 mBuf
[mOutputPos
++] = (UINT8
) p
;
1230 for (i
= 0; i
< NC
; i
++) {
1233 for (i
= 0; i
< NP
; i
++) {
1236 mOutputPos
= mOutputMask
= 0;
1248 // Flush remaining bits
1250 PutBits(UINT8_BIT
- 1, 0);
1262 for (i
= 0; i
<= UINT8_MAX
; i
++) {
1264 for (j
= 0; j
< UINT8_BIT
; j
++) {
1266 r
= (r
>> 1) ^ CRCPOLY
;
1271 mCrcTable
[i
] = (UINT16
)r
;
1283 Routine Description:
1285 Outputs rightmost n bits of x
1289 n - the rightmost n bits of the data is used
1298 if (n
< mBitCount
) {
1299 mSubBitBuf
|= x
<< (mBitCount
-= n
);
1302 Temp
= (UINT8
)(mSubBitBuf
| (x
>> (n
-= mBitCount
)));
1303 if (mDst
< mDstUpperLimit
) {
1308 if (n
< UINT8_BIT
) {
1309 mSubBitBuf
= x
<< (mBitCount
= UINT8_BIT
- n
);
1312 Temp
= (UINT8
)(x
>> (n
- UINT8_BIT
));
1313 if (mDst
< mDstUpperLimit
) {
1318 mSubBitBuf
= x
<< (mBitCount
= 2 * UINT8_BIT
- n
);
1331 Routine Description:
1337 p - the buffer to hold the data
1338 n - number of bytes to read
1342 number of bytes actually read
1348 for (i
= 0; mSrc
< mSrcUpperLimit
&& i
< n
; i
++) {
1366 mBitCount
= UINT8_BIT
;
1377 Routine Description:
1379 Count the number of each code length for a Huffman tree.
1389 STATIC INT32 Depth
= 0;
1392 mLenCnt
[(Depth
< 16) ? Depth
: 16]++;
1395 CountLen(mLeft
[i
]);
1396 CountLen(mRight
[i
]);
1408 Routine Description:
1410 Create code length array for a Huffman tree
1414 Root - the root of the tree
1421 for (i
= 0; i
<= 16; i
++) {
1427 // Adjust the length count array so that
1428 // no code will be generated longer than its designated length
1432 for (i
= 16; i
> 0; i
--) {
1433 Cum
+= mLenCnt
[i
] << (16 - i
);
1435 while (Cum
!= (1U << 16)) {
1437 for (i
= 15; i
> 0; i
--) {
1438 if (mLenCnt
[i
] != 0) {
1446 for (i
= 16; i
> 0; i
--) {
1449 mLen
[*mSortPtr
++] = (UINT8
)i
;
1463 // priority queue: send i-th entry down heap
1467 while ((j
= 2 * i
) <= mHeapSize
) {
1468 if (j
< mHeapSize
&& mFreq
[mHeap
[j
]] > mFreq
[mHeap
[j
+ 1]]) {
1471 if (mFreq
[k
] <= mFreq
[mHeap
[j
]]) {
1474 mHeap
[i
] = mHeap
[j
];
1477 mHeap
[i
] = (INT16
)k
;
1489 Routine Description:
1491 Assign code to each symbol based on the code length array
1495 n - number of symbols
1496 Len - the code length array
1497 Code - stores codes for each symbol
1507 for (i
= 1; i
<= 16; i
++) {
1508 Start
[i
+ 1] = (UINT16
)((Start
[i
] + mLenCnt
[i
]) << 1);
1510 for (i
= 0; i
< n
; i
++) {
1511 Code
[i
] = Start
[Len
[i
]]++;
1519 IN UINT16 FreqParm
[],
1520 OUT UINT8 LenParm
[],
1521 OUT UINT16 CodeParm
[]
1525 Routine Description:
1527 Generates Huffman codes given a frequency distribution of symbols
1531 NParm - number of symbols
1532 FreqParm - frequency of each symbol
1533 LenParm - code length for each symbol
1534 CodeParm - code for each symbol
1538 Root of the Huffman tree.
1542 INT32 i
, j
, k
, Avail
;
1545 // make tree, calculate len[], return root
1554 for (i
= 0; i
< mN
; i
++) {
1557 mHeap
[++mHeapSize
] = (INT16
)i
;
1560 if (mHeapSize
< 2) {
1561 CodeParm
[mHeap
[1]] = 0;
1564 for (i
= mHeapSize
/ 2; i
>= 1; i
--) {
1567 // make priority queue
1571 mSortPtr
= CodeParm
;
1575 *mSortPtr
++ = (UINT16
)i
;
1577 mHeap
[1] = mHeap
[mHeapSize
--];
1581 *mSortPtr
++ = (UINT16
)j
;
1584 mFreq
[k
] = (UINT16
)(mFreq
[i
] + mFreq
[j
]);
1585 mHeap
[1] = (INT16
)k
;
1587 mLeft
[k
] = (UINT16
)i
;
1588 mRight
[k
] = (UINT16
)j
;
1589 } while (mHeapSize
> 1);
1591 mSortPtr
= CodeParm
;
1593 MakeCode(NParm
, LenParm
, CodeParm
);