1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     cx_Compression.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: 47707 $
14  *---------------------------------------------------------------------------*/
15 
16 #include <nn/types.h>
17 #include <nn/assert.h>
18 #include <nn/cx/cx_Uncompression.h>
19 #include <nn/cx/cx_Compression.h>
20 #include "cx_Utility.h"
21 
22 namespace nn {
23 namespace cx {
24 
25 namespace {
26 
27 //===========================================================================
28 //  LZ Encoding
29 //===========================================================================
30 
31 // Temporary information for LZ high-speed encoding
32 struct LZCompressInfo
33 {
34     u16     windowPos;                 // Initial position of the history window
35     u16     windowLen;                 // Length of the history window
36 
37     s16    *LZOffsetTable;             // Offset buffer of the history window
38     s16    *LZByteTable;               // Pointer to the most recent character history
39     s16    *LZEndTable;                // Pointer to the oldest character history
40 };
41 
42 void        LZInitTable( LZCompressInfo * info, void *work );
43 u32         SearchLZ   ( LZCompressInfo * info, const u8 *nextp, u32 remainSize, u16 *offset, u32 maxLength );
44 void        SlideByte  ( LZCompressInfo * info, const u8 *srcp );
45 inline void LZSlide    ( LZCompressInfo * info, const u8 *srcp, u32 n );
46 
47 }   // Namespace
48 
49 
50 /*---------------------------------------------------------------------------*
51   Name:         CompressLZ
52 
53   Description:  Performs LZ77 compression.
54 
55   Arguments:    srcp:            Pointer to compression source data
56                 size:            Size of compression source data
57                 dstp            Pointer to compressed data
58                                 The buffer must be larger than the size of the compression source data.
59                 work            Temporary buffer for compression
60                                 A region for the size of  CX_LZ_FAST_COMPRESS_WORK_SIZE is necessary.
61 
62   Returns:      The data size after compression.
63                 If compressed data is larger than original data, compression is terminated and 0 is returned.
64  *---------------------------------------------------------------------------*/
CompressLZImpl(const u8 * srcp,u32 size,u8 * dstp,void * work,bool exFormat)65 u32 CompressLZImpl(const u8 *srcp, u32 size, u8 *dstp, void *work, bool exFormat)
66 {
67     u32     LZDstCount;                // Number of bytes of compressed data
68     u8      LZCompFlags;               // Flag sequence indicating whether there is a compression
69     u8     *LZCompFlagsp;              // Point to memory regions storing LZCompFlags
70     u16     lastOffset;                // Offset to matching data (the longest matching data at the time)
71     u32     lastLength;                // Length of matching data (the longest matching data at the time)
72     u8      i;
73     u32     dstMax;
74     LZCompressInfo info;               // Temporary LZ compression information
75     const u32 MAX_LENGTH = (exFormat)? (0xFFFF + 0xFF + 0xF + 3U) : (0xF + 3U);
76 
77     NN_ASSERT( ((u32)srcp & 0x1) == 0 );
78     NN_ASSERT( work != NULL );
79     NN_ASSERT( size > 4 );
80 
81     if ( size < (1 << 24) )
82     {
83         *(u32 *)dstp = internal::ConvertEndian( size << 8 | COMPRESSION_LZ | (exFormat? 1 : 0) );  // Data header
84         dstp += 4;
85         LZDstCount = 4;
86     }
87     else
88     // Use extended header if the size is larger than 24 bits
89     {
90         *(u32 *)dstp = internal::ConvertEndian( COMPRESSION_LZ | (exFormat? 1U : 0U) );  // Data header
91         dstp += 4;
92         *(u32 *)dstp = internal::ConvertEndian( size ); // Size extended header
93         dstp += 4;
94         LZDstCount = 8;
95     }
96     dstMax = size;
97     LZInitTable(&info, work);
98 
99     while ( size > 0 )
100     {
101         LZCompFlags = 0;
102         LZCompFlagsp = dstp++;         // Destination for storing flag sequence
103         LZDstCount++;
104 
105         // Because flag sequence is stored as 8-bit data, loop eight times
106         for ( i = 0; i < 8; i++ )
107         {
108             LZCompFlags <<= 1;         // No meaning for the first time (i=0)
109             if (size <= 0)
110             {
111                 // When reached the end, quit after shifting flag to the end
112                 continue;
113             }
114 
115             if ( (lastLength = SearchLZ( &info, srcp, size, &lastOffset, MAX_LENGTH)) != 0 )
116             {
117                 u32 length;
118                 // Enable flag if compression is possible
119                 LZCompFlags |= 0x1;
120 
121                 if (LZDstCount + 2 >= dstMax)   // Quit on error if size becomes larger than source
122                 {
123                     return 0;
124                 }
125 
126                 if ( exFormat )
127                 {
128                     if ( lastLength >= 0xFF + 0xF + 3 )
129                     {
130                         length  = (u32)( lastLength - 0xFF - 0xF - 3 );
131                         *dstp++ = (u8)( 0x10 | (length >> 12) );
132                         *dstp++ = (u8)( length >> 4 );
133                         LZDstCount += 2;
134                     }
135                     else if ( lastLength >= 0xF + 2 )
136                     {
137                         length  = (u32)( lastLength - 0xF - 2 );
138                         *dstp++ = (u8)( length >> 4 );
139                         LZDstCount += 1;
140                     }
141                     else
142                     {
143                         length = (u32)( lastLength - 1 );
144                     }
145                 }
146                 else
147                 {
148                     length = (u32)( lastLength - 3 );
149                 }
150 
151                 // Divide offset into upper 4 bits and lower 8 bits and store
152                 *dstp++ = (u8)( length << 4 | (lastOffset - 1) >> 8 );
153                 *dstp++ = (u8)( (lastOffset - 1) & 0xff);
154                 LZDstCount += 2;
155                 LZSlide(&info, srcp, lastLength);
156                 srcp += lastLength;
157                 size -= lastLength;
158             }
159             else
160             {
161                 // No compression
162                 if (LZDstCount + 1 >= dstMax)       // Quit on error if size becomes larger than source
163                 {
164                     return 0;
165                 }
166                 LZSlide(&info, srcp, 1);
167                 *dstp++ = *srcp++;
168                 size--;
169                 LZDstCount++;
170             }
171         }                              // Completed eight loops
172         *LZCompFlagsp = LZCompFlags;   // Store flag series
173     }
174 
175     // 4-byte boundary alignment
176     //   Does not include Data0 used for alignment in data size
177     i = 0;
178     while ( (LZDstCount + i) & 0x3 )
179     {
180         *dstp++ = 0;
181         i++;
182     }
183 
184     return LZDstCount;
185 }
186 
187 namespace {
188 
189 //--------------------------------------------------------
190 // With LZ77 Compression, searches for the longest matching string from the slide window.
191 //  Arguments:    startp                 Pointer to starting position of data
192 //                nextp                  Pointer to data where search will start
193 //                remainSize             Size of remaining data
194 //                offset                 Pointer to region storing matched offset
195 //  Return:    TRUE if matching string is found
196 //                FALSE if not found.
197 //--------------------------------------------------------
SearchLZ(LZCompressInfo * info,const u8 * nextp,u32 remainSize,u16 * offset,u32 maxLength)198 u32 SearchLZ( LZCompressInfo * info, const u8 *nextp, u32 remainSize, u16 *offset, u32 maxLength )
199 {
200     const u8 *searchp;
201     const u8 *headp, *searchHeadp;
202     u16     maxOffset = 0;
203     u32     currLength = 2;
204     u32     tmpLength;
205     s32     w_offset;
206     s16    *const LZOffsetTable = info->LZOffsetTable;
207     const u16 windowPos = info->windowPos;
208     const u16 windowLen = info->windowLen;
209 
210     if (remainSize < 3)
211     {
212         return 0;
213     }
214 
215     w_offset = info->LZByteTable[*nextp];
216 
217     while (w_offset != -1)
218     {
219         if (w_offset < windowPos)
220         {
221             searchp = nextp - windowPos + w_offset;
222         }
223         else
224         {
225             searchp = nextp - windowLen - windowPos + w_offset;
226         }
227 
228         /* This isn't needed, but it seems to make it a little faster */
229         if (*(searchp + 1) != *(nextp + 1) || *(searchp + 2) != *(nextp + 2))
230         {
231             w_offset = LZOffsetTable[w_offset];
232             continue;
233         }
234 
235         if (nextp - searchp < 2)
236         {
237             // Since VRAM is 2-byte access (since there are times when data is read from VRAM), the search target data must be set to data that is two bytes before that.
238             //
239             //
240             // Because the offset is stored in 12 bits, the value is 4096 or less
241             break;
242         }
243         tmpLength = 3;
244         searchHeadp = searchp + 3;
245         headp = nextp + 3;
246 
247         // Increments the compression size until the data ends or different data is encountered
248         while (((u32)(headp - nextp) < remainSize) && (*headp == *searchHeadp))
249         {
250             headp++;
251             searchHeadp++;
252             tmpLength++;
253 
254             // Because the data length is stored in 4 bits, the value is 18 or less (3 is added)
255             if (tmpLength == maxLength)
256             {
257                 break;
258             }
259         }
260 
261         if (tmpLength > currLength)
262         {
263             // Update the maximum-length offset
264             currLength = tmpLength;
265             maxOffset = (u16)(nextp - searchp);
266             if (currLength == maxLength || currLength == remainSize)
267             {
268                 // This is the longest matching length, so end search
269                 break;
270             }
271         }
272         w_offset = LZOffsetTable[w_offset];
273     }
274 
275     if (currLength < 3)
276     {
277         return 0;
278     }
279     *offset = maxOffset;
280     return currLength;
281 }
282 
283 //--------------------------------------------------------
284 // Initialize the dictionary index
285 //--------------------------------------------------------
LZInitTable(LZCompressInfo * info,void * work)286 void LZInitTable(LZCompressInfo * info, void *work)
287 {
288     u16     i;
289 
290     info->LZOffsetTable = (s16*)work;
291     info->LZByteTable   = (s16*)( (u32)work + 4096 * sizeof(s16)         );
292     info->LZEndTable    = (s16*)( (u32)work + (4096 + 256) * sizeof(s16) );
293 
294     for ( i = 0; i < 256; i++ )
295     {
296         info->LZByteTable[i] = -1;
297         info->LZEndTable [i]  = -1;
298     }
299     info->windowPos = 0;
300     info->windowLen = 0;
301 }
302 
303 //--------------------------------------------------------
304 // Slide the dictionary 1 byte
305 //--------------------------------------------------------
SlideByte(LZCompressInfo * info,const u8 * srcp)306 void SlideByte(LZCompressInfo * info, const u8 *srcp)
307 {
308     s16     offset;
309     u8      in_data = *srcp;
310     u16     insert_offset;
311 
312     s16    *const LZByteTable   = info->LZByteTable;
313     s16    *const LZOffsetTable = info->LZOffsetTable;
314     s16    *const LZEndTable    = info->LZEndTable;
315     const u16 windowPos = info->windowPos;
316     const u16 windowLen = info->windowLen;
317 
318     if (windowLen == 4096)
319     {
320         u8      out_data = *(srcp - 4096);
321         if ((LZByteTable[out_data] = LZOffsetTable[LZByteTable[out_data]]) == -1)
322         {
323             LZEndTable[out_data] = -1;
324         }
325         insert_offset = windowPos;
326     }
327     else
328     {
329         insert_offset = windowLen;
330     }
331 
332     offset = LZEndTable[in_data];
333     if (offset == -1)
334     {
335         LZByteTable[in_data] = (s16)insert_offset;
336     }
337     else
338     {
339         LZOffsetTable[offset] = (s16)insert_offset;
340     }
341     LZEndTable[in_data] = (s16)insert_offset;
342     LZOffsetTable[insert_offset] = -1;
343 
344     if (windowLen == 4096)
345     {
346         info->windowPos = (u16)((windowPos + 1) % 0x1000);
347     }
348     else
349     {
350         info->windowLen++;
351     }
352 }
353 
354 //--------------------------------------------------------
355 // Slide the dictionary n bytes
356 //--------------------------------------------------------
LZSlide(LZCompressInfo * info,const u8 * srcp,u32 n)357 inline void LZSlide(LZCompressInfo * info, const u8 *srcp, u32 n)
358 {
359     u32     i;
360 
361     for (i = 0; i < n; i++)
362     {
363         SlideByte(info, srcp++);
364     }
365 }
366 
367 }   // Namespace
368 
369 
370 //===========================================================================
371 //  Run-Length Encoding
372 //===========================================================================
373 
374 /*---------------------------------------------------------------------------*
375   Name:         CompressRL
376 
377   Description:  Performs run-length compression.
378 
379   Arguments:    srcp:            Pointer to compression source data
380                 size:            Size of compression source data
381                 dstp            Pointer to compressed data
382                                 The buffer must be larger than the size of the compression source data.
383 
384   Returns:      The data size after compression.
385                 If compressed data is larger than original data, compression is terminated and 0 is returned.
386  *---------------------------------------------------------------------------*/
CompressRL(const u8 * srcp,u32 size,u8 * dstp)387 u32 CompressRL(const u8 *srcp, u32 size, u8 *dstp)
388 {
389     u32 RLDstCount;                    // Number of bytes of compressed data
390     u32 RLSrcCount;                    // Processed data volume of the compression target data (in bytes)
391     u8  RLCompFlag;                    // 1 if performing run-length encoding
392     u8  runLength;                     // Run length
393     u8  rawDataLength;                 // Length of data not run
394     u32 i;
395 
396     const u8 *startp;                  // Point to the start of compression target data for each process loop
397 
398     NN_ASSERT( srcp != NULL );
399     NN_ASSERT( dstp != NULL );
400     NN_ASSERT( size > 4     );
401 
402     //  Data header        (The size after decompression)
403     // To create the same output data as Nitro, work on on the endian.
404     if ( size < (1 << 24) )
405     {
406         *(u32 *)dstp = internal::ConvertEndian(size << 8 | COMPRESSION_RL);       // Data header
407         RLDstCount   = 4;
408     }
409     else
410     // Use extended header if the size is larger than 24 bits
411     {
412         *(u32 *)dstp       = internal::ConvertEndian(COMPRESSION_RL);       // Data header
413         *(u32 *)(dstp + 4) = internal::ConvertEndian(size);                  // Extend header size
414         RLDstCount         = 8;
415     }
416     RLSrcCount = 0;
417     rawDataLength = 0;
418     RLCompFlag = 0;
419 
420     while (RLSrcCount < size)
421     {
422         startp = &srcp[RLSrcCount];    // Set compression target data
423 
424         for (i = 0; i < 128; i++)      // Data volume that can be expressed in 7 bits is 0 to 127
425         {
426             // Reach the end of the compression target data
427             if (RLSrcCount + rawDataLength >= size)
428             {
429                 rawDataLength = (u8)(size - RLSrcCount);
430                 break;
431             }
432 
433             if (RLSrcCount + rawDataLength + 2 < size)
434             {
435                 if (startp[i] == startp[i + 1] && startp[i] == startp[i + 2])
436                 {
437                     RLCompFlag = 1;
438                     break;
439                 }
440             }
441             rawDataLength++;
442         }
443 
444         // Store data that will not be encoded
445         // If the 8th bit of the data length storage byte is 0, the data sequence that is not encoded.
446         // The data length is x - 1, so 0-127 becomes 1-128.
447         if (rawDataLength)
448         {
449             if (RLDstCount + rawDataLength + 1 >= size) // Quit on error if size becomes larger than source
450             {
451                 return 0;
452             }
453             dstp[RLDstCount++] = (u8)(rawDataLength - 1);       // Store "data length - 1" (7 bits)
454             for (i = 0; i < rawDataLength; i++)
455             {
456                 dstp[RLDstCount++] = srcp[RLSrcCount++];
457             }
458             rawDataLength = 0;
459         }
460 
461         // Run-Length Encoding
462         if (RLCompFlag)
463         {
464             runLength = 3;
465             for (i = 3; i < 128 + 2; i++)
466             {
467                 // Reach the end of the data for compression
468                 if (RLSrcCount + runLength >= size)
469                 {
470                     runLength = (u8)(size - RLSrcCount);
471                     break;
472                 }
473 
474                 // If run is interrupted
475                 if (srcp[RLSrcCount] != srcp[RLSrcCount + runLength])
476                 {
477                     break;
478                 }
479                 // Run continues
480                 runLength++;
481             }
482 
483             // If the 8th bit of the data length storage byte is 1, the data sequence that is encoded
484             if (RLDstCount + 2 >= size) // Quit on error if size becomes larger than source
485             {
486                 return 0;
487             }
488             dstp[RLDstCount++] = (u8)(0x80 | (runLength - 3));  // Add 3, and store from 3 to 130
489             dstp[RLDstCount++] = srcp[RLSrcCount];
490             RLSrcCount += runLength;
491             RLCompFlag = 0;
492         }
493     }
494 
495     // 4-byte boundary alignment
496     //   Does not include Data0 used for alignment in data size
497     i = 0;
498     while ((RLDstCount + i) & 0x3)
499     {
500         dstp[RLDstCount + i] = 0;
501         i++;
502     }
503     return RLDstCount;
504 }
505 
506 
507 //===========================================================================
508 //  Huffman encoding
509 //===========================================================================
510 #define HUFF_END_L  0x80
511 #define HUFF_END_R  0x40
512 
513 namespace {
514 
515 struct HuffData
516 {
517     u32 Freq;                          // Frequency of occurrence
518     u16 No;                            // Data number
519     s16 PaNo;                          // Parent number
520     s16 ChNo[2];                       // Child Number (0: left side, 1: right side)
521     u16 PaDepth;                       // Parent node depth
522     u16 LeafDepth;                     // Depth to leaf
523     u32 HuffCode;                      // Huffman code
524     u8  Bit;                           // Node's bit data
525     u8  _padding;
526     u16 HWord;                         // For each intermediate node, the amount of memory needed to store in HuffTree the subtree that has that node as its root
527 };
528                                        // Total of 24 bytes
529 
530 struct HuffTreeCtrlData
531 {
532     u8  leftOffsetNeed;                // 1 if offset to left child node is required
533     u8  rightOffsetNeed;               // 1 if an offset to the right child node is required
534     u16 leftNodeNo;                    // The left child node number
535     u16 rightNodeNo;                   // Right child node number
536 };
537                                        // Total of 6 bytes
538 
539 // Structure of the Huffman work buffer
540 struct HuffCompressionInfo
541 {
542     HuffData         *huffTable;    //  huffTable[ 512 ];      12288B
543     u8               *huffTree;     //  huffTree[ 256 * 2 ];     512B
544     HuffTreeCtrlData *huffTreeCtrl; //  huffTreeCtrl[ 256 ];    1536B
545     u8               huffTreeTop;   //
546     u8               padding_[3];   //
547 };
548                                     // Total is 14340B
549 
550 void HuffInitTable( HuffCompressionInfo* info, void* work, u16 dataNum );
551 void HuffCountData( HuffData* table, const u8 *srcp, u32 size, u8 bitSize );
552 u16  HuffConstructTree( HuffData* table, u32 dataNum );
553 u32  HuffConvertData( const HuffData *table, const u8* srcp, u8* dstp, u32 srcSize, u32 maxSize, u8 bitSize );
554 
555 void HuffAddParentDepthToTable( HuffData *table, u16 leftNo, u16 rightNo );
556 void HuffAddCodeToTable       ( HuffData *table, u16 nodeNo, u32 paHuffCode );
557 u8   HuffAddCountHWordToTable ( HuffData *table, u16 nodeNo );
558 
559 void HuffMakeHuffTree             ( HuffCompressionInfo* info, u16 rootNo );
560 void HuffMakeSubsetHuffTree       ( HuffCompressionInfo* info, u16 huffTreeNo, u8 rightNodeFlag );
561 u8   HuffRemainingNodeCanSetOffset( HuffCompressionInfo* info, u8  costHWord );
562 void HuffSetOneNodeOffset         ( HuffCompressionInfo* info, u16 huffTreeNo, u8 rightNodeFlag );
563 
564 }   // Namespace
565 
566 
567 /*---------------------------------------------------------------------------*
568   Name:         CompressHuffman
569 
570   Description:  Performs Huffman compression.
571 
572   Arguments:    srcp:            Pointer to compression source data
573                 size:            Size of compression source data
574                 dstp            Pointer to compressed data
575                                 The buffer must be larger than the size of the compression source data.
576                 huffBitSize     The number of bits to encode
577                 work            Work buffer for Huffman compression
578 
579   Returns:      The data size after compression.
580                 If compressed data is larger than original data, compression is terminated and 0 is returned.
581  *---------------------------------------------------------------------------*/
CompressHuffman(const u8 * srcp,u32 size,u8 * dstp,u8 huffBitSize,void * work)582 u32 CompressHuffman( const u8 *srcp, u32 size, u8 *dstp, u8 huffBitSize, void *work )
583 {
584     u32 huffDstCount;                  // Number of bytes of compressed data
585     s32 i;
586     u16 rootNo;                        // Binary tree's root number
587     u16 huffDataNum  = (u16)(1 << huffBitSize);      // 8->256, 4->16
588     u32 tableOffset;
589     HuffCompressionInfo info;
590 
591     NN_ASSERT( srcp != NULL );
592     NN_ASSERT( dstp != NULL );
593     NN_ASSERT( huffBitSize == 4 || huffBitSize == 8 );
594     NN_ASSERT( work != NULL );
595     NN_ASSERT( ((u32)work & 0x3) == 0 );
596     NN_ASSERT( size > 4 );
597 
598     // Initialize table
599     HuffInitTable( &info, work, huffDataNum );
600 
601     // Check frequency of occurrence
602     HuffCountData( info.huffTable, srcp, size, huffBitSize );
603 
604     // Create tree table
605     rootNo = HuffConstructTree( info.huffTable, huffDataNum );
606 
607     // Create HuffTree
608     HuffMakeHuffTree( &info, rootNo );
609     info.huffTree[0] = --info.huffTreeTop;
610 
611     // Data header
612     // To create the same compression data as Nitro, work on the endian.
613     if ( size < (1 << 24) )
614     {
615         *(u32 *)dstp = internal::ConvertEndian(size << 8 | COMPRESSION_HUFFMAN | huffBitSize);
616         tableOffset  = 4;
617     }
618     else
619     // Use extended header if the size is larger than 24 bits
620     {
621         *(u32 *)dstp       = internal::ConvertEndian( (u32)(COMPRESSION_HUFFMAN | huffBitSize) );
622         *(u32 *)(dstp + 4) = internal::ConvertEndian( size );
623         tableOffset        = 8;
624     }
625     huffDstCount = tableOffset;
626 
627     if ( huffDstCount + (info.huffTreeTop + 1) * 2 >= size )   // Quit on error if size becomes larger than source
628     {
629         return 0;
630     }
631 
632     for ( i = 0; i < (u16)( (info.huffTreeTop + 1) * 2 ); i++ )  // Tree table
633     {
634         dstp[ huffDstCount++ ] = ((u8*)info.huffTree)[ i ];
635     }
636 
637     // 4-byte boundary alignment
638     //   Data0 used for alignment is included in data size (as per the decoder algorithm)
639     while ( huffDstCount & 0x3 )
640     {
641         if ( huffDstCount & 0x1 )
642         {
643             info.huffTreeTop++;
644             dstp[ tableOffset ]++;
645         }
646         dstp[ huffDstCount++ ] = 0;
647     }
648 
649     // Data conversion via the Huffman table
650     {
651         u32 convSize = HuffConvertData( info.huffTable, srcp, &dstp[ huffDstCount ], size, size - huffDstCount, huffBitSize );
652         if ( convSize == 0 )
653         {
654             // Compression fails because the compressed data is larger than the source
655             return 0;
656         }
657         huffDstCount += convSize;
658     }
659 
660     return huffDstCount;
661 }
662 
663 namespace {
664 
665 /*---------------------------------------------------------------------------*
666   Name:         HuffInitTable
667   Description:  Initializes the Huffman table.
668   Arguments:    table
669                 size
670   Returns:      None.
671  *---------------------------------------------------------------------------*/
HuffInitTable(HuffCompressionInfo * info,void * work,u16 dataNum)672 void HuffInitTable( HuffCompressionInfo* info, void* work, u16 dataNum )
673 {
674     u32 i;
675     info->huffTable    = (HuffData*)(work);
676     info->huffTree     = (u8*)( (u32)work + sizeof(HuffData) * 512 );
677     info->huffTreeCtrl = (HuffTreeCtrlData*)( (u32)info->huffTree + sizeof(u8) * 512 );
678     info->huffTreeTop  = 1;
679 
680     // Initialize huffTable
681     {
682         HuffData* table = info->huffTable;
683 
684         const HuffData  HUFF_TABLE_INIT_DATA  = { 0, 0, 0, {-1, -1}, 0, 0, 0, 0, 0 };
685         for ( i = 0; i < dataNum * 2U; i++ )
686         {
687             table[ i ]    = HUFF_TABLE_INIT_DATA;
688             table[ i ].No = (u16)i;
689         }
690     }
691 
692     // Initialize huffTree and huffTreeCtrl
693     {
694         const HuffTreeCtrlData HUFF_TREE_CTRL_INIT_DATA = { 1, 1, 0, 0 };
695         u8*               huffTree     = info->huffTree;
696         HuffTreeCtrlData* huffTreeCtrl = info->huffTreeCtrl;
697 
698         for ( i = 0; i < 256; i++ )
699         {
700             huffTree[ i * 2 ]     = 0;
701             huffTree[ i * 2 + 1 ] = 0;
702             huffTreeCtrl[ i ]     = HUFF_TREE_CTRL_INIT_DATA;
703         }
704     }
705 }
706 
707 
708 /*---------------------------------------------------------------------------*
709   Name:         HuffCountData
710   Description:  Count of frequency of appearance.
711   Arguments:    table
712                 *srcp
713                 size
714                 bitSize
715   Returns:      None.
716  *---------------------------------------------------------------------------*/
HuffCountData(HuffData * table,const u8 * srcp,u32 size,u8 bitSize)717 void HuffCountData( HuffData* table, const u8 *srcp, u32 size, u8 bitSize )
718 {
719     u32 i;
720     u8  tmp;
721 
722     if ( bitSize == 8 )
723     {
724         for ( i = 0; i < size; i++ )
725         {
726             table[ srcp[ i ] ].Freq++; // 8-bit encoding
727         }
728     }
729     else
730     {
731         for ( i = 0; i < size; i++ )   // 4-bit encoding
732         {
733             tmp = (u8)( (srcp[ i ] & 0xf0) >> 4 );
734             table[ tmp ].Freq++;       // Store from upper 4 bits first // Either is OK
735             tmp = (u8)( srcp[ i ] & 0x0f );
736             table[ tmp ].Freq++;       // The problem is the encoding
737         }
738     }
739 }
740 
741 
742 /*---------------------------------------------------------------------------*
743   Name:         HuffConstructTree
744   Description:  Constructs a Huffman tree
745   Arguments:    *table
746                 dataNum
747   Returns:      None.
748  *---------------------------------------------------------------------------*/
HuffConstructTree(HuffData * table,u32 dataNum)749 u16 HuffConstructTree( HuffData *table, u32 dataNum )
750 {
751     s32     i;
752     s32     leftNo, rightNo;         // Node number for creating binary tree
753     u16     tableTop = (u16)dataNum; // When creating table, the table top number
754     u16     rootNo;                  // Binary tree's root number
755     // u16     nodeNum;             // Number of valid nodes (unreferenced)
756 
757     leftNo  = -1;
758     rightNo = -1;
759     while ( 1 )
760     {
761         // Search for two subtree vertices with low Freq value. At least one should be found.
762         // Search child node (left)
763         for ( i = 0; i < tableTop; i++ )
764         {
765             if ( ( table[i].Freq == 0 ) ||
766                  ( table[i].PaNo != 0 ) )
767             {
768                 continue;
769             }
770 
771             if ( leftNo < 0 )
772             {
773                 leftNo = i;
774             }
775             else if ( table[i].Freq < table[ leftNo ].Freq )
776             {
777                 leftNo = i;
778             }
779         }
780 
781         // Search child node (right)
782         for ( i = 0; i < tableTop; i++ )
783         {
784             if ( ( table[i].Freq == 0 ) ||
785                  ( table[i].PaNo != 0 ) ||
786                  ( i == leftNo ) )
787             {
788                 continue;
789             }
790 
791             if ( rightNo < 0 )
792             {
793                 rightNo = i;
794             }
795             else if ( table[i].Freq < table[rightNo].Freq )
796             {
797                 rightNo = i;
798             }
799         }
800 
801         // If only one, then end table creation
802         if ( rightNo < 0 )
803         {
804             // When only one type of value exists or doesn't exist, then create one node that takes the same value for both 0 and 1
805             if ( tableTop == dataNum )
806             {
807                 table[ tableTop ].Freq      = table[ leftNo ].Freq;
808                 table[ tableTop ].ChNo[0]   = (s16)leftNo;
809                 table[ tableTop ].ChNo[1]   = (s16)leftNo;
810                 table[ tableTop ].LeafDepth = 1;
811                 table[ leftNo   ].PaNo      = (s16)tableTop;
812                 table[ leftNo   ].Bit       = 0;
813                 table[ leftNo   ].PaDepth   = 1;
814             }
815             else
816             {
817                 tableTop--;
818             }
819             rootNo  = tableTop;
820             // nodeNum = (u16)( (rootNo - dataNum + 1) * 2 + 1 ); // Commented out due to non-reference
821             break;
822         }
823 
824         // Create vertex that combines left subtree and right subtree
825         table[ tableTop ].Freq = table[ leftNo ].Freq + table[ rightNo ].Freq;
826         table[ tableTop ].ChNo[0] = (s16)leftNo;
827         table[ tableTop ].ChNo[1] = (s16)rightNo;
828         if ( table[ leftNo ].LeafDepth > table[ rightNo ].LeafDepth )
829         {
830             table[ tableTop ].LeafDepth = (u16)( table[ leftNo ].LeafDepth + 1 );
831         }
832         else
833         {
834             table[ tableTop ].LeafDepth = (u16)( table[ rightNo ].LeafDepth + 1 );
835         }
836 
837         table[ leftNo  ].PaNo = table[ rightNo ].PaNo = (s16)(tableTop);
838         table[ leftNo  ].Bit  = 0;
839         table[ rightNo ].Bit  = 1;
840 
841         HuffAddParentDepthToTable( table, (u16)leftNo, (u16)rightNo );
842 
843         tableTop++;
844         leftNo = rightNo = -1;
845     }
846 
847     // Generate Huffman code (In Table[i].HuffCode)
848     HuffAddCodeToTable( table, rootNo, 0x00 );        // The Huffman code is the code with HuffCode's lower bit masked for PaDepth bits
849 
850     // For each intermediate node, calculate the amount of memory needed to store the subtree that has that node as the root in HuffTree.
851     HuffAddCountHWordToTable( table, rootNo );
852 
853     return rootNo;
854 }
855 
856 //-----------------------------------------------------------------------
857 // When creating binary tree and when combining subtrees, add 1 to the depth of every node in the subtree.
858 //-----------------------------------------------------------------------
HuffAddParentDepthToTable(HuffData * table,u16 leftNo,u16 rightNo)859 void HuffAddParentDepthToTable( HuffData *table, u16 leftNo, u16 rightNo )
860 {
861     table[ leftNo  ].PaDepth++;
862     table[ rightNo ].PaDepth++;
863 
864     if ( table[ leftNo ].LeafDepth != 0 )
865     {
866         HuffAddParentDepthToTable( table, (u16)table[ leftNo  ].ChNo[0], (u16)table[ leftNo  ].ChNo[1] );
867     }
868     if ( table[ rightNo ].LeafDepth != 0 )
869     {
870         HuffAddParentDepthToTable( table, (u16)table[ rightNo ].ChNo[0], (u16)table[ rightNo ].ChNo[1] );
871     }
872 }
873 
874 //-----------------------------------------------------------------------
875 // Create Huffman code
876 //-----------------------------------------------------------------------
HuffAddCodeToTable(HuffData * table,u16 nodeNo,u32 paHuffCode)877 void HuffAddCodeToTable( HuffData* table, u16 nodeNo, u32 paHuffCode )
878 {
879     table[ nodeNo ].HuffCode = (paHuffCode << 1) | table[ nodeNo ].Bit;
880 
881     if ( table[ nodeNo ].LeafDepth != 0 )
882     {
883         HuffAddCodeToTable( table, (u16)table[ nodeNo ].ChNo[0], table[ nodeNo ].HuffCode );
884         HuffAddCodeToTable( table, (u16)table[ nodeNo ].ChNo[1], table[ nodeNo ].HuffCode );
885     }
886 }
887 
888 
889 //-----------------------------------------------------------------------
890 // Data volume required of intermediate node to create HuffTree
891 //-----------------------------------------------------------------------
HuffAddCountHWordToTable(HuffData * table,u16 nodeNo)892 u8 HuffAddCountHWordToTable( HuffData *table, u16 nodeNo)
893 {
894     u8      leftHWord, rightHWord;
895 
896     switch ( table[ nodeNo ].LeafDepth )
897     {
898     case 0:
899         return 0;
900     case 1:
901         leftHWord = rightHWord = 0;
902         break;
903     default:
904         leftHWord  = HuffAddCountHWordToTable( table, (u16)table[nodeNo].ChNo[0] );
905         rightHWord = HuffAddCountHWordToTable( table, (u16)table[nodeNo].ChNo[1] );
906         break;
907     }
908 
909     table[ nodeNo ].HWord = (u16)( leftHWord + rightHWord + 1 );
910     return (u8)( leftHWord + rightHWord + 1 );
911 }
912 
913 
914 //-----------------------------------------------------------------------
915 // Create Huffman code table
916 //-----------------------------------------------------------------------
HuffMakeHuffTree(HuffCompressionInfo * info,u16 rootNo)917 void HuffMakeHuffTree( HuffCompressionInfo* info, u16 rootNo )
918 {
919     s16 i;
920     s16 costHWord, tmpCostHWord;       // Make subtree code table for most-costly node when subtree code table has not been created.
921     s16 costOffsetNeed, tmpCostOffsetNeed;
922     s16 costMaxKey, costMaxRightFlag = 0;  // Information for singling out the least costly node from HuffTree
923     u8  offsetNeedNum;
924     // u8  tmpKey; // Unreferenced
925     u8  tmpRightFlag;
926 
927     info->huffTreeTop = 1;
928     costOffsetNeed    = 0;
929 
930     info->huffTreeCtrl[0].leftOffsetNeed = 0; // Do not use (used as table size)
931     info->huffTreeCtrl[0].rightNodeNo    = rootNo;
932 
933     while ( 1 )                          // Until return
934     {
935         // Calculate the number of nodes required to set offset
936         offsetNeedNum = 0;
937         for ( i = 0; i < info->huffTreeTop; i++ )
938         {
939             if ( info->huffTreeCtrl[ i ].leftOffsetNeed )
940             {
941                 offsetNeedNum++;
942             }
943             if ( info->huffTreeCtrl[ i ].rightOffsetNeed )
944             {
945                 offsetNeedNum++;
946             }
947         }
948 
949         // Search for node with greatest cost
950         costHWord    = -1;
951         costMaxKey   = -1;
952         // tmpKey       =  0; // Commented out because unreferenced
953         tmpRightFlag =  0;
954 
955         for ( i = 0; i < info->huffTreeTop; i++ )
956         {
957             tmpCostOffsetNeed = (u8)( info->huffTreeTop - i );
958 
959             // Evaluate cost of left child node
960             if (info->huffTreeCtrl[i].leftOffsetNeed)
961             {
962                 tmpCostHWord = (s16)info->huffTable[ info->huffTreeCtrl[i].leftNodeNo ].HWord;
963 
964                 if ( (tmpCostHWord + offsetNeedNum) > 64 )
965                 {
966                     goto leftCostEvaluationEnd;
967                 }
968                 if ( ! HuffRemainingNodeCanSetOffset( info, (u8)tmpCostHWord ) )
969                 {
970                     goto leftCostEvaluationEnd;
971                 }
972                 if ( tmpCostHWord > costHWord )
973                 {
974                     costMaxKey = i;
975                     costMaxRightFlag = 0;
976                 }
977                 else if ( (tmpCostHWord == costHWord) && (tmpCostOffsetNeed > costOffsetNeed) )
978                 {
979                     costMaxKey = i;
980                     costMaxRightFlag = 0;
981                 }
982             }
983 leftCostEvaluationEnd:{}
984 
985             // Evaluate cost of right child node
986             if ( info->huffTreeCtrl[i].rightOffsetNeed)
987             {
988                 tmpCostHWord = (s16)info->huffTable[info->huffTreeCtrl[i].rightNodeNo].HWord;
989 
990                 if ( (tmpCostHWord + offsetNeedNum) > 64 )
991                 {
992                     goto rightCostEvaluationEnd;
993                 }
994                 if ( ! HuffRemainingNodeCanSetOffset( info, (u8)tmpCostHWord ) )
995                 {
996                     goto rightCostEvaluationEnd;
997                 }
998                 if ( tmpCostHWord > costHWord )
999                 {
1000                     costMaxKey = i;
1001                     costMaxRightFlag = 1;
1002                 }
1003                 else if ( (tmpCostHWord == costHWord) && (tmpCostOffsetNeed > costOffsetNeed) )
1004                 {
1005                     costMaxKey = i;
1006                     costMaxRightFlag = 1;
1007                 }
1008             }
1009 rightCostEvaluationEnd:{}
1010         }
1011 
1012         // Store entire subtree in HuffTree
1013         if ( costMaxKey >= 0 )
1014         {
1015             HuffMakeSubsetHuffTree( info, (u8)costMaxKey, (u8)costMaxRightFlag);
1016             goto nextTreeMaking;
1017         }
1018         else
1019         {
1020             // Search for node with largest required offset
1021             for ( i = 0; i < info->huffTreeTop; i++ )
1022             {
1023                 u16 tmp = 0;
1024                 tmpRightFlag = 0;
1025                 if (info->huffTreeCtrl[i].leftOffsetNeed)
1026                 {
1027                     tmp = info->huffTable[ info->huffTreeCtrl[i].leftNodeNo ].HWord;
1028                 }
1029                 if (info->huffTreeCtrl[i].rightOffsetNeed)
1030                 {
1031                     if ( info->huffTable[info->huffTreeCtrl[i].rightNodeNo ].HWord > tmp )
1032                     {
1033                         tmpRightFlag = 1;
1034                     }
1035                 }
1036                 if ( (tmp != 0) || (tmpRightFlag) )
1037                 {
1038                     HuffSetOneNodeOffset( info, (u8)i, tmpRightFlag);
1039                     goto nextTreeMaking;
1040                 }
1041             }
1042         }
1043         return;
1044 nextTreeMaking:{}
1045     }
1046 }
1047 
1048 //-----------------------------------------------------------------------
1049 // Store entire subtree in HuffTree
1050 //-----------------------------------------------------------------------
HuffMakeSubsetHuffTree(HuffCompressionInfo * info,u16 huffTreeNo,u8 rightNodeFlag)1051 void HuffMakeSubsetHuffTree( HuffCompressionInfo* info, u16 huffTreeNo, u8 rightNodeFlag )
1052 {
1053     u8  i;
1054 
1055     i = info->huffTreeTop;
1056     HuffSetOneNodeOffset( info, huffTreeNo, rightNodeFlag);
1057 
1058     if ( rightNodeFlag )
1059     {
1060         info->huffTreeCtrl[ huffTreeNo ].rightOffsetNeed = 0;
1061     }
1062     else
1063     {
1064         info->huffTreeCtrl[ huffTreeNo ].leftOffsetNeed = 0;
1065     }
1066 
1067     while ( i < info->huffTreeTop )
1068     {
1069         if ( info->huffTreeCtrl[ i ].leftOffsetNeed )
1070         {
1071             HuffSetOneNodeOffset( info, i, 0);
1072             info->huffTreeCtrl[ i ].leftOffsetNeed = 0;
1073         }
1074         if ( info->huffTreeCtrl[ i ].rightOffsetNeed )
1075         {
1076             HuffSetOneNodeOffset( info, i, 1);
1077             info->huffTreeCtrl[ i ].rightOffsetNeed = 0;
1078         }
1079         i++;
1080     }
1081 }
1082 
1083 //-----------------------------------------------------------------------
1084 // Check if there is any problems with huffTree construction if subtree of obtained data size is decompressed.
1085 //-----------------------------------------------------------------------
HuffRemainingNodeCanSetOffset(HuffCompressionInfo * info,u8 costHWord)1086 u8 HuffRemainingNodeCanSetOffset( HuffCompressionInfo* info, u8 costHWord )
1087 {
1088     u8  i;
1089     s16 capacity;
1090 
1091     capacity = (s16)( 64 - costHWord );
1092 
1093     // The offset value is larger for smaller values of i, so you should calculate without sorting, with i=0 -> huffTreeTop
1094     for ( i = 0; i < info->huffTreeTop; i++ )
1095     {
1096         if ( info->huffTreeCtrl[i].leftOffsetNeed )
1097         {
1098             if ( (info->huffTreeTop - i) <= capacity )
1099             {
1100                 capacity--;
1101             }
1102             else
1103             {
1104                 return 0;
1105             }
1106         }
1107         if ( info->huffTreeCtrl[i].rightOffsetNeed )
1108         {
1109             if ( (info->huffTreeTop - i) <= capacity )
1110             {
1111                 capacity--;
1112             }
1113             else
1114             {
1115                 return 0;
1116             }
1117         }
1118     }
1119 
1120     return 1;
1121 }
1122 
1123 /*---------------------------------------------------------------------------*
1124   Name:         HuffSetOneNodeOffset
1125   Description:  Create Huffman code table for one node
1126   Arguments:    *info           Pointer to data for constructing a Huffman tree
1127                 huffTreeNo
1128                 rightNodeFlag   Flag for whether node is at right
1129   Returns:      None.
1130  *---------------------------------------------------------------------------*/
HuffSetOneNodeOffset(HuffCompressionInfo * info,u16 huffTreeNo,u8 rightNodeFlag)1131 void HuffSetOneNodeOffset( HuffCompressionInfo* info, u16 huffTreeNo, u8 rightNodeFlag )
1132 {
1133     u16 nodeNo;
1134     u8  offsetData = 0;
1135 
1136     HuffData*         huffTable    = info->huffTable;
1137     u8*               huffTree     = info->huffTree;
1138     HuffTreeCtrlData* huffTreeCtrl = info->huffTreeCtrl;
1139     u8                huffTreeTop  = info->huffTreeTop;
1140 
1141     if (rightNodeFlag)
1142     {
1143         nodeNo = huffTreeCtrl[ huffTreeNo ].rightNodeNo;
1144         huffTreeCtrl[ huffTreeNo ].rightOffsetNeed = 0;
1145     }
1146     else
1147     {
1148         nodeNo = huffTreeCtrl[ huffTreeNo ].leftNodeNo;
1149         huffTreeCtrl [huffTreeNo ].leftOffsetNeed = 0;
1150     }
1151 
1152     // Left child node
1153     if ( huffTable[ huffTable[nodeNo].ChNo[0] ].LeafDepth == 0)
1154     {
1155         offsetData |= 0x80;
1156         huffTree[ huffTreeTop * 2 + 0 ] = (u8)huffTable[ nodeNo ].ChNo[0];
1157         huffTreeCtrl[ huffTreeTop ].leftNodeNo = (u8)huffTable[ nodeNo ].ChNo[0];
1158         huffTreeCtrl[ huffTreeTop ].leftOffsetNeed = 0;   // Offset no longer required
1159     }
1160     else
1161     {
1162         huffTreeCtrl[ huffTreeTop ].leftNodeNo = (u16)huffTable[ nodeNo ].ChNo[0];  // Offset is required
1163     }
1164 
1165     // Right child node
1166     if ( huffTable[ huffTable[ nodeNo ].ChNo[1] ].LeafDepth == 0 )
1167     {
1168         offsetData |= 0x40;
1169         huffTree[ huffTreeTop * 2 + 1 ] = (u8)huffTable[nodeNo].ChNo[1];
1170         huffTreeCtrl[ huffTreeTop ].rightNodeNo = (u8)huffTable[ nodeNo ].ChNo[1];
1171         huffTreeCtrl[ huffTreeTop ].rightOffsetNeed = 0;  // Offset no longer required
1172     }
1173     else
1174     {
1175         huffTreeCtrl[ huffTreeTop ].rightNodeNo = (u16)huffTable[ nodeNo ].ChNo[1]; // Offset is required
1176     }
1177 
1178     offsetData |= (u8)( huffTreeTop - huffTreeNo - 1 );
1179     huffTree[ huffTreeNo * 2 + rightNodeFlag ] = offsetData;
1180 
1181     info->huffTreeTop++;
1182 }
1183 
1184 
1185 /*---------------------------------------------------------------------------*
1186   Name:         HuffConvertData
1187   Description:  Data conversion based on Huffman table.
1188   Arguments:    *table
1189                 srcp
1190                 dstp
1191                 srcSize
1192                 bitSize
1193   Returns:      None.
1194  *---------------------------------------------------------------------------*/
HuffConvertData(const HuffData * table,const u8 * srcp,u8 * dstp,u32 srcSize,u32 maxSize,u8 bitSize)1195 u32 HuffConvertData( const HuffData *table, const u8* srcp, u8* dstp, u32 srcSize, u32 maxSize, u8 bitSize )
1196 {
1197     u32     i, ii, iii;
1198     u8      srcTmp;
1199     u32     bitStream    = 0;
1200     u32     streamLength = 0;
1201     u32     dstSize      = 0;
1202 
1203     // Huffman encoding
1204     for ( i = 0; i < srcSize; i++ )
1205     {                                  // Data compression
1206         u8 val = srcp[ i ];
1207         if ( bitSize == 8 )
1208         {                              // 8-bit Huffman
1209             bitStream = (bitStream << table[ val ].PaDepth) | table[ val ].HuffCode;
1210             streamLength += table[ val ].PaDepth;
1211 
1212             if ( dstSize + (streamLength / 8) >= maxSize )
1213             {
1214                 // Error if size becomes larger than source
1215                 return 0;
1216             }
1217 
1218             for ( ii = 0; ii < streamLength / 8; ii++ )
1219             {
1220                 dstp[ dstSize++ ] = (u8)(bitStream >> (streamLength - (ii + 1) * 8));
1221             }
1222             streamLength %= 8;
1223         }
1224         else                           // 4-bit Huffman
1225         {
1226             for ( ii = 0; ii < 2; ii++ )
1227             {
1228                 if ( ii )
1229                 {
1230                     srcTmp = (u8)( val >> 4 );     // First four bits come later
1231                 }
1232                 else
1233                 {
1234                     srcTmp = (u8)( val & 0x0F );   // Last four bits come first (because the decoder accesses in a Little-Endian method)
1235                 }
1236                 bitStream = (bitStream << table[ srcTmp ].PaDepth) | table[ srcTmp ].HuffCode;
1237                 streamLength += table[ srcTmp ].PaDepth;
1238                 if ( dstSize + (streamLength / 8) >= maxSize )
1239                 {
1240                     // Error if size becomes larger than source
1241                     return 0;
1242                 }
1243                 for ( iii = 0; iii < streamLength / 8; iii++ )
1244                 {
1245                     dstp[ dstSize++ ] = (u8)(bitStream >> (streamLength - (iii + 1) * 8));
1246                 }
1247                 streamLength %= 8;
1248             }
1249         }
1250     }
1251 
1252     if ( streamLength != 0 )
1253     {
1254         if ( dstSize + 1 >= maxSize )
1255         {
1256             // Error if size becomes larger than source
1257             return 0;
1258         }
1259         dstp[ dstSize++ ] = (u8)( bitStream << (8 - streamLength) );
1260     }
1261 
1262     // 4-byte boundary alignment
1263     //   Data0 for alignment is included in data size
1264     //   This is special to Huffman encoding!  Data is stored after the alignment-boundary data because little endian conversion is used.
1265     while ( dstSize & 0x3 )
1266     {
1267         dstp[ dstSize++ ] = 0;
1268     }
1269 
1270     // Little endian conversion
1271     for ( i = 0; i < dstSize / 4; i++ )
1272     {
1273         u8 tmp;
1274         tmp = dstp[i * 4 + 0];
1275         dstp[i * 4 + 0] = dstp[i * 4 + 3];
1276         dstp[i * 4 + 3] = tmp;         // Swap
1277         tmp = dstp[i * 4 + 1];
1278         dstp[i * 4 + 1] = dstp[i * 4 + 2];
1279         dstp[i * 4 + 2] = tmp;         // Swap
1280     }
1281     return dstSize;
1282 }
1283 
1284 }   // Namespace
1285 }   // namespace cx
1286 }   // namespace nn
1287 
1288 
1289 #include "zutil.h"
1290 #include "zlib.h"
1291 #include "deflate.h"
1292 
1293 namespace nn {
1294 namespace cx {
1295 
1296     namespace
1297     {
1298         const int MEM_LEVEL = MAX_MEM_LEVEL - 1;
1299 
1300         void ZlibStaticAssert() NN_IS_UNUSED_VAR;
ZlibStaticAssert()1301         void ZlibStaticAssert()
1302         {
1303             NN_STATIC_ASSERT( sizeof(deflate_state)
1304                             + (1 << (MAX_WBITS + 2))
1305                             + (1 << (MEM_LEVEL + 9))
1306                             == GZIP_COMPRESS_WORK_SIZE );
1307             NN_STATIC_ASSERT( sizeof(deflate_state) == 5828 );
1308             NN_STATIC_ASSERT( MAX_WBITS == 15 );
1309             NN_STATIC_ASSERT( MAX_MEM_LEVEL == 9 );
1310         }
1311 
CompressDeflateCommon(void * pDest,size_t destSize,const void * pSrc,size_t srcSize,void * pWork,int wbits)1312         s32 CompressDeflateCommon( void* pDest, size_t destSize, const void* pSrc, size_t srcSize, void* pWork, int wbits )
1313         {
1314             NN_POINTER_TASSERT_(pDest);
1315             NN_POINTER_TASSERT_(pSrc);
1316             NN_POINTER_TASSERT_(pWork);
1317 
1318             detail::ZlibAllocator za(pWork, GZIP_COMPRESS_WORK_SIZE);
1319             z_stream s;
1320             int err;
1321 
1322             s.next_in   = reinterpret_cast<nncxZlib_Bytef*>(const_cast<void*>(pSrc));
1323             s.avail_in  = srcSize;
1324             s.next_out  = reinterpret_cast<nncxZlib_Bytef*>(pDest);
1325             s.avail_out = destSize;
1326 
1327             s.zalloc    = detail::ZlibAllocator::Allocate;
1328             s.zfree     = detail::ZlibAllocator::Free;
1329             s.opaque    = &za;
1330 
1331             err = deflateInit2(&s,
1332                     Z_DEFAULT_COMPRESSION,
1333                     Z_DEFLATED,
1334                     wbits,
1335                     MEM_LEVEL,
1336                     Z_DEFAULT_STRATEGY );
1337             if (err != Z_OK)
1338             {
1339                 return detail::ConvertZlibReturnCode(err);
1340             }
1341 
1342             err = nncxZlib_deflate(&s, Z_FINISH);
1343             if (err != Z_STREAM_END)
1344             {
1345                 nncxZlib_deflateEnd(&s);
1346                 return detail::ConvertZlibReturnCode(err);
1347             }
1348 
1349             size_t ret = s.total_out;
1350 
1351             err = nncxZlib_deflateEnd(&s);
1352             if (err != Z_OK)
1353             {
1354                 return detail::ConvertZlibReturnCode(err);
1355             }
1356 
1357             return ret;
1358         }
1359     }
1360 
CompressGzip(void * pDest,size_t destSize,const void * pSrc,size_t srcSize,void * pWork)1361 s32 CompressGzip( void* pDest, size_t destSize, const void* pSrc, size_t srcSize, void* pWork )
1362 {
1363     NN_POINTER_TASSERT_(pDest);
1364     NN_POINTER_TASSERT_(pSrc);
1365     NN_POINTER_TASSERT_(pWork);
1366 
1367     const int wbits = MAX_WBITS + 16;       // Specify +16 = gzip format
1368     return CompressDeflateCommon(pDest, destSize, pSrc, srcSize, pWork, wbits);
1369 }
1370 
CompressZlib(void * pDest,size_t destSize,const void * pSrc,size_t srcSize,void * pWork)1371 s32 CompressZlib( void* pDest, size_t destSize, const void* pSrc, size_t srcSize, void* pWork )
1372 {
1373     NN_POINTER_TASSERT_(pDest);
1374     NN_POINTER_TASSERT_(pSrc);
1375     NN_POINTER_TASSERT_(pWork);
1376 
1377     return CompressDeflateCommon(pDest, destSize, pSrc, srcSize, pWork, MAX_WBITS);
1378 }
1379 
CompressDeflate(void * pDest,size_t destSize,const void * pSrc,size_t srcSize,void * pWork)1380 s32 CompressDeflate( void* pDest, size_t destSize, const void* pSrc, size_t srcSize, void* pWork )
1381 {
1382     NN_POINTER_TASSERT_(pDest);
1383     NN_POINTER_TASSERT_(pSrc);
1384     NN_POINTER_TASSERT_(pWork);
1385 
1386     int headerSize;
1387     bit8* p8 = reinterpret_cast<bit8*>(pDest);
1388     *p8++ = COMPRESSION_DEFLATE;
1389     if( srcSize < (1 << 24) )
1390     {
1391         *p8++ = ((srcSize >>  0) & 0xFF);
1392         *p8++ = ((srcSize >>  8) & 0xFF);
1393         *p8++ = ((srcSize >> 16) & 0xFF);
1394         headerSize = 4;
1395     }
1396     else
1397     {
1398         *p8++ = 0;
1399         *p8++ = 0;
1400         *p8++ = 0;
1401         *p8++ = ((srcSize >>  0) & 0xFF);
1402         *p8++ = ((srcSize >>  8) & 0xFF);
1403         *p8++ = ((srcSize >> 16) & 0xFF);
1404         *p8++ = ((srcSize >> 24) & 0xFF);
1405         headerSize = 8;
1406     }
1407 
1408     const int wbits = - MAX_WBITS;      // Specify - = raw deflate format
1409     s32 ret = CompressDeflateCommon(p8, destSize - headerSize, pSrc, srcSize, pWork, wbits);
1410 
1411     if( ret > 0 )
1412     {
1413         return ret + headerSize;
1414     }
1415     else
1416     {
1417         return ret;
1418     }
1419 }
1420 
1421 }   // namespace cx
1422 }   // namespace nn
1423