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
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,