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