chd 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +30 -0
- data/chd.gemspec +29 -0
- data/ext/chd.c +1008 -0
- data/ext/extconf.rb +60 -0
- data/lib/chd/cd.rb +272 -0
- data/lib/chd/metadata.rb +196 -0
- data/lib/chd/version.rb +4 -0
- data/lib/chd.rb +21 -0
- data/libchdr/CMakeLists.txt +104 -0
- data/libchdr/LICENSE.txt +24 -0
- data/libchdr/README.md +7 -0
- data/libchdr/deps/lzma-19.00/CMakeLists.txt +33 -0
- data/libchdr/deps/lzma-19.00/LICENSE +3 -0
- data/libchdr/deps/lzma-19.00/include/7zTypes.h +375 -0
- data/libchdr/deps/lzma-19.00/include/Alloc.h +51 -0
- data/libchdr/deps/lzma-19.00/include/Bra.h +64 -0
- data/libchdr/deps/lzma-19.00/include/Compiler.h +33 -0
- data/libchdr/deps/lzma-19.00/include/CpuArch.h +336 -0
- data/libchdr/deps/lzma-19.00/include/Delta.h +19 -0
- data/libchdr/deps/lzma-19.00/include/LzFind.h +121 -0
- data/libchdr/deps/lzma-19.00/include/LzHash.h +57 -0
- data/libchdr/deps/lzma-19.00/include/Lzma86.h +111 -0
- data/libchdr/deps/lzma-19.00/include/LzmaDec.h +234 -0
- data/libchdr/deps/lzma-19.00/include/LzmaEnc.h +76 -0
- data/libchdr/deps/lzma-19.00/include/LzmaLib.h +131 -0
- data/libchdr/deps/lzma-19.00/include/Precomp.h +10 -0
- data/libchdr/deps/lzma-19.00/include/Sort.h +18 -0
- data/libchdr/deps/lzma-19.00/lzma-history.txt +446 -0
- data/libchdr/deps/lzma-19.00/lzma.txt +328 -0
- data/libchdr/deps/lzma-19.00/lzma.vcxproj +543 -0
- data/libchdr/deps/lzma-19.00/lzma.vcxproj.filters +17 -0
- data/libchdr/deps/lzma-19.00/src/Alloc.c +455 -0
- data/libchdr/deps/lzma-19.00/src/Bra86.c +82 -0
- data/libchdr/deps/lzma-19.00/src/BraIA64.c +53 -0
- data/libchdr/deps/lzma-19.00/src/CpuArch.c +218 -0
- data/libchdr/deps/lzma-19.00/src/Delta.c +64 -0
- data/libchdr/deps/lzma-19.00/src/LzFind.c +1127 -0
- data/libchdr/deps/lzma-19.00/src/Lzma86Dec.c +54 -0
- data/libchdr/deps/lzma-19.00/src/LzmaDec.c +1185 -0
- data/libchdr/deps/lzma-19.00/src/LzmaEnc.c +1330 -0
- data/libchdr/deps/lzma-19.00/src/Sort.c +141 -0
- data/libchdr/deps/zlib-1.2.11/CMakeLists.txt +29 -0
- data/libchdr/deps/zlib-1.2.11/ChangeLog +1515 -0
- data/libchdr/deps/zlib-1.2.11/FAQ +368 -0
- data/libchdr/deps/zlib-1.2.11/INDEX +68 -0
- data/libchdr/deps/zlib-1.2.11/Makefile +5 -0
- data/libchdr/deps/zlib-1.2.11/Makefile.in +410 -0
- data/libchdr/deps/zlib-1.2.11/README +115 -0
- data/libchdr/deps/zlib-1.2.11/adler32.c +186 -0
- data/libchdr/deps/zlib-1.2.11/compress.c +86 -0
- data/libchdr/deps/zlib-1.2.11/configure +921 -0
- data/libchdr/deps/zlib-1.2.11/crc32.c +442 -0
- data/libchdr/deps/zlib-1.2.11/crc32.h +441 -0
- data/libchdr/deps/zlib-1.2.11/deflate.c +2163 -0
- data/libchdr/deps/zlib-1.2.11/deflate.h +349 -0
- data/libchdr/deps/zlib-1.2.11/doc/algorithm.txt +209 -0
- data/libchdr/deps/zlib-1.2.11/doc/rfc1950.txt +619 -0
- data/libchdr/deps/zlib-1.2.11/doc/rfc1951.txt +955 -0
- data/libchdr/deps/zlib-1.2.11/doc/rfc1952.txt +675 -0
- data/libchdr/deps/zlib-1.2.11/doc/txtvsbin.txt +107 -0
- data/libchdr/deps/zlib-1.2.11/gzclose.c +25 -0
- data/libchdr/deps/zlib-1.2.11/gzguts.h +218 -0
- data/libchdr/deps/zlib-1.2.11/gzlib.c +637 -0
- data/libchdr/deps/zlib-1.2.11/gzread.c +654 -0
- data/libchdr/deps/zlib-1.2.11/gzwrite.c +665 -0
- data/libchdr/deps/zlib-1.2.11/infback.c +640 -0
- data/libchdr/deps/zlib-1.2.11/inffast.c +323 -0
- data/libchdr/deps/zlib-1.2.11/inffast.h +11 -0
- data/libchdr/deps/zlib-1.2.11/inffixed.h +94 -0
- data/libchdr/deps/zlib-1.2.11/inflate.c +1561 -0
- data/libchdr/deps/zlib-1.2.11/inflate.h +125 -0
- data/libchdr/deps/zlib-1.2.11/inftrees.c +304 -0
- data/libchdr/deps/zlib-1.2.11/inftrees.h +62 -0
- data/libchdr/deps/zlib-1.2.11/make_vms.com +867 -0
- data/libchdr/deps/zlib-1.2.11/treebuild.xml +116 -0
- data/libchdr/deps/zlib-1.2.11/trees.c +1203 -0
- data/libchdr/deps/zlib-1.2.11/trees.h +128 -0
- data/libchdr/deps/zlib-1.2.11/uncompr.c +93 -0
- data/libchdr/deps/zlib-1.2.11/zconf.h +534 -0
- data/libchdr/deps/zlib-1.2.11/zconf.h.cmakein +536 -0
- data/libchdr/deps/zlib-1.2.11/zconf.h.in +534 -0
- data/libchdr/deps/zlib-1.2.11/zlib.3 +149 -0
- data/libchdr/deps/zlib-1.2.11/zlib.3.pdf +0 -0
- data/libchdr/deps/zlib-1.2.11/zlib.h +1912 -0
- data/libchdr/deps/zlib-1.2.11/zlib.map +94 -0
- data/libchdr/deps/zlib-1.2.11/zlib.pc.cmakein +13 -0
- data/libchdr/deps/zlib-1.2.11/zlib.pc.in +13 -0
- data/libchdr/deps/zlib-1.2.11/zlib2ansi +152 -0
- data/libchdr/deps/zlib-1.2.11/zutil.c +325 -0
- data/libchdr/deps/zlib-1.2.11/zutil.h +271 -0
- data/libchdr/include/dr_libs/dr_flac.h +12280 -0
- data/libchdr/include/libchdr/bitstream.h +43 -0
- data/libchdr/include/libchdr/cdrom.h +110 -0
- data/libchdr/include/libchdr/chd.h +427 -0
- data/libchdr/include/libchdr/chdconfig.h +10 -0
- data/libchdr/include/libchdr/coretypes.h +60 -0
- data/libchdr/include/libchdr/flac.h +50 -0
- data/libchdr/include/libchdr/huffman.h +90 -0
- data/libchdr/pkg-config.pc.in +10 -0
- data/libchdr/src/libchdr_bitstream.c +125 -0
- data/libchdr/src/libchdr_cdrom.c +415 -0
- data/libchdr/src/libchdr_chd.c +2744 -0
- data/libchdr/src/libchdr_flac.c +302 -0
- data/libchdr/src/libchdr_huffman.c +545 -0
- data/libchdr/src/link.T +5 -0
- data/libchdr/tests/CMakeLists.txt +2 -0
- data/libchdr/tests/benchmark.c +52 -0
- metadata +183 -0
@@ -0,0 +1,545 @@
|
|
1
|
+
/* license:BSD-3-Clause
|
2
|
+
* copyright-holders:Aaron Giles
|
3
|
+
****************************************************************************
|
4
|
+
|
5
|
+
huffman.c
|
6
|
+
|
7
|
+
Static Huffman compression and decompression helpers.
|
8
|
+
|
9
|
+
****************************************************************************
|
10
|
+
|
11
|
+
Maximum codelength is officially (alphabetsize - 1). This would be 255 bits
|
12
|
+
(since we use 1 byte values). However, it is also dependent upon the number
|
13
|
+
of samples used, as follows:
|
14
|
+
|
15
|
+
2 bits -> 3..4 samples
|
16
|
+
3 bits -> 5..7 samples
|
17
|
+
4 bits -> 8..12 samples
|
18
|
+
5 bits -> 13..20 samples
|
19
|
+
6 bits -> 21..33 samples
|
20
|
+
7 bits -> 34..54 samples
|
21
|
+
8 bits -> 55..88 samples
|
22
|
+
9 bits -> 89..143 samples
|
23
|
+
10 bits -> 144..232 samples
|
24
|
+
11 bits -> 233..376 samples
|
25
|
+
12 bits -> 377..609 samples
|
26
|
+
13 bits -> 610..986 samples
|
27
|
+
14 bits -> 987..1596 samples
|
28
|
+
15 bits -> 1597..2583 samples
|
29
|
+
16 bits -> 2584..4180 samples -> note that a 4k data size guarantees codelength <= 16 bits
|
30
|
+
17 bits -> 4181..6764 samples
|
31
|
+
18 bits -> 6765..10945 samples
|
32
|
+
19 bits -> 10946..17710 samples
|
33
|
+
20 bits -> 17711..28656 samples
|
34
|
+
21 bits -> 28657..46367 samples
|
35
|
+
22 bits -> 46368..75024 samples
|
36
|
+
23 bits -> 75025..121392 samples
|
37
|
+
24 bits -> 121393..196417 samples
|
38
|
+
25 bits -> 196418..317810 samples
|
39
|
+
26 bits -> 317811..514228 samples
|
40
|
+
27 bits -> 514229..832039 samples
|
41
|
+
28 bits -> 832040..1346268 samples
|
42
|
+
29 bits -> 1346269..2178308 samples
|
43
|
+
30 bits -> 2178309..3524577 samples
|
44
|
+
31 bits -> 3524578..5702886 samples
|
45
|
+
32 bits -> 5702887..9227464 samples
|
46
|
+
|
47
|
+
Looking at it differently, here is where powers of 2 fall into these buckets:
|
48
|
+
|
49
|
+
256 samples -> 11 bits max
|
50
|
+
512 samples -> 12 bits max
|
51
|
+
1k samples -> 14 bits max
|
52
|
+
2k samples -> 15 bits max
|
53
|
+
4k samples -> 16 bits max
|
54
|
+
8k samples -> 18 bits max
|
55
|
+
16k samples -> 19 bits max
|
56
|
+
32k samples -> 21 bits max
|
57
|
+
64k samples -> 22 bits max
|
58
|
+
128k samples -> 24 bits max
|
59
|
+
256k samples -> 25 bits max
|
60
|
+
512k samples -> 27 bits max
|
61
|
+
1M samples -> 28 bits max
|
62
|
+
2M samples -> 29 bits max
|
63
|
+
4M samples -> 31 bits max
|
64
|
+
8M samples -> 32 bits max
|
65
|
+
|
66
|
+
****************************************************************************
|
67
|
+
|
68
|
+
Delta-RLE encoding works as follows:
|
69
|
+
|
70
|
+
Starting value is assumed to be 0. All data is encoded as a delta
|
71
|
+
from the previous value, such that final[i] = final[i - 1] + delta.
|
72
|
+
Long runs of 0s are RLE-encoded as follows:
|
73
|
+
|
74
|
+
0x100 = repeat count of 8
|
75
|
+
0x101 = repeat count of 9
|
76
|
+
0x102 = repeat count of 10
|
77
|
+
0x103 = repeat count of 11
|
78
|
+
0x104 = repeat count of 12
|
79
|
+
0x105 = repeat count of 13
|
80
|
+
0x106 = repeat count of 14
|
81
|
+
0x107 = repeat count of 15
|
82
|
+
0x108 = repeat count of 16
|
83
|
+
0x109 = repeat count of 32
|
84
|
+
0x10a = repeat count of 64
|
85
|
+
0x10b = repeat count of 128
|
86
|
+
0x10c = repeat count of 256
|
87
|
+
0x10d = repeat count of 512
|
88
|
+
0x10e = repeat count of 1024
|
89
|
+
0x10f = repeat count of 2048
|
90
|
+
|
91
|
+
Note that repeat counts are reset at the end of a row, so if a 0 run
|
92
|
+
extends to the end of a row, a large repeat count may be used.
|
93
|
+
|
94
|
+
The reason for starting the run counts at 8 is that 0 is expected to
|
95
|
+
be the most common symbol, and is typically encoded in 1 or 2 bits.
|
96
|
+
|
97
|
+
***************************************************************************/
|
98
|
+
|
99
|
+
#include <stdlib.h>
|
100
|
+
#include <stdio.h>
|
101
|
+
#include <string.h>
|
102
|
+
|
103
|
+
#include <libchdr/huffman.h>
|
104
|
+
|
105
|
+
#define MAX(x,y) ((x) > (y) ? (x) : (y))
|
106
|
+
|
107
|
+
/***************************************************************************
|
108
|
+
* MACROS
|
109
|
+
***************************************************************************
|
110
|
+
*/
|
111
|
+
|
112
|
+
#define MAKE_LOOKUP(code,bits) (((code) << 5) | ((bits) & 0x1f))
|
113
|
+
|
114
|
+
/***************************************************************************
|
115
|
+
* IMPLEMENTATION
|
116
|
+
***************************************************************************
|
117
|
+
*/
|
118
|
+
|
119
|
+
/*-------------------------------------------------
|
120
|
+
* huffman_context_base - create an encoding/
|
121
|
+
* decoding context
|
122
|
+
*-------------------------------------------------
|
123
|
+
*/
|
124
|
+
|
125
|
+
struct huffman_decoder* create_huffman_decoder(int numcodes, int maxbits)
|
126
|
+
{
|
127
|
+
struct huffman_decoder* decoder = NULL;
|
128
|
+
|
129
|
+
/* limit to 24 bits */
|
130
|
+
if (maxbits > 24)
|
131
|
+
return NULL;
|
132
|
+
|
133
|
+
decoder = (struct huffman_decoder*)malloc(sizeof(struct huffman_decoder));
|
134
|
+
decoder->numcodes = numcodes;
|
135
|
+
decoder->maxbits = maxbits;
|
136
|
+
decoder->lookup = (lookup_value*)malloc(sizeof(lookup_value) * (1 << maxbits));
|
137
|
+
decoder->huffnode = (struct node_t*)malloc(sizeof(struct node_t) * numcodes);
|
138
|
+
decoder->datahisto = NULL;
|
139
|
+
decoder->prevdata = 0;
|
140
|
+
decoder->rleremaining = 0;
|
141
|
+
return decoder;
|
142
|
+
}
|
143
|
+
|
144
|
+
void delete_huffman_decoder(struct huffman_decoder* decoder)
|
145
|
+
{
|
146
|
+
if (decoder != NULL)
|
147
|
+
{
|
148
|
+
if (decoder->lookup != NULL)
|
149
|
+
free(decoder->lookup);
|
150
|
+
if (decoder->huffnode != NULL)
|
151
|
+
free(decoder->huffnode);
|
152
|
+
free(decoder);
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
/*-------------------------------------------------
|
157
|
+
* decode_one - decode a single code from the
|
158
|
+
* huffman stream
|
159
|
+
*-------------------------------------------------
|
160
|
+
*/
|
161
|
+
|
162
|
+
uint32_t huffman_decode_one(struct huffman_decoder* decoder, struct bitstream* bitbuf)
|
163
|
+
{
|
164
|
+
/* peek ahead to get maxbits worth of data */
|
165
|
+
uint32_t bits = bitstream_peek(bitbuf, decoder->maxbits);
|
166
|
+
|
167
|
+
/* look it up, then remove the actual number of bits for this code */
|
168
|
+
lookup_value lookup = decoder->lookup[bits];
|
169
|
+
bitstream_remove(bitbuf, lookup & 0x1f);
|
170
|
+
|
171
|
+
/* return the value */
|
172
|
+
return lookup >> 5;
|
173
|
+
}
|
174
|
+
|
175
|
+
/*-------------------------------------------------
|
176
|
+
* import_tree_rle - import an RLE-encoded
|
177
|
+
* huffman tree from a source data stream
|
178
|
+
*-------------------------------------------------
|
179
|
+
*/
|
180
|
+
|
181
|
+
enum huffman_error huffman_import_tree_rle(struct huffman_decoder* decoder, struct bitstream* bitbuf)
|
182
|
+
{
|
183
|
+
int numbits;
|
184
|
+
uint32_t curnode;
|
185
|
+
enum huffman_error error;
|
186
|
+
|
187
|
+
/* bits per entry depends on the maxbits */
|
188
|
+
if (decoder->maxbits >= 16)
|
189
|
+
numbits = 5;
|
190
|
+
else if (decoder->maxbits >= 8)
|
191
|
+
numbits = 4;
|
192
|
+
else
|
193
|
+
numbits = 3;
|
194
|
+
|
195
|
+
/* loop until we read all the nodes */
|
196
|
+
for (curnode = 0; curnode < decoder->numcodes; )
|
197
|
+
{
|
198
|
+
/* a non-one value is just raw */
|
199
|
+
int nodebits = bitstream_read(bitbuf, numbits);
|
200
|
+
if (nodebits != 1)
|
201
|
+
decoder->huffnode[curnode++].numbits = nodebits;
|
202
|
+
|
203
|
+
/* a one value is an escape code */
|
204
|
+
else
|
205
|
+
{
|
206
|
+
/* a double 1 is just a single 1 */
|
207
|
+
nodebits = bitstream_read(bitbuf, numbits);
|
208
|
+
if (nodebits == 1)
|
209
|
+
decoder->huffnode[curnode++].numbits = nodebits;
|
210
|
+
|
211
|
+
/* otherwise, we need one for value for the repeat count */
|
212
|
+
else
|
213
|
+
{
|
214
|
+
int repcount = bitstream_read(bitbuf, numbits) + 3;
|
215
|
+
while (repcount--)
|
216
|
+
decoder->huffnode[curnode++].numbits = nodebits;
|
217
|
+
}
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
/* make sure we ended up with the right number */
|
222
|
+
if (curnode != decoder->numcodes)
|
223
|
+
return HUFFERR_INVALID_DATA;
|
224
|
+
|
225
|
+
/* assign canonical codes for all nodes based on their code lengths */
|
226
|
+
error = huffman_assign_canonical_codes(decoder);
|
227
|
+
if (error != HUFFERR_NONE)
|
228
|
+
return error;
|
229
|
+
|
230
|
+
/* build the lookup table */
|
231
|
+
huffman_build_lookup_table(decoder);
|
232
|
+
|
233
|
+
/* determine final input length and report errors */
|
234
|
+
return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
|
235
|
+
}
|
236
|
+
|
237
|
+
|
238
|
+
/*-------------------------------------------------
|
239
|
+
* import_tree_huffman - import a huffman-encoded
|
240
|
+
* huffman tree from a source data stream
|
241
|
+
*-------------------------------------------------
|
242
|
+
*/
|
243
|
+
|
244
|
+
enum huffman_error huffman_import_tree_huffman(struct huffman_decoder* decoder, struct bitstream* bitbuf)
|
245
|
+
{
|
246
|
+
int start;
|
247
|
+
int last = 0;
|
248
|
+
int count = 0;
|
249
|
+
int index;
|
250
|
+
uint32_t curcode;
|
251
|
+
uint8_t rlefullbits = 0;
|
252
|
+
uint32_t temp;
|
253
|
+
enum huffman_error error;
|
254
|
+
/* start by parsing the lengths for the small tree */
|
255
|
+
struct huffman_decoder* smallhuff = create_huffman_decoder(24, 6);
|
256
|
+
smallhuff->huffnode[0].numbits = bitstream_read(bitbuf, 3);
|
257
|
+
start = bitstream_read(bitbuf, 3) + 1;
|
258
|
+
for (index = 1; index < 24; index++)
|
259
|
+
{
|
260
|
+
if (index < start || count == 7)
|
261
|
+
smallhuff->huffnode[index].numbits = 0;
|
262
|
+
else
|
263
|
+
{
|
264
|
+
count = bitstream_read(bitbuf, 3);
|
265
|
+
smallhuff->huffnode[index].numbits = (count == 7) ? 0 : count;
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
/* then regenerate the tree */
|
270
|
+
error = huffman_assign_canonical_codes(smallhuff);
|
271
|
+
if (error != HUFFERR_NONE)
|
272
|
+
return error;
|
273
|
+
huffman_build_lookup_table(smallhuff);
|
274
|
+
|
275
|
+
/* determine the maximum length of an RLE count */
|
276
|
+
temp = decoder->numcodes - 9;
|
277
|
+
while (temp != 0)
|
278
|
+
temp >>= 1, rlefullbits++;
|
279
|
+
|
280
|
+
/* now process the rest of the data */
|
281
|
+
for (curcode = 0; curcode < decoder->numcodes; )
|
282
|
+
{
|
283
|
+
int value = huffman_decode_one(smallhuff, bitbuf);
|
284
|
+
if (value != 0)
|
285
|
+
decoder->huffnode[curcode++].numbits = last = value - 1;
|
286
|
+
else
|
287
|
+
{
|
288
|
+
int count = bitstream_read(bitbuf, 3) + 2;
|
289
|
+
if (count == 7+2)
|
290
|
+
count += bitstream_read(bitbuf, rlefullbits);
|
291
|
+
for ( ; count != 0 && curcode < decoder->numcodes; count--)
|
292
|
+
decoder->huffnode[curcode++].numbits = last;
|
293
|
+
}
|
294
|
+
}
|
295
|
+
|
296
|
+
/* make sure we ended up with the right number */
|
297
|
+
if (curcode != decoder->numcodes)
|
298
|
+
return HUFFERR_INVALID_DATA;
|
299
|
+
|
300
|
+
/* assign canonical codes for all nodes based on their code lengths */
|
301
|
+
error = huffman_assign_canonical_codes(decoder);
|
302
|
+
if (error != HUFFERR_NONE)
|
303
|
+
return error;
|
304
|
+
|
305
|
+
/* build the lookup table */
|
306
|
+
huffman_build_lookup_table(decoder);
|
307
|
+
|
308
|
+
/* determine final input length and report errors */
|
309
|
+
return bitstream_overflow(bitbuf) ? HUFFERR_INPUT_BUFFER_TOO_SMALL : HUFFERR_NONE;
|
310
|
+
}
|
311
|
+
|
312
|
+
/*-------------------------------------------------
|
313
|
+
* compute_tree_from_histo - common backend for
|
314
|
+
* computing a tree based on the data histogram
|
315
|
+
*-------------------------------------------------
|
316
|
+
*/
|
317
|
+
|
318
|
+
enum huffman_error huffman_compute_tree_from_histo(struct huffman_decoder* decoder)
|
319
|
+
{
|
320
|
+
uint32_t i;
|
321
|
+
uint32_t lowerweight;
|
322
|
+
uint32_t upperweight;
|
323
|
+
/* compute the number of data items in the histogram */
|
324
|
+
uint32_t sdatacount = 0;
|
325
|
+
for (i = 0; i < decoder->numcodes; i++)
|
326
|
+
sdatacount += decoder->datahisto[i];
|
327
|
+
|
328
|
+
/* binary search to achieve the optimum encoding */
|
329
|
+
lowerweight = 0;
|
330
|
+
upperweight = sdatacount * 2;
|
331
|
+
while (1)
|
332
|
+
{
|
333
|
+
/* build a tree using the current weight */
|
334
|
+
uint32_t curweight = (upperweight + lowerweight) / 2;
|
335
|
+
int curmaxbits = huffman_build_tree(decoder, sdatacount, curweight);
|
336
|
+
|
337
|
+
/* apply binary search here */
|
338
|
+
if (curmaxbits <= decoder->maxbits)
|
339
|
+
{
|
340
|
+
lowerweight = curweight;
|
341
|
+
|
342
|
+
/* early out if it worked with the raw weights, or if we're done searching */
|
343
|
+
if (curweight == sdatacount || (upperweight - lowerweight) <= 1)
|
344
|
+
break;
|
345
|
+
}
|
346
|
+
else
|
347
|
+
upperweight = curweight;
|
348
|
+
}
|
349
|
+
|
350
|
+
/* assign canonical codes for all nodes based on their code lengths */
|
351
|
+
return huffman_assign_canonical_codes(decoder);
|
352
|
+
}
|
353
|
+
|
354
|
+
/***************************************************************************
|
355
|
+
* INTERNAL FUNCTIONS
|
356
|
+
***************************************************************************
|
357
|
+
*/
|
358
|
+
|
359
|
+
/*-------------------------------------------------
|
360
|
+
* tree_node_compare - compare two tree nodes
|
361
|
+
* by weight
|
362
|
+
*-------------------------------------------------
|
363
|
+
*/
|
364
|
+
|
365
|
+
static int huffman_tree_node_compare(const void *item1, const void *item2)
|
366
|
+
{
|
367
|
+
const struct node_t *node1 = *(const struct node_t **)item1;
|
368
|
+
const struct node_t *node2 = *(const struct node_t **)item2;
|
369
|
+
if (node2->weight != node1->weight)
|
370
|
+
return node2->weight - node1->weight;
|
371
|
+
if (node2->bits - node1->bits == 0)
|
372
|
+
fprintf(stderr, "identical node sort keys, should not happen!\n");
|
373
|
+
return (int)node1->bits - (int)node2->bits;
|
374
|
+
}
|
375
|
+
|
376
|
+
/*-------------------------------------------------
|
377
|
+
* build_tree - build a huffman tree based on the
|
378
|
+
* data distribution
|
379
|
+
*-------------------------------------------------
|
380
|
+
*/
|
381
|
+
|
382
|
+
int huffman_build_tree(struct huffman_decoder* decoder, uint32_t totaldata, uint32_t totalweight)
|
383
|
+
{
|
384
|
+
uint32_t curcode;
|
385
|
+
int nextalloc;
|
386
|
+
int listitems = 0;
|
387
|
+
int maxbits = 0;
|
388
|
+
/* make a list of all non-zero nodes */
|
389
|
+
struct node_t** list = (struct node_t**)malloc(sizeof(struct node_t*) * decoder->numcodes * 2);
|
390
|
+
memset(decoder->huffnode, 0, decoder->numcodes * sizeof(decoder->huffnode[0]));
|
391
|
+
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
392
|
+
if (decoder->datahisto[curcode] != 0)
|
393
|
+
{
|
394
|
+
list[listitems++] = &decoder->huffnode[curcode];
|
395
|
+
decoder->huffnode[curcode].count = decoder->datahisto[curcode];
|
396
|
+
decoder->huffnode[curcode].bits = curcode;
|
397
|
+
|
398
|
+
/* scale the weight by the current effective length, ensuring we don't go to 0 */
|
399
|
+
decoder->huffnode[curcode].weight = ((uint64_t)decoder->datahisto[curcode]) * ((uint64_t)totalweight) / ((uint64_t)totaldata);
|
400
|
+
if (decoder->huffnode[curcode].weight == 0)
|
401
|
+
decoder->huffnode[curcode].weight = 1;
|
402
|
+
}
|
403
|
+
|
404
|
+
#if 0
|
405
|
+
fprintf(stderr, "Pre-sort:\n");
|
406
|
+
for (int i = 0; i < listitems; i++) {
|
407
|
+
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
|
408
|
+
}
|
409
|
+
#endif
|
410
|
+
|
411
|
+
/* sort the list by weight, largest weight first */
|
412
|
+
qsort(&list[0], listitems, sizeof(list[0]), huffman_tree_node_compare);
|
413
|
+
|
414
|
+
#if 0
|
415
|
+
fprintf(stderr, "Post-sort:\n");
|
416
|
+
for (int i = 0; i < listitems; i++) {
|
417
|
+
fprintf(stderr, "weight: %d code: %d\n", list[i]->m_weight, list[i]->m_bits);
|
418
|
+
}
|
419
|
+
fprintf(stderr, "===================\n");
|
420
|
+
#endif
|
421
|
+
|
422
|
+
/* now build the tree */
|
423
|
+
nextalloc = decoder->numcodes;
|
424
|
+
while (listitems > 1)
|
425
|
+
{
|
426
|
+
int curitem;
|
427
|
+
/* remove lowest two items */
|
428
|
+
struct node_t* node1 = &(*list[--listitems]);
|
429
|
+
struct node_t* node0 = &(*list[--listitems]);
|
430
|
+
|
431
|
+
/* create new node */
|
432
|
+
struct node_t* newnode = &decoder->huffnode[nextalloc++];
|
433
|
+
newnode->parent = NULL;
|
434
|
+
node0->parent = node1->parent = newnode;
|
435
|
+
newnode->weight = node0->weight + node1->weight;
|
436
|
+
|
437
|
+
/* insert into list at appropriate location */
|
438
|
+
for (curitem = 0; curitem < listitems; curitem++)
|
439
|
+
if (newnode->weight > list[curitem]->weight)
|
440
|
+
{
|
441
|
+
memmove(&list[curitem+1], &list[curitem], (listitems - curitem) * sizeof(list[0]));
|
442
|
+
break;
|
443
|
+
}
|
444
|
+
list[curitem] = newnode;
|
445
|
+
listitems++;
|
446
|
+
}
|
447
|
+
|
448
|
+
/* compute the number of bits in each code, and fill in another histogram */
|
449
|
+
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
450
|
+
{
|
451
|
+
struct node_t *curnode;
|
452
|
+
struct node_t* node = &decoder->huffnode[curcode];
|
453
|
+
node->numbits = 0;
|
454
|
+
node->bits = 0;
|
455
|
+
|
456
|
+
/* if we have a non-zero weight, compute the number of bits */
|
457
|
+
if (node->weight > 0)
|
458
|
+
{
|
459
|
+
/* determine the number of bits for this node */
|
460
|
+
for (curnode = node; curnode->parent != NULL; curnode = curnode->parent)
|
461
|
+
node->numbits++;
|
462
|
+
if (node->numbits == 0)
|
463
|
+
node->numbits = 1;
|
464
|
+
|
465
|
+
/* keep track of the max */
|
466
|
+
maxbits = MAX(maxbits, ((int)node->numbits));
|
467
|
+
}
|
468
|
+
}
|
469
|
+
return maxbits;
|
470
|
+
}
|
471
|
+
|
472
|
+
/*-------------------------------------------------
|
473
|
+
* assign_canonical_codes - assign canonical codes
|
474
|
+
* to all the nodes based on the number of bits
|
475
|
+
* in each
|
476
|
+
*-------------------------------------------------
|
477
|
+
*/
|
478
|
+
|
479
|
+
enum huffman_error huffman_assign_canonical_codes(struct huffman_decoder* decoder)
|
480
|
+
{
|
481
|
+
uint32_t curcode;
|
482
|
+
int codelen;
|
483
|
+
uint32_t curstart = 0;
|
484
|
+
/* build up a histogram of bit lengths */
|
485
|
+
uint32_t bithisto[33] = { 0 };
|
486
|
+
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
487
|
+
{
|
488
|
+
struct node_t* node = &decoder->huffnode[curcode];
|
489
|
+
if (node->numbits > decoder->maxbits)
|
490
|
+
return HUFFERR_INTERNAL_INCONSISTENCY;
|
491
|
+
if (node->numbits <= 32)
|
492
|
+
bithisto[node->numbits]++;
|
493
|
+
}
|
494
|
+
|
495
|
+
/* for each code length, determine the starting code number */
|
496
|
+
for (codelen = 32; codelen > 0; codelen--)
|
497
|
+
{
|
498
|
+
uint32_t nextstart = (curstart + bithisto[codelen]) >> 1;
|
499
|
+
if (codelen != 1 && nextstart * 2 != (curstart + bithisto[codelen]))
|
500
|
+
return HUFFERR_INTERNAL_INCONSISTENCY;
|
501
|
+
bithisto[codelen] = curstart;
|
502
|
+
curstart = nextstart;
|
503
|
+
}
|
504
|
+
|
505
|
+
/* now assign canonical codes */
|
506
|
+
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
507
|
+
{
|
508
|
+
struct node_t* node = &decoder->huffnode[curcode];
|
509
|
+
if (node->numbits > 0)
|
510
|
+
node->bits = bithisto[node->numbits]++;
|
511
|
+
}
|
512
|
+
return HUFFERR_NONE;
|
513
|
+
}
|
514
|
+
|
515
|
+
/*-------------------------------------------------
|
516
|
+
* build_lookup_table - build a lookup table for
|
517
|
+
* fast decoding
|
518
|
+
*-------------------------------------------------
|
519
|
+
*/
|
520
|
+
|
521
|
+
void huffman_build_lookup_table(struct huffman_decoder* decoder)
|
522
|
+
{
|
523
|
+
uint32_t curcode;
|
524
|
+
/* iterate over all codes */
|
525
|
+
for (curcode = 0; curcode < decoder->numcodes; curcode++)
|
526
|
+
{
|
527
|
+
/* process all nodes which have non-zero bits */
|
528
|
+
struct node_t* node = &decoder->huffnode[curcode];
|
529
|
+
if (node->numbits > 0)
|
530
|
+
{
|
531
|
+
int shift;
|
532
|
+
lookup_value *dest;
|
533
|
+
lookup_value *destend;
|
534
|
+
/* set up the entry */
|
535
|
+
lookup_value value = MAKE_LOOKUP(curcode, node->numbits);
|
536
|
+
|
537
|
+
/* fill all matching entries */
|
538
|
+
shift = decoder->maxbits - node->numbits;
|
539
|
+
dest = &decoder->lookup[node->bits << shift];
|
540
|
+
destend = &decoder->lookup[((node->bits + 1) << shift) - 1];
|
541
|
+
while (dest <= destend)
|
542
|
+
*dest++ = value;
|
543
|
+
}
|
544
|
+
}
|
545
|
+
}
|
@@ -0,0 +1,52 @@
|
|
1
|
+
#include <libchdr/chd.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <time.h>
|
5
|
+
|
6
|
+
int main(int argc, char** argv)
|
7
|
+
{
|
8
|
+
chd_error err;
|
9
|
+
chd_file* file;
|
10
|
+
const chd_header* header;
|
11
|
+
void* buffer;
|
12
|
+
unsigned int i;
|
13
|
+
unsigned int totalbytes;
|
14
|
+
clock_t start, end;
|
15
|
+
double time_taken;
|
16
|
+
|
17
|
+
printf("\nlibchdr benchmark tool....");
|
18
|
+
|
19
|
+
/* Recording the starting clock tick.*/
|
20
|
+
start = clock();
|
21
|
+
|
22
|
+
/* Sequential read all hunks */
|
23
|
+
err = chd_open(argv[1], CHD_OPEN_READ, NULL, &file);
|
24
|
+
if (err)
|
25
|
+
{
|
26
|
+
printf("\nchd_open() error: %s", chd_error_string(err));
|
27
|
+
return 0;
|
28
|
+
}
|
29
|
+
header = chd_get_header(file);
|
30
|
+
totalbytes = header->hunkbytes * header->totalhunks;
|
31
|
+
buffer = malloc(header->hunkbytes);
|
32
|
+
for (i = 0 ; i < header->totalhunks ; i++)
|
33
|
+
{
|
34
|
+
err = chd_read(file, i, buffer);
|
35
|
+
if (err)
|
36
|
+
printf("\nchd_read() error: %s", chd_error_string(err));
|
37
|
+
}
|
38
|
+
free(buffer);
|
39
|
+
chd_close(file);
|
40
|
+
|
41
|
+
/* Recording the end clock tick. */
|
42
|
+
end = clock();
|
43
|
+
|
44
|
+
/* Calculating total time taken by the program. */
|
45
|
+
time_taken = ((double)(end - start)) / ((double)CLOCKS_PER_SEC);
|
46
|
+
|
47
|
+
/* Print results */
|
48
|
+
printf("\nRead %d bytes in %lf seconds", totalbytes, time_taken);
|
49
|
+
printf("\nRate is %lf MB/s", (((double)totalbytes)/(1024*1024)) / time_taken);
|
50
|
+
printf("\n\n");
|
51
|
+
return 0;
|
52
|
+
}
|