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