Skip to content

Commit cc22550

Browse files
mtheallfincs
authored andcommitted
Add decompressHeader
1 parent 1165b4c commit cc22550

2 files changed

Lines changed: 151 additions & 67 deletions

File tree

libctru/include/3ds/util/decompress.h

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,28 @@
55
#pragma once
66

77
#include <stdbool.h>
8+
#include <stdint.h>
89
#include <sys/types.h>
910

11+
/** @brief Compression types */
12+
typedef enum
13+
{
14+
DECOMPRESS_DUMMY = 0x00, ///< Dummy compression
15+
DECOMPRESS_LZSS = 0x10, ///< LZSS/LZ10 compression
16+
DECOMPRESS_LZ10 = 0x10, ///< LZSS/LZ10 compression
17+
DECOMPRESS_LZ11 = 0x11, ///< LZ11 compression
18+
DECOMPRESS_HUFF1 = 0x21, ///< Huffman compression with 1-bit data
19+
DECOMPRESS_HUFF2 = 0x22, ///< Huffman compression with 2-bit data
20+
DECOMPRESS_HUFF3 = 0x23, ///< Huffman compression with 3-bit data
21+
DECOMPRESS_HUFF4 = 0x24, ///< Huffman compression with 4-bit data
22+
DECOMPRESS_HUFF5 = 0x25, ///< Huffman compression with 5-bit data
23+
DECOMPRESS_HUFF6 = 0x26, ///< Huffman compression with 6-bit data
24+
DECOMPRESS_HUFF7 = 0x27, ///< Huffman compression with 7-bit data
25+
DECOMPRESS_HUFF8 = 0x28, ///< Huffman compression with 8-bit data
26+
DECOMPRESS_HUFF = 0x28, ///< Huffman compression with 8-bit data
27+
DECOMPRESS_RLE = 0x30, ///< Run-length encoding compression
28+
} decompressType;
29+
1030
/** @brief I/O vector */
1131
typedef struct
1232
{
@@ -39,6 +59,19 @@ ssize_t decompressCallback_FD(void *userdata, void *buffer, size_t size);
3959
*/
4060
ssize_t decompressCallback_Stdio(void *userdata, void *buffer, size_t size);
4161

62+
/** @brief Decode decompression header
63+
* @param[out] type Decompression type
64+
* @param[out] size Decompressed size
65+
* @param[in] callback Data callback (see decompressV())
66+
* @param[in] userdata User data passed to callback (see decompressV())
67+
* @param[in] insize Size of userdata (see decompressV())
68+
* @returns Bytes consumed
69+
* @retval -1 error
70+
*/
71+
ssize_t decompressHeader(decompressType *type, size_t *size,
72+
decompressCallback callback, void *userdata,
73+
size_t insize);
74+
4275
/** @brief Decompress data
4376
* @param[in] iov Output vector
4477
* @param[in] iovcnt Number of buffers
@@ -137,18 +170,20 @@ decompress_LZ11(void *output, size_t size, decompressCallback callback,
137170
}
138171

139172
/** @brief Decompress Huffman
173+
* @param[in] bits Data size in bits (usually 4 or 8)
140174
* @param[in] iov Output vector
141175
* @param[in] iovcnt Number of buffers
142176
* @param[in] callback Data callback (see decompressV())
143177
* @param[in] userdata User data passed to callback (see decompressV())
144178
* @param[in] insize Size of userdata (see decompressV())
145179
* @returns Whether succeeded
146180
*/
147-
bool decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
181+
bool decompressV_Huff(size_t bits, const decompressIOVec *iov, size_t iovcnt,
148182
decompressCallback callback, void *userdata,
149183
size_t insize);
150184

151185
/** @brief Decompress Huffman
186+
* @param[in] bits Data size in bits (usually 4 or 8)
152187
* @param[in] output Output buffer
153188
* @param[in] size Output size limit
154189
* @param[in] callback Data callback (see decompressV())
@@ -157,14 +192,14 @@ bool decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
157192
* @returns Whether succeeded
158193
*/
159194
static inline bool
160-
decompress_Huff(void *output, size_t size, decompressCallback callback,
161-
void *userdata, size_t insize)
195+
decompress_Huff(size_t bits, void *output, size_t size,
196+
decompressCallback callback, void *userdata, size_t insize)
162197
{
163198
decompressIOVec iov;
164199
iov.data = output;
165200
iov.size = size;
166201

167-
return decompressV_Huff(&iov, 1, callback, userdata, insize);
202+
return decompressV_Huff(bits, &iov, 1, callback, userdata, insize);
168203
}
169204

170205
/** @brief Decompress run-length encoding

libctru/source/util/decompress/decompress.c

Lines changed: 112 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -31,24 +31,39 @@ typedef struct
3131

3232
/** @brief Initialize buffer object from memory
3333
* @param[in] buffer Decompression buffer object
34-
* @param[in] data Data to buffer
34+
* @param[in] data Data to emulate buffering
3535
* @param[in] size Data size
3636
*/
3737
static inline void
3838
buffer_memory(buffer_t *buffer, const void *data, size_t size)
3939
{
40-
buffer->data = (void*)data;
41-
buffer->size = size;
42-
buffer->pos = 0;
40+
buffer->data = (void*)data;
41+
buffer->limit = size;
42+
buffer->size = size;
43+
buffer->pos = 0;
44+
}
45+
46+
/** @brief Initialize buffer object with static memory
47+
* @param[in] buffer Decompression buffer object
48+
* @param[in] data Data buffer
49+
* @param[in] size Data size
50+
*/
51+
static inline void
52+
buffer_static(buffer_t *buffer, const void *data, size_t size)
53+
{
54+
buffer->data = (void*)data;
55+
buffer->limit = size;
56+
buffer->size = 0;
57+
buffer->pos = 0;
4358
}
4459

45-
/** @brief Initialize buffer object
60+
/** @brief Initialize buffer object with dynamic memory
4661
* @param[in] buffer Decompression buffer object
4762
* @param[in] size Buffer size limit
4863
* @returns Whether succeeded
4964
*/
5065
static inline bool
51-
buffer_init(buffer_t *buffer, size_t size)
66+
buffer_dynamic(buffer_t *buffer, size_t size)
5267
{
5368
buffer->data = (uint8_t*)malloc(size);
5469
if(!buffer->data)
@@ -498,6 +513,7 @@ decompress_lz11(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
498513
}
499514

500515
/** @brief Decompress Huffman
516+
* @param[in] bits Data size in bits (usually 4 or 8)
501517
* @param[in] buffer Decompression buffer object
502518
* @param[in] iov Output vector
503519
* @param[in] iovcnt Number of buffers
@@ -507,9 +523,13 @@ decompress_lz11(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
507523
* @returns Whether succeeded
508524
*/
509525
static bool
510-
decompress_huff(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
511-
size_t size, decompressCallback callback, void *userdata)
526+
decompress_huff(const size_t bits, buffer_t *buffer, const decompressIOVec *iov,
527+
size_t iovcnt, size_t size, decompressCallback callback,
528+
void *userdata)
512529
{
530+
if(bits < 1 || bits > 8)
531+
return false;
532+
513533
uint8_t *tree = (uint8_t*)malloc(512);
514534
if(!tree)
515535
return false;
@@ -528,14 +548,13 @@ decompress_huff(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
528548
return false;
529549
}
530550

531-
iov_iter out = iov_begin(iov, iovcnt);
532-
const size_t bits = 8;
533-
uint32_t word = 0; // 32-bits of input bitstream
534-
uint32_t mask = 0; // which bit we are reading
535-
uint32_t dataMask = (1<<bits)-1; // mask to apply to data
536-
size_t node; // node in the huffman tree
537-
size_t child; // child of a node
538-
uint32_t offset; // offset from node to child
551+
iov_iter out = iov_begin(iov, iovcnt);
552+
uint32_t word = 0; // 32-bits of input bitstream
553+
uint32_t mask = 0; // which bit we are reading
554+
uint8_t dataMask = (1<<bits)-1; // mask to apply to data
555+
size_t node; // node in the huffman tree
556+
size_t child; // child of a node
557+
uint32_t offset; // offset from node to child
539558

540559
// point to the root of the huffman tree
541560
node = 1;
@@ -686,45 +705,67 @@ decompressCallback_Stdio(void *userdata, void *buffer, size_t size)
686705
return fread(buffer, 1, size, fp);
687706
}
688707

689-
bool
690-
decompressV(const decompressIOVec *iov, size_t iovcnt,
691-
decompressCallback callback, void *userdata, size_t usersize)
708+
ssize_t
709+
decompressHeader(decompressType *type, size_t *size,
710+
decompressCallback callback, void *userdata, size_t insize)
692711
{
693-
if(iovcnt == 0)
694-
return false;
695-
696712
buffer_t buffer;
713+
uint8_t bufferdata[4];
697714
if(!callback)
698-
buffer_memory(&buffer, userdata, usersize);
699-
else if(!buffer_init(&buffer, BUFFERSIZE))
700-
return false;
715+
buffer_memory(&buffer, userdata, insize);
716+
else
717+
buffer_static(&buffer, bufferdata, sizeof(bufferdata));
701718

702-
uint8_t header[8];
719+
uint8_t header[4];
703720
if(!buffer_read(&buffer, header, 4, callback, userdata))
721+
return -1;
722+
723+
size_t bytes = 4;
724+
725+
decompressType outtype = header[0] & ~0x80;
726+
size_t outsize = (header[1] << 0)
727+
| (header[2] << 8)
728+
| (header[3] << 16);
729+
730+
if(header[0] & 0x80)
704731
{
705-
if(callback)
706-
buffer_destroy(&buffer);
707-
return false;
732+
if(!buffer_read(&buffer, header, 4, callback, userdata))
733+
return -1;
734+
735+
bytes += 4;
736+
outsize |= header[0] << 24;
708737
}
709738

710-
uint8_t type = header[0];
711-
size_t size = (header[1] << 0)
712-
| (header[2] << 8)
713-
| (header[3] << 16);
739+
if(type)
740+
*type = outtype;
741+
if(size)
742+
*size = outsize;
714743

715-
if(type & 0x80)
716-
{
717-
type &= ~0x80;
744+
return bytes;
745+
}
718746

719-
if(!buffer_read(&buffer, &header[4], 4, callback, userdata))
720-
{
721-
if(callback)
722-
buffer_destroy(&buffer);
723-
return false;
724-
}
747+
bool
748+
decompressV(const decompressIOVec *iov, size_t iovcnt,
749+
decompressCallback callback, void *userdata, size_t insize)
750+
{
751+
if(iovcnt == 0)
752+
return false;
725753

726-
size |= header[4] << 24;
754+
decompressType type;
755+
size_t size;
756+
ssize_t bytes = decompressHeader(&type, &size, callback, userdata, insize);
757+
if(bytes < 0)
758+
return false;
759+
760+
buffer_t buffer;
761+
if(!callback)
762+
{
763+
userdata = (uint8_t*)userdata + bytes;
764+
insize -= bytes;
765+
buffer_memory(&buffer, userdata, insize);
727766
}
767+
else if(!buffer_dynamic(&buffer, BUFFERSIZE))
768+
return false;
728769

729770
size_t iovsize = iov_size(iov, iovcnt);
730771
if(iovsize < size)
@@ -733,26 +774,34 @@ decompressV(const decompressIOVec *iov, size_t iovcnt,
733774
bool result = false;
734775
switch(type)
735776
{
736-
case 0x00:
777+
case DECOMPRESS_DUMMY:
737778
{
738779
iov_iter out = iov_begin(iov, iovcnt);
739780
result = iov_read(&buffer, &out, size, callback, userdata);
740781
break;
741782
}
742783

743-
case 0x10:
784+
case DECOMPRESS_LZSS:
744785
result = decompress_lzss(&buffer, iov, iovcnt, size, callback, userdata);
745786
break;
746787

747-
case 0x11:
788+
case DECOMPRESS_LZ11:
748789
result = decompress_lz11(&buffer, iov, iovcnt, size, callback, userdata);
749790
break;
750791

751-
case 0x28:
752-
result = decompress_huff(&buffer, iov, iovcnt, size, callback, userdata);
792+
case DECOMPRESS_HUFF1:
793+
case DECOMPRESS_HUFF2:
794+
case DECOMPRESS_HUFF3:
795+
case DECOMPRESS_HUFF4:
796+
case DECOMPRESS_HUFF5:
797+
case DECOMPRESS_HUFF6:
798+
case DECOMPRESS_HUFF7:
799+
case DECOMPRESS_HUFF8:
800+
result = decompress_huff(type & 0xF, &buffer, iov, iovcnt, size,
801+
callback, userdata);
753802
break;
754803

755-
case 0x30:
804+
case DECOMPRESS_RLE:
756805
result = decompress_rle(&buffer, iov, iovcnt, size, callback, userdata);
757806
break;
758807
}
@@ -764,12 +813,12 @@ decompressV(const decompressIOVec *iov, size_t iovcnt,
764813

765814
bool
766815
decompressV_LZSS(const decompressIOVec *iov, size_t iovcnt,
767-
decompressCallback callback, void *userdata, size_t usersize)
816+
decompressCallback callback, void *userdata, size_t insize)
768817
{
769818
buffer_t buffer;
770819
if(!callback)
771-
buffer_memory(&buffer, userdata, usersize);
772-
else if(!buffer_init(&buffer, BUFFERSIZE))
820+
buffer_memory(&buffer, userdata, insize);
821+
else if(!buffer_dynamic(&buffer, BUFFERSIZE))
773822
return false;
774823

775824
size_t size = iov_size(iov, iovcnt);
@@ -782,12 +831,12 @@ decompressV_LZSS(const decompressIOVec *iov, size_t iovcnt,
782831

783832
bool
784833
decompressV_LZ11(const decompressIOVec *iov, size_t iovcnt,
785-
decompressCallback callback, void *userdata, size_t usersize)
834+
decompressCallback callback, void *userdata, size_t insize)
786835
{
787836
buffer_t buffer;
788837
if(!callback)
789-
buffer_memory(&buffer, userdata, usersize);
790-
else if(!buffer_init(&buffer, BUFFERSIZE))
838+
buffer_memory(&buffer, userdata, insize);
839+
else if(!buffer_dynamic(&buffer, BUFFERSIZE))
791840
return false;
792841

793842
size_t size = iov_size(iov, iovcnt);
@@ -799,17 +848,17 @@ decompressV_LZ11(const decompressIOVec *iov, size_t iovcnt,
799848
}
800849

801850
bool
802-
decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
803-
decompressCallback callback, void *userdata, size_t usersize)
851+
decompressV_Huff(size_t bits, const decompressIOVec *iov, size_t iovcnt,
852+
decompressCallback callback, void *userdata, size_t insize)
804853
{
805854
buffer_t buffer;
806855
if(!callback)
807-
buffer_memory(&buffer, userdata, usersize);
808-
else if(!buffer_init(&buffer, BUFFERSIZE))
856+
buffer_memory(&buffer, userdata, insize);
857+
else if(!buffer_dynamic(&buffer, BUFFERSIZE))
809858
return false;
810859

811860
size_t size = iov_size(iov, iovcnt);
812-
bool result = decompress_huff(&buffer, iov, iovcnt, size, callback, userdata);
861+
bool result = decompress_huff(bits, &buffer, iov, iovcnt, size, callback, userdata);
813862

814863
if(callback)
815864
buffer_destroy(&buffer);
@@ -818,12 +867,12 @@ decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
818867

819868
bool
820869
decompressV_RLE(const decompressIOVec *iov, size_t iovcnt,
821-
decompressCallback callback, void *userdata, size_t usersize)
870+
decompressCallback callback, void *userdata, size_t insize)
822871
{
823872
buffer_t buffer;
824873
if(!callback)
825-
buffer_memory(&buffer, userdata, usersize);
826-
else if(!buffer_init(&buffer, BUFFERSIZE))
874+
buffer_memory(&buffer, userdata, insize);
875+
else if(!buffer_dynamic(&buffer, BUFFERSIZE))
827876
return false;
828877

829878
size_t size = iov_size(iov, iovcnt);

0 commit comments

Comments
 (0)