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.
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
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MWNkODM0N2JmMDRjNGNiNmIyYzliYWVjYWRiOWJjZTdjM2FhMTczZg==
5
- data.tar.gz: !binary |-
6
- OWQ4YjNmMzBhNjc1NjRkOTUyYzk2Y2VkOTdmZmM3ODRmZTRjZjA4Nw==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- OTQxNThkMzU3OWRkMmE0YzU5MzE0YTFlNjBiZjJjMzg4NGVjYTAyMjNjZTY4
10
- OTk1OGUyYTRjMzM1ODE5YjAxMjEyZTg1ZTY0MzhjYWRhYmVjNGVmNTgyZjhi
11
- YzA2MWFiOGQyNjZmMmFiMWI4OGFiMjI5YmUxZDhiYmExYmVkNDM=
12
- data.tar.gz: !binary |-
13
- ZjM1N2E1MjA5NDViMmZkYmFhZWVjZWQzODE2ZDAxMmZkNDUyNWMzMGZlMTBl
14
- MWM0OTA3OGIzOGViOGE0YTAyZGVjNTliZmVlMjJlMjBmZDhiODdiZjE1OWM3
15
- M2VmODAzMWUyNDQ4YzJiMjcwNDk3Mzg2YjUxMzA0MTY0NzQzMWU=
2
+ SHA256:
3
+ metadata.gz: 3121a61abacb0a102a03f4ec91ac9e6ee4a6132942d6e402bcfded04a25f39bd
4
+ data.tar.gz: 544aee94aaaa325abcaee491d8b052a59dbd6809794fb2cdd4dd3fd787c466dd
5
+ SHA512:
6
+ metadata.gz: 5ff282d1b59f9bd4ab899cb1a16b63cadc64bb5a24c72b76289b136eadd8b50fcd14cb3a787169bc342ca1c6bb4ca5f405cc412eb3c13af6f4aa0c389cae2ec9
7
+ data.tar.gz: 24c803340ae499cf43da0d62b4fd916a0a05db1db07967461a7e65145810b70129a8063d4b972a1dad67ec8a6691b0ecf4d057390a78be771efae17983cae142
@@ -1,3 +1,3 @@
1
1
  [submodule "vendor/zopfli"]
2
2
  path = vendor/zopfli
3
- url = https://code.google.com/p/zopfli/
3
+ url = https://github.com/google/zopfli.git
@@ -0,0 +1,23 @@
1
+ language: ruby
2
+ sudo: false
3
+ cache:
4
+ bundler: true
5
+ directories:
6
+ - "$HOME/.ccache"
7
+ rvm:
8
+ - 2.3.3
9
+ - 2.4.0
10
+ env:
11
+ global:
12
+ - PATH="/usr/lib/ccache:$PATH"
13
+ before_install:
14
+ - travis_retry gem install bundler --no-document
15
+ deploy:
16
+ provider: rubygems
17
+ api_key:
18
+ secure: Ix2H4oY1Ypo5mdYj9JTXufY/E7H/TWjAM54dtG2i/94yV8wMVINl+rhjnFso87LN6y0Tpt7rWy1OG1y3YPbwhBUPLbRXZ+xGjnsLA8/sUpEFODFk/QaYgOkCk2g3+xCgzzNvctd2u9fii/q9eIUts8BznegxtAYbat5a8dGvoVEkYAvHUX4lMRcEZVgMMpjT+xz3IGRe9rnW4umLd8P2mE6CEXAtrwFNSsjL1SVfKVOwwJ/UyiJfUnK6U/mDWdCDYWiPEE/CTz7PbrGGo4nAGoShLmkMUDsOamgECObT2rsNo42XzzrB4GAP+4PPQnias34BtJQLI9x2IEAUkM8vnKhSrtshp43S+ikU01W6rj4NMAvER4s9WNmRjsWgZQ/vEIHIwZXmdnkGvlYSiwRru+17YL2HCbrVp/YXi7X5HgBczuGOt3TZLB0xAKJG21qz+HdtP1nZTZe3EONDvWx9bM3XF2YjJ5gt3UNno8GsefTl71PFDubs1/LrVbkGgGwO6VTb4OgS2bEzntk17488BLTBo3l7bke5FTu8xQUbCawX2dqtOiukP45Ke8hRmgwWSMK+EH8YYcRcuZSbOXYJtGfpfC6nHtlArW+EjJ2Og+nWX68n7NFOIfGfCSX+V7cNgnKsqMjaesF+jEP+53CfVa2xnYxkZx7TgGrFyQEKr9s=
19
+ gem: zopfli
20
+ on:
21
+ tags: true
22
+ repo: miyucy/zopfli
23
+ script: bundle exec rake && ./smoke.sh
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in zopfli.gemspec
4
4
  gemspec
