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 performs the appropriate decompression.
50                 Since decompression processing is linked for all types of compression, it may be better to execute a separate function for each compression type when only a specific compression format is used.
51 
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 :          Bit size of 1 data (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               .
296               .
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  Working buffer
464                         The required size is CX_UNCOMPRESS_LH_WORK_SIZE (18 KB)
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
806                 dstp
807                 work
808 
809   Returns:      None.
810  *---------------------------------------------------------------------------*/
811 void
CXUncompressLRC(const u8 * srcp,u8 * dstp,void * work)812 CXUncompressLRC( const u8* srcp, u8* dstp, void* work )
813 {
814 #define LENGTH_BITS  9
815 #define OFFSET_BITS  12
816     RCCompressionInfo infoVal;
817     RCCompressionInfo infoOfs;
818     RCState           rcState;
819     const u8*         pSrc = srcp;
820     u32               dstCnt  = 0;
821     u32               dstSize = 0;
822 
823     RCInitInfo_( &infoVal, LENGTH_BITS, work );
824     RCInitInfo_( &infoOfs, OFFSET_BITS, (u8*)work + (1 << LENGTH_BITS) * sizeof(u32) * 2 );
825     RCInitState_( &rcState );
826 
827     // load the header
828     dstSize = CXiConvertEndian_( *(u32*)pSrc ) >> 8;
829     pSrc += 4;
830     if ( dstSize == 0 )
831     {
832         dstSize = CXiConvertEndian_( *(u32*)pSrc );
833         pSrc += 4;
834     }
835 
836     // load the initial code
837     rcState.code = (u32)( (*pSrc       << 24) |
838                           (*(pSrc + 1) << 16) |
839                           (*(pSrc + 2) <<  8) |
840                           (*(pSrc + 3)      ) );
841     pSrc += 4;
842 
843     // continue to get values from the range coder and perform LZ decompression
844     while ( dstCnt < dstSize )
845     {
846         u32 cnt;
847         u16 val = (u16)( RCGetData_( pSrc, &infoVal, &rcState, &cnt ) );
848         pSrc += cnt;
849 
850         if ( val < 0x100 )
851         // uncompressed data
852         {
853             dstp[ dstCnt++ ] = (u8)val;
854         }
855         else
856         // compressed data
857         {
858             u16 length = (u16)( (val & 0xFF) + 3 );
859             val = (u16)( RCGetData_( pSrc, &infoOfs, &rcState, &cnt ) + 1 );
860             pSrc += cnt;
861 
862             // check for a buffer overrun
863             if ( dstCnt + length > dstSize )
864             {
865                 return;
866             }
867             if ( dstCnt < val )
868             {
869                 return;
870             }
871 
872             while ( length-- > 0 )
873             {
874                 dstp[ dstCnt ] = dstp[ dstCnt - val ];
875                 ++dstCnt;
876             }
877         }
878     }
879 #undef LENGTH_BITS
880 #undef OFFSET_BITS
881 }
882 
883 
884 
885 /*---------------------------------------------------------------------------*
886   Name:         CXUnfilterDiff
887 
888   Description:  8-bit decompression to restore differential filter conversion.
889 
890     - Decompresses a differential filter, writing in 8 bit units.
891     - Use 4 byte alignment for the source address.
892 
893   Arguments:    *srcp   Source address
894                 *destp  Destination address
895 
896   Returns:      None.
897  *---------------------------------------------------------------------------*/
CXUnfilterDiff(register const void * srcp,register void * destp)898 void CXUnfilterDiff( register const void *srcp, register void *destp )
899 {
900     const u8* pSrc = srcp;
901     u8*       pDst = destp;
902     u32 bitSize    = *pSrc & 0xFU;
903     s32 destCount  = (s32)( CXiConvertEndian_( *(u32*)pSrc ) >> 8 );
904     u32 sum = 0;
905 
906     pSrc += 4;
907 
908     if ( bitSize != 1 )
909     {
910         // Difference calculation in units of 8 bits
911         do
912         {
913             u8 tmp = *(pSrc++);
914             destCount--;
915             sum += tmp;
916             *(pDst++) = (u8)sum;
917         } while ( destCount > 0 );
918     }
919     else
920     {
921         // Difference calculation in units of 16 bits
922         do
923         {
924             u16 tmp = CXiConvertEndian16_( *(u16*)pSrc );
925             pSrc += 2;
926             destCount -= 2;
927             sum += tmp;
928             *(u16*)pDst = CXiConvertEndian16_( (u16)sum );
929             pDst += 2;
930         } while ( destCount > 0 );
931     }
932 }
933 
934 
935 /*---------------------------------------------------------------------------*
936   Name:         CXGetCompressionHeader
937 
938   Description:  Gets header information from the first four bytes in the compression data.
939 
940   Arguments:    data    First 8 bytes of compressed data
941  *---------------------------------------------------------------------------*/
CXGetCompressionHeader(const void * data)942 CXCompressionHeader CXGetCompressionHeader( const void* data )
943 {
944     CXCompressionHeader ret;
945 
946     ret.compType  = (u8)( (*(u8*)data & 0xF0) >> 4 );
947     ret.compParam = (u8)( *(u8*)data & 0x0F );
948 
949     ret.destSize  = CXiConvertEndian_( *(u32*)data ) >> 8;
950     if ( ret.destSize == 0 )
951     {
952         ret.destSize = CXiConvertEndian_( *((u32*)data + 1) );
953     }
954     return ret;
955 }
956 
957