]>
git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/EfiCompress.c
3 Copyright (c) 2006 - 2008, 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.
35 #define UINT8_MAX 0xff
40 #define WNDSIZ (1U << WNDBIT)
42 #define PERC_FLAG 0x8000U
45 #define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
46 #define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
47 #define CRCPOLY 0xA001
48 #define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
51 // C: the Char&Len Set; P: the Position Set; T: the exTra Set
54 #define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
56 #define NP (WNDBIT + 1)
58 #define NT (CODE_BIT + 3)
67 // Function Prototypes
238 IN UINT16 FreqParm
[],
240 OUT UINT16 CodeParm
[]
248 STATIC UINT8
*mSrc
, *mDst
, *mSrcUpperLimit
, *mDstUpperLimit
;
250 STATIC UINT8
*mLevel
, *mText
, *mChildCount
, *mBuf
, mCLen
[NC
], mPTLen
[NPT
], *mLen
;
251 STATIC INT16 mHeap
[NC
+ 1];
252 STATIC INT32 mRemainder
, mMatchLen
, mBitCount
, mHeapSize
, mN
;
253 STATIC UINT32 mBufSiz
= 0, mOutputPos
, mOutputMask
, mSubBitBuf
, mCrc
;
254 STATIC UINT32 mCompSize
, mOrigSize
;
256 STATIC UINT16
*mFreq
, *mSortPtr
, mLenCnt
[17], mLeft
[2 * NC
- 1], mRight
[2 * NC
- 1],
257 mCrcTable
[UINT8_MAX
+ 1], mCFreq
[2 * NC
- 1],mCCode
[NC
],
258 mPFreq
[2 * NP
- 1], mPTCode
[NPT
], mTFreq
[2 * NT
- 1];
260 STATIC NODE mPos
, mMatchPos
, mAvail
, *mPosition
, *mParent
, *mPrev
, *mNext
= NULL
;
272 IN OUT UINT32
*DstSize
278 The main compression routine.
282 SrcBuffer - The buffer storing the source data
283 SrcSize - The size of source data
284 DstBuffer - The buffer to store the compressed data
285 DstSize - On input, the size of DstBuffer; On output,
286 the size of the actual compressed data.
290 EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case,
291 DstSize contains the size needed.
292 EFI_SUCCESS - Compression is successful.
296 EFI_STATUS Status
= EFI_SUCCESS
;
313 mSrcUpperLimit
= mSrc
+ SrcSize
;
315 mDstUpperLimit
= mDst
+ *DstSize
;
322 mOrigSize
= mCompSize
= 0;
330 if (EFI_ERROR (Status
)) {
331 return EFI_OUT_OF_RESOURCES
;
335 // Null terminate the compressed data
337 if (mDst
< mDstUpperLimit
) {
342 // Fill in compressed size and original size
345 PutDword(mCompSize
+1);
352 if (mCompSize
+ 1 + 8 > *DstSize
) {
353 *DstSize
= mCompSize
+ 1 + 8;
354 return EFI_BUFFER_TOO_SMALL
;
356 *DstSize
= mCompSize
+ 1 + 8;
371 Put a dword to output stream
375 Data - the dword to put
381 if (mDst
< mDstUpperLimit
) {
382 *mDst
++ = (UINT8
)(((UINT8
)(Data
)) & 0xff);
385 if (mDst
< mDstUpperLimit
) {
386 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x08)) & 0xff);
389 if (mDst
< mDstUpperLimit
) {
390 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x10)) & 0xff);
393 if (mDst
< mDstUpperLimit
) {
394 *mDst
++ = (UINT8
)(((UINT8
)(Data
>> 0x18)) & 0xff);
405 Allocate memory spaces for data structures used in compression process
411 EFI_SUCCESS - Memory is allocated successfully
412 EFI_OUT_OF_RESOURCES - Allocation fails
418 mText
= malloc (WNDSIZ
* 2 + MAXMATCH
);
419 for (i
= 0 ; i
< WNDSIZ
* 2 + MAXMATCH
; i
++) {
423 mLevel
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mLevel
));
424 mChildCount
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mChildCount
));
425 mPosition
= malloc ((WNDSIZ
+ UINT8_MAX
+ 1) * sizeof(*mPosition
));
426 mParent
= malloc (WNDSIZ
* 2 * sizeof(*mParent
));
427 mPrev
= malloc (WNDSIZ
* 2 * sizeof(*mPrev
));
428 mNext
= malloc ((MAX_HASH_VAL
+ 1) * sizeof(*mNext
));
430 mBufSiz
= 16 * 1024U;
431 while ((mBuf
= malloc(mBufSiz
)) == NULL
) {
432 mBufSiz
= (mBufSiz
/ 10U) * 9U;
433 if (mBufSiz
< 4 * 1024U) {
434 return EFI_OUT_OF_RESOURCES
;
448 Called when compression is completed to free memory previously allocated.
499 Initialize String Info Log data structures
509 for (i
= WNDSIZ
; i
<= WNDSIZ
+ UINT8_MAX
; i
++) {
511 mPosition
[i
] = NIL
; /* sentinel */
513 for (i
= WNDSIZ
; i
< WNDSIZ
* 2; i
++) {
517 for (i
= 1; i
< WNDSIZ
- 1; i
++) {
518 mNext
[i
] = (NODE
)(i
+ 1);
521 mNext
[WNDSIZ
- 1] = NIL
;
522 for (i
= WNDSIZ
* 2; i
<= MAX_HASH_VAL
; i
++) {
538 Find child node given the parent node and the edge character
543 c - the edge character
547 The child node (NIL if not found)
553 r
= mNext
[HASH(q
, c
)];
554 mParent
[NIL
] = q
; /* sentinel */
555 while (mParent
[r
] != q
) {
573 Create a new child for a given parent node.
578 c - the edge character
587 h
= (NODE
)HASH(q
, c
);
610 Old - the node to split
620 mChildCount
[New
] = 0;
627 mParent
[New
] = mParent
[Old
];
628 mLevel
[New
] = (UINT8
)mMatchLen
;
629 mPosition
[New
] = mPos
;
630 MakeChild(New
, mText
[mMatchPos
+ mMatchLen
], Old
);
631 MakeChild(New
, mText
[mPos
+ mMatchLen
], mPos
);
641 Insert string info for current position into the String Info Log
652 if (mMatchLen
>= 4) {
655 // We have just got a long match, the target tree
656 // can be located by MatchPos + 1. Travese the tree
657 // from bottom up to get to a proper starting point.
658 // The usage of PERC_FLAG ensures proper node deletion
659 // in DeleteNode() later.
663 r
= (INT16
)((mMatchPos
+ 1) | WNDSIZ
);
664 while ((q
= mParent
[r
]) == NIL
) {
667 while (mLevel
[q
] >= mMatchLen
) {
668 r
= q
; q
= mParent
[q
];
671 while (mPosition
[t
] < 0) {
676 mPosition
[t
] = (NODE
)(mPos
| PERC_FLAG
);
681 // Locate the target tree
684 q
= (INT16
)(mText
[mPos
] + WNDSIZ
);
686 if ((r
= Child(q
, c
)) == NIL
) {
687 MakeChild(q
, c
, mPos
);
695 // Traverse down the tree to find a match.
696 // Update Position value along the route.
697 // Node split or creation is involved.
706 mMatchPos
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
708 if (mMatchPos
>= mPos
) {
711 t1
= &mText
[mPos
+ mMatchLen
];
712 t2
= &mText
[mMatchPos
+ mMatchLen
];
713 while (mMatchLen
< j
) {
722 if (mMatchLen
>= MAXMATCH
) {
727 if ((r
= Child(q
, *t1
)) == NIL
) {
728 MakeChild(q
, *t1
, mPos
);
743 // Special usage of 'next'
756 Delete outdated string info. (The Usage of PERC_FLAG
757 ensures a clean deletion)
767 if (mParent
[mPos
] == NIL
) {
777 if (r
>= WNDSIZ
|| --mChildCount
[r
] > 1) {
780 t
= (NODE
)(mPosition
[r
] & ~PERC_FLAG
);
786 while ((u
= mPosition
[q
]) & PERC_FLAG
) {
794 mPosition
[q
] = (INT16
)(s
| WNDSIZ
);
804 mPosition
[q
] = (INT16
)(s
| WNDSIZ
| PERC_FLAG
);
806 s
= Child(r
, mText
[t
+ mLevel
[r
]]);
817 mParent
[s
] = mParent
[r
];
830 Advance the current position (read in new data if needed).
831 Delete outdated string info. Find a match string for current position.
842 if (++mPos
== WNDSIZ
* 2) {
843 memmove(&mText
[0], &mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
844 n
= FreadCrc(&mText
[WNDSIZ
+ MAXMATCH
], WNDSIZ
);
859 The main controlling routine for compression process.
865 EFI_SUCCESS - The compression is successful
866 EFI_OUT_0F_RESOURCES - Not enough memory for compression process
874 Status
= AllocateMemory();
875 if (EFI_ERROR(Status
)) {
884 mRemainder
= FreadCrc(&mText
[WNDSIZ
], WNDSIZ
+ MAXMATCH
);
889 if (mMatchLen
> mRemainder
) {
890 mMatchLen
= mRemainder
;
892 while (mRemainder
> 0) {
893 LastMatchLen
= mMatchLen
;
894 LastMatchPos
= mMatchPos
;
896 if (mMatchLen
> mRemainder
) {
897 mMatchLen
= mRemainder
;
900 if (mMatchLen
> LastMatchLen
|| LastMatchLen
< THRESHOLD
) {
903 // Not enough benefits are gained by outputting a pointer,
904 // so just output the original character
907 Output(mText
[mPos
- 1], 0);
911 // Outputting a pointer is beneficial enough, do it.
914 Output(LastMatchLen
+ (UINT8_MAX
+ 1 - THRESHOLD
),
915 (mPos
- LastMatchPos
- 2) & (WNDSIZ
- 1));
916 while (--LastMatchLen
> 0) {
919 if (mMatchLen
> mRemainder
) {
920 mMatchLen
= mRemainder
;
937 Count the frequencies for the Extra Set
945 INT32 i
, k
, n
, Count
;
947 for (i
= 0; i
< NT
; i
++) {
951 while (n
> 0 && mCLen
[n
- 1] == 0) {
959 while (i
< n
&& mCLen
[i
] == 0) {
964 mTFreq
[0] = (UINT16
)(mTFreq
[0] + Count
);
965 } else if (Count
<= 18) {
967 } else if (Count
== 19) {
990 Outputs the code length array for the Extra Set or the Position Set.
994 n - the number of symbols
995 nbit - the number of bits needed to represent 'n'
996 Special - the special symbol that needs to be take care of
1004 while (n
> 0 && mPTLen
[n
- 1] == 0) {
1014 PutBits(k
- 3, (1U << (k
- 3)) - 2);
1017 while (i
< 6 && mPTLen
[i
] == 0) {
1020 PutBits(2, (i
- 3) & 3);
1030 Routine Description:
1032 Outputs the code length array for Char&Length Set
1040 INT32 i
, k
, n
, Count
;
1043 while (n
> 0 && mCLen
[n
- 1] == 0) {
1052 while (i
< n
&& mCLen
[i
] == 0) {
1057 for (k
= 0; k
< Count
; k
++) {
1058 PutBits(mPTLen
[0], mPTCode
[0]);
1060 } else if (Count
<= 18) {
1061 PutBits(mPTLen
[1], mPTCode
[1]);
1062 PutBits(4, Count
- 3);
1063 } else if (Count
== 19) {
1064 PutBits(mPTLen
[0], mPTCode
[0]);
1065 PutBits(mPTLen
[1], mPTCode
[1]);
1068 PutBits(mPTLen
[2], mPTCode
[2]);
1069 PutBits(CBIT
, Count
- 20);
1072 PutBits(mPTLen
[k
+ 2], mPTCode
[k
+ 2]);
1083 PutBits(mCLen
[c
], mCCode
[c
]);
1100 PutBits(mPTLen
[c
], mPTCode
[c
]);
1102 PutBits(c
- 1, p
& (0xFFFFU
>> (17 - c
)));
1111 Routine Description:
1113 Huffman code the block and output it.
1121 UINT32 i
, k
, Flags
, Root
, Pos
, Size
;
1124 Root
= MakeTree(NC
, mCFreq
, mCLen
, mCCode
);
1125 Size
= mCFreq
[Root
];
1129 Root
= MakeTree(NT
, mTFreq
, mPTLen
, mPTCode
);
1131 WritePTLen(NT
, TBIT
, 3);
1134 PutBits(TBIT
, Root
);
1141 PutBits(CBIT
, Root
);
1143 Root
= MakeTree(NP
, mPFreq
, mPTLen
, mPTCode
);
1145 WritePTLen(NP
, PBIT
, -1);
1148 PutBits(PBIT
, Root
);
1151 for (i
= 0; i
< Size
; i
++) {
1152 if (i
% UINT8_BIT
== 0) {
1153 Flags
= mBuf
[Pos
++];
1157 if (Flags
& (1U << (UINT8_BIT
- 1))) {
1158 EncodeC(mBuf
[Pos
++] + (1U << UINT8_BIT
));
1159 k
= mBuf
[Pos
++] << UINT8_BIT
;
1163 EncodeC(mBuf
[Pos
++]);
1166 for (i
= 0; i
< NC
; i
++) {
1169 for (i
= 0; i
< NP
; i
++) {
1183 Routine Description:
1185 Outputs an Original Character or a Pointer
1189 c - The original character or the 'String Length' element of a Pointer
1190 p - The 'Position' field of a Pointer
1198 if ((mOutputMask
>>= 1) == 0) {
1199 mOutputMask
= 1U << (UINT8_BIT
- 1);
1200 if (mOutputPos
>= mBufSiz
- 3 * UINT8_BIT
) {
1204 CPos
= mOutputPos
++;
1207 mBuf
[mOutputPos
++] = (UINT8
) c
;
1209 if (c
>= (1U << UINT8_BIT
)) {
1210 mBuf
[CPos
] |= mOutputMask
;
1211 mBuf
[mOutputPos
++] = (UINT8
)(p
>> UINT8_BIT
);
1212 mBuf
[mOutputPos
++] = (UINT8
) p
;
1228 for (i
= 0; i
< NC
; i
++) {
1231 for (i
= 0; i
< NP
; i
++) {
1234 mOutputPos
= mOutputMask
= 0;
1246 // Flush remaining bits
1248 PutBits(UINT8_BIT
- 1, 0);
1260 for (i
= 0; i
<= UINT8_MAX
; i
++) {
1262 for (j
= 0; j
< UINT8_BIT
; j
++) {
1264 r
= (r
>> 1) ^ CRCPOLY
;
1269 mCrcTable
[i
] = (UINT16
)r
;
1281 Routine Description:
1283 Outputs rightmost n bits of x
1287 n - the rightmost n bits of the data is used
1296 if (n
< mBitCount
) {
1297 mSubBitBuf
|= x
<< (mBitCount
-= n
);
1300 Temp
= (UINT8
)(mSubBitBuf
| (x
>> (n
-= mBitCount
)));
1301 if (mDst
< mDstUpperLimit
) {
1306 if (n
< UINT8_BIT
) {
1307 mSubBitBuf
= x
<< (mBitCount
= UINT8_BIT
- n
);
1310 Temp
= (UINT8
)(x
>> (n
- UINT8_BIT
));
1311 if (mDst
< mDstUpperLimit
) {
1316 mSubBitBuf
= x
<< (mBitCount
= 2 * UINT8_BIT
- n
);
1329 Routine Description:
1335 p - the buffer to hold the data
1336 n - number of bytes to read
1340 number of bytes actually read
1346 for (i
= 0; mSrc
< mSrcUpperLimit
&& i
< n
; i
++) {
1364 mBitCount
= UINT8_BIT
;
1375 Routine Description:
1377 Count the number of each code length for a Huffman tree.
1387 STATIC INT32 Depth
= 0;
1390 mLenCnt
[(Depth
< 16) ? Depth
: 16]++;
1393 CountLen(mLeft
[i
]);
1394 CountLen(mRight
[i
]);
1406 Routine Description:
1408 Create code length array for a Huffman tree
1412 Root - the root of the tree
1419 for (i
= 0; i
<= 16; i
++) {
1425 // Adjust the length count array so that
1426 // no code will be generated longer than its designated length
1430 for (i
= 16; i
> 0; i
--) {
1431 Cum
+= mLenCnt
[i
] << (16 - i
);
1433 while (Cum
!= (1U << 16)) {
1435 for (i
= 15; i
> 0; i
--) {
1436 if (mLenCnt
[i
] != 0) {
1444 for (i
= 16; i
> 0; i
--) {
1447 mLen
[*mSortPtr
++] = (UINT8
)i
;
1461 // priority queue: send i-th entry down heap
1465 while ((j
= 2 * i
) <= mHeapSize
) {
1466 if (j
< mHeapSize
&& mFreq
[mHeap
[j
]] > mFreq
[mHeap
[j
+ 1]]) {
1469 if (mFreq
[k
] <= mFreq
[mHeap
[j
]]) {
1472 mHeap
[i
] = mHeap
[j
];
1475 mHeap
[i
] = (INT16
)k
;
1487 Routine Description:
1489 Assign code to each symbol based on the code length array
1493 n - number of symbols
1494 Len - the code length array
1495 Code - stores codes for each symbol
1505 for (i
= 1; i
<= 16; i
++) {
1506 Start
[i
+ 1] = (UINT16
)((Start
[i
] + mLenCnt
[i
]) << 1);
1508 for (i
= 0; i
< n
; i
++) {
1509 Code
[i
] = Start
[Len
[i
]]++;
1517 IN UINT16 FreqParm
[],
1518 OUT UINT8 LenParm
[],
1519 OUT UINT16 CodeParm
[]
1523 Routine Description:
1525 Generates Huffman codes given a frequency distribution of symbols
1529 NParm - number of symbols
1530 FreqParm - frequency of each symbol
1531 LenParm - code length for each symbol
1532 CodeParm - code for each symbol
1536 Root of the Huffman tree.
1540 INT32 i
, j
, k
, Avail
;
1543 // make tree, calculate len[], return root
1552 for (i
= 0; i
< mN
; i
++) {
1555 mHeap
[++mHeapSize
] = (INT16
)i
;
1558 if (mHeapSize
< 2) {
1559 CodeParm
[mHeap
[1]] = 0;
1562 for (i
= mHeapSize
/ 2; i
>= 1; i
--) {
1565 // make priority queue
1569 mSortPtr
= CodeParm
;
1573 *mSortPtr
++ = (UINT16
)i
;
1575 mHeap
[1] = mHeap
[mHeapSize
--];
1579 *mSortPtr
++ = (UINT16
)j
;
1582 mFreq
[k
] = (UINT16
)(mFreq
[i
] + mFreq
[j
]);
1583 mHeap
[1] = (INT16
)k
;
1585 mLeft
[k
] = (UINT16
)i
;
1586 mRight
[k
] = (UINT16
)j
;
1587 } while (mHeapSize
> 1);
1589 mSortPtr
= CodeParm
;
1591 MakeCode(NParm
, LenParm
, CodeParm
);