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