1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: cx_StreamingUncompression.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 47712 $
14 *---------------------------------------------------------------------------*/
15
16 #include <nn/cx/cx_Uncompression.h>
17 #include <nn/cx/cx_StreamingUncompression.h>
18 #include <nn/cx/cx_SecureUncompression.h>
19 #include <nn/math.h>
20 #include "cx_Utility.h"
21 #include <zlib.h>
22 #include <new>
23
24 namespace nn {
25 namespace cx {
26
27 namespace
28 {
29 struct UncompressContextDeflate_
30 {
31 static const size_t WORK_SIZE = UNCOMPRESS_GZIP_WORK_SIZE + (1 << MAX_WBITS);
32
33 s32 headerSize;
34 size_t rawSize;
35 detail::ZlibAllocator za;
36 z_stream s;
37 bit8 workBuffer[WORK_SIZE];
38 };
39
GetUncompressContextDeflate_(UncompContextDeflate * p)40 UncompressContextDeflate_* GetUncompressContextDeflate_(UncompContextDeflate* p)
41 {
42 NN_STATIC_ASSERT( sizeof(UncompressContextDeflate_)
43 == sizeof(UncompContextDeflate) );
44 return reinterpret_cast<UncompressContextDeflate_*>(p);
45 }
46 }
47
48
49
50 /*---------------------------------------------------------------------------*
51 Name: InitUncompContextRL
52
53 Description: Initializes the streaming decompression context for run-length compressed data.
54
55
56 Arguments: context Pointer to the run-length uncompressed context
57 dest Destination address for uncompressed data
58
59 Returns: Can get the data size after decompression.
60
61 *---------------------------------------------------------------------------*/
InitUncompContextRL(UncompContextRL * context,void * dest)62 void InitUncompContextRL( UncompContextRL *context, void* dest )
63 {
64 NN_NULL_TASSERT_(context);
65 context->destp = (u8*)dest;
66 context->destCount = 0;
67 context->flags = 0;
68 context->length = 0;
69 context->headerSize = 8;
70 context->forceDestCount = 0;
71 }
72
73
74 /*---------------------------------------------------------------------------*
75 Name: InitUncompContextLZ
76
77 Description: Initializes the streaming decompression context for LZ-compressed data.
78
79 Arguments: context Pointer to the LZ uncompressed context
80 dest Destination address for uncompressed data
81 header Pointer to the start data for the compressed data
82
83 *---------------------------------------------------------------------------*/
InitUncompContextLZ(UncompContextLZ * context,void * dest)84 void InitUncompContextLZ( UncompContextLZ *context, void* dest )
85 {
86 NN_NULL_TASSERT_(context);
87 context->destp = (u8*)dest;
88 context->destCount = 0;
89 context->flags = 0;
90 context->flagIndex = 0;
91 context->length = 0;
92 context->lengthFlg = 3;
93 context->headerSize = 8;
94 context->exFormat = 0;
95 context->forceDestCount = 0;
96 }
97
98
99 /*---------------------------------------------------------------------------*
100 Name: InitUncompContextHuffman
101
102 Description: Initializes the streaming decompression context for Huffman-compressed data.
103
104 Arguments: context Pointer to the Huffman uncompressed context
105 dest Destination address for uncompressed data
106 header Pointer to the start data for the compressed data
107
108 *---------------------------------------------------------------------------*/
InitUncompContextHuffman(UncompContextHuffman * context,void * dest)109 void InitUncompContextHuffman( UncompContextHuffman *context, void* dest )
110 {
111 NN_NULL_TASSERT_(context);
112 context->destp = (u8*)dest;
113 context->destCount = 0;
114 context->bitSize = 0;
115 context->treeSize = -1;
116 context->treep = &context->tree[ 0 ];
117 context->destTmp = 0;
118 context->destTmpCnt = 0;
119 context->srcTmp = 0;
120 context->srcTmpCnt = 0;
121 context->headerSize = 8;
122 context->forceDestCount = 0;
123 }
124
125 namespace {
126
127 /*---------------------------------------------------------------------------*
128 Name: ReadHeader
129
130 Description: Header parsing
131
132 Arguments: headerSize Pointer to the remaining size of the header to be read
133 *destCount Pointer to the uncompressed data size
134 srcp Pointer to a buffer containing the header information
135 srcSize Pointer to the size of the buffer containing the header information
136 forceDestSize Uncompressed data size (if 0, use the binary header information as is)
137
138 Returns: Size of the loaded source data
139 *---------------------------------------------------------------------------*/
ReadHeader(u8 * headerSize,s32 * destCount,const u8 * srcp,u32 srcSize,s32 forceDestSize)140 inline u32 ReadHeader( u8* headerSize, s32 *destCount, const u8* srcp, u32 srcSize, s32 forceDestSize )
141 {
142 NN_NULL_TASSERT_(headerSize);
143 NN_NULL_TASSERT_(destCount);
144
145 u32 readLen = 0;
146 while ( *headerSize > 0 )
147 {
148 --(*headerSize);
149 if ( *headerSize <= 3 )
150 {
151 *destCount |= (*srcp << ((3 - *headerSize) * 8));
152 }
153 else if ( *headerSize <= 6 )
154 {
155 *destCount |= (*srcp << ((6 - *headerSize) * 8));
156 }
157 ++srcp;
158 ++readLen;
159 if ( *headerSize == 4 && *destCount > 0 )
160 {
161 *headerSize = 0;
162 }
163 if ( --srcSize == 0 && *headerSize > 0 )
164 {
165 return readLen;
166 }
167 }
168
169 if ( ( forceDestSize > 0 ) &&
170 ( forceDestSize < *destCount ) )
171 {
172 *destCount = forceDestSize;
173 }
174 return readLen;
175 }
176
177 } // Namespace
178
179 /*---------------------------------------------------------------------------*
180 Name: ReadUncompRL
181
182 Description: This function performs streaming decompression of run-length compressed data.
183 Data is written in units of 8 bits. Data cannot be directly uncompressed to VRAM.
184
185 Arguments: context Pointer to the run-length uncompressed context
186 data Pointer to the next data
187 len Data size
188
189 Returns: Size of remaining uncompressed data.
190 Returns a negative error code if failed.
191
192 *---------------------------------------------------------------------------*/
ReadUncompRL(UncompContextRL * context,const void * data,u32 len)193 s32 ReadUncompRL( UncompContextRL *context, const void* data, u32 len )
194 {
195 NN_NULL_TASSERT_(context);
196 NN_NULL_TASSERT_(data);
197
198 const u8* srcp = (const u8*)data;
199 u8 srcTmp;
200
201 // Header parsing
202 if ( context->headerSize > 0 )
203 {
204 u32 read_len;
205 if ( context->headerSize == 8 )
206 {
207 if ( (*srcp & COMPRESSION_TYPE_MASK) != COMPRESSION_RL )
208 {
209 return CX_ERR_UNSUPPORTED;
210 }
211 if ( (*srcp & 0x0F ) != 0 )
212 {
213 return CX_ERR_UNSUPPORTED;
214 }
215 }
216 read_len = ReadHeader( &context->headerSize, &context->destCount, srcp, len, context->forceDestCount );
217 srcp += read_len;
218 len -= read_len;
219 if ( len == 0 )
220 {
221 return (context->headerSize == 0)? context->destCount : -1;
222 }
223 }
224
225 while ( context->destCount > 0 )
226 {
227 // Process if length > 0.
228 if ( ! (context->flags & 0x80) )
229 // Uncompressed data has a length not equal to 0
230 {
231 while ( context->length > 0 )
232 {
233 *context->destp++ = *srcp++;
234 context->length--;
235 context->destCount--;
236 len--;
237 // End when the prepared buffer has been read in full
238 if ( len == 0 )
239 {
240 return context->destCount;
241 }
242 }
243 }
244 else if ( context->length > 0 )
245 // Compressed data has a length not equal to 0
246 {
247 srcTmp = *srcp++;
248 len--;
249 while ( context->length > 0 )
250 {
251 *context->destp++ = srcTmp;
252 context->length--;
253 context->destCount--;
254 }
255 if ( len == 0 )
256 {
257 return context->destCount;
258 }
259 }
260
261 // Reading the flag byte
262 context->flags = *srcp++;
263 len--;
264 context->length = (u16)(context->flags & 0x7F);
265 if ( context->flags & 0x80 )
266 {
267 context->length += 3;
268 }
269 else
270 {
271 context->length += 1;
272 }
273
274 if ( context->length > context->destCount )
275 // Measures for buffer overrun when invalid data is decompressed.
276 {
277 if ( context->forceDestCount == 0 )
278 {
279 return CX_ERR_DEST_OVERRUN;
280 }
281 context->length = (u16)context->destCount;
282 }
283 if ( len == 0 )
284 {
285 return context->destCount;
286 }
287 }
288
289 // Processing to perform in the event that (context->destCount == 0)
290 if ( (context->forceDestCount == 0) && (len > 32) )
291 {
292 return CX_ERR_SRC_REMAINDER;
293 }
294 return 0;
295 }
296
297
298 /*---------------------------------------------------------------------------*
299 Name: ReadUncompLZ
300
301 Description: This function performs streaming decompression of LZ-compressed data.
302 Data is written in units of 8 bits. Data cannot be directly uncompressed to VRAM.
303
304 Arguments: context Pointer to the LZ uncompressed context
305 data Pointer to the next data
306 len Data size
307
308 Returns: Size of remaining uncompressed data.
309 Returns a negative error code if failed.
310
311 *---------------------------------------------------------------------------*/
ReadUncompLZ(UncompContextLZ * context,const void * data,u32 len)312 s32 ReadUncompLZ( UncompContextLZ *context, const void* data, u32 len )
313 {
314 NN_NULL_TASSERT_(context);
315 NN_NULL_TASSERT_(data);
316
317 const u8* srcp = (const u8*)data;
318 s32 offset;
319
320 // Header parsing
321 if ( context->headerSize > 0 )
322 {
323 u32 read_len;
324 // Process the first byte
325 if ( context->headerSize == 8 )
326 {
327 if ( ( *srcp & COMPRESSION_TYPE_MASK ) != COMPRESSION_LZ )
328 {
329 return CX_ERR_UNSUPPORTED;
330 }
331 // Record as an LZ compression parameter
332 context->exFormat = (u8)( *srcp & 0x0F );
333 if ( (context->exFormat != 0x0) && (context->exFormat != 0x1) )
334 {
335 return CX_ERR_UNSUPPORTED;
336 }
337 }
338 read_len = ReadHeader( &context->headerSize, &context->destCount, srcp, len, context->forceDestCount );
339 srcp += read_len;
340 len -= read_len;
341 if ( len == 0 )
342 {
343 return (context->headerSize == 0)? context->destCount : -1;
344 }
345 }
346
347 while ( context->destCount > 0 )
348 {
349 while ( context->flagIndex > 0 )
350 {
351 if ( len == 0 )
352 {
353 return context->destCount;
354 }
355
356 if ( ! (context->flags & 0x80) )
357 // Process for non-compressed data
358 {
359 *context->destp++ = *srcp++;
360 context->destCount--;
361 len--;
362 }
363 else
364 // Process for compressed data
365 {
366 while ( context->lengthFlg > 0 )
367 {
368 --context->lengthFlg;
369 if ( ! context->exFormat )
370 {
371 context->length = *srcp++;
372 context->length += (3 << 4);
373 context->lengthFlg = 0;
374 }
375 else
376 {
377 switch ( context->lengthFlg )
378 {
379 case 2:
380 {
381 context->length = *srcp++;
382 if ( (context->length >> 4) == 1 )
383 {
384 // Read two more bytes
385 context->length = (context->length & 0x0F) << 16;
386 context->length += ( (0xFF + 0xF + 3) << 4 );
387 }
388 else if ( (context->length >> 4) == 0 )
389 {
390 // Read one more byte
391 context->length = (context->length & 0x0F) << 8;
392 context->length += ( (0xF + 2) << 4 );
393 context->lengthFlg = 1;
394 }
395 else
396 {
397 context->length += (1 << 4);
398 context->lengthFlg = 0;
399 }
400 }
401 break;
402 case 1:
403 {
404 context->length += (*srcp++ << 8);
405 }
406 break;
407 case 0:
408 {
409 context->length += *srcp++;
410 }
411 break;
412 }
413 }
414 if ( --len == 0 )
415 {
416 return context->destCount;
417 }
418 }
419
420 offset = (context->length & 0xF) << 8;
421 context->length = context->length >> 4;
422 offset = (offset | *srcp++) + 1;
423 len--;
424 context->lengthFlg = 3;
425
426 // Measures for buffer overrun when invalid data is decompressed.
427 if ( context->length > context->destCount )
428 {
429 if ( context->forceDestCount == 0 )
430 {
431 return CX_ERR_DEST_OVERRUN;
432 }
433 context->length = context->destCount;
434 }
435 // Copy a length amount of data located at the offset position
436 while ( context->length > 0 )
437 {
438 *context->destp = context->destp[ -offset ];
439 context->destp++;
440 context->destCount--;
441 context->length--;
442 }
443 }
444
445 if ( context->destCount == 0 )
446 {
447 goto out;
448 }
449 context->flags <<= 1;
450 context->flagIndex--;
451 }
452
453 if ( len == 0 )
454 {
455 return context->destCount;
456 }
457 // Read a new flag
458 context->flags = *srcp++;
459 context->flagIndex = 8;
460 len--;
461 }
462
463 out:
464 // Processing to perform in the event that (context->destCount == 0)
465 if ( (context->forceDestCount == 0) && (len > 32) )
466 {
467 return CX_ERR_SRC_REMAINDER;
468 }
469 return 0;
470 }
471
472 namespace {
473
474 // Get the next node in the Huffman signed table
GetNextNode(const u8 * pTree,u32 select)475 inline u8* GetNextNode( const u8* pTree, u32 select )
476 {
477 return (u8*)( ((u32)pTree & ~0x1) + ( ( (*pTree & 0x3F) + 1 ) * 2 ) + select );
478 }
479
480 } // Namespace
481
482 /*---------------------------------------------------------------------------*
483 Name: ReadUncompHuffman
484
485 Description: This function performs streaming decompression of Huffman-compressed data.
486 Returns a negative error code if failed.
487
488 Arguments: context Pointer to the Huffman uncompressed context
489 data Pointer to the next data
490 len Data size
491
492 Returns: Size of remaining uncompressed data.
493 Returns a negative error code if failed.
494
495 *---------------------------------------------------------------------------*/
ReadUncompHuffman(UncompContextHuffman * context,const void * data,u32 len)496 s32 ReadUncompHuffman( UncompContextHuffman *context, const void* data, u32 len )
497 {
498 NN_NULL_TASSERT_(context);
499 NN_NULL_TASSERT_(data);
500
501 #define TREE_END_MASK 0x80U
502 const u8* srcp = (const u8*)data;
503 u32 select;
504 u32 endFlag;
505
506 // Header parsing
507 if ( context->headerSize > 0 )
508 {
509 u32 read_len;
510 // Process the first byte
511 if ( context->headerSize == 8 )
512 {
513 context->bitSize = (u8)(*srcp & 0xF);
514
515 if ( ( *srcp & COMPRESSION_TYPE_MASK ) != COMPRESSION_HUFFMAN )
516 {
517 return CX_ERR_UNSUPPORTED;
518 }
519 if ( (context->bitSize != 4) && (context->bitSize != 8) )
520 {
521 return CX_ERR_UNSUPPORTED;
522 }
523 }
524 read_len = ReadHeader( &context->headerSize, &context->destCount, srcp, len, context->forceDestCount );
525 srcp += read_len;
526 len -= read_len;
527 if ( len == 0 )
528 {
529 return (context->headerSize == 0)? context->destCount : -1;
530 }
531 }
532
533 // treeSize is set to -1 in InitUncompContextHuffman.
534 // When context->treeSize is negative, it indicates the start of the data.
535 if ( context->treeSize < 0 )
536 {
537 context->treeSize = (s16)( ( *srcp + 1 ) * 2 - 1 );
538 *context->treep++ = *srcp++;
539 len--;
540 }
541
542 // Load the Huffman signed table
543 while ( context->treeSize > 0 )
544 {
545 if ( len == 0 )
546 {
547 return context->destCount;
548 }
549 *context->treep++ = *srcp++;
550 context->treeSize--;
551 len--;
552 if ( context->treeSize == 0 )
553 {
554 context->treep = &context->tree[ 1 ];
555 if ( ! internal::VerifyHuffmanTable( &context->tree[ 0 ], context->bitSize ) )
556 {
557 return CX_ERR_ILLEGAL_TABLE;
558 }
559 }
560 }
561
562 // Decoding process
563 while ( context->destCount > 0 )
564 {
565 // src data is read in 4-byte units
566 while ( context->srcTmpCnt < 32 )
567 {
568 if ( len == 0 )
569 {
570 return context->destCount;
571 }
572 context->srcTmp |= (*srcp++) << context->srcTmpCnt;
573 len--;
574 context->srcTmpCnt += 8;
575 }
576
577 // Decode the 32 bits that were loaded. After those 32 bits are processed, the next 4 bytes are read.
578 while ( context->srcTmpCnt > 0 )
579 {
580 select = context->srcTmp >> 31;
581 endFlag = (*context->treep << select) & TREE_END_MASK;
582 context->treep = GetNextNode( context->treep, select );
583 context->srcTmp <<= 1;
584 context->srcTmpCnt--;
585
586 if ( ! endFlag )
587 {
588 continue;
589 }
590
591 // When the Huffman tree's terminal flag is set, data is stored after the offset
592 //
593 context->destTmp >>= context->bitSize;
594 context->destTmp |= *context->treep << ( 32 - context->bitSize );
595 context->treep = &context->tree[ 1 ];
596 context->destTmpCnt += context->bitSize;
597
598 if ( context->destCount <= (context->destTmpCnt / 8) )
599 {
600 context->destTmp >>= (32 - context->destTmpCnt);
601 context->destTmpCnt = 32;
602 }
603
604 // Write in 4-byte units
605 if ( context->destTmpCnt == 32 )
606 {
607 *(u32*)context->destp = internal::ConvertEndian( context->destTmp );
608 context->destp += 4;
609 context->destCount -= 4;
610 context->destTmpCnt = 0;
611 if ( context->destCount <= 0 )
612 {
613 goto out;
614 }
615 }
616 }
617 }
618
619 out:
620 // Processing to perform in the event that (context->destCount == 0)
621 if ( (context->forceDestCount == 0) && (len > 32) )
622 {
623 return CX_ERR_SRC_REMAINDER;
624 }
625 return 0;
626 }
627
628
629 namespace {
630
631 struct BitReader
632 {
633 const u8* srcp;
634 u32 cnt;
635 u32 stream;
636 u32 stream_len;
637 };
638
639
640 inline s32
BitReader_Read(BitReader * context,u8 bits)641 BitReader_Read( BitReader* context, u8 bits )
642 {
643 s32 value;
644
645 while ( context->stream_len < bits )
646 {
647 if ( context->cnt == 0 )
648 {
649 return -1;
650 }
651 context->stream <<= 8;
652 context->stream += *context->srcp;
653 context->srcp++;
654 context->cnt--;
655 context->stream_len += 8;
656 }
657
658 value = (s32)( (context->stream >> (context->stream_len - bits)) & ((1 << bits) - 1) );
659 context->stream_len -= bits;
660 return value;
661 }
662
663 inline s64
BitReader_ReadEx(BitReader * context,u8 bits)664 BitReader_ReadEx( BitReader* context, u8 bits )
665 {
666 s64 value;
667 u8 stock = 0;
668
669 while ( context->stream_len < bits )
670 {
671 if ( context->cnt == 0 )
672 {
673 return -1;
674 }
675 if ( context->stream_len > 24 )
676 {
677 stock = (u8)( context->stream >> 24 );
678 }
679 context->stream <<= 8;
680 context->stream += *context->srcp;
681 context->srcp++;
682 context->cnt--;
683 context->stream_len += 8;
684 }
685 value = context->stream;
686 value |= (s64)stock << 32;
687 value = (s64)( (value >> (context->stream_len - bits)) & ((1 << bits) - 1) );
688 context->stream_len -= bits;
689
690 return value;
691 }
692
693 } // Namespace
694
695
696 #define ENC_OFFSET_WIDTH
697
698 /*---------------------------------------------------------------------------*
699 Name: InitUncompContextLH
700
701 Description:
702
703 Arguments: context
704 dest
705
706 Returns: None.
707 *---------------------------------------------------------------------------*/
708 void
InitUncompContextLH(UncompContextLH * context,void * dest)709 InitUncompContextLH( UncompContextLH * context, void* dest )
710 {
711 NN_NULL_TASSERT_(context);
712 context->destp = static_cast<u8*>(dest);
713 context->destCount = -1;
714 context->nodep = context->huffTable9 + 1;
715 context->tableSize9 = -1;
716 context->tableSize12 = -1;
717 context->headerSize = 8;
718 context->length = 0;
719 context->stream = 0;
720 context->stream_len = 0;
721 context->offset_bits = -1;
722 context->forceDestCount = 0;
723 }
724
725 /*---------------------------------------------------------------------------*
726 Name: ReadUncompLH
727
728 Description: This function performs streaming decompression of LZ-Huffman (combined) compressed data.
729
730 Arguments: *context: Pointer to the decompressed context
731 data Data pointer
732 len Data size
733
734 Returns: Size of remaining uncompressed data
735 Returns a negative error code if failed.
736 *---------------------------------------------------------------------------*/
737 s32
ReadUncompLH(UncompContextLH * context,const void * data,u32 len)738 ReadUncompLH( UncompContextLH *context, const void* data, u32 len )
739 {
740 NN_NULL_TASSERT_(context);
741 NN_NULL_TASSERT_(data);
742
743 #define LENGTH_BITS 9
744 #if defined(ENC_OFFSET_WIDTH)
745 #define OFFSET_BITS 5
746 #define OFFSET_MASK 0x07
747 #define LEAF_FLAG 0x10
748 #else
749 #define OFFSET_BITS 12
750 #define OFFSET_MASK 0x3FF
751 #define LEAF_FLAG 0x800
752 #endif
753
754 const u8* srcp = (const u8*)data;
755 BitReader stream;
756 s32 val;
757 u16* nodep;
758 u16 length;
759
760 stream.srcp = srcp;
761 stream.cnt = len;
762 stream.stream = context->stream;
763 stream.stream_len = context->stream_len;
764
765 // Header parsing
766 while ( context->headerSize > 0 )
767 {
768 s64 val32 = BitReader_ReadEx( &stream, 32 );
769 if ( val32 < 0 )
770 {
771 goto out;
772 }
773 context->headerSize -= 4;
774 if ( context->headerSize == 4 )
775 {
776 u32 headerVal = internal::ForceConvertEndian( (u32)val32 );
777 if ( (headerVal & COMPRESSION_TYPE_MASK) != COMPRESSION_LH )
778 {
779 return CX_ERR_UNSUPPORTED;
780 }
781 context->destCount = (s32)( headerVal >> 8 );
782
783 if ( context->destCount == 0 )
784 {
785 context->headerSize = 4;
786 context->destCount = -1;
787 }
788 else
789 {
790 context->headerSize = 0;
791 }
792 }
793 else // if ( context->headerSize == 0 )
794 {
795 context->destCount = (s32)internal::ForceConvertEndian( (u32)val32 );
796 }
797
798 if ( context->headerSize == 0 )
799 {
800 if ( ( context->forceDestCount > 0 ) && ( context->forceDestCount < context->destCount ) )
801 {
802 context->destCount = context->forceDestCount;
803 }
804 }
805 }
806
807 // load the Huffman table
808 {
809 if ( context->tableSize9 < 0 )
810 {
811 if ( ( val = BitReader_Read( &stream, 16 ) ) < 0 )
812 {
813 goto out;
814 }
815 context->tableSize9 = (internal::ForceConvertEndian16( (u16)val ) + 1) * 4 * 8; // shown with the bit count
816 context->tableIdx = 1;
817 context->tableSize9 -= 16;
818 }
819
820 const u32 MAX_IDX = (u32)( (1 << LENGTH_BITS) * 2 );
821
822 while ( context->tableSize9 >= LENGTH_BITS )
823 {
824 if ( ( val = BitReader_Read( &stream, LENGTH_BITS ) ) < 0 )
825 {
826 goto out;
827 }
828
829 if ( context->tableIdx < MAX_IDX )
830 {
831 context->huffTable9[ context->tableIdx++ ] = (u16)val;
832 }
833 context->tableSize9 -= LENGTH_BITS;
834 }
835
836 context->huffTable9[ 0 ] = (u16)context->tableIdx;
837
838 if ( context->tableSize9 > 0 )
839 {
840 if ( ( val = BitReader_Read( &stream, (u8)context->tableSize9 ) ) < 0 )
841 {
842 goto out;
843 }
844
845 context->tableSize9 = 0;
846
847 // verify the table
848 if ( ! internal::LHVerifyTable( context->huffTable9, LENGTH_BITS ) )
849 {
850 return CX_ERR_ILLEGAL_TABLE;
851 }
852 }
853 }
854 {
855 if ( context->tableSize12 < 0 )
856 {
857 if ( ( val = BitReader_Read( &stream, (OFFSET_BITS > 8)? 16 : 8 ) ) < 0 )
858 {
859 goto out;
860 }
861 #if ( OFFSET_BITS > 8 )
862 context->tableSize12 = (internal::ForceConvertEndian16( (u16)val ) + 1) * 4 * 8;
863 #else // ( OFFSET_BITS <= 8 )
864 context->tableSize12 = ((u16)val + 1) * 4 * 8;
865 #endif
866 context->tableIdx = 1;
867 context->tableSize12 -= (OFFSET_BITS > 8)? 16 : 8;
868 }
869
870 const u32 MAX_IDX = (u32)( (1 << OFFSET_BITS) * 2 );
871
872 while ( context->tableSize12 >= OFFSET_BITS )
873 {
874 if ( ( val = BitReader_Read( &stream, OFFSET_BITS ) ) < 0 )
875 {
876 goto out;
877 }
878
879 if ( context->tableIdx < MAX_IDX )
880 {
881 context->huffTable12[ context->tableIdx++ ] = (u16)val;
882 }
883 context->tableSize12 -= OFFSET_BITS;
884 }
885
886 context->huffTable12[ 0 ] = (u16)context->tableIdx;
887
888 if ( context->tableSize12 > 0 )
889 {
890 if ( ( val = BitReader_Read( &stream, (u8)context->tableSize12 ) ) < 0 )
891 {
892 goto out;
893 }
894
895 context->tableSize12 = 0;
896
897 // verify the table
898 if ( ! internal::LHVerifyTable( context->huffTable12, OFFSET_BITS ) )
899 {
900 return CX_ERR_ILLEGAL_TABLE;
901 }
902 }
903 }
904
905 nodep = context->nodep;
906 length = context->length;
907
908 // Data conversion
909 while ( context->destCount > 0 )
910 {
911 // get length data
912 if ( length == 0 )
913 {
914 do
915 {
916 u8 bit;
917 u32 offset;
918 if ( ( val = BitReader_Read( &stream, 1 ) ) < 0 )
919 {
920 context->nodep = nodep;
921 context->length = length;
922 goto out;
923 }
924 bit = (u8)( val & 1 );
925 offset = (((*nodep & 0x7F) + 1U) << 1) + bit;
926
927 if ( *nodep & (0x100 >> bit) )
928 {
929 nodep = (u16*)((u32)nodep & ~0x3);
930 length = *(nodep + offset);
931 nodep = context->huffTable12 + 1;
932 break;
933 }
934 else
935 {
936 nodep = (u16*)((u32)nodep & ~0x3);
937 nodep += offset;
938 }
939 } while ( 1 );
940 }
941
942 if ( length < 0x100 )
943 // uncompressed data
944 {
945 *context->destp++ = (u8)length;
946 context->destCount--;
947 nodep = context->huffTable9 + 1;
948 length = 0;
949 }
950 else
951 // compressed data
952 {
953 u16 lzOffset;
954 u16 lzLength = (u16)( (length & 0xFF) + 3 );
955
956 #if defined(ENC_OFFSET_WIDTH)
957 if ( context->offset_bits < 0 )
958 {
959 #endif
960 do
961 {
962 u8 bit;
963 u32 offset;
964
965 if ( ( val = BitReader_Read( &stream, 1 ) ) < 0 )
966 {
967 context->nodep = nodep;
968 context->length = length;
969 goto out;
970 }
971 bit = (u8)( val & 1 );
972 offset = (((*nodep & OFFSET_MASK) + 1U) << 1) + bit;
973
974 if ( *nodep & (LEAF_FLAG >> bit) )
975 {
976 nodep = (u16*)((u32)nodep & ~0x3);
977 #if defined(ENC_OFFSET_WIDTH)
978 context->offset_bits = (s8)( *(nodep + offset) );
979 #else
980 lzOffset = (u16)( *(nodep + offset) + 1 );
981 #endif
982 break;
983 }
984 else
985 {
986 nodep = (u16*)((u32)nodep & ~0x3);
987 nodep += offset;
988 }
989 } while ( 1 );
990 #if defined(ENC_OFFSET_WIDTH)
991 }
992 #endif
993
994 #if defined(ENC_OFFSET_WIDTH)
995 if ( context->offset_bits <= 1 )
996 {
997 val = context->offset_bits;
998 }
999 else if ( ( val = BitReader_Read( &stream, (u8)(context->offset_bits - 1) ) ) < 0 )
1000 {
1001 context->nodep = nodep;
1002 context->length = length;
1003 goto out;
1004 }
1005 if ( context->offset_bits >= 2 )
1006 {
1007 val |= (1 << (context->offset_bits - 1));
1008 }
1009
1010 context->offset_bits = -1;
1011 lzOffset = (u16)(val + 1);
1012 #endif
1013
1014 if ( context->destCount < lzLength )
1015 // Measures for buffer overrun when invalid data is decompressed.
1016 {
1017 if ( context->forceDestCount == 0 )
1018 {
1019 return CX_ERR_DEST_OVERRUN;
1020 }
1021 lzLength = (u16)context->destCount;
1022 }
1023
1024 context->destCount -= lzLength;
1025 while ( lzLength-- )
1026 {
1027 *context->destp = *(context->destp - lzOffset);
1028 ++context->destp;
1029 }
1030 length = 0;
1031 nodep = context->huffTable9 + 1;
1032 }
1033 }
1034
1035 out:
1036 context->stream = stream.stream;
1037 context->stream_len = stream.stream_len;
1038
1039
1040 // After decompression, remaining source data will be treated as an error
1041 if ( (context->destCount == 0) &&
1042 (context->forceDestCount == 0) &&
1043 (stream.cnt > 32) )
1044 {
1045 return CX_ERR_SRC_REMAINDER;
1046 }
1047
1048 return context->destCount;
1049
1050 #undef OFFSET_BITS
1051 #undef OFFSET_MASK
1052 #undef LEAF_FLAG
1053 }
1054
1055 namespace {
1056
1057 // Structure for the range coder state
1058 struct RCState
1059 {
1060 u32 low;
1061 u32 range;
1062 u32 code; // only used during decompression
1063 u8 carry; // only used during compression
1064 u8 padding_[3];
1065 u32 carry_cnt; // only used during compression
1066 };
1067
1068 // Range coder structure
1069 struct RCCompressionInfo
1070 {
1071 u32 *freq; // Table for occurrence frequency: (1 << bitSize) * sizeof(u32) bytes
1072 u32 *low_cnt; // Table for the LOW border value: (1 << bitSize) * sizeof(u32) bytes
1073 u32 total; // Total: 4 bytes
1074 u8 bitSize; // Bit size: 1 byte
1075 u8 padding_[3]; //
1076 };
1077
1078 #define RC_MAX_RANGE 0x80000000
1079
1080 /*---------------------------------------------------------------------------*
1081 Name: LRCIntro_
1082
1083 Description: Processing to set up streaming loads
1084
1085 Arguments: context
1086 info8
1087 info9
1088 state
1089
1090 Returns: None.
1091 *---------------------------------------------------------------------------*/
1092 inline void
LRCIntro_(UncompContextLRC * context,RCCompressionInfo * info9,RCCompressionInfo * info12,RCState * state)1093 LRCIntro_(
1094 UncompContextLRC *context,
1095 RCCompressionInfo *info9,
1096 RCCompressionInfo *info12,
1097 RCState *state )
1098 {
1099 info9->freq = context->freq9;
1100 info9->low_cnt = context->low_cnt9;
1101 info9->total = context->total9;
1102 info9->bitSize = 9;
1103
1104 info12->freq = context->freq12;
1105 info12->low_cnt = context->low_cnt12;
1106 info12->total = context->total12;
1107 info12->bitSize = 12;
1108
1109 state->low = context->low;
1110 state->range = context->range;
1111 state->code = context->code;
1112 state->carry = context->carry;
1113 state->carry_cnt = context->carry_cnt;
1114 }
1115
1116
1117 /*---------------------------------------------------------------------------*
1118 Name: LRCFin_
1119
1120 Description: Processing to stop streaming loads
1121
1122 Arguments: *context
1123 *info9
1124 *info12
1125 *state
1126
1127 Returns: None.
1128 *---------------------------------------------------------------------------*/
1129 inline void
LRCFin_(UncompContextLRC * context,const RCCompressionInfo * info9,const RCCompressionInfo * info12,const RCState * state)1130 LRCFin_(
1131 UncompContextLRC *context,
1132 const RCCompressionInfo *info9,
1133 const RCCompressionInfo *info12,
1134 const RCState *state )
1135 {
1136 context->total9 = info9->total;
1137 context->total12 = info12->total;
1138
1139 context->low = state->low;
1140 context->range = state->range;
1141 context->code = state->code;
1142 context->carry = state->carry;
1143 context->carry_cnt = state->carry_cnt;
1144 }
1145
1146 /*---------------------------------------------------------------------------*
1147 Name: RCInitState_
1148
1149 Description: Initializes the RC state.
1150
1151 Arguments: state: Pointer to an RC state structure
1152
1153 Returns: None.
1154 *---------------------------------------------------------------------------*/
1155 inline void
RCInitState_(RCState * state)1156 RCInitState_( RCState* state )
1157 {
1158 state->low = 0;
1159 state->range = RC_MAX_RANGE;
1160 state->code = 0;
1161 state->carry = 0;
1162 state->carry_cnt = 0;
1163 }
1164
1165 /*---------------------------------------------------------------------------*
1166 Name: RCInitInfo_
1167
1168 Description: Initialize the table for the adaptive range coder.
1169 All occurrence frequencies are initialized to 1.
1170
1171 Arguments: info: Pointer to an RC table information structure
1172
1173 Returns: None.
1174 *---------------------------------------------------------------------------*/
1175 inline void
RCInitInfo_(RCCompressionInfo * info,u8 bitSize)1176 RCInitInfo_( RCCompressionInfo* info, u8 bitSize )
1177 {
1178 u32 tableSize = (u32)(1 << bitSize);
1179 u32 i;
1180
1181 info->bitSize = bitSize;
1182
1183 for ( i = 0; i < tableSize; i++ )
1184 {
1185 info->freq[ i ] = 1;
1186 info->low_cnt[ i ] = i;
1187 }
1188 info->total = tableSize;
1189 }
1190
1191
1192 /*---------------------------------------------------------------------------*
1193 Name: RCAAddCount_
1194
1195 Description: Updates the frequency table for an adaptive range coder.
1196
1197 Arguments: info: Table information for a range coder
1198 val: Value to add
1199
1200 Returns: None.
1201 *---------------------------------------------------------------------------*/
1202 void
RCAddCount_(RCCompressionInfo * info,u16 val)1203 RCAddCount_( RCCompressionInfo* info, u16 val )
1204 {
1205 u32 i;
1206 u32 tableSize = (u32)(1 << info->bitSize);
1207
1208 info->freq[ val ]++;
1209 info->total++;
1210 for ( i = (u32)(val + 1); i < tableSize; i++ )
1211 {
1212 info->low_cnt[ i ]++;
1213 }
1214
1215 // Reconstruct if the total exceeds the maximum value.
1216 if ( info->total >= 0x00010000 )
1217 {
1218 if ( info->freq[ 0 ] > 1 )
1219 {
1220 info->freq[ 0 ] = info->freq[ 0 ] / 2;
1221 }
1222 info->low_cnt[ 0 ] = 0;
1223 info->total = info->freq[ 0 ];
1224
1225 for ( i = 1; i < tableSize; i++ )
1226 {
1227 if ( info->freq[ i ] > 1 )
1228 {
1229 info->freq[ i ] >>= 1;
1230 }
1231 info->low_cnt[ i ] = info->low_cnt[ i - 1 ] + info->freq[ i - 1 ];
1232 info->total += info->freq[ i ];
1233 }
1234 }
1235 }
1236
1237
1238 /*---------------------------------------------------------------------------*
1239 Name: RCSearch_
1240
1241 Description: Searches for the value that must be obtained next from the code, range, and low values.
1242
1243 Arguments: info: Table information for a range coder
1244 code: Current code value
1245 range: Current Range value
1246 low: Current Low value
1247
1248 Returns:
1249 *---------------------------------------------------------------------------*/
1250 u16
RCSearch_(RCCompressionInfo * info,u32 code,u32 range,u32 low)1251 RCSearch_( RCCompressionInfo* info, u32 code, u32 range, u32 low )
1252 {
1253 u32 tableSize = (u32)(1 << info->bitSize);
1254 u32 codeVal = code - low;
1255 u32 i;
1256 u32 temp = range / info->total;
1257 u32 tempVal = codeVal / temp;
1258
1259 // binary search
1260 u32 left = 0;
1261 u32 right = tableSize - 1;
1262
1263 while ( left < right )
1264 {
1265 i = (left + right) / 2;
1266
1267 if ( info->low_cnt[ i ] > tempVal )
1268 {
1269 right = i;
1270 }
1271 else
1272 {
1273 left = i + 1;
1274 }
1275 }
1276
1277 i = left;
1278 while ( info->low_cnt[ i ] > tempVal )
1279 {
1280 --i;
1281 }
1282 return (u16)i;
1283 }
1284
1285
1286 /*---------------------------------------------------------------------------*
1287 Name: RCGetData_
1288
1289 Description: Gets the next value from the state in RCState, then updates the state.
1290
1291 Arguments: stream
1292 info
1293 state
1294 adaptive
1295
1296 Returns:
1297 *---------------------------------------------------------------------------*/
1298 u16
RCGetData_(const u8 * srcp,RCCompressionInfo * info,RCState * state,u32 srcCnt,s32 * pReadCnt)1299 RCGetData_( const u8* srcp, RCCompressionInfo* info, RCState* state, u32 srcCnt, s32* pReadCnt )
1300 {
1301 #define MIN_RANGE 0x01000000
1302 u16 val = RCSearch_( info, state->code, state->range, state->low );
1303 s32 cnt = 0;
1304
1305 {
1306 u32 tmp;
1307 tmp = state->range / info->total;
1308 state->low += info->low_cnt[ val ] * tmp;
1309 state->range = info->freq[ val ] * tmp;
1310 }
1311
1312 // Update the table for occurrence frequency
1313 RCAddCount_( info, val );
1314
1315 while ( state->range < MIN_RANGE )
1316 {
1317 if ( srcCnt == 0 )
1318 {
1319 cnt = (cnt < 0 )? ( cnt - 1 ) : ( -1 );
1320 }
1321 else
1322 {
1323 state->code <<= 8;
1324 state->code += srcp[ cnt++ ];
1325 --srcCnt;
1326 }
1327 state->range <<= 8;
1328 state->low <<= 8;
1329 }
1330 *pReadCnt = cnt;
1331
1332 return val;
1333 #undef MIN_RANGE
1334 }
1335
1336 } // Namespace
1337
1338
1339 /*---------------------------------------------------------------------------*
1340 Name: InitUncompContextLRC
1341
1342 Description: Initializes the streaming decompression context for LZ/Range Coder (combined) compressed data.
1343
1344 Arguments: context Pointer to the decompressed context
1345 dest Destination address for uncompressed data
1346
1347 Returns: None.
1348 *---------------------------------------------------------------------------*/
1349 void
InitUncompContextLRC(UncompContextLRC * context,void * dest)1350 InitUncompContextLRC( UncompContextLRC * context, void* dest )
1351 {
1352 NN_NULL_TASSERT_(context);
1353
1354 #define LENGTH_BITS 9
1355 #define OFFSET_BITS 12
1356 RCCompressionInfo info9;
1357 RCCompressionInfo info12;
1358 RCState rcState;
1359
1360 // Set up processing
1361 LRCIntro_( context, &info9, &info12, &rcState );
1362
1363 context->destp = static_cast<u8*>(dest);
1364 context->destCount = 0;
1365 context->headerSize = 8;
1366 context->length = 0;
1367 context->forceDestCount = 0;
1368
1369 context->codeLen = 4;
1370
1371 RCInitInfo_( &info9, LENGTH_BITS );
1372 RCInitInfo_( &info12, OFFSET_BITS );
1373
1374 RCInitState_( &rcState );
1375
1376 // Stop processing
1377 LRCFin_( context, &info9, &info12, &rcState );
1378
1379 #undef LENGTH_BITS
1380 #undef OFFSET_BITS
1381 }
1382
1383
1384 /*---------------------------------------------------------------------------*
1385 Name: ReadUncompLRC
1386
1387 Description: This function performs streaming decompression of LZ/Range Coder (combined) compressed data.
1388
1389 Arguments: *context: Pointer to the decompressed context
1390 data Data pointer
1391 len Data size
1392
1393 Returns: Size of remaining uncompressed data
1394 Returns a negative error code if failed.
1395 *---------------------------------------------------------------------------*/
1396 s32
ReadUncompLRC(UncompContextLRC * context,const void * data,u32 len)1397 ReadUncompLRC( UncompContextLRC *context, const void* data, u32 len )
1398 {
1399 NN_NULL_TASSERT_(context);
1400 NN_NULL_TASSERT_(data);
1401
1402 RCCompressionInfo info9;
1403 RCCompressionInfo info12;
1404 RCState rcState;
1405 const u8* srcp = (const u8*)data;
1406
1407 // Set up processing
1408 LRCIntro_( context, &info9, &info12, &rcState );
1409
1410 // Header parsing
1411 if ( context->headerSize > 0 )
1412 {
1413 u32 read_len;
1414 if ( context->headerSize == 8 )
1415 {
1416 if ( (*srcp & COMPRESSION_TYPE_MASK) != COMPRESSION_LRC )
1417 {
1418 return CX_ERR_UNSUPPORTED;
1419 }
1420 if ( (*srcp & 0x0F) != 0 )
1421 {
1422 return CX_ERR_UNSUPPORTED;
1423 }
1424 }
1425
1426 read_len = ReadHeader( &context->headerSize, &context->destCount, srcp, len, context->forceDestCount );
1427 srcp += read_len;
1428 len -= read_len;
1429 if ( len == 0 )
1430 {
1431 return (context->headerSize == 0)? context->destCount : -1;
1432 }
1433 }
1434
1435 // load the code
1436 while ( context->codeLen > 0 )
1437 {
1438 if ( len == 0 )
1439 {
1440 goto out;
1441 }
1442 rcState.code <<= 8;
1443 rcState.code += *srcp;
1444 ++srcp;
1445 --len;
1446 --context->codeLen;
1447 }
1448
1449 while ( context->destCount > 0 )
1450 {
1451 // get the value for length
1452 if ( context->length == 0 )
1453 {
1454 s32 cnt;
1455 u16 val = RCGetData_( srcp, &info9, &rcState, len, &cnt );
1456
1457 if ( val < 0x100 )
1458 // uncompressed data
1459 {
1460 *context->destp++ = (u8)val;
1461 context->destCount--;
1462 }
1463 else
1464 // compressed data
1465 {
1466 context->length = (u16)( (val & 0xFF) + 3 );
1467 }
1468
1469 // prepare to read the next data
1470 if ( cnt < 0 )
1471 {
1472 context->codeLen = (u8)( -cnt );
1473 goto out;
1474 }
1475 srcp += cnt;
1476 len -= cnt;
1477 }
1478
1479 // Expanding compressed data
1480 if ( context->length > 0 )
1481 {
1482 s32 cnt;
1483 u16 val = (u16)( RCGetData_( srcp, &info12, &rcState, len, &cnt ) + 1 );
1484
1485 // Measures for buffer overrun when invalid data is decompressed.
1486 if ( context->length > context->destCount )
1487 {
1488 if ( context->forceDestCount == 0 )
1489 {
1490 return CX_ERR_DEST_OVERRUN;
1491 }
1492 context->length = (u16)( context->destCount );
1493 }
1494
1495 while ( context->length > 0 )
1496 {
1497 *context->destp = context->destp[ -val ];
1498 context->destp++;
1499 context->destCount--;
1500 context->length--;
1501 }
1502 // advance the load position
1503 if ( cnt < 0 )
1504 {
1505 context->codeLen = (u8)( -cnt );
1506 goto out;
1507 }
1508 srcp += cnt;
1509 len -= cnt;
1510 }
1511 }
1512 out:
1513 // Stop processing
1514 LRCFin_( context, &info9, &info12, &rcState );
1515
1516 // After decompression, remaining source data will be treated as an error
1517 if ( (context->destCount == 0) &&
1518 (context->forceDestCount == 0) &&
1519 (len > 32) )
1520 {
1521 return CX_ERR_SRC_REMAINDER;
1522 }
1523
1524 return context->destCount;
1525 }
1526
1527 namespace
1528 {
InitUncompressContextDeflateCommon(UncompContextDeflate * pContext,void * pDest,size_t destSize,int wbits)1529 void InitUncompressContextDeflateCommon( UncompContextDeflate* pContext, void* pDest, size_t destSize, int wbits )
1530 {
1531 NN_POINTER_TASSERT_(pContext);
1532 NN_POINTER_TASSERT_(pDest);
1533
1534 UncompressContextDeflate_* pucd = GetUncompressContextDeflate_(pContext);
1535 pucd->headerSize = 0;
1536 pucd->rawSize = 0;
1537
1538 new (&pucd->za) detail::ZlibAllocator(pucd->workBuffer, sizeof(pucd->workBuffer));
1539
1540 z_stream& s = pucd->s;
1541 int err NN_IS_UNUSED_VAR;
1542
1543 s.next_in = NULL;
1544 s.avail_in = 0;
1545 s.next_out = reinterpret_cast<nncxZlib_Bytef*>(pDest);
1546 s.avail_out = destSize;
1547
1548 s.zalloc = detail::ZlibAllocator::Allocate;
1549 s.zfree = detail::ZlibAllocator::Free;
1550 s.opaque = &pucd->za;
1551
1552 err = inflateInit2(&s, wbits);
1553 NN_TASSERT_( err == Z_OK );
1554 }
1555
ReadUncompressDeflateCommon(UncompContextDeflate * pContext,const void * pData,size_t dataSize)1556 s32 ReadUncompressDeflateCommon( UncompContextDeflate* pContext, const void* pData, size_t dataSize )
1557 {
1558 NN_POINTER_TASSERT_(pContext);
1559 NN_POINTER_TASSERT_(pData);
1560
1561 z_stream& s = GetUncompressContextDeflate_(pContext)->s;
1562 int err;
1563
1564 s.next_in = reinterpret_cast<nncxZlib_Bytef*>(const_cast<void*>(pData));
1565 s.avail_in = dataSize;
1566
1567 const u32 availOutBefore = s.avail_out;
1568 err = nncxZlib_inflate(&s, Z_NO_FLUSH);
1569
1570 if (err != Z_OK)
1571 {
1572 if( err == Z_STREAM_END )
1573 {
1574 err = nncxZlib_inflate(&s, Z_FINISH);
1575 }
1576 nncxZlib_deflateEnd(&s);
1577 }
1578
1579 s32 cxErr = detail::ConvertZlibReturnCode(err);
1580 if( cxErr != ERROR_CODE_SUCCESS )
1581 {
1582 return cxErr;
1583 }
1584
1585 const u32 outSize = availOutBefore - s.avail_out;
1586 return outSize;
1587 }
1588 }
1589
InitUncompContextDeflate(UncompContextDeflate * pContext,void * pDest,size_t destSize)1590 void InitUncompContextDeflate( UncompContextDeflate* pContext, void* pDest, size_t destSize )
1591 {
1592 NN_POINTER_TASSERT_(pContext);
1593 NN_POINTER_TASSERT_(pDest);
1594
1595 const int wbits = - MAX_WBITS; // Specify - = raw deflate format
1596 InitUncompressContextDeflateCommon(pContext, pDest, destSize, wbits);
1597 }
1598
InitUncompContextGzip(UncompContextGzip * pContext,void * pDest,size_t destSize)1599 void InitUncompContextGzip( UncompContextGzip* pContext, void* pDest, size_t destSize )
1600 {
1601 NN_POINTER_TASSERT_(pContext);
1602 NN_POINTER_TASSERT_(pDest);
1603
1604 const int wbits = MAX_WBITS + 16; // Specify +16 = gzip format
1605 InitUncompressContextDeflateCommon(pContext, pDest, destSize, wbits);
1606 }
1607
InitUncompContextZlib(UncompContextZlib * pContext,void * pDest,size_t destSize)1608 void InitUncompContextZlib( UncompContextZlib* pContext, void* pDest, size_t destSize )
1609 {
1610 NN_POINTER_TASSERT_(pContext);
1611 NN_POINTER_TASSERT_(pDest);
1612
1613 InitUncompressContextDeflateCommon(pContext, pDest, destSize, MAX_WBITS);
1614 }
1615
ReadUncompDeflate(UncompContextDeflate * pContext,const void * pData,size_t dataSize)1616 s32 ReadUncompDeflate( UncompContextDeflate* pContext, const void* pData, size_t dataSize )
1617 {
1618 NN_POINTER_TASSERT_(pContext);
1619 NN_POINTER_TASSERT_(pData);
1620
1621 UncompressContextDeflate_* pucd = GetUncompressContextDeflate_(pContext);
1622
1623 if( pucd->headerSize < 8 )
1624 {
1625 if( pucd->headerSize < 4 )
1626 {
1627 int copySize = math::Min<int>(dataSize, 4 - pucd->headerSize);
1628 std::memcpy( reinterpret_cast<bit8*>(&pucd->rawSize) + pucd->headerSize,
1629 pData,
1630 copySize );
1631 pData = reinterpret_cast<const bit8*>(pData) + copySize;
1632 dataSize -= copySize;
1633 pucd->headerSize += copySize;
1634
1635 if( pucd->headerSize < 4 )
1636 {
1637 return ERROR_CODE_DATA_SHORTAGE;
1638 }
1639
1640 u32 size = (internal::Read32Le(reinterpret_cast<bit8*>(&pucd->rawSize)) >> 8);
1641
1642 if( size > 0 )
1643 {
1644 pucd->headerSize = 8;
1645 pucd->rawSize = size;
1646 }
1647 }
1648
1649 NN_TASSERT_( pucd->headerSize >= 4 );
1650
1651 if( pucd->headerSize < 8 )
1652 {
1653 int copySize = math::Min<int>(dataSize, 8 - pucd->headerSize);
1654 std::memcpy( reinterpret_cast<bit8*>(&pucd->rawSize) + pucd->headerSize - 4,
1655 pData,
1656 copySize );
1657 pData = reinterpret_cast<const bit8*>(pData) + copySize;
1658 dataSize -= copySize;
1659 pucd->headerSize += copySize;
1660
1661 if( pucd->headerSize < 8 )
1662 {
1663 return ERROR_CODE_DATA_SHORTAGE;
1664 }
1665
1666 pucd->rawSize = internal::Read32Le(reinterpret_cast<bit8*>(&pucd->rawSize));
1667 }
1668 }
1669
1670 s32 ret = ReadUncompressDeflateCommon(pContext, pData, dataSize);
1671
1672 if( ret > 0 )
1673 {
1674 pucd->rawSize -= ret;
1675 return pucd->rawSize;
1676 }
1677 else
1678 {
1679 return ret;
1680 }
1681 }
1682
ReadUncompGzip(UncompContextGzip * pContext,const void * pData,size_t dataSize)1683 s32 ReadUncompGzip( UncompContextGzip* pContext, const void* pData, size_t dataSize )
1684 {
1685 NN_POINTER_TASSERT_(pContext);
1686 NN_POINTER_TASSERT_(pData);
1687
1688 return ReadUncompressDeflateCommon(pContext, pData, dataSize);
1689 }
1690
ReadUncompZlib(UncompContextZlib * pContext,const void * pData,size_t dataSize)1691 s32 ReadUncompZlib( UncompContextZlib* pContext, const void* pData, size_t dataSize )
1692 {
1693 NN_POINTER_TASSERT_(pContext);
1694 NN_POINTER_TASSERT_(pData);
1695
1696 return ReadUncompressDeflateCommon(pContext, pData, dataSize);
1697 }
1698
1699 } // namespace cx
1700 } // namespace nn
1701