]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/EfiCompress.c
2 Compression routine. The compression algorithm is a mixture of LZ77 and Huffman
3 coding. LZ77 transforms the source data into a sequence of Original Characters
4 and Pointers to repeated strings. This sequence is further divided into Blocks
5 and Huffman codings are applied to each Block.
7 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
8 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #define UINT8_MAX 0xff
26 #define WNDSIZ (1U << WNDBIT)
28 #define PERC_FLAG 0x8000U
31 #define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
32 #define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
33 #define CRCPOLY 0xA001
34 #define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
37 // C: the Char&Len Set; P: the Position Set; T: the exTra Set
40 #define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
42 #define NP (WNDBIT + 1)
44 #define NT (CODE_BIT + 3)
53 // Function Prototypes
224 IN UINT16 FreqParm
[],
226 OUT UINT16 CodeParm
[]
234 STATIC UINT8
*mSrc
, *mDst
, *mSrcUpperLimit
, *mDstUpperLimit
;
236 STATIC UINT8
*mLevel
, *mText
, *mChildCount
, *mBuf
, mCLen
[NC
], mPTLen
[NPT
], *mLen
;
237 STATIC INT16 mHeap
[NC
+ 1];
238 STATIC INT32 mRemainder
, mMatchLen
, mBitCount
, mHeapSize
, mN
;
239 STATIC UINT32 mBufSiz
= 0, mOutputPos
, mOutputMask
, mSubBitBuf
, mCrc
;
240 STATIC UINT32 mCompSize
, mOrigSize
;
242 STATIC UINT16
*mFreq
, *mSortPtr
, mLenCnt
[17], mLeft
[2 * NC
- 1], mRight
[2 * NC
- 1],
243 mCrcTable
[UINT8_MAX
+ 1], mCFreq
[2 * NC
- 1],mCCode
[NC
],
244 mPFreq
[2 * NP
- 1], mPTCode
[NPT
], mTFreq
[2 * NT
- 1];
246 STATIC NODE mPos
, mMatchPos
, mAvail
, *mPosition
, *mParent
, *mPrev
, *mNext
= NULL
;
258 IN OUT UINT32
*DstSize
264 The main compression routine.
268 SrcBuffer - The buffer storing the source data
269 SrcSize - The size of source data
270 DstBuffer - The buffer to store the compressed data
271 DstSize - On input, the size of DstBuffer; On output,
272 the size of the actual compressed data.
276 EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case,
277 DstSize contains the size needed.
278 EFI_SUCCESS - Compression is successful.
282 EFI_STATUS Status
= EFI_SUCCESS
;
299 mSrcUpperLimit
= mSrc
+ SrcSize
;
301 mDstUpperLimit
= mDst
+ *DstSize
;
308 mOrigSize
= mCompSize
= 0;
316 if (EFI_ERROR (Status
)) {
317 return EFI_OUT_OF_RESOURCES
;
321 // Null terminate the compressed data
323 if (mDst
< mDstUpperLimit
) {
328 // Fill in compressed size and original size
331 PutDword(mCompSize
+1);
338 if (mCompSize
+ 1 + 8 > *DstSize
) {
339 *DstSize
= mCompSize
+ 1 + 8;
340 return EFI_BUFFER_TOO_SMALL
;
342 *DstSize
= mCompSize
+ 1 + 8;
357 Put a dword to output stream
361 Data - the dword to put
367 if (mDst
< mDstUpperLimit
) {
368 *mDst
++ = (UINT8
)(((UINT8
)(Data
)) & 0xff);
371 if (mDst
< mDstUpperLimit
) {
372 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x08)) & 0xff);
375 if (mDst
< mDstUpperLimit
) {
376 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x10)) & 0xff);
379 if (mDst
< mDstUpperLimit
) {
380 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x18)) & 0xff);
391 Allocate memory spaces for data structures used in compression process
397 EFI_SUCCESS - Memory is allocated successfully
398 EFI_OUT_OF_RESOURCES - Allocation fails
404 mText
= malloc (WNDSIZ
* 2 + MAXMATCH
);
406 return EFI_OUT_OF_RESOURCES
;
408 for (i
= 0 ; i
< WNDSIZ
* 2 + MAXMATCH
; i
++) {
412 mLevel
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mLevel
));
413 mChildCount
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mChildCount
));
414 mPosition
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mPosition
));
415 mParent
= malloc (WNDSIZ
* 2 * sizeof(*mParent
));
416 mPrev
= malloc (WNDSIZ
* 2 * sizeof(*mPrev
));
417 mNext
= malloc ((MAX_HASH_VAL
+ 1) * sizeof(*mNext
));
418 if (mLevel
== NULL
|| mChildCount
== NULL
|| mPosition
== NULL
||
419 mParent
== NULL
|| mPrev
== NULL
|| mNext
== NULL
) {
420 return EFI_OUT_OF_RESOURCES
;
423 mBufSiz
= 16 * 1024U;
424 while ((mBuf
= malloc(mBufSiz
)) == NULL
) {
425 mBufSiz
= (mBufSiz
/ 10U) * 9U;
426 if (mBufSiz
< 4 * 1024U) {
427 return EFI_OUT_OF_RESOURCES
;
441 Called when compression is completed to free memory previously allocated.
492 Initialize String Info Log data structures
502 for (i
= WNDSIZ
; i
<= WNDSIZ
+ UINT8_MAX
; i
++) {
504 mPosition
[i
] = NIL
; /* sentinel */
506 for (i
= WNDSIZ
; i
< WNDSIZ
* 2; i
++) {
510 for (i
= 1; i
< WNDSIZ
- 1; i
++) {
511 mNext
[i
] = (NODE
)(i
+ 1);
514 mNext
[WNDSIZ
- 1] = NIL
;
515 for (i
= WNDSIZ
* 2; i
<= MAX_HASH_VAL
; i
++) {
531 Find child node given the parent node and the edge character
536 c - the edge character
540 The child node (NIL if not found)
546 r
= mNext
[HASH(q
, c
)];
547 mParent
[NIL
] = q
; /* sentinel */
548 while (mParent
[r
] != q
) {
566 Create a new child for a given parent node.
571 c - the edge character
580 h
= (NODE
)HASH(q
, c
);
603 Old - the node to split
613 mChildCount
[New
] = 0;
620 mParent
[New
] = mParent
[Old
];
621 mLevel
[New
] = (UINT8
)mMatchLen
;
622 mPosition
[New
] = mPos
;
623 MakeChild(New
, mText
[mMatchPos
+ mMatchLen
], Old
);
624 MakeChild(New
, mText
[mPos
+ mMatchLen
], mPos
);
634 Insert string info for current position into the String Info Log
645 if (mMatchLen
>= 4) {
648 // We have just got a long match, the target tree
649 // can be located by MatchPos + 1. Traverse the tree
650 // from bottom up to get to a proper starting point.
651 // The usage of PERC_FLAG ensures proper node deletion
652 // in DeleteNode() later.
656 r
= (INT16
)((mMatchPos
+ 1) | WNDSIZ
);
657 while ((q
= mParent
[r
]) == NIL
) {
660 while (mLevel
[q
] >= mMatchLen
) {
661 r
= q
; q
= mParent
[q
];
664 while (mPosition
[t
] < 0) {
669 mPosition
[t
] = (NODE
)(mPos
| PERC_FLAG
);
674 // Locate the target tree
677 q
= (INT16
)(mText
[mPos
] + WNDSIZ
);
679 if ((r
= Child(q
, c
)) == NIL
) {
680 MakeChild(q
, c
, mPos
);
688 // Traverse down the tree to find a match.
689 // Update Position value along the route.
690 // Node split or creation is involved.
699 mMatchPos
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
701 if (mMatchPos
>= mPos
) {
704 t1
= &mText
[mPos
+ mMatchLen
];
705 t2
= &mText
[mMatchPos
+ mMatchLen
];
706 while (mMatchLen
< j
) {
715 if (mMatchLen
>= MAXMATCH
) {
720 if ((r
= Child(q
, *t1
)) == NIL
) {
721 MakeChild(q
, *t1
, mPos
);
736 // Special usage of 'next'
749 Delete outdated string info. (The Usage of PERC_FLAG
750 ensures a clean deletion)
760 if (mParent
[mPos
] == NIL
) {
770 if (r
>= WNDSIZ
|| --mChildCount
[r
] > 1) {
773 t
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
779 while ((u
= mPosition
[q
]) & PERC_FLAG
) {
787 mPosition
[q
] = (INT16
)(s
| WNDSIZ
);
797 mPosition
[q
] = (INT16
)(s
| WNDSIZ
| PERC_FLAG
);
799 s
= Child(r
, mText
[t
+ mLevel
[r
]]);
810 mParent
[s
] = mParent
[r
];
823 Advance the current position (read in new data if needed).
824 Delete outdated string info. Find a match string for current position.
835 if (++mPos
== WNDSIZ
* 2) {
836 memmove(&mText
[0], &mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
837 n
= FreadCrc(&mText
[WNDSIZ
+ MAXMATCH
], WNDSIZ
);
852 The main controlling routine for compression process.
858 EFI_SUCCESS - The compression is successful
859 EFI_OUT_0F_RESOURCES - Not enough memory for compression process
867 Status
= AllocateMemory();
868 if (EFI_ERROR(Status
)) {
877 mRemainder
= FreadCrc(&mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
882 if (mMatchLen
> mRemainder
) {
883 mMatchLen
= mRemainder
;
885 while (mRemainder
> 0) {
886 LastMatchLen
= mMatchLen
;
887 LastMatchPos
= mMatchPos
;
889 if (mMatchLen
> mRemainder
) {
890 mMatchLen
= mRemainder
;
893 if (mMatchLen
> LastMatchLen
|| LastMatchLen
< THRESHOLD
) {
896 // Not enough benefits are gained by outputting a pointer,
897 // so just output the original character
900 Output(mText
[mPos
- 1], 0);
904 // Outputting a pointer is beneficial enough, do it.
907 Output(LastMatchLen
+ (UINT8_MAX
+ 1 - THRESHOLD
),
908 (mPos
- LastMatchPos
- 2) & (WNDSIZ
- 1));
909 while (--LastMatchLen
> 0) {
912 if (mMatchLen
> mRemainder
) {
913 mMatchLen
= mRemainder
;
930 Count the frequencies for the Extra Set
938 INT32 i
, k
, n
, Count
;
940 for (i
= 0; i
< NT
; i
++) {
944 while (n
> 0 && mCLen
[n
- 1] == 0) {
952 while (i
< n
&& mCLen
[i
] == 0) {
957 mTFreq
[0] = (UINT16
)(mTFreq
[0] + Count
);
958 } else if (Count
<= 18) {
960 } else if (Count
== 19) {
983 Outputs the code length array for the Extra Set or the Position Set.
987 n - the number of symbols
988 nbit - the number of bits needed to represent 'n'
989 Special - the special symbol that needs to be take care of
997 while (n
> 0 && mPTLen
[n
- 1] == 0) {
1007 PutBits(k
- 3, (1U << (k
- 3)) - 2);
1010 while (i
< 6 && mPTLen
[i
] == 0) {
1013 PutBits(2, (i
- 3) & 3);
1023 Routine Description:
1025 Outputs the code length array for Char&Length Set
1033 INT32 i
, k
, n
, Count
;
1036 while (n
> 0 && mCLen
[n
- 1] == 0) {
1045 while (i
< n
&& mCLen
[i
] == 0) {
1050 for (k
= 0; k
< Count
; k
++) {
1051 PutBits(mPTLen
[0], mPTCode
[0]);
1053 } else if (Count
<= 18) {
1054 PutBits(mPTLen
[1], mPTCode
[1]);
1055 PutBits(4, Count
- 3);
1056 } else if (Count
== 19) {
1057 PutBits(mPTLen
[0], mPTCode
[0]);
1058 PutBits(mPTLen
[1], mPTCode
[1]);
1061 PutBits(mPTLen
[2], mPTCode
[2]);
1062 PutBits(CBIT
, Count
- 20);
1065 PutBits(mPTLen
[k
+ 2], mPTCode
[k
+ 2]);
1076 PutBits(mCLen
[c
], mCCode
[c
]);
1093 PutBits(mPTLen
[c
], mPTCode
[c
]);
1095 PutBits(c
- 1, p
& (0xFFFFU
>> (17 - c
)));
1104 Routine Description:
1106 Huffman code the block and output it.
1114 UINT32 i
, k
, Flags
, Root
, Pos
, Size
;
1117 Root
= MakeTree(NC
, mCFreq
, mCLen
, mCCode
);
1118 Size
= mCFreq
[Root
];
1122 Root
= MakeTree(NT
, mTFreq
, mPTLen
, mPTCode
);
1124 WritePTLen(NT
, TBIT
, 3);
1127 PutBits(TBIT
, Root
);
1134 PutBits(CBIT
, Root
);
1136 Root
= MakeTree(NP
, mPFreq
, mPTLen
, mPTCode
);
1138 WritePTLen(NP
, PBIT
, -1);
1141 PutBits(PBIT
, Root
);
1144 for (i
= 0; i
< Size
; i
++) {
1145 if (i
% UINT8_BIT
== 0) {
1146 Flags
= mBuf
[Pos
++];
1150 if (Flags
& (1U << (UINT8_BIT
- 1))) {
1151 EncodeC(mBuf
[Pos
++] + (1U << UINT8_BIT
));
1152 k
= mBuf
[Pos
++] << UINT8_BIT
;
1156 EncodeC(mBuf
[Pos
++]);
1159 for (i
= 0; i
< NC
; i
++) {
1162 for (i
= 0; i
< NP
; i
++) {
1176 Routine Description:
1178 Outputs an Original Character or a Pointer
1182 c - The original character or the 'String Length' element of a Pointer
1183 p - The 'Position' field of a Pointer
1191 if ((mOutputMask
>>= 1) == 0) {
1192 mOutputMask
= 1U << (UINT8_BIT
- 1);
1193 if (mOutputPos
>= mBufSiz
- 3 * UINT8_BIT
) {
1197 CPos
= mOutputPos
++;
1200 mBuf
[mOutputPos
++] = (UINT8
) c
;
1202 if (c
>= (1U << UINT8_BIT
)) {
1203 mBuf
[CPos
] |= mOutputMask
;
1204 mBuf
[mOutputPos
++] = (UINT8
)(p
>> UINT8_BIT
);
1205 mBuf
[mOutputPos
++] = (UINT8
) p
;
1221 for (i
= 0; i
< NC
; i
++) {
1224 for (i
= 0; i
< NP
; i
++) {
1227 mOutputPos
= mOutputMask
= 0;
1239 // Flush remaining bits
1241 PutBits(UINT8_BIT
- 1, 0);
1253 for (i
= 0; i
<= UINT8_MAX
; i
++) {
1255 for (j
= 0; j
< UINT8_BIT
; j
++) {
1257 r
= (r
>> 1) ^ CRCPOLY
;
1262 mCrcTable
[i
] = (UINT16
)r
;
1274 Routine Description:
1276 Outputs rightmost n bits of x
1280 n - the rightmost n bits of the data is used
1289 if (n
< mBitCount
) {
1290 mSubBitBuf
|= x
<< (mBitCount
-= n
);
1293 Temp
= (UINT8
)(mSubBitBuf
| (x
>> (n
-= mBitCount
)));
1294 if (mDst
< mDstUpperLimit
) {
1299 if (n
< UINT8_BIT
) {
1300 mSubBitBuf
= x
<< (mBitCount
= UINT8_BIT
- n
);
1303 Temp
= (UINT8
)(x
>> (n
- UINT8_BIT
));
1304 if (mDst
< mDstUpperLimit
) {
1309 mSubBitBuf
= x
<< (mBitCount
= 2 * UINT8_BIT
- n
);
1322 Routine Description:
1328 p - the buffer to hold the data
1329 n - number of bytes to read
1333 number of bytes actually read
1339 for (i
= 0; mSrc
< mSrcUpperLimit
&& i
< n
; i
++) {
1357 mBitCount
= UINT8_BIT
;
1368 Routine Description:
1370 Count the number of each code length for a Huffman tree.
1380 STATIC INT32 Depth
= 0;
1383 mLenCnt
[(Depth
< 16) ? Depth
: 16]++;
1386 CountLen(mLeft
[i
]);
1387 CountLen(mRight
[i
]);
1399 Routine Description:
1401 Create code length array for a Huffman tree
1405 Root - the root of the tree
1412 for (i
= 0; i
<= 16; i
++) {
1418 // Adjust the length count array so that
1419 // no code will be generated longer than its designated length
1423 for (i
= 16; i
> 0; i
--) {
1424 Cum
+= mLenCnt
[i
] << (16 - i
);
1426 while (Cum
!= (1U << 16)) {
1428 for (i
= 15; i
> 0; i
--) {
1429 if (mLenCnt
[i
] != 0) {
1437 for (i
= 16; i
> 0; i
--) {
1440 mLen
[*mSortPtr
++] = (UINT8
)i
;
1454 // priority queue: send i-th entry down heap
1458 while ((j
= 2 * i
) <= mHeapSize
) {
1459 if (j
< mHeapSize
&& mFreq
[mHeap
[j
]] > mFreq
[mHeap
[j
+ 1]]) {
1462 if (mFreq
[k
] <= mFreq
[mHeap
[j
]]) {
1465 mHeap
[i
] = mHeap
[j
];
1468 mHeap
[i
] = (INT16
)k
;
1480 Routine Description:
1482 Assign code to each symbol based on the code length array
1486 n - number of symbols
1487 Len - the code length array
1488 Code - stores codes for each symbol
1498 for (i
= 1; i
<= 16; i
++) {
1499 Start
[i
+ 1] = (UINT16
)((Start
[i
] + mLenCnt
[i
]) << 1);
1501 for (i
= 0; i
< n
; i
++) {
1502 Code
[i
] = Start
[Len
[i
]]++;
1510 IN UINT16 FreqParm
[],
1511 OUT UINT8 LenParm
[],
1512 OUT UINT16 CodeParm
[]
1516 Routine Description:
1518 Generates Huffman codes given a frequency distribution of symbols
1522 NParm - number of symbols
1523 FreqParm - frequency of each symbol
1524 LenParm - code length for each symbol
1525 CodeParm - code for each symbol
1529 Root of the Huffman tree.
1533 INT32 i
, j
, k
, Avail
;
1536 // make tree, calculate len[], return root
1545 for (i
= 0; i
< mN
; i
++) {
1548 mHeap
[++mHeapSize
] = (INT16
)i
;
1551 if (mHeapSize
< 2) {
1552 CodeParm
[mHeap
[1]] = 0;
1555 for (i
= mHeapSize
/ 2; i
>= 1; i
--) {
1558 // make priority queue
1562 mSortPtr
= CodeParm
;
1566 *mSortPtr
++ = (UINT16
)i
;
1568 mHeap
[1] = mHeap
[mHeapSize
--];
1572 *mSortPtr
++ = (UINT16
)j
;
1575 mFreq
[k
] = (UINT16
)(mFreq
[i
] + mFreq
[j
]);
1576 mHeap
[1] = (INT16
)k
;
1578 mLeft
[k
] = (UINT16
)i
;
1579 mRight
[k
] = (UINT16
)j
;
1580 } while (mHeapSize
> 1);
1582 mSortPtr
= CodeParm
;
1584 MakeCode(NParm
, LenParm
, CodeParm
);