zopfli 0.0.2 → 0.0.8
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 +6 -14
- data/.gitmodules +1 -1
- data/.travis.yml +23 -0
- data/Gemfile +2 -0
- data/README.md +6 -1
- data/Rakefile +8 -10
- data/ext/extconf.rb +2 -1
- data/ext/zopfli.c +39 -20
- data/lib/zopfli/version.rb +1 -1
- data/smoke.sh +9 -0
- data/{test → spec}/fixtures/alice29.txt +0 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/zopfli_spec.rb +68 -0
- data/vendor/zopfli/{blocksplitter.c → src/zopfli/blocksplitter.c} +41 -53
- data/vendor/zopfli/{blocksplitter.h → src/zopfli/blocksplitter.h} +2 -6
- data/vendor/zopfli/{cache.c → src/zopfli/cache.c} +6 -0
- data/vendor/zopfli/{cache.h → src/zopfli/cache.h} +0 -0
- data/vendor/zopfli/src/zopfli/deflate.c +931 -0
- data/vendor/zopfli/{deflate.h → src/zopfli/deflate.h} +17 -2
- data/vendor/zopfli/src/zopfli/gzip_container.c +124 -0
- data/vendor/zopfli/{gzip_container.h → src/zopfli/gzip_container.h} +8 -0
- data/vendor/zopfli/{hash.c → src/zopfli/hash.c} +18 -10
- data/vendor/zopfli/{hash.h → src/zopfli/hash.h} +10 -7
- data/vendor/zopfli/{katajainen.c → src/zopfli/katajainen.c} +73 -62
- data/vendor/zopfli/{katajainen.h → src/zopfli/katajainen.h} +1 -1
- data/vendor/zopfli/{lz77.c → src/zopfli/lz77.c} +190 -42
- data/vendor/zopfli/{lz77.h → src/zopfli/lz77.h} +39 -23
- data/vendor/zopfli/{squeeze.c → src/zopfli/squeeze.c} +75 -61
- data/vendor/zopfli/{squeeze.h → src/zopfli/squeeze.h} +1 -0
- data/vendor/zopfli/{util.c → src/zopfli/symbols.h} +49 -23
- data/vendor/zopfli/{tree.c → src/zopfli/tree.c} +0 -0
- data/vendor/zopfli/{tree.h → src/zopfli/tree.h} +0 -0
- data/vendor/zopfli/src/zopfli/util.c +35 -0
- data/vendor/zopfli/{util.h → src/zopfli/util.h} +6 -23
- data/vendor/zopfli/{zlib_container.c → src/zopfli/zlib_container.c} +1 -1
- data/vendor/zopfli/{zlib_container.h → src/zopfli/zlib_container.h} +8 -0
- data/vendor/zopfli/{zopfli.h → src/zopfli/zopfli.h} +10 -4
- data/vendor/zopfli/{zopfli_bin.c → src/zopfli/zopfli_bin.c} +31 -15
- data/vendor/zopfli/{zopfli_lib.c → src/zopfli/zopfli_lib.c} +1 -2
- data/zopfli.gemspec +9 -28
- metadata +51 -50
- data/test/test_zopfli_deflate.rb +0 -47
- data/vendor/zopfli/CONTRIBUTORS +0 -6
- data/vendor/zopfli/README +0 -25
- data/vendor/zopfli/deflate.c +0 -698
- data/vendor/zopfli/gzip_container.c +0 -117
- data/vendor/zopfli/makefile +0 -5
@@ -25,8 +25,13 @@ Functions to compress according to the DEFLATE specification, using the
|
|
25
25
|
"squeeze" LZ77 compression backend.
|
26
26
|
*/
|
27
27
|
|
28
|
+
#include "lz77.h"
|
28
29
|
#include "zopfli.h"
|
29
30
|
|
31
|
+
#ifdef __cplusplus
|
32
|
+
extern "C" {
|
33
|
+
#endif
|
34
|
+
|
30
35
|
/*
|
31
36
|
Compresses according to the deflate specification and append the compressed
|
32
37
|
result to the output.
|
@@ -71,7 +76,17 @@ dists: ll77 distances
|
|
71
76
|
lstart: start of block
|
72
77
|
lend: end of block (not inclusive)
|
73
78
|
*/
|
74
|
-
double ZopfliCalculateBlockSize(const
|
75
|
-
const unsigned short* dists,
|
79
|
+
double ZopfliCalculateBlockSize(const ZopfliLZ77Store* lz77,
|
76
80
|
size_t lstart, size_t lend, int btype);
|
81
|
+
|
82
|
+
/*
|
83
|
+
Calculates block size in bits, automatically using the best btype.
|
84
|
+
*/
|
85
|
+
double ZopfliCalculateBlockSizeAutoType(const ZopfliLZ77Store* lz77,
|
86
|
+
size_t lstart, size_t lend);
|
87
|
+
|
88
|
+
#ifdef __cplusplus
|
89
|
+
} // extern "C"
|
90
|
+
#endif
|
91
|
+
|
77
92
|
#endif /* ZOPFLI_DEFLATE_H_ */
|
@@ -0,0 +1,124 @@
|
|
1
|
+
/*
|
2
|
+
Copyright 2013 Google Inc. All Rights Reserved.
|
3
|
+
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
you may not use this file except in compliance with the License.
|
6
|
+
You may obtain a copy of the License at
|
7
|
+
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
See the License for the specific language governing permissions and
|
14
|
+
limitations under the License.
|
15
|
+
|
16
|
+
Author: lode.vandevenne@gmail.com (Lode Vandevenne)
|
17
|
+
Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
|
18
|
+
*/
|
19
|
+
|
20
|
+
#include "gzip_container.h"
|
21
|
+
#include "util.h"
|
22
|
+
|
23
|
+
#include <stdio.h>
|
24
|
+
|
25
|
+
#include "deflate.h"
|
26
|
+
|
27
|
+
/* CRC polynomial: 0xedb88320 */
|
28
|
+
static const unsigned long crc32_table[256] = {
|
29
|
+
0u, 1996959894u, 3993919788u, 2567524794u, 124634137u, 1886057615u,
|
30
|
+
3915621685u, 2657392035u, 249268274u, 2044508324u, 3772115230u, 2547177864u,
|
31
|
+
162941995u, 2125561021u, 3887607047u, 2428444049u, 498536548u, 1789927666u,
|
32
|
+
4089016648u, 2227061214u, 450548861u, 1843258603u, 4107580753u, 2211677639u,
|
33
|
+
325883990u, 1684777152u, 4251122042u, 2321926636u, 335633487u, 1661365465u,
|
34
|
+
4195302755u, 2366115317u, 997073096u, 1281953886u, 3579855332u, 2724688242u,
|
35
|
+
1006888145u, 1258607687u, 3524101629u, 2768942443u, 901097722u, 1119000684u,
|
36
|
+
3686517206u, 2898065728u, 853044451u, 1172266101u, 3705015759u, 2882616665u,
|
37
|
+
651767980u, 1373503546u, 3369554304u, 3218104598u, 565507253u, 1454621731u,
|
38
|
+
3485111705u, 3099436303u, 671266974u, 1594198024u, 3322730930u, 2970347812u,
|
39
|
+
795835527u, 1483230225u, 3244367275u, 3060149565u, 1994146192u, 31158534u,
|
40
|
+
2563907772u, 4023717930u, 1907459465u, 112637215u, 2680153253u, 3904427059u,
|
41
|
+
2013776290u, 251722036u, 2517215374u, 3775830040u, 2137656763u, 141376813u,
|
42
|
+
2439277719u, 3865271297u, 1802195444u, 476864866u, 2238001368u, 4066508878u,
|
43
|
+
1812370925u, 453092731u, 2181625025u, 4111451223u, 1706088902u, 314042704u,
|
44
|
+
2344532202u, 4240017532u, 1658658271u, 366619977u, 2362670323u, 4224994405u,
|
45
|
+
1303535960u, 984961486u, 2747007092u, 3569037538u, 1256170817u, 1037604311u,
|
46
|
+
2765210733u, 3554079995u, 1131014506u, 879679996u, 2909243462u, 3663771856u,
|
47
|
+
1141124467u, 855842277u, 2852801631u, 3708648649u, 1342533948u, 654459306u,
|
48
|
+
3188396048u, 3373015174u, 1466479909u, 544179635u, 3110523913u, 3462522015u,
|
49
|
+
1591671054u, 702138776u, 2966460450u, 3352799412u, 1504918807u, 783551873u,
|
50
|
+
3082640443u, 3233442989u, 3988292384u, 2596254646u, 62317068u, 1957810842u,
|
51
|
+
3939845945u, 2647816111u, 81470997u, 1943803523u, 3814918930u, 2489596804u,
|
52
|
+
225274430u, 2053790376u, 3826175755u, 2466906013u, 167816743u, 2097651377u,
|
53
|
+
4027552580u, 2265490386u, 503444072u, 1762050814u, 4150417245u, 2154129355u,
|
54
|
+
426522225u, 1852507879u, 4275313526u, 2312317920u, 282753626u, 1742555852u,
|
55
|
+
4189708143u, 2394877945u, 397917763u, 1622183637u, 3604390888u, 2714866558u,
|
56
|
+
953729732u, 1340076626u, 3518719985u, 2797360999u, 1068828381u, 1219638859u,
|
57
|
+
3624741850u, 2936675148u, 906185462u, 1090812512u, 3747672003u, 2825379669u,
|
58
|
+
829329135u, 1181335161u, 3412177804u, 3160834842u, 628085408u, 1382605366u,
|
59
|
+
3423369109u, 3138078467u, 570562233u, 1426400815u, 3317316542u, 2998733608u,
|
60
|
+
733239954u, 1555261956u, 3268935591u, 3050360625u, 752459403u, 1541320221u,
|
61
|
+
2607071920u, 3965973030u, 1969922972u, 40735498u, 2617837225u, 3943577151u,
|
62
|
+
1913087877u, 83908371u, 2512341634u, 3803740692u, 2075208622u, 213261112u,
|
63
|
+
2463272603u, 3855990285u, 2094854071u, 198958881u, 2262029012u, 4057260610u,
|
64
|
+
1759359992u, 534414190u, 2176718541u, 4139329115u, 1873836001u, 414664567u,
|
65
|
+
2282248934u, 4279200368u, 1711684554u, 285281116u, 2405801727u, 4167216745u,
|
66
|
+
1634467795u, 376229701u, 2685067896u, 3608007406u, 1308918612u, 956543938u,
|
67
|
+
2808555105u, 3495958263u, 1231636301u, 1047427035u, 2932959818u, 3654703836u,
|
68
|
+
1088359270u, 936918000u, 2847714899u, 3736837829u, 1202900863u, 817233897u,
|
69
|
+
3183342108u, 3401237130u, 1404277552u, 615818150u, 3134207493u, 3453421203u,
|
70
|
+
1423857449u, 601450431u, 3009837614u, 3294710456u, 1567103746u, 711928724u,
|
71
|
+
3020668471u, 3272380065u, 1510334235u, 755167117u
|
72
|
+
};
|
73
|
+
|
74
|
+
/* Returns the CRC32 */
|
75
|
+
static unsigned long CRC(const unsigned char* data, size_t size) {
|
76
|
+
unsigned long result = 0xffffffffu;
|
77
|
+
for (; size > 0; size--) {
|
78
|
+
result = crc32_table[(result ^ *(data++)) & 0xff] ^ (result >> 8);
|
79
|
+
}
|
80
|
+
return result ^ 0xffffffffu;
|
81
|
+
}
|
82
|
+
|
83
|
+
/* Compresses the data according to the gzip specification, RFC 1952. */
|
84
|
+
void ZopfliGzipCompress(const ZopfliOptions* options,
|
85
|
+
const unsigned char* in, size_t insize,
|
86
|
+
unsigned char** out, size_t* outsize) {
|
87
|
+
unsigned long crcvalue = CRC(in, insize);
|
88
|
+
unsigned char bp = 0;
|
89
|
+
|
90
|
+
ZOPFLI_APPEND_DATA(31, out, outsize); /* ID1 */
|
91
|
+
ZOPFLI_APPEND_DATA(139, out, outsize); /* ID2 */
|
92
|
+
ZOPFLI_APPEND_DATA(8, out, outsize); /* CM */
|
93
|
+
ZOPFLI_APPEND_DATA(0, out, outsize); /* FLG */
|
94
|
+
/* MTIME */
|
95
|
+
ZOPFLI_APPEND_DATA(0, out, outsize);
|
96
|
+
ZOPFLI_APPEND_DATA(0, out, outsize);
|
97
|
+
ZOPFLI_APPEND_DATA(0, out, outsize);
|
98
|
+
ZOPFLI_APPEND_DATA(0, out, outsize);
|
99
|
+
|
100
|
+
ZOPFLI_APPEND_DATA(2, out, outsize); /* XFL, 2 indicates best compression. */
|
101
|
+
ZOPFLI_APPEND_DATA(3, out, outsize); /* OS follows Unix conventions. */
|
102
|
+
|
103
|
+
ZopfliDeflate(options, 2 /* Dynamic block */, 1,
|
104
|
+
in, insize, &bp, out, outsize);
|
105
|
+
|
106
|
+
/* CRC */
|
107
|
+
ZOPFLI_APPEND_DATA(crcvalue % 256, out, outsize);
|
108
|
+
ZOPFLI_APPEND_DATA((crcvalue >> 8) % 256, out, outsize);
|
109
|
+
ZOPFLI_APPEND_DATA((crcvalue >> 16) % 256, out, outsize);
|
110
|
+
ZOPFLI_APPEND_DATA((crcvalue >> 24) % 256, out, outsize);
|
111
|
+
|
112
|
+
/* ISIZE */
|
113
|
+
ZOPFLI_APPEND_DATA(insize % 256, out, outsize);
|
114
|
+
ZOPFLI_APPEND_DATA((insize >> 8) % 256, out, outsize);
|
115
|
+
ZOPFLI_APPEND_DATA((insize >> 16) % 256, out, outsize);
|
116
|
+
ZOPFLI_APPEND_DATA((insize >> 24) % 256, out, outsize);
|
117
|
+
|
118
|
+
if (options->verbose) {
|
119
|
+
fprintf(stderr,
|
120
|
+
"Original Size: %d, Gzip: %d, Compression: %f%% Removed\n",
|
121
|
+
(int)insize, (int)*outsize,
|
122
|
+
100.0 * (double)(insize - *outsize) / (double)insize);
|
123
|
+
}
|
124
|
+
}
|
@@ -26,6 +26,10 @@ Functions to compress according to the Gzip specification.
|
|
26
26
|
|
27
27
|
#include "zopfli.h"
|
28
28
|
|
29
|
+
#ifdef __cplusplus
|
30
|
+
extern "C" {
|
31
|
+
#endif
|
32
|
+
|
29
33
|
/*
|
30
34
|
Compresses according to the gzip specification and append the compressed
|
31
35
|
result to the output.
|
@@ -39,4 +43,8 @@ void ZopfliGzipCompress(const ZopfliOptions* options,
|
|
39
43
|
const unsigned char* in, size_t insize,
|
40
44
|
unsigned char** out, size_t* outsize);
|
41
45
|
|
46
|
+
#ifdef __cplusplus
|
47
|
+
} // extern "C"
|
48
|
+
#endif
|
49
|
+
|
42
50
|
#endif /* ZOPFLI_GZIP_H_ */
|
@@ -26,13 +26,26 @@ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
|
|
26
26
|
#define HASH_SHIFT 5
|
27
27
|
#define HASH_MASK 32767
|
28
28
|
|
29
|
-
void
|
30
|
-
size_t i;
|
31
|
-
|
32
|
-
h->val = 0;
|
29
|
+
void ZopfliAllocHash(size_t window_size, ZopfliHash* h) {
|
33
30
|
h->head = (int*)malloc(sizeof(*h->head) * 65536);
|
34
31
|
h->prev = (unsigned short*)malloc(sizeof(*h->prev) * window_size);
|
35
32
|
h->hashval = (int*)malloc(sizeof(*h->hashval) * window_size);
|
33
|
+
|
34
|
+
#ifdef ZOPFLI_HASH_SAME
|
35
|
+
h->same = (unsigned short*)malloc(sizeof(*h->same) * window_size);
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#ifdef ZOPFLI_HASH_SAME_HASH
|
39
|
+
h->head2 = (int*)malloc(sizeof(*h->head2) * 65536);
|
40
|
+
h->prev2 = (unsigned short*)malloc(sizeof(*h->prev2) * window_size);
|
41
|
+
h->hashval2 = (int*)malloc(sizeof(*h->hashval2) * window_size);
|
42
|
+
#endif
|
43
|
+
}
|
44
|
+
|
45
|
+
void ZopfliResetHash(size_t window_size, ZopfliHash* h) {
|
46
|
+
size_t i;
|
47
|
+
|
48
|
+
h->val = 0;
|
36
49
|
for (i = 0; i < 65536; i++) {
|
37
50
|
h->head[i] = -1; /* -1 indicates no head so far. */
|
38
51
|
}
|
@@ -42,7 +55,6 @@ void ZopfliInitHash(size_t window_size, ZopfliHash* h) {
|
|
42
55
|
}
|
43
56
|
|
44
57
|
#ifdef ZOPFLI_HASH_SAME
|
45
|
-
h->same = (unsigned short*)malloc(sizeof(*h->same) * window_size);
|
46
58
|
for (i = 0; i < window_size; i++) {
|
47
59
|
h->same[i] = 0;
|
48
60
|
}
|
@@ -50,9 +62,6 @@ void ZopfliInitHash(size_t window_size, ZopfliHash* h) {
|
|
50
62
|
|
51
63
|
#ifdef ZOPFLI_HASH_SAME_HASH
|
52
64
|
h->val2 = 0;
|
53
|
-
h->head2 = (int*)malloc(sizeof(*h->head2) * 65536);
|
54
|
-
h->prev2 = (unsigned short*)malloc(sizeof(*h->prev2) * window_size);
|
55
|
-
h->hashval2 = (int*)malloc(sizeof(*h->hashval2) * window_size);
|
56
65
|
for (i = 0; i < 65536; i++) {
|
57
66
|
h->head2[i] = -1;
|
58
67
|
}
|
@@ -129,7 +138,6 @@ void ZopfliUpdateHash(const unsigned char* array, size_t pos, size_t end,
|
|
129
138
|
|
130
139
|
void ZopfliWarmupHash(const unsigned char* array, size_t pos, size_t end,
|
131
140
|
ZopfliHash* h) {
|
132
|
-
(void)end;
|
133
141
|
UpdateHashValue(h, array[pos + 0]);
|
134
|
-
UpdateHashValue(h, array[pos + 1]);
|
142
|
+
if (pos + 1 < end) UpdateHashValue(h, array[pos + 1]);
|
135
143
|
}
|
@@ -27,16 +27,16 @@ The hash for ZopfliFindLongestMatch of lz77.c.
|
|
27
27
|
#include "util.h"
|
28
28
|
|
29
29
|
typedef struct ZopfliHash {
|
30
|
-
int* head; /* Hash value to index of its most recent
|
31
|
-
unsigned short* prev; /* Index to index of prev.
|
30
|
+
int* head; /* Hash value to index of its most recent occurrence. */
|
31
|
+
unsigned short* prev; /* Index to index of prev. occurrence of same hash. */
|
32
32
|
int* hashval; /* Index to hash value at this index. */
|
33
33
|
int val; /* Current hash value. */
|
34
34
|
|
35
35
|
#ifdef ZOPFLI_HASH_SAME_HASH
|
36
36
|
/* Fields with similar purpose as the above hash, but for the second hash with
|
37
37
|
a value that is calculated differently. */
|
38
|
-
int* head2; /* Hash value to index of its most recent
|
39
|
-
unsigned short* prev2; /* Index to index of prev.
|
38
|
+
int* head2; /* Hash value to index of its most recent occurrence. */
|
39
|
+
unsigned short* prev2; /* Index to index of prev. occurrence of same hash. */
|
40
40
|
int* hashval2; /* Index to hash value at this index. */
|
41
41
|
int val2; /* Current hash value. */
|
42
42
|
#endif
|
@@ -46,10 +46,13 @@ typedef struct ZopfliHash {
|
|
46
46
|
#endif
|
47
47
|
} ZopfliHash;
|
48
48
|
|
49
|
-
/* Allocates
|
50
|
-
void
|
49
|
+
/* Allocates ZopfliHash memory. */
|
50
|
+
void ZopfliAllocHash(size_t window_size, ZopfliHash* h);
|
51
51
|
|
52
|
-
/*
|
52
|
+
/* Resets all fields of ZopfliHash. */
|
53
|
+
void ZopfliResetHash(size_t window_size, ZopfliHash* h);
|
54
|
+
|
55
|
+
/* Frees ZopfliHash memory. */
|
53
56
|
void ZopfliCleanHash(ZopfliHash* h);
|
54
57
|
|
55
58
|
/*
|
@@ -26,6 +26,7 @@ Jyrki Katajainen, Alistair Moffat, Andrew Turpin".
|
|
26
26
|
#include "katajainen.h"
|
27
27
|
#include <assert.h>
|
28
28
|
#include <stdlib.h>
|
29
|
+
#include <limits.h>
|
29
30
|
|
30
31
|
typedef struct Node Node;
|
31
32
|
|
@@ -36,16 +37,13 @@ struct Node {
|
|
36
37
|
size_t weight; /* Total weight (symbol count) of this chain. */
|
37
38
|
Node* tail; /* Previous node(s) of this chain, or 0 if none. */
|
38
39
|
int count; /* Leaf symbol index, or number of leaves before this chain. */
|
39
|
-
char inuse; /* Tracking for garbage collection. */
|
40
40
|
};
|
41
41
|
|
42
42
|
/*
|
43
43
|
Memory pool for nodes.
|
44
44
|
*/
|
45
45
|
typedef struct NodePool {
|
46
|
-
Node*
|
47
|
-
Node* next; /* Pointer to a possibly free node in the pool. */
|
48
|
-
int size; /* Size of the memory pool. */
|
46
|
+
Node* next; /* Pointer to a free node in the pool. */
|
49
47
|
} NodePool;
|
50
48
|
|
51
49
|
/*
|
@@ -55,40 +53,8 @@ static void InitNode(size_t weight, int count, Node* tail, Node* node) {
|
|
55
53
|
node->weight = weight;
|
56
54
|
node->count = count;
|
57
55
|
node->tail = tail;
|
58
|
-
node->inuse = 1;
|
59
56
|
}
|
60
57
|
|
61
|
-
/*
|
62
|
-
Finds a free location in the memory pool. Performs garbage collection if needed.
|
63
|
-
lists: If given, used to mark in-use nodes during garbage collection.
|
64
|
-
maxbits: Size of lists.
|
65
|
-
pool: Memory pool to get free node from.
|
66
|
-
*/
|
67
|
-
static Node* GetFreeNode(Node* (*lists)[2], int maxbits, NodePool* pool) {
|
68
|
-
for (;;) {
|
69
|
-
if (pool->next >= &pool->nodes[pool->size]) {
|
70
|
-
/* Garbage collection. */
|
71
|
-
int i;
|
72
|
-
for (i = 0; i < pool->size; i++) {
|
73
|
-
pool->nodes[i].inuse = 0;
|
74
|
-
}
|
75
|
-
if (lists) {
|
76
|
-
for (i = 0; i < maxbits * 2; i++) {
|
77
|
-
Node* node;
|
78
|
-
for (node = lists[i / 2][i % 2]; node; node = node->tail) {
|
79
|
-
node->inuse = 1;
|
80
|
-
}
|
81
|
-
}
|
82
|
-
}
|
83
|
-
pool->next = &pool->nodes[0];
|
84
|
-
}
|
85
|
-
if (!pool->next->inuse) break; /* Found one. */
|
86
|
-
pool->next++;
|
87
|
-
}
|
88
|
-
return pool->next++;
|
89
|
-
}
|
90
|
-
|
91
|
-
|
92
58
|
/*
|
93
59
|
Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
|
94
60
|
new chain is, depending on the weights, a leaf or a combination of two chains
|
@@ -99,18 +65,16 @@ leaves: The leaves, one per symbol.
|
|
99
65
|
numsymbols: Number of leaves.
|
100
66
|
pool: the node memory pool.
|
101
67
|
index: The index of the list in which a new chain or leaf is required.
|
102
|
-
final: Whether this is the last time this function is called. If it is then it
|
103
|
-
is no more needed to recursively call self.
|
104
68
|
*/
|
105
|
-
static void BoundaryPM(Node* (*lists)[2], int
|
106
|
-
|
69
|
+
static void BoundaryPM(Node* (*lists)[2], Node* leaves, int numsymbols,
|
70
|
+
NodePool* pool, int index) {
|
107
71
|
Node* newchain;
|
108
72
|
Node* oldchain;
|
109
73
|
int lastcount = lists[index][1]->count; /* Count of last chain of list. */
|
110
74
|
|
111
75
|
if (index == 0 && lastcount >= numsymbols) return;
|
112
76
|
|
113
|
-
newchain =
|
77
|
+
newchain = pool->next++;
|
114
78
|
oldchain = lists[index][1];
|
115
79
|
|
116
80
|
/* These are set up before the recursive calls below, so that there is a list
|
@@ -129,15 +93,31 @@ static void BoundaryPM(Node* (*lists)[2], int maxbits,
|
|
129
93
|
newchain);
|
130
94
|
} else {
|
131
95
|
InitNode(sum, lastcount, lists[index - 1][1], newchain);
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
BoundaryPM(lists, maxbits, leaves, numsymbols, pool, index - 1, 0);
|
136
|
-
}
|
96
|
+
/* Two lookahead chains of previous list used up, create new ones. */
|
97
|
+
BoundaryPM(lists, leaves, numsymbols, pool, index - 1);
|
98
|
+
BoundaryPM(lists, leaves, numsymbols, pool, index - 1);
|
137
99
|
}
|
138
100
|
}
|
139
101
|
}
|
140
102
|
|
103
|
+
static void BoundaryPMFinal(Node* (*lists)[2],
|
104
|
+
Node* leaves, int numsymbols, NodePool* pool, int index) {
|
105
|
+
int lastcount = lists[index][1]->count; /* Count of last chain of list. */
|
106
|
+
|
107
|
+
size_t sum = lists[index - 1][0]->weight + lists[index - 1][1]->weight;
|
108
|
+
|
109
|
+
if (lastcount < numsymbols && sum > leaves[lastcount].weight) {
|
110
|
+
Node* newchain = pool->next;
|
111
|
+
Node* oldchain = lists[index][1]->tail;
|
112
|
+
|
113
|
+
lists[index][1] = newchain;
|
114
|
+
newchain->count = lastcount + 1;
|
115
|
+
newchain->tail = oldchain;
|
116
|
+
} else {
|
117
|
+
lists[index][1]->tail = lists[index - 1][1];
|
118
|
+
}
|
119
|
+
}
|
120
|
+
|
141
121
|
/*
|
142
122
|
Initializes each list with as lookahead chains the two leaves with lowest
|
143
123
|
weights.
|
@@ -145,8 +125,8 @@ weights.
|
|
145
125
|
static void InitLists(
|
146
126
|
NodePool* pool, const Node* leaves, int maxbits, Node* (*lists)[2]) {
|
147
127
|
int i;
|
148
|
-
Node* node0 =
|
149
|
-
Node* node1 =
|
128
|
+
Node* node0 = pool->next++;
|
129
|
+
Node* node1 = pool->next++;
|
150
130
|
InitNode(leaves[0].weight, 1, 0, node0);
|
151
131
|
InitNode(leaves[1].weight, 2, 0, node1);
|
152
132
|
for (i = 0; i < maxbits; i++) {
|
@@ -161,12 +141,24 @@ last chain of the last list contains the amount of active leaves in each list.
|
|
161
141
|
chain: Chain to extract the bit length from (last chain from last list).
|
162
142
|
*/
|
163
143
|
static void ExtractBitLengths(Node* chain, Node* leaves, unsigned* bitlengths) {
|
144
|
+
int counts[16] = {0};
|
145
|
+
unsigned end = 16;
|
146
|
+
unsigned ptr = 15;
|
147
|
+
unsigned value = 1;
|
164
148
|
Node* node;
|
149
|
+
int val;
|
150
|
+
|
165
151
|
for (node = chain; node; node = node->tail) {
|
166
|
-
|
167
|
-
|
168
|
-
|
152
|
+
counts[--end] = node->count;
|
153
|
+
}
|
154
|
+
|
155
|
+
val = counts[15];
|
156
|
+
while (ptr >= end) {
|
157
|
+
for (; val > counts[ptr - 1]; val--) {
|
158
|
+
bitlengths[leaves[val - 1].count] = value;
|
169
159
|
}
|
160
|
+
ptr--;
|
161
|
+
value++;
|
170
162
|
}
|
171
163
|
}
|
172
164
|
|
@@ -183,6 +175,7 @@ int ZopfliLengthLimitedCodeLengths(
|
|
183
175
|
int i;
|
184
176
|
int numsymbols = 0; /* Amount of symbols with frequency > 0. */
|
185
177
|
int numBoundaryPMRuns;
|
178
|
+
Node* nodes;
|
186
179
|
|
187
180
|
/* Array of lists of chains. Each list requires only two lookahead chains at
|
188
181
|
a time, so each list is a array of two Node*'s. */
|
@@ -219,33 +212,51 @@ int ZopfliLengthLimitedCodeLengths(
|
|
219
212
|
free(leaves);
|
220
213
|
return 0; /* Only one symbol, give it bitlength 1, not 0. OK. */
|
221
214
|
}
|
215
|
+
if (numsymbols == 2) {
|
216
|
+
bitlengths[leaves[0].count]++;
|
217
|
+
bitlengths[leaves[1].count]++;
|
218
|
+
free(leaves);
|
219
|
+
return 0;
|
220
|
+
}
|
222
221
|
|
223
|
-
/* Sort the leaves from lightest to heaviest.
|
222
|
+
/* Sort the leaves from lightest to heaviest. Add count into the same
|
223
|
+
variable for stable sorting. */
|
224
|
+
for (i = 0; i < numsymbols; i++) {
|
225
|
+
if (leaves[i].weight >=
|
226
|
+
((size_t)1 << (sizeof(leaves[0].weight) * CHAR_BIT - 9))) {
|
227
|
+
free(leaves);
|
228
|
+
return 1; /* Error, we need 9 bits for the count. */
|
229
|
+
}
|
230
|
+
leaves[i].weight = (leaves[i].weight << 9) | leaves[i].count;
|
231
|
+
}
|
224
232
|
qsort(leaves, numsymbols, sizeof(Node), LeafComparator);
|
233
|
+
for (i = 0; i < numsymbols; i++) {
|
234
|
+
leaves[i].weight >>= 9;
|
235
|
+
}
|
225
236
|
|
226
|
-
|
227
|
-
|
228
|
-
pool.nodes = (Node*)malloc(pool.size * sizeof(*pool.nodes));
|
229
|
-
pool.next = pool.nodes;
|
230
|
-
for (i = 0; i < pool.size; i++) {
|
231
|
-
pool.nodes[i].inuse = 0;
|
237
|
+
if (numsymbols - 1 < maxbits) {
|
238
|
+
maxbits = numsymbols - 1;
|
232
239
|
}
|
233
240
|
|
241
|
+
/* Initialize node memory pool. */
|
242
|
+
nodes = (Node*)malloc(maxbits * 2 * numsymbols * sizeof(Node));
|
243
|
+
pool.next = nodes;
|
244
|
+
|
234
245
|
lists = (Node* (*)[2])malloc(maxbits * sizeof(*lists));
|
235
246
|
InitLists(&pool, leaves, maxbits, lists);
|
236
247
|
|
237
248
|
/* In the last list, 2 * numsymbols - 2 active chains need to be created. Two
|
238
249
|
are already created in the initialization. Each BoundaryPM run creates one. */
|
239
250
|
numBoundaryPMRuns = 2 * numsymbols - 4;
|
240
|
-
for (i = 0; i < numBoundaryPMRuns; i++) {
|
241
|
-
|
242
|
-
BoundaryPM(lists, maxbits, leaves, numsymbols, &pool, maxbits - 1, final);
|
251
|
+
for (i = 0; i < numBoundaryPMRuns - 1; i++) {
|
252
|
+
BoundaryPM(lists, leaves, numsymbols, &pool, maxbits - 1);
|
243
253
|
}
|
254
|
+
BoundaryPMFinal(lists, leaves, numsymbols, &pool, maxbits - 1);
|
244
255
|
|
245
256
|
ExtractBitLengths(lists[maxbits - 1][1], leaves, bitlengths);
|
246
257
|
|
247
258
|
free(lists);
|
248
259
|
free(leaves);
|
249
|
-
free(
|
260
|
+
free(nodes);
|
250
261
|
return 0; /* OK. */
|
251
262
|
}
|