2 * dernc.c decompress RNC data
4 * Compiled normally, this file is a well-behaved, re-entrant code
5 * module exporting only `rnc_ulen', `rnc_unpack' and `rnc_error'.
6 * Compiled with MAIN defined, it's a standalone program which will
7 * decompress argv[1] into argv[2].
16 ////////////////////////////////////////////////////////////////////////////////
18 unsigned int bitbuf
; /* holds between 16 and 32 bits */
19 int bitcount
; /* how many bits does bitbuf hold? */
24 int num
; /* number of nodes in the tree */
33 ////////////////////////////////////////////////////////////////////////////////
35 * Return the big-endian longword at p.
37 static inline unsigned int blong (unsigned char *p
) {
49 * Return the little-endian longword at p.
52 static inline unsigned int llong (unsigned char *p) {
65 * Return the big-endian word at p.
67 static inline unsigned int bword (unsigned char *p
) {
77 * Return the little-endian word at p.
79 static inline unsigned int lword (unsigned char *p
) {
89 * Mirror the bottom n bits of x.
91 static inline unsigned int mirror (unsigned int x
, int n
) {
92 unsigned int top
= 1<<(n
-1), bottom
= 1;
94 while (top
> bottom
) {
95 unsigned int mask
= top
|bottom
;
96 unsigned int masked
= x
&mask
;
98 if (masked
!= 0 && masked
!= mask
) x
^= mask
;
107 * Initialises a bit stream with the first two bytes of the packed
110 static inline void bitread_init (bit_stream
*bs
, unsigned char **p
) {
111 bs
->bitbuf
= lword (*p
);
117 * Fixes up a bit stream after literals have been read out of the
120 static inline void bitread_fix (bit_stream
*bs
, unsigned char **p
) {
122 bs
->bitbuf
&= (1<<bs
->bitcount
)-1; /* remove the top 16 bits */
123 bs
->bitbuf
|= (lword(*p
)<<bs
->bitcount
); /* replace with what's at *p */
131 static inline unsigned int bit_peek (bit_stream
*bs
, unsigned int mask
) {
132 return bs
->bitbuf
&mask
;
137 * Advances the bit stream.
139 static inline void bit_advance (bit_stream
*bs
, int n
, unsigned char **p
) {
142 if (bs
->bitcount
< 16) {
144 bs
->bitbuf
|= (lword(*p
)<<bs
->bitcount
);
151 * Reads some bits in one go (ie the above two routines combined).
153 static inline unsigned int bit_read (bit_stream
*bs
, unsigned int mask
, int n
, unsigned char **p
) {
154 unsigned int result
= bit_peek(bs
, mask
);
156 bit_advance(bs
, n
, p
);
162 * Read a Huffman table out of the bit stream and data stream given.
164 static void read_huftable (huf_table
*h
, bit_stream
*bs
, unsigned char **p
) {
168 unsigned int codeb
; /* big-endian form of code */
170 num
= bit_read(bs
, 0x1f, 5, p
);
173 for (int i
= 0; i
< num
; ++i
) {
174 leaflen
[i
] = bit_read(bs
, 0x0F, 4, p
);
175 if (leafmax
< leaflen
[i
]) leafmax
= leaflen
[i
];
179 for (int i
= 1; i
<= leafmax
; ++i
) {
180 for (int j
= 0; j
< num
; ++j
) {
181 if (leaflen
[j
] == i
) {
182 h
->table
[k
].code
= mirror(codeb
, i
);
183 h
->table
[k
].codelen
= i
;
184 h
->table
[k
].value
= j
;
196 * Read a value out of the bit stream using the given Huffman table.
198 static unsigned int huf_read (huf_table
*h
, bit_stream
*bs
, unsigned char **p
) {
202 for (i
= 0; i
< h
->num
; i
++) {
203 unsigned int mask
= (1<<h
->table
[i
].codelen
)-1;
205 if (bit_peek(bs
, mask
) == h
->table
[i
].code
) break;
207 if (i
== h
->num
) return -1;
208 bit_advance(bs
, h
->table
[i
].codelen
, p
);
209 val
= h
->table
[i
].value
;
212 val
|= bit_read (bs
, val
-1, h
->table
[i
].value
-1, p
);
218 ////////////////////////////////////////////////////////////////////////////////
220 * Decompress a packed data block. Returns the unpacked length if
221 * successful, or negative error codes if not.
223 * If COMPRESSOR is defined, it also returns the leeway number
224 * (which gets stored at offset 16 into the compressed-file header)
225 * in `*leeway', if `leeway' isn't NULL.
227 int rnc_unpack (void *packed
, void *unpacked
, int *leeway
) {
228 unsigned char *input
= packed
;
229 unsigned char *output
= unpacked
;
230 unsigned char *inputend
, *outputend
;
232 huf_table raw
, dist
, len
;
233 unsigned int ch_count
;
234 unsigned int ret_len
;
238 if (blong(input
) != RNC_SIGNATURE
) return RNC_FILE_IS_NOT_RNC
;
239 ret_len
= blong(input
+4);
240 outputend
= output
+ret_len
;
241 inputend
= input
+18+blong(input
+8);
242 input
+= 18; /* skip header */
243 // check the packed-data CRC. Also save the unpacked-data CRC for later
244 if (rnc_crc(input
, inputend
-input
) != bword(input
-4)) return RNC_PACKED_CRC_ERROR
;
245 out_crc
= bword(input
-6);
246 bitread_init(&bs
, &input
);
247 bit_advance(&bs
, 2, &input
); /* discard first two bits */
249 while (output
< outputend
) {
252 read_huftable(&raw
, &bs
, &input
);
253 read_huftable(&dist
, &bs
, &input
);
254 read_huftable(&len
, &bs
, &input
);
255 ch_count
= bit_read(&bs
, 0xffff, 16, &input
);
260 length
= huf_read(&raw
, &bs
, &input
);
261 if (length
== -1) return RNC_HUF_DECODE_ERROR
;
263 while (length
--) *output
++ = *input
++;
264 bitread_fix(&bs
, &input
);
266 if (--ch_count
<= 0) break;
267 posn
= huf_read(&dist
, &bs
, &input
);
268 if (posn
== -1) return RNC_HUF_DECODE_ERROR
;
269 length
= huf_read(&len
, &bs
, &input
);
270 if (length
== -1) return RNC_HUF_DECODE_ERROR
;
274 *output
= output
[-posn
];
277 this_lee
= (inputend
-input
)-(outputend
-output
);
278 if (lee
< this_lee
) lee
= this_lee
;
282 if (outputend
!= output
) return RNC_FILE_SIZE_MISMATCH
;
283 if (leeway
) *leeway
= lee
;
284 // check the unpacked-data CRC
285 if (rnc_crc(outputend
-ret_len
, ret_len
) != out_crc
) return RNC_UNPACKED_CRC_ERROR
;
290 ////////////////////////////////////////////////////////////////////////////////
292 * Return the uncompressed length of a packed data block, or a
293 * negative error code.
295 int rnc_ulen (void *packed
) {
296 unsigned char *p
= packed
;
298 if (blong(p
) != RNC_SIGNATURE
) return RNC_FILE_IS_NOT_RNC
;
303 ////////////////////////////////////////////////////////////////////////////////
305 * Calculate a CRC, the RNC way.
307 int rnc_crc (void *data
, int len
) {
308 static int initialized
= 0;
309 static unsigned short crctab
[256];
311 unsigned char *p
= data
;
314 for (int i
= 0; i
< 256; ++i
) {
316 for (int j
= 0; j
< 8; ++j
) if (val
&1) val
= (val
>>1)^0xA001; else val
= (val
>>1);
324 val
= (val
>>8)^crctab
[val
&0xFF];
331 ////////////////////////////////////////////////////////////////////////////////
333 * Return an error string corresponding to an error return code.
335 const char *rnc_error (int errcode
) {
336 static const char *const errors
[] = {
338 "File is not RNC-1 format",
339 "Huffman decode error",
340 "File size mismatch",
341 "CRC error in packed data",
342 "CRC error in unpacked data",
347 if (errcode
< 0) errcode
= 0;
348 if (errcode
> sizeof(errors
)/sizeof(*errors
)-1) errcode
= sizeof(errors
)/sizeof(*errors
)-1;
349 return errors
[errcode
];