zopfli 0.0.3 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
  }