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