5
+
6
+ gem 'travis'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Zopfli
2
2
 
3
- see https://code.google.com/p/zopfli/
3
+ see https://github.com/google/zopfli
4
4
 
5
5
  ## Installation
6
6
 
@@ -30,6 +30,11 @@ compressed_data = Zopfli.deflate string
30
30
  uncompressed_data = Zlib::Inflate.inflate compressed_data
31
31
  uncompressed_data == string
32
32
  # => true
33
+
34
+ Zlib.deflate(File.read('LICENSE.txt'), Zlib::BEST_COMPRESSION).bytesize
35
+ # => 628
36
+ Zopfli.deflate(File.read('LICENSE.txt')).bytesize
37
+ # => 601
33
38
  ```
34
39
 
35
40
  ## Contributing
data/Rakefile CHANGED
@@ -1,25 +1,23 @@
1
1
  require "bundler/gem_tasks"
2
- require "rake/testtask"
2
+ require "rspec/core/rake_task"
3
3
  require "rbconfig"
4
4
 
5
5
  DLEXT = RbConfig::CONFIG["DLEXT"]
6
6
 
7
- file "ext/zopfli.#{DLEXT}" => Dir.glob("ext/*{.rb,.c}") do
7
+ file "ext/zopfli.#{DLEXT}" => Dir.glob("ext/*{.rb,.c,.h}") do
8
8
  Dir.chdir("ext") do
9
- ruby "extconf.rb"
10
- sh "make"
9
+ ruby "extconf.rb"
10
+ sh "make"
11
11
  end
12
12
  cp "ext/zopfli.#{DLEXT}", "lib"
13
13
  end
14
14
 
15
15
  task :clean do
16
16
  files = Dir["ext/*"] - ["ext/extconf.rb", "ext/zopfli.c"]
17
- files+= ["ext/zopfli.#{DLEXT}", "lib/zopfli.#{DLEXT}"]
17
+ files += ["ext/zopfli.#{DLEXT}", "lib/zopfli.#{DLEXT}"]
18
18
  rm_rf(files) unless files.empty?
19
19
  end
20
20
 
21
- Rake::TestTask.new do |t|
22
- t.warning = true
23
- t.verbose = true
24
- end
25
- task :test => "ext/zopfli.#{DLEXT}"
21
+ RSpec::Core::RakeTask.new(:spec)
22
+ task :spec => "ext/zopfli.#{DLEXT}"
23
+ task :default => :spec
@@ -9,7 +9,7 @@
9
9
  require "mkmf"
10
10
 
11
11
  dst = File.dirname File.expand_path __FILE__
12
- src = File.join dst, "..", "vendor", "zopfli"
12
+ src = File.join dst, "..", "vendor", "zopfli", "src", "zopfli"
13
13
 
14
14
  %w(
15
15
  blocksplitter.c
@@ -28,6 +28,7 @@ lz77.c
28
28
  lz77.h
29
29
  squeeze.c
30
30
  squeeze.h
31
+ symbols.h
31
32
  tree.c
32
33
  tree.h
33
34
  util.c
@@ -1,12 +1,11 @@
1
1
  #include "ruby.h"
2
+ #include "ruby/thread.h"
2
3
  #include "zopfli.h"
3
4
 
4
5
  #define CSTR2SYM(x) ID2SYM(rb_intern(x))
5
6
  #define DEFAULT_FORMAT ZOPFLI_FORMAT_ZLIB
6
7
 
7
- static VALUE rb_mZopfli;
8
-
9
- ZopfliFormat
8
+ static ZopfliFormat
10
9
  zopfli_deflate_parse_options(ZopfliOptions *options, VALUE opts)
11
10
  {
12
11
  ZopfliFormat format;
@@ -50,35 +49,56 @@ zopfli_deflate_parse_options(ZopfliOptions *options, VALUE opts)
50
49
  return format;
51
50
  }
52
51
 
53
- VALUE
54
- zopfli_deflate(int argc, VALUE *argv, VALUE self)
55
- {
56
- VALUE in, out, opts;
52
+ typedef struct {
57
53
  ZopfliOptions options;
58
54
  ZopfliFormat format;
59
- unsigned char *tmp = NULL;
60
- size_t tmpsize = 0;
55
+ unsigned char *in;
56
+ size_t insize;
57
+ unsigned char *out;
58
+ size_t outsize;
59
+ } zopfli_deflate_args_t;
60
+
61
+ static void*
62
+ zopfli_deflate_no_gvl(void* arg)
63
+ {
64
+ zopfli_deflate_args_t *args = (zopfli_deflate_args_t*)arg;
61
65
 
62
- ZopfliInitOptions(&options);
66
+ ZopfliCompress(&args->options, args->format,
67
+ args->in, args->insize,
68
+ &args->out, &args->outsize);
69
+
70
+ return arg;
71
+ }
72
+
73
+ static VALUE
74
+ zopfli_deflate(int argc, VALUE *argv, VALUE self)
75
+ {
76
+ zopfli_deflate_args_t args;
77
+ VALUE in, out, opts;
78
+
79
+ ZopfliInitOptions(&args.options);
63
80
 
64
81
  rb_scan_args(argc, argv, "11", &in, &opts);
65
82
 
66
83
  if (!NIL_P(opts)) {
67
- format = zopfli_deflate_parse_options(&options, opts);
84
+ args.format = zopfli_deflate_parse_options(&args.options, opts);
68
85
  } else {
69
- format = DEFAULT_FORMAT;
86
+ args.format = DEFAULT_FORMAT;
70
87
  }
71
88
 
72
89
  StringValue(in);
73
90
 
74
- ZopfliCompress(&options,
75
- format,
76
- RSTRING_PTR(in), RSTRING_LEN(in),
77
- &tmp, &tmpsize);
91
+ args.in = (unsigned char*)RSTRING_PTR(in);
92
+ args.insize = RSTRING_LEN(in);
93
+
94
+ args.out = NULL;
95
+ args.outsize = 0;
96
+
97
+ rb_thread_call_without_gvl(zopfli_deflate_no_gvl, (void *)&args, NULL, NULL);
78
98
 
79
- out = rb_str_new(tmp, tmpsize);
99
+ out = rb_str_new((const char*)args.out, args.outsize);
80
100
 
81
- free(tmp);
101
+ free(args.out);
82
102
 
83
103
  return out;
84
104
  }
@@ -86,7 +106,6 @@ zopfli_deflate(int argc, VALUE *argv, VALUE self)
86
106
  void
87
107
  Init_zopfli()
88
108
  {
89
- rb_mZopfli = rb_define_module("Zopfli");
109
+ VALUE rb_mZopfli = rb_define_module("Zopfli");
90
110
  rb_define_singleton_method(rb_mZopfli, "deflate", zopfli_deflate, -1);
91
- rb_require("zopfli/version");
92
111
  }
@@ -1,3 +1,3 @@
1
1
  module Zopfli
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.8"
3
3
  end
@@ -0,0 +1,9 @@
1
+ #!/bin/bash
2
+ gem list | grep zopfli && gem uninstall --force zopfli
3
+ bundle exec rake clean build
4
+ gem install --force --local --no-document "$(ls pkg/zopfli-*.gem)"
5
+ cat <<EOF | ruby
6
+ require 'zopfli'
7
+ require 'zlib'
8
+ abort if Zlib::Inflate.inflate(Zopfli.deflate(File.read('smoke.sh'))) != File.read('smoke.sh')
9
+ EOF
File without changes
@@ -0,0 +1,2 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'zopfli'
@@ -0,0 +1,68 @@
1
+ require 'spec_helper'
2
+ require 'zlib'
3
+ require 'stringio'
4
+ require 'benchmark'
5
+ require 'thread'
6
+
7
+ RSpec.describe Zopfli do
8
+ let(:fixture) { File.read(File.expand_path('fixtures/alice29.txt', File.dirname(__FILE__))) }
9
+
10
+ it 'works' do
11
+ expect(Zopfli.deflate(fixture)).to eq Zopfli.deflate(fixture, format: :zlib)
12
+ end
13
+
14
+ it 'works (zlib format)' do
15
+ deflated = Zopfli.deflate fixture, format: :zlib
16
+
17
+ uncompressed = Zlib::Inflate.inflate deflated
18
+
19
+ expect(uncompressed).to eq fixture
20
+ end
21
+
22
+ it 'works (gzip format)' do
23
+ deflated = Zopfli.deflate fixture, format: :gzip
24
+
25
+ uncompressed = Zlib::GzipReader.wrap(StringIO.new(deflated), &:read)
26
+
27
+ expect(uncompressed).to eq fixture
28
+ end
29
+
30
+ it 'works (deflate format)' do
31
+ deflated = Zopfli.deflate fixture, format: :deflate
32
+ p fixture.bytesize, deflated.bytesize
33
+ end
34
+
35
+ context 'benchmark' do
36
+ it 'seq' do
37
+ data = 10.times.map { fixture.dup }
38
+ deflates = nil
39
+ t = Benchmark.realtime { deflates = data.map { |datum| Zopfli.deflate datum } }
40
+ deflates.each { |deflate| expect(Zlib::Inflate.inflate(deflate)).to eq fixture }
41
+ puts t
42
+ # => 4.483513999963179
43
+ end
44
+
45
+ it 'thread' do
46
+ q = Queue.new
47
+ 10.times { q.push fixture.dup }
48
+ 10.times { q.push nil }
49
+ w = 10.times.map do
50
+ Thread.new do
51
+ deflates = []
52
+ loop do
53
+ datum = q.pop
54
+ break if datum.nil?
55
+ deflates << Zopfli.deflate(datum)
56
+ end
57
+ deflates
58
+ end
59
+ end
60
+ deflates = nil
61
+ t = Benchmark.realtime { deflates = w.map(&:value) }
62
+ deflates.flatten.each { |deflate| expect(Zlib::Inflate.inflate(deflate)).to eq fixture }
63
+ puts t
64
+ # => 2.6099140000296757
65
+ # => 0.9405940000433475 (w/o gvl)
66
+ end
67
+ end
68
+ end
@@ -24,7 +24,6 @@ Author: jyrki.alakuijala@gmail.com (Jyrki Alakuijala)
24
24
  #include <stdlib.h>
25
25
 
26
26
  #include "deflate.h"
27
- #include "lz77.h"
28
27
  #include "squeeze.h"
29
28
  #include "tree.h"
30
29
  #include "util.h"
@@ -39,9 +38,10 @@ typedef double FindMinimumFun(size_t i, void* context);
39
38
  /*
40
39
  Finds minimum of function f(i) where is is of type size_t, f(i) is of type
41
40
  double, i is in range start-end (excluding end).
41
+ Outputs the minimum value in *smallest and returns the index of this value.
42
42
  */
43
43
  static size_t FindMinimum(FindMinimumFun f, void* context,
44
- size_t start, size_t end) {
44
+ size_t start, size_t end, double* smallest) {
45
45
  if (end - start < 1024) {
46
46
  double best = ZOPFLI_LARGE_FLOAT;
47
47
  size_t result = start;
@@ -53,6 +53,7 @@ static size_t FindMinimum(FindMinimumFun f, void* context,
53
53
  result = i;
54
54
  }
55
55
  }
56
+ *smallest = best;
56
57
  return result;
57
58
  } else {
58
59
  /* Try to find minimum faster by recursively checking multiple points. */
@@ -88,6 +89,7 @@ static size_t FindMinimum(FindMinimumFun f, void* context,
88
89
  pos = p[besti];
89
90
  lastbest = best;
90
91
  }
92
+ *smallest = lastbest;
91
93
  return pos;
92
94
  #undef NUM
93
95
  }
@@ -103,16 +105,13 @@ dists: ll77 distances
103
105
  lstart: start of block
104
106
  lend: end of block (not inclusive)
105
107
  */
106
- static double EstimateCost(const unsigned short* litlens,
107
- const unsigned short* dists,
108
+ static double EstimateCost(const ZopfliLZ77Store* lz77,
108
109
  size_t lstart, size_t lend) {
109
- return ZopfliCalculateBlockSize(litlens, dists, lstart, lend, 2);
110
+ return ZopfliCalculateBlockSizeAutoType(lz77, lstart, lend);
110
111
  }
111
112
 
112
113
  typedef struct SplitCostContext {
113
- const unsigned short* litlens;
114
- const unsigned short* dists;
115
- size_t llsize;
114
+ const ZopfliLZ77Store* lz77;
116
115
  size_t start;
117
116
  size_t end;
118
117
  } SplitCostContext;
@@ -125,23 +124,20 @@ type: FindMinimumFun
125
124
  */
126
125
  static double SplitCost(size_t i, void* context) {
127
126
  SplitCostContext* c = (SplitCostContext*)context;
128
- return EstimateCost(c->litlens, c->dists, c->start, i) +
129
- EstimateCost(c->litlens, c->dists, i, c->end);
127
+ return EstimateCost(c->lz77, c->start, i) + EstimateCost(c->lz77, i, c->end);
130
128
  }
131
129
 
132
130
  static void AddSorted(size_t value, size_t** out, size_t* outsize) {
133
131
  size_t i;
134
132
  ZOPFLI_APPEND_DATA(value, out, outsize);
135
- if (*outsize > 0) {
136
- for (i = 0; i < *outsize - 1; i++) {
137
- if ((*out)[i] > value) {
138
- size_t j;
139
- for (j = *outsize - 1; j > i; j--) {
140
- (*out)[j] = (*out)[j - 1];
141
- }
142
- (*out)[i] = value;
143
- break;
133
+ for (i = 0; i + 1 < *outsize; i++) {
134
+ if ((*out)[i] > value) {
135
+ size_t j;
136
+ for (j = *outsize - 1; j > i; j--) {
137
+ (*out)[j] = (*out)[j - 1];
144
138
  }
139
+ (*out)[i] = value;
140
+ break;
145
141
  }
146
142
  }
147
143
  }
@@ -149,9 +145,8 @@ static void AddSorted(size_t value, size_t** out, size_t* outsize) {
149
145
  /*
150
146
  Prints the block split points as decimal and hex values in the terminal.
151
147
  */
152
- static void PrintBlockSplitPoints(const unsigned short* litlens,
153
- const unsigned short* dists,
154
- size_t llsize, const size_t* lz77splitpoints,
148
+ static void PrintBlockSplitPoints(const ZopfliLZ77Store* lz77,
149
+ const size_t* lz77splitpoints,
155
150
  size_t nlz77points) {
156
151
  size_t* splitpoints = 0;
157
152
  size_t npoints = 0;
@@ -160,8 +155,8 @@ static void PrintBlockSplitPoints(const unsigned short* litlens,
160
155
  index values. */
161
156
  size_t pos = 0;
162
157
  if (nlz77points > 0) {
163
- for (i = 0; i < llsize; i++) {
164
- size_t length = dists[i] == 0 ? 1 : litlens[i];
158
+ for (i = 0; i < lz77->size; i++) {
159
+ size_t length = lz77->dists[i] == 0 ? 1 : lz77->litlens[i];
165
160
  if (lz77splitpoints[npoints] == i) {
166
161
  ZOPFLI_APPEND_DATA(pos, &splitpoints, &npoints);
167
162
  if (npoints == nlz77points) break;
@@ -188,7 +183,7 @@ static void PrintBlockSplitPoints(const unsigned short* litlens,
188
183
  Finds next block to try to split, the largest of the available ones.
189
184
  The largest is chosen to make sure that if only a limited amount of blocks is
190
185
  requested, their sizes are spread evenly.
191
- llsize: the size of the LL77 data, which is the size of the done array here.
186
+ lz77size: the size of the LL77 data, which is the size of the done array here.
192
187
  done: array indicating which blocks starting at that position are no longer
193
188
  splittable (splitting them increases rather than decreases cost).
194
189
  splitpoints: the splitpoints found so far.
@@ -198,7 +193,7 @@ lend: output variable, giving end of block.
198
193
  returns 1 if a block was found, 0 if no block found (all are done).
199
194
  */
200
195
  static int FindLargestSplittableBlock(
201
- size_t llsize, const unsigned char* done,
196
+ size_t lz77size, const unsigned char* done,
202
197
  const size_t* splitpoints, size_t npoints,
203
198
  size_t* lstart, size_t* lend) {
204
199
  size_t longest = 0;
@@ -206,7 +201,7 @@ static int FindLargestSplittableBlock(
206
201
  size_t i;
207
202
  for (i = 0; i <= npoints; i++) {
208
203
  size_t start = i == 0 ? 0 : splitpoints[i - 1];
209
- size_t end = i == npoints ? llsize - 1 : splitpoints[i];
204
+ size_t end = i == npoints ? lz77size - 1 : splitpoints[i];
210
205
  if (!done[start] && end - start > longest) {
211
206
  *lstart = start;
212
207
  *lend = end;
@@ -218,9 +213,7 @@ static int FindLargestSplittableBlock(
218
213
  }
219
214
 
220
215
  void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
221
- const unsigned short* litlens,
222
- const unsigned short* dists,
223
- size_t llsize, size_t maxblocks,
216
+ const ZopfliLZ77Store* lz77, size_t maxblocks,
224
217
  size_t** splitpoints, size_t* npoints) {
225
218
  size_t lstart, lend;
226
219
  size_t i;
@@ -229,14 +222,14 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
229
222
  unsigned char* done;
230
223
  double splitcost, origcost;
231
224
 
232
- if (llsize < 10) return; /* This code fails on tiny files. */
225
+ if (lz77->size < 10) return; /* This code fails on tiny files. */
233
226
 
234
- done = (unsigned char*)malloc(llsize);
227
+ done = (unsigned char*)malloc(lz77->size);
235
228
  if (!done) exit(-1); /* Allocation failed. */
236
- for (i = 0; i < llsize; i++) done[i] = 0;
229
+ for (i = 0; i < lz77->size; i++) done[i] = 0;
237
230
 
238
231
  lstart = 0;
239
- lend = llsize;
232
+ lend = lz77->size;
240
233
  for (;;) {
241
234
  SplitCostContext c;
242
235
 
@@ -244,20 +237,16 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
244
237
  break;
245
238
  }
246
239
 
247
- c.litlens = litlens;
248
- c.dists = dists;
249
- c.llsize = llsize;
240
+ c.lz77 = lz77;
250
241
  c.start = lstart;
251
242
  c.end = lend;
252
243
  assert(lstart < lend);
253
- llpos = FindMinimum(SplitCost, &c, lstart + 1, lend);
244
+ llpos = FindMinimum(SplitCost, &c, lstart + 1, lend, &splitcost);
254
245
 
255
246
  assert(llpos > lstart);
256
247
  assert(llpos < lend);
257
248
 
258
- splitcost = EstimateCost(litlens, dists, lstart, llpos) +
259
- EstimateCost(litlens, dists, llpos, lend);
260
- origcost = EstimateCost(litlens, dists, lstart, lend);
249
+ origcost = EstimateCost(lz77, lstart, lend);
261
250
 
262
251
  if (splitcost > origcost || llpos == lstart + 1 || llpos == lend) {
263
252
  done[lstart] = 1;
@@ -267,7 +256,7 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
267
256
  }
268
257
 
269
258
  if (!FindLargestSplittableBlock(
270
- llsize, done, *splitpoints, *npoints, &lstart, &lend)) {
259
+ lz77->size, done, *splitpoints, *npoints, &lstart, &lend)) {
271
260
  break; /* No further split will probably reduce compression. */
272
261
  }
273
262
 
@@ -277,7 +266,7 @@ void ZopfliBlockSplitLZ77(const ZopfliOptions* options,
277
266
  }
278
267
 
279
268
  if (options->verbose) {
280
- PrintBlockSplitPoints(litlens, dists, llsize, *splitpoints, *npoints);
269
+ PrintBlockSplitPoints(lz77, *splitpoints, *npoints);
281
270
  }
282
271
 
283
272
  free(done);
@@ -292,25 +281,22 @@ void ZopfliBlockSplit(const ZopfliOptions* options,
292
281
  size_t* lz77splitpoints = 0;
293
282
  size_t nlz77points = 0;
294
283
  ZopfliLZ77Store store;
284
+ ZopfliHash hash;
285
+ ZopfliHash* h = &hash;
295
286
 
296
- ZopfliInitLZ77Store(&store);
297
-
298
- s.options = options;
299
- s.blockstart = instart;
300
- s.blockend = inend;
301
- #ifdef ZOPFLI_LONGEST_MATCH_CACHE
302
- s.lmc = 0;
303
- #endif
287
+ ZopfliInitLZ77Store(in, &store);
288
+ ZopfliInitBlockState(options, instart, inend, 0, &s);
289
+ ZopfliAllocHash(ZOPFLI_WINDOW_SIZE, h);
304
290
 
305
291
  *npoints = 0;
306
292
  *splitpoints = 0;
307
293
 
308
294
  /* Unintuitively, Using a simple LZ77 method here instead of ZopfliLZ77Optimal
309
295
  results in better blocks. */
310
- ZopfliLZ77Greedy(&s, in, instart, inend, &store);
296
+ ZopfliLZ77Greedy(&s, in, instart, inend, &store, h);
311
297
 
312
298
  ZopfliBlockSplitLZ77(options,
313
- store.litlens, store.dists, store.size, maxblocks,
299
+ &store, maxblocks,
314
300
  &lz77splitpoints, &nlz77points);
315
301
 
316
302
  /* Convert LZ77 positions to positions in the uncompressed input. */
@@ -328,7 +314,9 @@ void ZopfliBlockSplit(const ZopfliOptions* options,
328
314
  assert(*npoints == nlz77points);
329
315
 
330
316
  free(lz77splitpoints);
317
+ ZopfliCleanBlockState(&s);
331
318
  ZopfliCleanLZ77Store(&store);
319
+ ZopfliCleanHash(h);
332
320
  }
333
321
 
334
322
  void ZopfliBlockSplitSimple(const unsigned char* in,