zopfli 0.0.2 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +6 -14
  2. data/.gitmodules +1 -1
  3. data/.travis.yml +23 -0
  4. data/Gemfile +2 -0
  5. data/README.md +6 -1
  6. data/Rakefile +8 -10
  7. data/ext/extconf.rb +2 -1
  8. data/ext/zopfli.c +39 -20
  9. data/lib/zopfli/version.rb +1 -1
  10. data/smoke.sh +9 -0
  11. data/{test → spec}/fixtures/alice29.txt +0 -0
  12. data/spec/spec_helper.rb +2 -0
  13. data/spec/zopfli_spec.rb +68 -0
  14. data/vendor/zopfli/{blocksplitter.c → src/zopfli/blocksplitter.c} +41 -53
  15. data/vendor/zopfli/{blocksplitter.h → src/zopfli/blocksplitter.h} +2 -6
  16. data/vendor/zopfli/{cache.c → src/zopfli/cache.c} +6 -0
  17. data/vendor/zopfli/{cache.h → src/zopfli/cache.h} +0 -0
  18. data/vendor/zopfli/src/zopfli/deflate.c +931 -0
  19. data/vendor/zopfli/{deflate.h → src/zopfli/deflate.h} +17 -2
  20. data/vendor/zopfli/src/zopfli/gzip_container.c +124 -0
  21. data/vendor/zopfli/{gzip_container.h → src/zopfli/gzip_container.h} +8 -0
  22. data/vendor/zopfli/{hash.c → src/zopfli/hash.c} +18 -10
  23. data/vendor/zopfli/{hash.h → src/zopfli/hash.h} +10 -7
  24. data/vendor/zopfli/{katajainen.c → src/zopfli/katajainen.c} +73 -62
  25. data/vendor/zopfli/{katajainen.h → src/zopfli/katajainen.h} +1 -1
  26. data/vendor/zopfli/{lz77.c → src/zopfli/lz77.c} +190 -42
  27. data/vendor/zopfli/{lz77.h → src/zopfli/lz77.h} +39 -23
  28. data/vendor/zopfli/{squeeze.c → src/zopfli/squeeze.c} +75 -61
  29. data/vendor/zopfli/{squeeze.h → src/zopfli/squeeze.h} +1 -0
  30. data/vendor/zopfli/{util.c → src/zopfli/symbols.h} +49 -23
  31. data/vendor/zopfli/{tree.c → src/zopfli/tree.c} +0 -0
  32. data/vendor/zopfli/{tree.h → src/zopfli/tree.h} +0 -0
  33. data/vendor/zopfli/src/zopfli/util.c +35 -0
  34. data/vendor/zopfli/{util.h → src/zopfli/util.h} +6 -23
  35. data/vendor/zopfli/{zlib_container.c → src/zopfli/zlib_container.c} +1 -1
  36. data/vendor/zopfli/{zlib_container.h → src/zopfli/zlib_container.h} +8 -0
  37. data/vendor/zopfli/{zopfli.h → src/zopfli/zopfli.h} +10 -4
  38. data/vendor/zopfli/{zopfli_bin.c → src/zopfli/zopfli_bin.c} +31 -15
  39. data/vendor/zopfli/{zopfli_lib.c → src/zopfli/zopfli_lib.c} +1 -2
  40. data/zopfli.gemspec +9 -28
  41. metadata +51 -50
  42. data/test/test_zopfli_deflate.rb +0 -47
  43. data/vendor/zopfli/CONTRIBUTORS +0 -6
  44. data/vendor/zopfli/README +0 -25
  45. data/vendor/zopfli/deflate.c +0 -698
  46. data/vendor/zopfli/gzip_container.c +0 -117
  47. 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 unsigned short* litlens,
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 ZopfliInitHash(size_t window_size, ZopfliHash* h) {
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 occurance. */
31
- unsigned short* prev; /* Index to index of prev. occurance of same hash. */
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 occurance. */
39
- unsigned short* prev2; /* Index to index of prev. occurance of same hash. */
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 and initializes all fields of ZopfliHash. */
50
- void ZopfliInitHash(size_t window_size, ZopfliHash* h);
49
+ /* Allocates ZopfliHash memory. */
50
+ void ZopfliAllocHash(size_t window_size, ZopfliHash* h);
51
51
 
52
- /* Frees all fields of ZopfliHash. */
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* nodes; /* The pool. */
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 maxbits,
106
- Node* leaves, int numsymbols, NodePool* pool, int index, char final) {
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 = GetFreeNode(lists, maxbits, pool);
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
- if (!final) {
133
- /* Two lookahead chains of previous list used up, create new ones. */
134
- BoundaryPM(lists, maxbits, leaves, numsymbols, pool, index - 1, 0);
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 = GetFreeNode(0, maxbits, pool);
149
- Node* node1 = GetFreeNode(0, maxbits, pool);
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
- int i;
167
- for (i = 0; i < node->count; i++) {
168
- bitlengths[leaves[i].count]++;
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
- /* Initialize node memory pool. */
227
- pool.size = 2 * maxbits * (maxbits + 1);
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
- char final = i == numBoundaryPMRuns - 1;
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(pool.nodes);
260
+ free(nodes);
250
261
  return 0; /* OK. */
251
262
  }