zopfli 0.0.3 → 0.1.0

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.
Files changed (48) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/main.yml +35 -0
  3. data/.github/workflows/publish.yml +34 -0
  4. data/.gitmodules +1 -1
  5. data/Gemfile +4 -0
  6. data/README.md +6 -1
  7. data/Rakefile +14 -10
  8. data/ext/extconf.rb +36 -32
  9. data/ext/zopfli.c +52 -20
  10. data/lib/zopfli/version.rb +1 -1
  11. data/smoke.sh +9 -0
  12. data/test/test_helper.rb +7 -0
  13. data/test/zopfli_test.rb +63 -0
  14. data/vendor/zopfli/src/zopfli/blocksplitter.c +41 -53
  15. data/vendor/zopfli/src/zopfli/blocksplitter.h +2 -6
  16. data/vendor/zopfli/src/zopfli/cache.c +6 -0
  17. data/vendor/zopfli/src/zopfli/deflate.c +613 -381
  18. data/vendor/zopfli/src/zopfli/deflate.h +8 -2
  19. data/vendor/zopfli/src/zopfli/gzip_container.c +54 -47
  20. data/vendor/zopfli/src/zopfli/hash.c +18 -10
  21. data/vendor/zopfli/src/zopfli/hash.h +10 -7
  22. data/vendor/zopfli/src/zopfli/katajainen.c +73 -62
  23. data/vendor/zopfli/src/zopfli/katajainen.h +1 -1
  24. data/vendor/zopfli/src/zopfli/lz77.c +190 -42
  25. data/vendor/zopfli/src/zopfli/lz77.h +39 -23
  26. data/vendor/zopfli/src/zopfli/squeeze.c +75 -61
  27. data/vendor/zopfli/src/zopfli/squeeze.h +1 -0
  28. data/vendor/zopfli/src/zopfli/symbols.h +239 -0
  29. data/vendor/zopfli/src/zopfli/util.c +0 -178
  30. data/vendor/zopfli/src/zopfli/util.h +6 -23
  31. data/vendor/zopfli/src/zopfli/zlib_container.c +1 -1
  32. data/vendor/zopfli/src/zopfli/zopfli.h +1 -4
  33. data/vendor/zopfli/src/zopfli/zopfli_bin.c +31 -15
  34. data/zopfli.gemspec +12 -32
  35. metadata +20 -68
  36. data/test/fixtures/alice29.txt +0 -3609
  37. data/test/test_zopfli_deflate.rb +0 -47
  38. data/vendor/zopfli/CONTRIBUTORS +0 -7
  39. data/vendor/zopfli/README +0 -32
  40. data/vendor/zopfli/README.zopflipng +0 -35
  41. data/vendor/zopfli/makefile +0 -37
  42. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.cpp +0 -6253
  43. data/vendor/zopfli/src/zopflipng/lodepng/lodepng.h +0 -1705
  44. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.cpp +0 -656
  45. data/vendor/zopfli/src/zopflipng/lodepng/lodepng_util.h +0 -151
  46. data/vendor/zopfli/src/zopflipng/zopflipng_bin.cc +0 -407
  47. data/vendor/zopfli/src/zopflipng/zopflipng_lib.cc +0 -376
  48. data/vendor/zopfli/src/zopflipng/zopflipng_lib.h +0 -79
@@ -25,6 +25,7 @@ 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
 
30
31
  #ifdef __cplusplus
@@ -75,10 +76,15 @@ dists: ll77 distances
75
76
  lstart: start of block
76
77
  lend: end of block (not inclusive)
77
78
  */
78
- double ZopfliCalculateBlockSize(const unsigned short* litlens,
79
- const unsigned short* dists,
79
+ double ZopfliCalculateBlockSize(const ZopfliLZ77Store* lz77,
80
80
  size_t lstart, size_t lend, int btype);
81
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
+
82
88
  #ifdef __cplusplus
83
89
  } // extern "C"
84
90
  #endif
@@ -24,56 +24,63 @@ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
24
24
 
25
25
  #include "deflate.h"
26
26
 
27
- /* Table of CRCs of all 8-bit messages. */
28
- static unsigned long crc_table[256];
29
-
30
- /* Flag: has the table been computed? Initially false. */
31
- static int crc_table_computed = 0;
32
-
33
- /* Makes the table for a fast CRC. */
34
- static void MakeCRCTable() {
35
- unsigned long c;
36
- int n, k;
37
- for (n = 0; n < 256; n++) {
38
- c = (unsigned long) n;
39
- for (k = 0; k < 8; k++) {
40
- if (c & 1) {
41
- c = 0xedb88320L ^ (c >> 1);
42
- } else {
43
- c = c >> 1;
44
- }
45
- }
46
- crc_table[n] = c;
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);
47
79
  }
48
- crc_table_computed = 1;
80
+ return result ^ 0xffffffffu;
49
81
  }
50
82
 
51
-
52
- /*
53
- Updates a running crc with the bytes buf[0..len-1] and returns
54
- the updated crc. The crc should be initialized to zero.
55
- */
56
- static unsigned long UpdateCRC(unsigned long crc,
57
- const unsigned char *buf, size_t len) {
58
- unsigned long c = crc ^ 0xffffffffL;
59
- unsigned n;
60
-
61
- if (!crc_table_computed)
62
- MakeCRCTable();
63
- for (n = 0; n < len; n++) {
64
- c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
65
- }
66
- return c ^ 0xffffffffL;
67
- }
68
-
69
- /* Returns the CRC of the bytes buf[0..len-1]. */
70
- static unsigned long CRC(const unsigned char* buf, int len) {
71
- return UpdateCRC(0L, buf, len);
72
- }
73
-
74
- /*
75
- Compresses the data according to the gzip specification.
76
- */
83
+ /* Compresses the data according to the gzip specification, RFC 1952. */
77
84
  void ZopfliGzipCompress(const ZopfliOptions* options,
78
85
  const unsigned char* in, size_t insize,
79
86
  unsigned char** out, size_t* outsize) {
@@ -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
  }