1 /*---------------------------------------------------------------------------*
2 Project: Compress/uncompress library
3 File: CXUncompression.h
4 Programmer: Makoto Takano
5
6 Copyright 2005 Nintendo. All rights reserved.
7
8 These coded instructions, statements, and computer programs contain
9 proprietary information of Nintendo of America Inc. and/or Nintendo
10 Company Ltd., and are protected by Federal copyright law. They may
11 not be disclosed to third parties or copied or duplicated in any form,
12 in whole or in part, without the prior written consent of Nintendo.
13 *---------------------------------------------------------------------------*/
14
15 #include <dolphin/types.h>
16 #include <dolphin/os.h>
17 #include <revolution/cx/CXUncompression.h>
18 #include "CXUtil.h"
19
20
21 //======================================================================
22 // Expanding compressed data
23 //======================================================================
24
25 /*---------------------------------------------------------------------------*
26 Name: CXGetUncompressedSize
27
28 Description: Gets the data size after decompression.
29 This function can be used for data in all compression formats handled by CX.
30
31 Arguments: srcp : Starting address of the compressed data
32
33 Returns: Data size after decompression
34 *---------------------------------------------------------------------------*/
CXGetUncompressedSize(const void * srcp)35 u32 CXGetUncompressedSize( const void *srcp )
36 {
37 u32 size = CXiConvertEndian_( *(u32*)srcp ) >> 8;
38 if ( size == 0 )
39 {
40 size = CXiConvertEndian_( *((u32*)srcp + 1) );
41 }
42 return size;
43 }
44
45
46 /*---------------------------------------------------------------------------*
47 Name: CXUncompressAny
48
49 Description: Determines the compression type from the data header and executes the proper decompression process.
50
51 Decompression processes for all compression types are linked so it might be better to execute functions for each compression type if not using compression formats other than specified format.
52
53
54
55 Arguments: srcp Source address
56 destp Destination address
57
58 Returns: None.
59 *---------------------------------------------------------------------------*/
CXUncompressAny(const void * srcp,void * destp)60 void CXUncompressAny( const void* srcp, void* destp )
61 {
62 switch ( CXGetCompressionType( srcp ) )
63 {
64 // Run-length compressed data
65 case CX_COMPRESSION_RL:
66 CXUncompressRL( srcp, destp );
67 break;
68 // LZ77-compressed data
69 case CX_COMPRESSION_LZ:
70 CXUncompressLZ( srcp, destp );
71 break;
72 // Huffman-compressed data
73 case CX_COMPRESSION_HUFFMAN:
74 CXUncompressHuffman( srcp, destp );
75 break;
76 // Difference filter
77 case CX_COMPRESSION_DIFF:
78 CXUnfilterDiff( srcp, destp );
79 break;
80 default:
81 ASSERTMSG( 0, "Unknown compressed format" );
82 }
83 }
84
85
86 /*---------------------------------------------------------------------------*
87 Name: CXUncompressRL
88
89 Description: 8-bit decompression of run-length compressed data
90
91 - Decompresses run-length compressed data, writing in 8 bit units.
92 - Use 4 byte alignment for the source address.
93
94 - Data header
95 u32 :4 Reserved
96 compType:4 Compression type( = 3)
97 destSize:24 Data size after decompression
98
99 - Flag data format
100 u8 length:7 Decompressed data length - 1 (When not compressed)
101 Decompressed data length - 3 (only compress when the contiguous length is 3 bytes or greater)
102 flag:1 (0, 1) = (not compressed, compressed)
103
104 Arguments: *srcp Source address
105 *destp Destination address
106
107 Returns: None.
108 *---------------------------------------------------------------------------*/
CXUncompressRL(const void * srcp,void * destp)109 void CXUncompressRL( const void *srcp, void *destp )
110 {
111 const u8 *pSrc = srcp;
112 u8 *pDst = destp;
113 u32 destCount = CXiConvertEndian_( *(u32*)pSrc ) >> 8;
114 pSrc += 4;
115
116 if ( destCount == 0 )
117 {
118 destCount = CXiConvertEndian_( *(u32*)pSrc );
119 pSrc += 4;
120 }
121
122 while ( destCount > 0 )
123 {
124 u8 flags = *pSrc++;
125 u32 length = flags & 0x7fU;
126 if ( !(flags & 0x80) )
127 {
128 length++;
129 if ( length > destCount )
130 // Measures for buffer overrun when invalid data is decompressed.
131 {
132 length = destCount;
133 }
134
135 destCount -= length;
136 do
137 {
138 *pDst++ = *pSrc++;
139 } while ( --length > 0 );
140 }
141 else
142 {
143 u8 srcTmp;
144
145 length += 3;
146 if ( length > destCount )
147 // Measures for buffer overrun when invalid data is decompressed.
148 {
149 length = destCount;
150 }
151
152 destCount -= length;
153 srcTmp = *pSrc++;
154 do
155 {
156 *pDst++ = srcTmp;
157 } while ( --length > 0 );
158 }
159 }
160 }
161
162
163 /*---------------------------------------------------------------------------*
164 Name: CXUncompressLZ
165
166 Description: 8-bit decompression of LZ77 compressed data
167
168 * Expands LZ77-compressed data and writes it in 8-bit units.
169 - Use 4 byte alignment for the source address.
170
171 - Data header
172 u32 :4 Reserved
173 compType:4 Compression type( = 1)
174 destSize:24 Data size after decompression
175
176 - Flag data format
177 u8 flags Compression/no compression flag
178 (0, 1) = (not compressed, compressed)
179 - Code data format (Big Endian)
180 u16 length:4 Decompressed data length - 3 (only compress when the match length is 3 bytes or greater)
181 offset:12 Match data offset - 1
182
183 Arguments: *srcp Source address
184 *destp Destination address
185
186 Returns: None.
187 *---------------------------------------------------------------------------*/
CXUncompressLZ(const void * srcp,void * destp)188 void CXUncompressLZ( const void *srcp, void *destp )
189 {
190 const u8* pSrc = srcp;
191 u8* pDst = destp;
192 u32 destCount = CXiConvertEndian_( *(u32 *)pSrc ) >> 8;
193 BOOL exFormat = (*pSrc & 0x0F)? TRUE : FALSE;
194
195 pSrc += 4;
196
197 if ( destCount == 0 )
198 {
199 destCount = CXiConvertEndian_( *(u32*)pSrc );
200 pSrc += 4;
201 }
202
203 while ( destCount > 0 )
204 {
205 u32 i;
206 u32 flags = *pSrc++;
207 for ( i = 0; i < 8; ++i )
208 {
209 if ( !(flags & 0x80) )
210 {
211 *pDst++ = *pSrc++;
212 destCount--;
213 }
214 else
215 {
216 s32 length = (*pSrc >> 4);
217 s32 offset;
218
219 if ( ! exFormat )
220 {
221 length += 3;
222 }
223 else
224 {
225 // LZ77 extended format
226 if ( length == 1 )
227 {
228 length = (*pSrc++ & 0x0F) << 12;
229 length |= (*pSrc++) << 4;
230 length |= (*pSrc >> 4);
231 length += 0xFF + 0xF + 3;
232 }
233 else if ( length == 0 )
234 {
235 length = (*pSrc++ & 0x0F) << 4;
236 length |= (*pSrc >> 4);
237 length += 0xF + 2;
238 }
239 else
240 {
241 length += 1;
242 }
243 }
244 offset = (*pSrc++ & 0x0f) << 8;
245 offset = (offset | *pSrc++) + 1;
246 if ( length > destCount )
247 // Measures for buffer overrun when invalid data is decompressed.
248 {
249 length = (s32)destCount;
250 }
251 destCount -= length;
252 do
253 {
254 *pDst++ = pDst[ -offset ];
255 } while ( --length > 0 );
256 }
257 if ( destCount <= 0 )
258 {
259 break;
260 }
261 flags <<= 1;
262 }
263 }
264 }
265
266
267 /*---------------------------------------------------------------------------*
268 Name: CXUncompressHuffman
269
270 Description: Decompression of Huffman compressed data
271
272 - Decompresses Huffman compressed data, writing in 32 bit units.
273 - Use 4 byte alignment for the source address.
274 - Use 4-byte alignment for the destination address.
275 - The target decompression buffer size must be prepared in 4-byte multiples.
276
277 - Data header
278 u32 bitSize:4 1 data bit size (Normally 4|8)
279 compType:4 Compression type( = 2)
280 destSize:24 Data size after decompression
281
282 - Tree table
283 u8 treeSize Tree table size/2 - 1
284 TreeNodeData nodeRoot Root node
285
286 TreeNodeData nodeLeft Root left node
287 TreeNodeData nodeRight Root right node
288
289 TreeNodeData nodeLeftLeft Left left node
290 TreeNodeData nodeLeftRight Left right node
291
292 TreeNodeData nodeRightLeft Right left node
293 TreeNodeData nodeRightRight Right right node
294
295 �E
296 �E
297
298 The compressed data itself follows
299
300 - TreeNodeData structure
301 u8 nodeNextOffset:6 : Offset to the next node data - 1 (2 byte units)
302 rightEndFlag:1 Right node end flag
303 leftEndzflag:1 Left node end flag
304 When the end flag is set
305 There is data in next node
306
307 Arguments: *srcp Source address
308 *destp Destination address
309
310 Returns: None.
311 *---------------------------------------------------------------------------*/
CXUncompressHuffman(const void * srcp,void * destp)312 void CXUncompressHuffman( const void *srcp, void *destp )
313 {
314 #define TREE_END 0x80
315 const u32 *pSrc = srcp;
316 u32 *pDst = destp;
317 s32 destCount = (s32)( CXiConvertEndian_( *pSrc ) >> 8 );
318 u8 *treep = (destCount != 0)? ((u8*)pSrc + 4) : ((u8*)pSrc + 8);
319 u8 *treeStartp = treep + 1;
320 u32 dataBit = *(u8*)pSrc & 0x0FU;
321 u32 destTmp = 0;
322 u32 destTmpCount = 0;
323 u32 destTmpDataNum = 4 + ( dataBit & 0x7 );
324
325 if ( destCount == 0 )
326 {
327 destCount = (s32)( CXiConvertEndian_( *(pSrc + 1) ) );
328 }
329
330 pSrc = (u32*)( treep + ((*treep + 1) << 1) );
331 treep = treeStartp;
332
333 while ( destCount > 0 )
334 {
335 s32 srcCount = 32;
336 u32 srcTmp = CXiConvertEndian_( *pSrc++ ); // Endian strategy
337 while ( --srcCount >= 0 )
338 {
339 u32 treeShift = (srcTmp >> 31) & 0x1;
340 u32 treeCheck = *treep;
341 treeCheck <<= treeShift;
342 treep = (u8*)( (((u32)treep >> 1) << 1) + (((*treep & 0x3f) + 1) << 1) + treeShift );
343 if ( treeCheck & TREE_END )
344 {
345 destTmp >>= dataBit;
346 destTmp |= *treep << (32 - dataBit);
347 treep = treeStartp;
348 if ( ++destTmpCount == destTmpDataNum )
349 {
350 // Over-access until the last 4-byte alignment of the decompression buffer
351 *pDst++ = CXiConvertEndian_(destTmp); // Endian strategy
352 destCount -= 4;
353 destTmpCount = 0;
354 }
355 }
356 if ( destCount <= 0 )
357 {
358 break;
359 }
360 srcTmp <<= 1;
361 }
362 }
363 }
364
365
366 /*---------------------------------------------------------------------------*
367 Name: CXiHuffImportTree
368
369 Description: Expands the Huffman table.
370
371 Arguments: pTable
372 srcp
373 bitSize
374
375 Returns:
376 *---------------------------------------------------------------------------*/
377 static u32
CXiHuffImportTree(u16 * pTable,const u8 * srcp,u8 bitSize)378 CXiHuffImportTree( u16* pTable, const u8* srcp, u8 bitSize )
379 {
380 u32 tableSize;
381 u32 idx = 1;
382 u32 data = 0;
383 u32 bitNum = 0;
384 u32 bitMask = (1 << bitSize) - 1U;
385 u32 srcCnt = 0;
386 const u32 MAX_IDX = (u32)( (1 << bitSize) * 2 );
387
388 if ( bitSize > 8 )
389 {
390 tableSize = CXiConvertEndian16_( *(u16*)srcp );
391 srcp += 2;
392 srcCnt += 2;
393 }
394 else
395 {
396 tableSize = *srcp;
397 srcp += 1;
398 srcCnt += 1;
399 }
400 tableSize = (tableSize + 1) * 4;
401
402 while ( srcCnt < tableSize )
403 {
404 while ( bitNum < bitSize )
405 {
406 data <<= 8;
407 data |= *srcp++;
408 ++srcCnt;
409 bitNum += 8;
410 }
411
412 if ( idx < MAX_IDX )
413 {
414 pTable[ idx++ ] = (u16)( ( data >> (bitNum - bitSize) ) & bitMask );
415 }
416 bitNum -= bitSize;
417 }
418 return tableSize;
419 }
420
421 typedef struct
422 {
423 const u8* srcp;
424 u32 cnt;
425 u32 stream;
426 u32 stream_len;
427 }
428 BitReader;
429
430 static inline void
BitReader_Init(BitReader * context,const u8 * srcp)431 BitReader_Init( BitReader* context, const u8* srcp )
432 {
433 context->srcp = srcp;
434 context->cnt = 0;
435 context->stream = 0;
436 context->stream_len = 0;
437 }
438
439 static u8
BitReader_Read(BitReader * context)440 BitReader_Read( BitReader* context )
441 {
442 u8 bit;
443 if ( context->stream_len == 0 )
444 {
445 context->stream = context->srcp[context->cnt++];
446 context->stream_len = 8;
447 }
448 bit = (u8)( (context->stream >> (context->stream_len - 1)) & 0x1 );
449 context->stream_len--;
450 return bit;
451 }
452
453
454 #define ENC_OFFSET_WIDTH
455
456 /*---------------------------------------------------------------------------*
457 Name: CXUncompressLH
458
459 Description: Decompress LZ-Huffman (combined) compression.
460
461 Arguments: *srcp Source address
462 *destp Destination address
463 *work Work buffer
464 The required size is CX_UNCOMPRESS_LH_WORK_SIZE (2176B)
465
466 Returns: None.
467 *---------------------------------------------------------------------------*/
468 void
CXUncompressLH(const u8 * srcp,u8 * dstp,void * work)469 CXUncompressLH( const u8* srcp, u8* dstp, void* work )
470 {
471 #define LENGTH_BITS 9
472 #if defined(ENC_OFFSET_WIDTH)
473 #define OFFSET_BITS 5
474 #define OFFSET_MASK 0x07
475 #define LEAF_FLAG 0x10
476 u16 offset_bit;
477 #else
478 #define OFFSET_BITS 12
479 #define OFFSET_MASK 0x3FF
480 #define LEAF_FLAG 0x800
481 #endif
482 u32 dstSize;
483 u32 dstCnt = 0;
484 const u8 *pSrc = srcp;
485 BitReader stream;
486 u16* huffTable9;
487 u16* huffTable12;
488
489 huffTable9 = work;
490 huffTable12 = (u16*)work + (1 << LENGTH_BITS) * 2;
491
492 // load the header
493 dstSize = CXiConvertEndian_( *(u32*)pSrc ) >> 8;
494 pSrc += 4;
495 if ( dstSize == 0 )
496 {
497 dstSize = CXiConvertEndian_( *(u32*)pSrc );
498 pSrc += 4;
499 }
500
501 // read the Huffman table
502 pSrc += CXiHuffImportTree( huffTable9, pSrc, LENGTH_BITS );
503 pSrc += CXiHuffImportTree( huffTable12, pSrc, OFFSET_BITS );
504
505 BitReader_Init( &stream, pSrc );
506
507 while ( dstCnt < dstSize )
508 {
509 u16* nodep = huffTable9 + 1;
510 u16 val;
511 do
512 {
513 u8 bit = BitReader_Read( &stream );
514 u32 offset = (((*nodep & 0x7F) + 1U) << 1) + bit;
515
516 if ( *nodep & (0x100 >> bit) )
517 {
518 nodep = (u16*)((u32)nodep & ~0x3);
519 val = *(nodep + offset);
520 break;
521 }
522 else
523 {
524 nodep = (u16*)((u32)nodep & ~0x3);
525 nodep += offset;
526 }
527 } while ( 1 );
528
529 if ( val < 0x100 )
530 // uncompressed data
531 {
532 dstp[dstCnt++] = (u8)val;
533 }
534 else
535 // compressed data
536 {
537 u16 length = (u16)( (val & 0xFF) + 3 );
538 u16* nodep = huffTable12 + 1;
539 do
540 {
541 u8 bit = BitReader_Read( &stream );
542 u32 offset = (((*nodep & OFFSET_MASK) + 1U) << 1) + bit;
543
544 if ( *nodep & (LEAF_FLAG >> bit) )
545 {
546 nodep = (u16*)((u32)nodep & ~0x3);
547 val = *(nodep + offset);
548 break;
549 }
550 else
551 {
552 nodep = (u16*)((u32)nodep & ~0x3);
553 nodep += offset;
554 }
555 } while ( 1 );
556
557 #if defined(ENC_OFFSET_WIDTH)
558 offset_bit = val;
559 val = 0;
560 if ( offset_bit > 0 )
561 {
562 val = 1;
563 while ( --offset_bit > 0 )
564 {
565 val <<= 1;
566 val |= BitReader_Read( &stream );
567 }
568 }
569 #endif
570 val += 1;
571 // Measures for buffer overrun when invalid data is decompressed.
572 if ( dstCnt + length > dstSize )
573 {
574 length = (u16)( dstSize - dstCnt );
575 }
576
577 while ( length-- > 0 )
578 {
579 dstp[dstCnt] = dstp[dstCnt - val];
580 ++dstCnt;
581 }
582 }
583 }
584 #undef LENGTH_BITS
585 #undef OFFSET_BITS
586 #undef OFFSET_MASK
587 #undef LEAF_FLAG
588 }
589
590
591 // Structure for the range coder state
592 typedef struct
593 {
594 u32 low;
595 u32 range;
596 u32 code; // only used during decompression
597 u8 carry; // only used during compression
598 u32 carry_cnt; // only used during compression
599 }
600 RCState;
601
602 // Range coder structure
603 typedef struct
604 {
605 u32 *freq; // Table for occurrence frequency: (1 << bitSize) * sizeof(u32) bytes
606 u32 *low_cnt; // Table for the LOW border value: (1 << bitSize) * sizeof(u32) bytes
607 u32 total; // Total: 4 bytes
608 u8 bitSize; // Bit size: 1 byte
609 u8 padding_[1]; //
610 }
611 RCCompressionInfo;
612
613 #define RC_MAX_RANGE 0x80000000
614
615
616 /*---------------------------------------------------------------------------*
617 Name: RCInitState_
618
619 Description: Initializes the RC state.
620
621 Arguments: state: Pointer to an RC state structure
622
623 Returns: None.
624 *---------------------------------------------------------------------------*/
625 static inline void
RCInitState_(RCState * state)626 RCInitState_( RCState* state )
627 {
628 state->low = 0;
629 state->range = RC_MAX_RANGE;
630 state->code = 0;
631 state->carry = 0;
632 state->carry_cnt = 0;
633 }
634
635 /*---------------------------------------------------------------------------*
636 Name: RCInitInfo_
637
638 Description: Initialize the table for the adaptive range coder.
639 All occurrence frequencies are initialized to 1.
640
641 Arguments: info: Pointer to an RC table information structure
642
643 Returns: None.
644 *---------------------------------------------------------------------------*/
645 static inline void
RCInitInfo_(RCCompressionInfo * info,u8 bitSize,void * work)646 RCInitInfo_( RCCompressionInfo* info, u8 bitSize, void* work )
647 {
648 u32 tableSize = (u32)(1 << bitSize);
649 u32 i;
650
651 info->bitSize = bitSize;
652 info->freq = (u32*)work;
653 info->low_cnt = (u32*)( (u32)work + tableSize * sizeof(u32) );
654
655 for ( i = 0; i < tableSize; i++ )
656 {
657 info->freq[ i ] = 1;
658 info->low_cnt[ i ] = i;
659 }
660 info->total = tableSize;
661 }
662
663 /*---------------------------------------------------------------------------*
664 Name: RCAAddCount_
665
666 Description: Updates the frequency table for an adaptive range coder.
667
668 Arguments: info: Table information for a range coder
669 val: Value to add
670
671 Returns: None.
672 *---------------------------------------------------------------------------*/
673 static void
RCAddCount_(RCCompressionInfo * info,u16 val)674 RCAddCount_( RCCompressionInfo* info, u16 val )
675 {
676 u32 i;
677 u32 tableSize = (u32)(1 << info->bitSize);
678
679 info->freq[ val ]++;
680 info->total++;
681 for ( i = (u32)(val + 1); i < tableSize; i++ )
682 {
683 info->low_cnt[ i ]++;
684 }
685
686 // Reconstruct if the total exceeds the maximum value.
687 if ( info->total >= 0x00010000 )
688 {
689 if ( info->freq[ 0 ] > 1 )
690 {
691 info->freq[ 0 ] = info->freq[ 0 ] / 2;
692 }
693 info->low_cnt[ 0 ] = 0;
694 info->total = info->freq[ 0 ];
695
696 for ( i = 1; i < tableSize; i++ )
697 {
698 if ( info->freq[ i ] > 1 )
699 {
700 info->freq[ i ] >>= 1;
701 }
702 info->low_cnt[ i ] = info->low_cnt[ i - 1 ] + info->freq[ i - 1 ];
703 info->total += info->freq[ i ];
704 }
705 }
706 }
707
708
709 /*---------------------------------------------------------------------------*
710 Name: RCSearch_
711
712 Description: Searches for the value that must be obtained next from the code, range, and low values.
713
714 Arguments: info: Table information for a range coder
715 code: Current code value
716 range: Current Range value
717 low: Current Low value
718
719 Returns:
720 *---------------------------------------------------------------------------*/
721 static u16
RCSearch_(RCCompressionInfo * info,u32 code,u32 range,u32 low)722 RCSearch_( RCCompressionInfo* info, u32 code, u32 range, u32 low )
723 {
724 u32 tableSize = (u32)(1 << info->bitSize);
725 u32 codeVal = code - low;
726 u32 i;
727 u32 temp = range / info->total;
728 u32 tempVal = codeVal / temp;
729
730 // Binary search
731 u32 left = 0;
732 u32 right = tableSize - 1;
733
734 while ( left < right )
735 {
736 i = (left + right) / 2;
737
738 if ( info->low_cnt[ i ] > tempVal )
739 {
740 right = i;
741 }
742 else
743 {
744 left = i + 1;
745 }
746 }
747
748 i = left;
749 while ( info->low_cnt[ i ] > tempVal )
750 {
751 --i;
752 }
753 return (u16)i;
754 }
755
756
757 /*---------------------------------------------------------------------------*
758 Name: RCGetData_
759
760 Description: Gets the next value from the state in RCState, then updates the state.
761
762 Arguments: stream
763 info
764 state
765 adaptive
766
767 Returns:
768 *---------------------------------------------------------------------------*/
769 static u16
RCGetData_(const u8 * srcp,RCCompressionInfo * info,RCState * state,u32 * pSrcCnt)770 RCGetData_( const u8* srcp, RCCompressionInfo* info, RCState* state, u32* pSrcCnt )
771 {
772 #define MIN_RANGE 0x01000000
773 u16 val = RCSearch_( info, state->code, state->range, state->low );
774 u32 cnt = 0;
775
776 {
777 u32 tmp;
778 tmp = state->range / info->total;
779 state->low += info->low_cnt[ val ] * tmp;
780 state->range = info->freq[ val ] * tmp;
781 }
782
783 // Update the table for occurrence frequency
784 RCAddCount_( info, val );
785
786 while ( state->range < MIN_RANGE )
787 {
788 state->code <<= 8;
789 state->code += srcp[ cnt++ ];
790 state->range <<= 8;
791 state->low <<= 8;
792 }
793 *pSrcCnt = cnt;
794
795 return val;
796 #undef MIN_RANGE
797 }
798
799
800 /*---------------------------------------------------------------------------*
801 Name: CXUncompressLRC
802
803 Description: LZ/Range Coder combined compression
804
805 Arguments: *srcp Source address
806 *destp Destination address
807 *work Work buffer
808 The required size is CX_UNCOMPRESS_LRC_WORK_SIZE (36864B)
809
810 Returns: None.
811 *---------------------------------------------------------------------------*/
812 void
CXUncompressLRC(const u8 * srcp,u8 * dstp,void * work)813 CXUncompressLRC( const u8* srcp, u8* dstp, void* work )
814 {
815 #define LENGTH_BITS 9
816 #define OFFSET_BITS 12
817 RCCompressionInfo infoVal;
818 RCCompressionInfo infoOfs;
819 RCState rcState;
820 const u8* pSrc = srcp;
821 u32 dstCnt = 0;
822 u32 dstSize = 0;
823
824 RCInitInfo_( &infoVal, LENGTH_BITS, work );
825 RCInitInfo_( &infoOfs, OFFSET_BITS, (u8*)work + (1 << LENGTH_BITS) * sizeof(u32) * 2 );
826 RCInitState_( &rcState );
827
828 // Load the header
829 dstSize = CXiConvertEndian_( *(u32*)pSrc ) >> 8;
830 pSrc += 4;
831 if ( dstSize == 0 )
832 {
833 dstSize = CXiConvertEndian_( *(u32*)pSrc );
834 pSrc += 4;
835 }
836
837 // Load the initial code
838 rcState.code = (u32)( (*pSrc << 24) |
839 (*(pSrc + 1) << 16) |
840 (*(pSrc + 2) << 8) |
841 (*(pSrc + 3) ) );
842 pSrc += 4;
843
844 // Continue to get values from the range coder and perform LZ decompression
845 while ( dstCnt < dstSize )
846 {
847 u32 cnt;
848 u16 val = (u16)( RCGetData_( pSrc, &infoVal, &rcState, &cnt ) );
849 pSrc += cnt;
850
851 if ( val < 0x100 )
852 // Uncompressed data
853 {
854 dstp[ dstCnt++ ] = (u8)val;
855 }
856 else
857 // Compressed data
858 {
859 u16 length = (u16)( (val & 0xFF) + 3 );
860 val = (u16)( RCGetData_( pSrc, &infoOfs, &rcState, &cnt ) + 1 );
861 pSrc += cnt;
862
863 // Check for a buffer overrun
864 if ( dstCnt + length > dstSize )
865 {
866 return;
867 }
868 if ( dstCnt < val )
869 {
870 return;
871 }
872
873 while ( length-- > 0 )
874 {
875 dstp[ dstCnt ] = dstp[ dstCnt - val ];
876 ++dstCnt;
877 }
878 }
879 }
880 #undef LENGTH_BITS
881 #undef OFFSET_BITS
882 }
883
884
885
886 /*---------------------------------------------------------------------------*
887 Name: CXUnfilterDiff
888
889 Description: 8-bit decompression to restore differential filter conversion.
890
891 - Restores a differential filter, writing in 8 bit units.
892 - Use 4 byte alignment for the source address.
893
894 Arguments: *srcp Source address
895 *destp Destination address
896
897 Returns: None.
898 *---------------------------------------------------------------------------*/
CXUnfilterDiff(register const void * srcp,register void * destp)899 void CXUnfilterDiff( register const void *srcp, register void *destp )
900 {
901 const u8* pSrc = srcp;
902 u8* pDst = destp;
903 u32 bitSize = *pSrc & 0xFU;
904 s32 destCount = (s32)( CXiConvertEndian_( *(u32*)pSrc ) >> 8 );
905 u32 sum = 0;
906
907 pSrc += 4;
908
909 if ( bitSize != 1 )
910 {
911 // Difference calculation in units of 8 bits
912 do
913 {
914 u8 tmp = *(pSrc++);
915 destCount--;
916 sum += tmp;
917 *(pDst++) = (u8)sum;
918 } while ( destCount > 0 );
919 }
920 else
921 {
922 // Difference calculation in units of 16 bits
923 do
924 {
925 u16 tmp = CXiConvertEndian16_( *(u16*)pSrc );
926 pSrc += 2;
927 destCount -= 2;
928 sum += tmp;
929 *(u16*)pDst = CXiConvertEndian16_( (u16)sum );
930 pDst += 2;
931 } while ( destCount > 0 );
932 }
933 }
934
935
936 /*---------------------------------------------------------------------------*
937 Name: CXGetCompressionHeader
938
939 Description: Gets header information from the first four bytes in the compression data.
940
941 Arguments: data First 8 bytes of compressed data
942 *---------------------------------------------------------------------------*/
CXGetCompressionHeader(const void * data)943 CXCompressionHeader CXGetCompressionHeader( const void* data )
944 {
945 CXCompressionHeader ret;
946
947 ret.compType = (u8)( (*(u8*)data & 0xF0) >> 4 );
948 ret.compParam = (u8)( *(u8*)data & 0x0F );
949
950 ret.destSize = CXiConvertEndian_( *(u32*)data ) >> 8;
951 if ( ret.destSize == 0 )
952 {
953 ret.destSize = CXiConvertEndian_( *((u32*)data + 1) );
954 }
955 return ret;
956 }
957
958