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