]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/EfiCompress.c
License header updated to match correct format.
[mirror_edk2.git] / BaseTools / Source / C / Common / EfiCompress.c
CommitLineData
30fdf114 1/** @file\r
97fa0ee9
YL
2Compression routine. The compression algorithm is a mixture of LZ77 and Huffman \r
3coding. LZ77 transforms the source data into a sequence of Original Characters \r
4and Pointers to repeated strings. This sequence is further divided into Blocks \r
5and Huffman codings are applied to each Block.\r
6 \r
7Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>\r
40d841f6 8This program and the accompanying materials \r
30fdf114
LG
9are licensed and made available under the terms and conditions of the BSD License \r
10which accompanies this distribution. The full text of the license may be found at \r
11http://opensource.org/licenses/bsd-license.php \r
12 \r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
15\r
30fdf114
LG
16**/\r
17\r
18#include "Compress.h"\r
19\r
20\r
21//\r
22// Macro Definitions\r
23//\r
24\r
25#undef UINT8_MAX\r
26typedef INT16 NODE;\r
27#define UINT8_MAX 0xff\r
28#define UINT8_BIT 8\r
29#define THRESHOLD 3\r
30#define INIT_CRC 0\r
31#define WNDBIT 13\r
32#define WNDSIZ (1U << WNDBIT)\r
33#define MAXMATCH 256\r
34#define PERC_FLAG 0x8000U\r
35#define CODE_BIT 16\r
36#define NIL 0\r
37#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)\r
38#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)\r
39#define CRCPOLY 0xA001\r
40#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)\r
41\r
42//\r
43// C: the Char&Len Set; P: the Position Set; T: the exTra Set\r
44//\r
45\r
46#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)\r
47#define CBIT 9\r
48#define NP (WNDBIT + 1)\r
49#define PBIT 4\r
50#define NT (CODE_BIT + 3)\r
51#define TBIT 5\r
52#if NT > NP\r
53 #define NPT NT\r
54#else\r
55 #define NPT NP\r
56#endif\r
57\r
58//\r
59// Function Prototypes\r
60//\r
61\r
62STATIC\r
63VOID \r
64PutDword(\r
65 IN UINT32 Data\r
66 );\r
67\r
68STATIC\r
69EFI_STATUS \r
70AllocateMemory (\r
71 );\r
72\r
73STATIC\r
74VOID\r
75FreeMemory (\r
76 );\r
77\r
78STATIC \r
79VOID \r
80InitSlide (\r
81 );\r
82\r
83STATIC \r
84NODE \r
85Child (\r
86 IN NODE q, \r
87 IN UINT8 c\r
88 );\r
89\r
90STATIC \r
91VOID \r
92MakeChild (\r
93 IN NODE q, \r
94 IN UINT8 c, \r
95 IN NODE r\r
96 );\r
97 \r
98STATIC \r
99VOID \r
100Split (\r
101 IN NODE Old\r
102 );\r
103\r
104STATIC \r
105VOID \r
106InsertNode (\r
107 );\r
108 \r
109STATIC \r
110VOID \r
111DeleteNode (\r
112 );\r
113\r
114STATIC \r
115VOID \r
116GetNextMatch (\r
117 );\r
118 \r
119STATIC \r
120EFI_STATUS \r
121Encode (\r
122 );\r
123\r
124STATIC \r
125VOID \r
126CountTFreq (\r
127 );\r
128\r
129STATIC \r
130VOID \r
131WritePTLen (\r
132 IN INT32 n, \r
133 IN INT32 nbit, \r
134 IN INT32 Special\r
135 );\r
136\r
137STATIC \r
138VOID \r
139WriteCLen (\r
140 );\r
141 \r
142STATIC \r
143VOID \r
144EncodeC (\r
145 IN INT32 c\r
146 );\r
147\r
148STATIC \r
149VOID \r
150EncodeP (\r
151 IN UINT32 p\r
152 );\r
153\r
154STATIC \r
155VOID \r
156SendBlock (\r
157 );\r
158 \r
159STATIC \r
160VOID \r
161Output (\r
162 IN UINT32 c, \r
163 IN UINT32 p\r
164 );\r
165\r
166STATIC \r
167VOID \r
168HufEncodeStart (\r
169 );\r
170 \r
171STATIC \r
172VOID \r
173HufEncodeEnd (\r
174 );\r
175 \r
176STATIC \r
177VOID \r
178MakeCrcTable (\r
179 );\r
180 \r
181STATIC \r
182VOID \r
183PutBits (\r
184 IN INT32 n, \r
185 IN UINT32 x\r
186 );\r
187 \r
188STATIC \r
189INT32 \r
190FreadCrc (\r
191 OUT UINT8 *p, \r
192 IN INT32 n\r
193 );\r
194 \r
195STATIC \r
196VOID \r
197InitPutBits (\r
198 );\r
199 \r
200STATIC \r
201VOID \r
202CountLen (\r
203 IN INT32 i\r
204 );\r
205\r
206STATIC \r
207VOID \r
208MakeLen (\r
209 IN INT32 Root\r
210 );\r
211 \r
212STATIC \r
213VOID \r
214DownHeap (\r
215 IN INT32 i\r
216 );\r
217\r
218STATIC \r
219VOID \r
220MakeCode (\r
221 IN INT32 n, \r
222 IN UINT8 Len[], \r
223 OUT UINT16 Code[]\r
224 );\r
225 \r
226STATIC \r
227INT32 \r
228MakeTree (\r
229 IN INT32 NParm, \r
230 IN UINT16 FreqParm[], \r
231 OUT UINT8 LenParm[], \r
232 OUT UINT16 CodeParm[]\r
233 );\r
234\r
235\r
236//\r
237// Global Variables\r
238//\r
239\r
240STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit;\r
241\r
242STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen;\r
243STATIC INT16 mHeap[NC + 1];\r
244STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN;\r
245STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc;\r
246STATIC UINT32 mCompSize, mOrigSize;\r
247\r
248STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1],\r
249 mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1],mCCode[NC],\r
250 mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];\r
251\r
252STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;\r
253\r
254\r
255//\r
256// functions\r
257//\r
258\r
259EFI_STATUS\r
260EfiCompress (\r
261 IN UINT8 *SrcBuffer,\r
262 IN UINT32 SrcSize,\r
263 IN UINT8 *DstBuffer,\r
264 IN OUT UINT32 *DstSize\r
265 )\r
266/*++\r
267\r
268Routine Description:\r
269\r
270 The main compression routine.\r
271\r
272Arguments:\r
273\r
274 SrcBuffer - The buffer storing the source data\r
275 SrcSize - The size of source data\r
276 DstBuffer - The buffer to store the compressed data\r
277 DstSize - On input, the size of DstBuffer; On output,\r
278 the size of the actual compressed data.\r
279\r
280Returns:\r
281\r
282 EFI_BUFFER_TOO_SMALL - The DstBuffer is too small. In this case,\r
283 DstSize contains the size needed.\r
284 EFI_SUCCESS - Compression is successful.\r
285\r
286--*/\r
287{\r
288 EFI_STATUS Status = EFI_SUCCESS;\r
289 \r
290 //\r
291 // Initializations\r
292 //\r
293 mBufSiz = 0;\r
294 mBuf = NULL;\r
295 mText = NULL;\r
296 mLevel = NULL;\r
297 mChildCount = NULL;\r
298 mPosition = NULL;\r
299 mParent = NULL;\r
300 mPrev = NULL;\r
301 mNext = NULL;\r
302\r
303 \r
304 mSrc = SrcBuffer;\r
305 mSrcUpperLimit = mSrc + SrcSize;\r
306 mDst = DstBuffer;\r
307 mDstUpperLimit = mDst + *DstSize;\r
308\r
309 PutDword(0L);\r
310 PutDword(0L);\r
311 \r
312 MakeCrcTable ();\r
313\r
314 mOrigSize = mCompSize = 0;\r
315 mCrc = INIT_CRC;\r
316 \r
317 //\r
318 // Compress it\r
319 //\r
320 \r
321 Status = Encode();\r
322 if (EFI_ERROR (Status)) {\r
323 return EFI_OUT_OF_RESOURCES;\r
324 }\r
325 \r
326 //\r
327 // Null terminate the compressed data\r
328 //\r
329 if (mDst < mDstUpperLimit) {\r
330 *mDst++ = 0;\r
331 }\r
332 \r
333 //\r
334 // Fill in compressed size and original size\r
335 //\r
336 mDst = DstBuffer;\r
337 PutDword(mCompSize+1);\r
338 PutDword(mOrigSize);\r
339\r
340 //\r
341 // Return\r
342 //\r
343 \r
344 if (mCompSize + 1 + 8 > *DstSize) {\r
345 *DstSize = mCompSize + 1 + 8;\r
346 return EFI_BUFFER_TOO_SMALL;\r
347 } else {\r
348 *DstSize = mCompSize + 1 + 8;\r
349 return EFI_SUCCESS;\r
350 }\r
351\r
352}\r
353\r
354STATIC \r
355VOID \r
356PutDword(\r
357 IN UINT32 Data\r
358 )\r
359/*++\r
360\r
361Routine Description:\r
362\r
363 Put a dword to output stream\r
364 \r
365Arguments:\r
366\r
367 Data - the dword to put\r
368 \r
369Returns: (VOID)\r
370 \r
371--*/\r
372{\r
373 if (mDst < mDstUpperLimit) {\r
374 *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff);\r
375 }\r
376\r
377 if (mDst < mDstUpperLimit) {\r
378 *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff);\r
379 }\r
380\r
381 if (mDst < mDstUpperLimit) {\r
382 *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff);\r
383 }\r
384\r
385 if (mDst < mDstUpperLimit) {\r
386 *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff);\r
387 }\r
388}\r
389\r
390STATIC\r
391EFI_STATUS\r
392AllocateMemory ()\r
393/*++\r
394\r
395Routine Description:\r
396\r
397 Allocate memory spaces for data structures used in compression process\r
398 \r
399Argements: (VOID)\r
400\r
401Returns:\r
402\r
403 EFI_SUCCESS - Memory is allocated successfully\r
404 EFI_OUT_OF_RESOURCES - Allocation fails\r
405\r
406--*/\r
407{\r
408 UINT32 i;\r
409 \r
410 mText = malloc (WNDSIZ * 2 + MAXMATCH);\r
411 for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {\r
412 mText[i] = 0;\r
413 }\r
414\r
415 mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel));\r
416 mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount));\r
417 mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition));\r
418 mParent = malloc (WNDSIZ * 2 * sizeof(*mParent));\r
419 mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev));\r
420 mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext));\r
421 \r
422 mBufSiz = 16 * 1024U;\r
423 while ((mBuf = malloc(mBufSiz)) == NULL) {\r
424 mBufSiz = (mBufSiz / 10U) * 9U;\r
425 if (mBufSiz < 4 * 1024U) {\r
426 return EFI_OUT_OF_RESOURCES;\r
427 }\r
428 }\r
429 mBuf[0] = 0;\r
430 \r
431 return EFI_SUCCESS;\r
432}\r
433\r
434VOID\r
435FreeMemory ()\r
436/*++\r
437\r
438Routine Description:\r
439\r
440 Called when compression is completed to free memory previously allocated.\r
441 \r
442Arguments: (VOID)\r
443\r
444Returns: (VOID)\r
445\r
446--*/\r
447{\r
448 if (mText) {\r
449 free (mText);\r
450 }\r
451 \r
452 if (mLevel) {\r
453 free (mLevel);\r
454 }\r
455 \r
456 if (mChildCount) {\r
457 free (mChildCount);\r
458 }\r
459 \r
460 if (mPosition) {\r
461 free (mPosition);\r
462 }\r
463 \r
464 if (mParent) {\r
465 free (mParent);\r
466 }\r
467 \r
468 if (mPrev) {\r
469 free (mPrev);\r
470 }\r
471 \r
472 if (mNext) {\r
473 free (mNext);\r
474 }\r
475 \r
476 if (mBuf) {\r
477 free (mBuf);\r
478 } \r
479\r
480 return;\r
481}\r
482\r
483\r
484STATIC \r
485VOID \r
486InitSlide ()\r
487/*++\r
488\r
489Routine Description:\r
490\r
491 Initialize String Info Log data structures\r
492 \r
493Arguments: (VOID)\r
494\r
495Returns: (VOID)\r
496\r
497--*/\r
498{\r
499 NODE i;\r
500\r
501 for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) {\r
502 mLevel[i] = 1;\r
503 mPosition[i] = NIL; /* sentinel */\r
504 }\r
505 for (i = WNDSIZ; i < WNDSIZ * 2; i++) {\r
506 mParent[i] = NIL;\r
507 } \r
508 mAvail = 1;\r
509 for (i = 1; i < WNDSIZ - 1; i++) {\r
510 mNext[i] = (NODE)(i + 1);\r
511 }\r
512 \r
513 mNext[WNDSIZ - 1] = NIL;\r
514 for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) {\r
515 mNext[i] = NIL;\r
516 } \r
517}\r
518\r
519\r
520STATIC \r
521NODE \r
522Child (\r
523 IN NODE q, \r
524 IN UINT8 c\r
525 )\r
526/*++\r
527\r
528Routine Description:\r
529\r
530 Find child node given the parent node and the edge character\r
531 \r
532Arguments:\r
533\r
534 q - the parent node\r
535 c - the edge character\r
536 \r
537Returns:\r
538\r
539 The child node (NIL if not found) \r
540 \r
541--*/\r
542{\r
543 NODE r;\r
544 \r
545 r = mNext[HASH(q, c)];\r
546 mParent[NIL] = q; /* sentinel */\r
547 while (mParent[r] != q) {\r
548 r = mNext[r];\r
549 }\r
550 \r
551 return r;\r
552}\r
553\r
554STATIC \r
555VOID \r
556MakeChild (\r
557 IN NODE q, \r
558 IN UINT8 c, \r
559 IN NODE r\r
560 )\r
561/*++\r
562\r
563Routine Description:\r
564\r
565 Create a new child for a given parent node.\r
566 \r
567Arguments:\r
568\r
569 q - the parent node\r
570 c - the edge character\r
571 r - the child node\r
572 \r
573Returns: (VOID)\r
574\r
575--*/\r
576{\r
577 NODE h, t;\r
578 \r
579 h = (NODE)HASH(q, c);\r
580 t = mNext[h];\r
581 mNext[h] = r;\r
582 mNext[r] = t;\r
583 mPrev[t] = r;\r
584 mPrev[r] = h;\r
585 mParent[r] = q;\r
586 mChildCount[q]++;\r
587}\r
588\r
589STATIC \r
590VOID \r
591Split (\r
592 NODE Old\r
593 )\r
594/*++\r
595\r
596Routine Description:\r
597\r
598 Split a node.\r
599 \r
600Arguments:\r
601\r
602 Old - the node to split\r
603 \r
604Returns: (VOID)\r
605\r
606--*/\r
607{\r
608 NODE New, t;\r
609\r
610 New = mAvail;\r
611 mAvail = mNext[New];\r
612 mChildCount[New] = 0;\r
613 t = mPrev[Old];\r
614 mPrev[New] = t;\r
615 mNext[t] = New;\r
616 t = mNext[Old];\r
617 mNext[New] = t;\r
618 mPrev[t] = New;\r
619 mParent[New] = mParent[Old];\r
620 mLevel[New] = (UINT8)mMatchLen;\r
621 mPosition[New] = mPos;\r
622 MakeChild(New, mText[mMatchPos + mMatchLen], Old);\r
623 MakeChild(New, mText[mPos + mMatchLen], mPos);\r
624}\r
625\r
626STATIC \r
627VOID \r
628InsertNode ()\r
629/*++\r
630\r
631Routine Description:\r
632\r
633 Insert string info for current position into the String Info Log\r
634 \r
635Arguments: (VOID)\r
636\r
637Returns: (VOID)\r
638\r
639--*/\r
640{\r
641 NODE q, r, j, t;\r
642 UINT8 c, *t1, *t2;\r
643\r
644 if (mMatchLen >= 4) {\r
645 \r
646 //\r
647 // We have just got a long match, the target tree\r
648 // can be located by MatchPos + 1. Travese the tree\r
649 // from bottom up to get to a proper starting point.\r
650 // The usage of PERC_FLAG ensures proper node deletion\r
651 // in DeleteNode() later.\r
652 //\r
653 \r
654 mMatchLen--;\r
655 r = (INT16)((mMatchPos + 1) | WNDSIZ);\r
656 while ((q = mParent[r]) == NIL) {\r
657 r = mNext[r];\r
658 }\r
659 while (mLevel[q] >= mMatchLen) {\r
660 r = q; q = mParent[q];\r
661 }\r
662 t = q;\r
663 while (mPosition[t] < 0) {\r
664 mPosition[t] = mPos;\r
665 t = mParent[t];\r
666 }\r
667 if (t < WNDSIZ) {\r
668 mPosition[t] = (NODE)(mPos | PERC_FLAG);\r
669 } \r
670 } else {\r
671 \r
672 //\r
673 // Locate the target tree\r
674 //\r
675 \r
676 q = (INT16)(mText[mPos] + WNDSIZ);\r
677 c = mText[mPos + 1];\r
678 if ((r = Child(q, c)) == NIL) {\r
679 MakeChild(q, c, mPos);\r
680 mMatchLen = 1;\r
681 return;\r
682 }\r
683 mMatchLen = 2;\r
684 }\r
685 \r
686 //\r
687 // Traverse down the tree to find a match.\r
688 // Update Position value along the route.\r
689 // Node split or creation is involved.\r
690 //\r
691 \r
692 for ( ; ; ) {\r
693 if (r >= WNDSIZ) {\r
694 j = MAXMATCH;\r
695 mMatchPos = r;\r
696 } else {\r
697 j = mLevel[r];\r
698 mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG);\r
699 }\r
700 if (mMatchPos >= mPos) {\r
701 mMatchPos -= WNDSIZ;\r
702 } \r
703 t1 = &mText[mPos + mMatchLen];\r
704 t2 = &mText[mMatchPos + mMatchLen];\r
705 while (mMatchLen < j) {\r
706 if (*t1 != *t2) {\r
707 Split(r);\r
708 return;\r
709 }\r
710 mMatchLen++;\r
711 t1++;\r
712 t2++;\r
713 }\r
714 if (mMatchLen >= MAXMATCH) {\r
715 break;\r
716 }\r
717 mPosition[r] = mPos;\r
718 q = r;\r
719 if ((r = Child(q, *t1)) == NIL) {\r
720 MakeChild(q, *t1, mPos);\r
721 return;\r
722 }\r
723 mMatchLen++;\r
724 }\r
725 t = mPrev[r];\r
726 mPrev[mPos] = t;\r
727 mNext[t] = mPos;\r
728 t = mNext[r];\r
729 mNext[mPos] = t;\r
730 mPrev[t] = mPos;\r
731 mParent[mPos] = q;\r
732 mParent[r] = NIL;\r
733 \r
734 //\r
735 // Special usage of 'next'\r
736 //\r
737 mNext[r] = mPos;\r
738 \r
739}\r
740\r
741STATIC \r
742VOID \r
743DeleteNode ()\r
744/*++\r
745\r
746Routine Description:\r
747\r
748 Delete outdated string info. (The Usage of PERC_FLAG\r
749 ensures a clean deletion)\r
750 \r
751Arguments: (VOID)\r
752\r
753Returns: (VOID)\r
754\r
755--*/\r
756{\r
757 NODE q, r, s, t, u;\r
758\r
759 if (mParent[mPos] == NIL) {\r
760 return;\r
761 }\r
762 \r
763 r = mPrev[mPos];\r
764 s = mNext[mPos];\r
765 mNext[r] = s;\r
766 mPrev[s] = r;\r
767 r = mParent[mPos];\r
768 mParent[mPos] = NIL;\r
769 if (r >= WNDSIZ || --mChildCount[r] > 1) {\r
770 return;\r
771 }\r
772 t = (NODE)(mPosition[r] & ~PERC_FLAG);\r
773 if (t >= mPos) {\r
774 t -= WNDSIZ;\r
775 }\r
776 s = t;\r
777 q = mParent[r];\r
778 while ((u = mPosition[q]) & PERC_FLAG) {\r
779 u &= ~PERC_FLAG;\r
780 if (u >= mPos) {\r
781 u -= WNDSIZ;\r
782 }\r
783 if (u > s) {\r
784 s = u;\r
785 }\r
786 mPosition[q] = (INT16)(s | WNDSIZ);\r
787 q = mParent[q];\r
788 }\r
789 if (q < WNDSIZ) {\r
790 if (u >= mPos) {\r
791 u -= WNDSIZ;\r
792 }\r
793 if (u > s) {\r
794 s = u;\r
795 }\r
796 mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG);\r
797 }\r
798 s = Child(r, mText[t + mLevel[r]]);\r
799 t = mPrev[s];\r
800 u = mNext[s];\r
801 mNext[t] = u;\r
802 mPrev[u] = t;\r
803 t = mPrev[r];\r
804 mNext[t] = s;\r
805 mPrev[s] = t;\r
806 t = mNext[r];\r
807 mPrev[t] = s;\r
808 mNext[s] = t;\r
809 mParent[s] = mParent[r];\r
810 mParent[r] = NIL;\r
811 mNext[r] = mAvail;\r
812 mAvail = r;\r
813}\r
814\r
815STATIC \r
816VOID \r
817GetNextMatch ()\r
818/*++\r
819\r
820Routine Description:\r
821\r
822 Advance the current position (read in new data if needed).\r
823 Delete outdated string info. Find a match string for current position.\r
824\r
825Arguments: (VOID)\r
826\r
827Returns: (VOID)\r
828\r
829--*/\r
830{\r
831 INT32 n;\r
832\r
833 mRemainder--;\r
834 if (++mPos == WNDSIZ * 2) {\r
835 memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH);\r
836 n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ);\r
837 mRemainder += n;\r
838 mPos = WNDSIZ;\r
839 }\r
840 DeleteNode();\r
841 InsertNode();\r
842}\r
843\r
844STATIC\r
845EFI_STATUS\r
846Encode ()\r
847/*++\r
848\r
849Routine Description:\r
850\r
851 The main controlling routine for compression process.\r
852\r
853Arguments: (VOID)\r
854\r
855Returns:\r
856 \r
857 EFI_SUCCESS - The compression is successful\r
858 EFI_OUT_0F_RESOURCES - Not enough memory for compression process\r
859\r
860--*/\r
861{\r
862 EFI_STATUS Status;\r
863 INT32 LastMatchLen;\r
864 NODE LastMatchPos;\r
865\r
866 Status = AllocateMemory();\r
867 if (EFI_ERROR(Status)) {\r
868 FreeMemory();\r
869 return Status;\r
870 }\r
871\r
872 InitSlide();\r
873 \r
874 HufEncodeStart();\r
875\r
876 mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH);\r
877 \r
878 mMatchLen = 0;\r
879 mPos = WNDSIZ;\r
880 InsertNode();\r
881 if (mMatchLen > mRemainder) {\r
882 mMatchLen = mRemainder;\r
883 }\r
884 while (mRemainder > 0) {\r
885 LastMatchLen = mMatchLen;\r
886 LastMatchPos = mMatchPos;\r
887 GetNextMatch();\r
888 if (mMatchLen > mRemainder) {\r
889 mMatchLen = mRemainder;\r
890 }\r
891 \r
892 if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {\r
893 \r
894 //\r
895 // Not enough benefits are gained by outputting a pointer,\r
896 // so just output the original character\r
897 //\r
898 \r
899 Output(mText[mPos - 1], 0);\r
900 } else {\r
901 \r
902 //\r
903 // Outputting a pointer is beneficial enough, do it.\r
904 //\r
905 \r
906 Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),\r
907 (mPos - LastMatchPos - 2) & (WNDSIZ - 1));\r
908 while (--LastMatchLen > 0) {\r
909 GetNextMatch();\r
910 }\r
911 if (mMatchLen > mRemainder) {\r
912 mMatchLen = mRemainder;\r
913 }\r
914 }\r
915 }\r
916 \r
917 HufEncodeEnd();\r
918 FreeMemory();\r
919 return EFI_SUCCESS;\r
920}\r
921\r
922STATIC \r
923VOID \r
924CountTFreq ()\r
925/*++\r
926\r
927Routine Description:\r
928\r
929 Count the frequencies for the Extra Set\r
930 \r
931Arguments: (VOID)\r
932\r
933Returns: (VOID)\r
934\r
935--*/\r
936{\r
937 INT32 i, k, n, Count;\r
938\r
939 for (i = 0; i < NT; i++) {\r
940 mTFreq[i] = 0;\r
941 }\r
942 n = NC;\r
943 while (n > 0 && mCLen[n - 1] == 0) {\r
944 n--;\r
945 }\r
946 i = 0;\r
947 while (i < n) {\r
948 k = mCLen[i++];\r
949 if (k == 0) {\r
950 Count = 1;\r
951 while (i < n && mCLen[i] == 0) {\r
952 i++;\r
953 Count++;\r
954 }\r
955 if (Count <= 2) {\r
956 mTFreq[0] = (UINT16)(mTFreq[0] + Count);\r
957 } else if (Count <= 18) {\r
958 mTFreq[1]++;\r
959 } else if (Count == 19) {\r
960 mTFreq[0]++;\r
961 mTFreq[1]++;\r
962 } else {\r
963 mTFreq[2]++;\r
964 }\r
965 } else {\r
966 mTFreq[k + 2]++;\r
967 }\r
968 }\r
969}\r
970\r
971STATIC \r
972VOID \r
973WritePTLen (\r
974 IN INT32 n, \r
975 IN INT32 nbit, \r
976 IN INT32 Special\r
977 )\r
978/*++\r
979\r
980Routine Description:\r
981\r
982 Outputs the code length array for the Extra Set or the Position Set.\r
983 \r
984Arguments:\r
985\r
986 n - the number of symbols\r
987 nbit - the number of bits needed to represent 'n'\r
988 Special - the special symbol that needs to be take care of\r
989 \r
990Returns: (VOID)\r
991\r
992--*/\r
993{\r
994 INT32 i, k;\r
995\r
996 while (n > 0 && mPTLen[n - 1] == 0) {\r
997 n--;\r
998 }\r
999 PutBits(nbit, n);\r
1000 i = 0;\r
1001 while (i < n) {\r
1002 k = mPTLen[i++];\r
1003 if (k <= 6) {\r
1004 PutBits(3, k);\r
1005 } else {\r
1006 PutBits(k - 3, (1U << (k - 3)) - 2);\r
1007 }\r
1008 if (i == Special) {\r
1009 while (i < 6 && mPTLen[i] == 0) {\r
1010 i++;\r
1011 }\r
1012 PutBits(2, (i - 3) & 3);\r
1013 }\r
1014 }\r
1015}\r
1016\r
1017STATIC \r
1018VOID \r
1019WriteCLen ()\r
1020/*++\r
1021\r
1022Routine Description:\r
1023\r
1024 Outputs the code length array for Char&Length Set\r
1025 \r
1026Arguments: (VOID)\r
1027\r
1028Returns: (VOID)\r
1029\r
1030--*/\r
1031{\r
1032 INT32 i, k, n, Count;\r
1033\r
1034 n = NC;\r
1035 while (n > 0 && mCLen[n - 1] == 0) {\r
1036 n--;\r
1037 }\r
1038 PutBits(CBIT, n);\r
1039 i = 0;\r
1040 while (i < n) {\r
1041 k = mCLen[i++];\r
1042 if (k == 0) {\r
1043 Count = 1;\r
1044 while (i < n && mCLen[i] == 0) {\r
1045 i++;\r
1046 Count++;\r
1047 }\r
1048 if (Count <= 2) {\r
1049 for (k = 0; k < Count; k++) {\r
1050 PutBits(mPTLen[0], mPTCode[0]);\r
1051 }\r
1052 } else if (Count <= 18) {\r
1053 PutBits(mPTLen[1], mPTCode[1]);\r
1054 PutBits(4, Count - 3);\r
1055 } else if (Count == 19) {\r
1056 PutBits(mPTLen[0], mPTCode[0]);\r
1057 PutBits(mPTLen[1], mPTCode[1]);\r
1058 PutBits(4, 15);\r
1059 } else {\r
1060 PutBits(mPTLen[2], mPTCode[2]);\r
1061 PutBits(CBIT, Count - 20);\r
1062 }\r
1063 } else {\r
1064 PutBits(mPTLen[k + 2], mPTCode[k + 2]);\r
1065 }\r
1066 }\r
1067}\r
1068\r
1069STATIC \r
1070VOID \r
1071EncodeC (\r
1072 IN INT32 c\r
1073 )\r
1074{\r
1075 PutBits(mCLen[c], mCCode[c]);\r
1076}\r
1077\r
1078STATIC \r
1079VOID \r
1080EncodeP (\r
1081 IN UINT32 p\r
1082 )\r
1083{\r
1084 UINT32 c, q;\r
1085\r
1086 c = 0;\r
1087 q = p;\r
1088 while (q) {\r
1089 q >>= 1;\r
1090 c++;\r
1091 }\r
1092 PutBits(mPTLen[c], mPTCode[c]);\r
1093 if (c > 1) {\r
1094 PutBits(c - 1, p & (0xFFFFU >> (17 - c)));\r
1095 }\r
1096}\r
1097\r
1098STATIC \r
1099VOID \r
1100SendBlock ()\r
1101/*++\r
1102\r
1103Routine Description:\r
1104\r
1105 Huffman code the block and output it.\r
1106 \r
1107Argument: (VOID)\r
1108\r
1109Returns: (VOID)\r
1110\r
1111--*/\r
1112{\r
1113 UINT32 i, k, Flags, Root, Pos, Size;\r
1114 Flags = 0;\r
1115\r
1116 Root = MakeTree(NC, mCFreq, mCLen, mCCode);\r
1117 Size = mCFreq[Root];\r
1118 PutBits(16, Size);\r
1119 if (Root >= NC) {\r
1120 CountTFreq();\r
1121 Root = MakeTree(NT, mTFreq, mPTLen, mPTCode);\r
1122 if (Root >= NT) {\r
1123 WritePTLen(NT, TBIT, 3);\r
1124 } else {\r
1125 PutBits(TBIT, 0);\r
1126 PutBits(TBIT, Root);\r
1127 }\r
1128 WriteCLen();\r
1129 } else {\r
1130 PutBits(TBIT, 0);\r
1131 PutBits(TBIT, 0);\r
1132 PutBits(CBIT, 0);\r
1133 PutBits(CBIT, Root);\r
1134 }\r
1135 Root = MakeTree(NP, mPFreq, mPTLen, mPTCode);\r
1136 if (Root >= NP) {\r
1137 WritePTLen(NP, PBIT, -1);\r
1138 } else {\r
1139 PutBits(PBIT, 0);\r
1140 PutBits(PBIT, Root);\r
1141 }\r
1142 Pos = 0;\r
1143 for (i = 0; i < Size; i++) {\r
1144 if (i % UINT8_BIT == 0) {\r
1145 Flags = mBuf[Pos++];\r
1146 } else {\r
1147 Flags <<= 1;\r
1148 }\r
1149 if (Flags & (1U << (UINT8_BIT - 1))) {\r
1150 EncodeC(mBuf[Pos++] + (1U << UINT8_BIT));\r
1151 k = mBuf[Pos++] << UINT8_BIT;\r
1152 k += mBuf[Pos++];\r
1153 EncodeP(k);\r
1154 } else {\r
1155 EncodeC(mBuf[Pos++]);\r
1156 }\r
1157 }\r
1158 for (i = 0; i < NC; i++) {\r
1159 mCFreq[i] = 0;\r
1160 }\r
1161 for (i = 0; i < NP; i++) {\r
1162 mPFreq[i] = 0;\r
1163 }\r
1164}\r
1165\r
1166\r
1167STATIC \r
1168VOID \r
1169Output (\r
1170 IN UINT32 c, \r
1171 IN UINT32 p\r
1172 )\r
1173/*++\r
1174\r
1175Routine Description:\r
1176\r
1177 Outputs an Original Character or a Pointer\r
1178\r
1179Arguments:\r
1180\r
1181 c - The original character or the 'String Length' element of a Pointer\r
1182 p - The 'Position' field of a Pointer\r
1183\r
1184Returns: (VOID)\r
1185\r
1186--*/\r
1187{\r
1188 STATIC UINT32 CPos;\r
1189\r
1190 if ((mOutputMask >>= 1) == 0) {\r
1191 mOutputMask = 1U << (UINT8_BIT - 1);\r
1192 if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) {\r
1193 SendBlock();\r
1194 mOutputPos = 0;\r
1195 }\r
1196 CPos = mOutputPos++; \r
1197 mBuf[CPos] = 0;\r
1198 }\r
1199 mBuf[mOutputPos++] = (UINT8) c;\r
1200 mCFreq[c]++;\r
1201 if (c >= (1U << UINT8_BIT)) {\r
1202 mBuf[CPos] |= mOutputMask;\r
1203 mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT);\r
1204 mBuf[mOutputPos++] = (UINT8) p;\r
1205 c = 0;\r
1206 while (p) {\r
1207 p >>= 1;\r
1208 c++;\r
1209 }\r
1210 mPFreq[c]++;\r
1211 }\r
1212}\r
1213\r
1214STATIC\r
1215VOID\r
1216HufEncodeStart ()\r
1217{\r
1218 INT32 i;\r
1219\r
1220 for (i = 0; i < NC; i++) {\r
1221 mCFreq[i] = 0;\r
1222 }\r
1223 for (i = 0; i < NP; i++) {\r
1224 mPFreq[i] = 0;\r
1225 }\r
1226 mOutputPos = mOutputMask = 0;\r
1227 InitPutBits();\r
1228 return;\r
1229}\r
1230\r
1231STATIC \r
1232VOID \r
1233HufEncodeEnd ()\r
1234{\r
1235 SendBlock();\r
1236 \r
1237 //\r
1238 // Flush remaining bits\r
1239 //\r
1240 PutBits(UINT8_BIT - 1, 0);\r
1241 \r
1242 return;\r
1243}\r
1244\r
1245\r
1246STATIC \r
1247VOID \r
1248MakeCrcTable ()\r
1249{\r
1250 UINT32 i, j, r;\r
1251\r
1252 for (i = 0; i <= UINT8_MAX; i++) {\r
1253 r = i;\r
1254 for (j = 0; j < UINT8_BIT; j++) {\r
1255 if (r & 1) {\r
1256 r = (r >> 1) ^ CRCPOLY;\r
1257 } else {\r
1258 r >>= 1;\r
1259 }\r
1260 }\r
1261 mCrcTable[i] = (UINT16)r; \r
1262 }\r
1263}\r
1264\r
1265STATIC \r
1266VOID \r
1267PutBits (\r
1268 IN INT32 n, \r
1269 IN UINT32 x\r
1270 )\r
1271/*++\r
1272\r
1273Routine Description:\r
1274\r
1275 Outputs rightmost n bits of x\r
1276\r
1277Argments:\r
1278\r
1279 n - the rightmost n bits of the data is used\r
1280 x - the data \r
1281\r
1282Returns: (VOID)\r
1283\r
1284--*/\r
1285{\r
1286 UINT8 Temp; \r
1287 \r
1288 if (n < mBitCount) {\r
1289 mSubBitBuf |= x << (mBitCount -= n);\r
1290 } else {\r
1291 \r
1292 Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount)));\r
1293 if (mDst < mDstUpperLimit) {\r
1294 *mDst++ = Temp;\r
1295 }\r
1296 mCompSize++;\r
1297\r
1298 if (n < UINT8_BIT) {\r
1299 mSubBitBuf = x << (mBitCount = UINT8_BIT - n);\r
1300 } else {\r
1301 \r
1302 Temp = (UINT8)(x >> (n - UINT8_BIT));\r
1303 if (mDst < mDstUpperLimit) {\r
1304 *mDst++ = Temp;\r
1305 }\r
1306 mCompSize++;\r
1307 \r
1308 mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n);\r
1309 }\r
1310 }\r
1311}\r
1312\r
1313STATIC \r
1314INT32 \r
1315FreadCrc (\r
1316 OUT UINT8 *p, \r
1317 IN INT32 n\r
1318 )\r
1319/*++\r
1320\r
1321Routine Description:\r
1322\r
1323 Read in source data\r
1324 \r
1325Arguments:\r
1326\r
1327 p - the buffer to hold the data\r
1328 n - number of bytes to read\r
1329\r
1330Returns:\r
1331\r
1332 number of bytes actually read\r
1333 \r
1334--*/\r
1335{\r
1336 INT32 i;\r
1337\r
1338 for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) {\r
1339 *p++ = *mSrc++;\r
1340 }\r
1341 n = i;\r
1342\r
1343 p -= n;\r
1344 mOrigSize += n;\r
1345 while (--i >= 0) {\r
1346 UPDATE_CRC(*p++);\r
1347 }\r
1348 return n;\r
1349}\r
1350\r
1351\r
1352STATIC \r
1353VOID \r
1354InitPutBits ()\r
1355{\r
1356 mBitCount = UINT8_BIT; \r
1357 mSubBitBuf = 0;\r
1358}\r
1359\r
1360STATIC \r
1361VOID \r
1362CountLen (\r
1363 IN INT32 i\r
1364 )\r
1365/*++\r
1366\r
1367Routine Description:\r
1368\r
1369 Count the number of each code length for a Huffman tree.\r
1370 \r
1371Arguments:\r
1372\r
1373 i - the top node\r
1374 \r
1375Returns: (VOID)\r
1376\r
1377--*/\r
1378{\r
1379 STATIC INT32 Depth = 0;\r
1380\r
1381 if (i < mN) {\r
1382 mLenCnt[(Depth < 16) ? Depth : 16]++;\r
1383 } else {\r
1384 Depth++;\r
1385 CountLen(mLeft [i]);\r
1386 CountLen(mRight[i]);\r
1387 Depth--;\r
1388 }\r
1389}\r
1390\r
1391STATIC \r
1392VOID \r
1393MakeLen (\r
1394 IN INT32 Root\r
1395 )\r
1396/*++\r
1397\r
1398Routine Description:\r
1399\r
1400 Create code length array for a Huffman tree\r
1401 \r
1402Arguments:\r
1403\r
1404 Root - the root of the tree\r
1405\r
1406--*/\r
1407{\r
1408 INT32 i, k;\r
1409 UINT32 Cum;\r
1410\r
1411 for (i = 0; i <= 16; i++) {\r
1412 mLenCnt[i] = 0;\r
1413 }\r
1414 CountLen(Root);\r
1415 \r
1416 //\r
1417 // Adjust the length count array so that\r
1418 // no code will be generated longer than its designated length\r
1419 //\r
1420 \r
1421 Cum = 0;\r
1422 for (i = 16; i > 0; i--) {\r
1423 Cum += mLenCnt[i] << (16 - i);\r
1424 }\r
1425 while (Cum != (1U << 16)) {\r
1426 mLenCnt[16]--;\r
1427 for (i = 15; i > 0; i--) {\r
1428 if (mLenCnt[i] != 0) {\r
1429 mLenCnt[i]--;\r
1430 mLenCnt[i+1] += 2;\r
1431 break;\r
1432 }\r
1433 }\r
1434 Cum--;\r
1435 }\r
1436 for (i = 16; i > 0; i--) {\r
1437 k = mLenCnt[i];\r
1438 while (--k >= 0) {\r
1439 mLen[*mSortPtr++] = (UINT8)i;\r
1440 }\r
1441 }\r
1442}\r
1443\r
1444STATIC \r
1445VOID \r
1446DownHeap (\r
1447 IN INT32 i\r
1448 )\r
1449{\r
1450 INT32 j, k;\r
1451\r
1452 //\r
1453 // priority queue: send i-th entry down heap\r
1454 //\r
1455 \r
1456 k = mHeap[i];\r
1457 while ((j = 2 * i) <= mHeapSize) {\r
1458 if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) {\r
1459 j++;\r
1460 }\r
1461 if (mFreq[k] <= mFreq[mHeap[j]]) {\r
1462 break;\r
1463 }\r
1464 mHeap[i] = mHeap[j];\r
1465 i = j;\r
1466 }\r
1467 mHeap[i] = (INT16)k;\r
1468}\r
1469\r
1470STATIC \r
1471VOID \r
1472MakeCode (\r
1473 IN INT32 n, \r
1474 IN UINT8 Len[], \r
1475 OUT UINT16 Code[]\r
1476 )\r
1477/*++\r
1478\r
1479Routine Description:\r
1480\r
1481 Assign code to each symbol based on the code length array\r
1482 \r
1483Arguments:\r
1484\r
1485 n - number of symbols\r
1486 Len - the code length array\r
1487 Code - stores codes for each symbol\r
1488\r
1489Returns: (VOID)\r
1490\r
1491--*/\r
1492{\r
1493 INT32 i;\r
1494 UINT16 Start[18];\r
1495\r
1496 Start[1] = 0;\r
1497 for (i = 1; i <= 16; i++) {\r
1498 Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1);\r
1499 }\r
1500 for (i = 0; i < n; i++) {\r
1501 Code[i] = Start[Len[i]]++;\r
1502 }\r
1503}\r
1504\r
1505STATIC \r
1506INT32 \r
1507MakeTree (\r
1508 IN INT32 NParm, \r
1509 IN UINT16 FreqParm[], \r
1510 OUT UINT8 LenParm[], \r
1511 OUT UINT16 CodeParm[]\r
1512 )\r
1513/*++\r
1514\r
1515Routine Description:\r
1516\r
1517 Generates Huffman codes given a frequency distribution of symbols\r
1518 \r
1519Arguments:\r
1520\r
1521 NParm - number of symbols\r
1522 FreqParm - frequency of each symbol\r
1523 LenParm - code length for each symbol\r
1524 CodeParm - code for each symbol\r
1525 \r
1526Returns:\r
1527\r
1528 Root of the Huffman tree.\r
1529 \r
1530--*/\r
1531{\r
1532 INT32 i, j, k, Avail;\r
1533 \r
1534 //\r
1535 // make tree, calculate len[], return root\r
1536 //\r
1537\r
1538 mN = NParm;\r
1539 mFreq = FreqParm;\r
1540 mLen = LenParm;\r
1541 Avail = mN;\r
1542 mHeapSize = 0;\r
1543 mHeap[1] = 0;\r
1544 for (i = 0; i < mN; i++) {\r
1545 mLen[i] = 0;\r
1546 if (mFreq[i]) {\r
1547 mHeap[++mHeapSize] = (INT16)i;\r
1548 } \r
1549 }\r
1550 if (mHeapSize < 2) {\r
1551 CodeParm[mHeap[1]] = 0;\r
1552 return mHeap[1];\r
1553 }\r
1554 for (i = mHeapSize / 2; i >= 1; i--) {\r
1555 \r
1556 //\r
1557 // make priority queue \r
1558 //\r
1559 DownHeap(i);\r
1560 }\r
1561 mSortPtr = CodeParm;\r
1562 do {\r
1563 i = mHeap[1];\r
1564 if (i < mN) {\r
1565 *mSortPtr++ = (UINT16)i;\r
1566 }\r
1567 mHeap[1] = mHeap[mHeapSize--];\r
1568 DownHeap(1);\r
1569 j = mHeap[1];\r
1570 if (j < mN) {\r
1571 *mSortPtr++ = (UINT16)j;\r
1572 }\r
1573 k = Avail++;\r
1574 mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]);\r
1575 mHeap[1] = (INT16)k;\r
1576 DownHeap(1);\r
1577 mLeft[k] = (UINT16)i;\r
1578 mRight[k] = (UINT16)j;\r
1579 } while (mHeapSize > 1);\r
1580 \r
1581 mSortPtr = CodeParm;\r
1582 MakeLen(k);\r
1583 MakeCode(NParm, LenParm, CodeParm);\r
1584 \r
1585 //\r
1586 // return root\r
1587 //\r
1588 return k;\r
1589}\r
1590\r