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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 116f5697342e3dbe9f08bcb519c661c51c263c63
4
- data.tar.gz: 8148085bad781a3dcb70465ef45ea29f6a24b918
2
+ SHA256:
3
+ metadata.gz: ea7e06b8390382908a91c402f02754fa8f2a325699d424731f3903595cbe2d73
4
+ data.tar.gz: 138f867202c10b77cca5cd0c06545add1a630dd8721e5d67dc667d5257c55915
5
5
  SHA512:
6
- metadata.gz: de7fcf5546c2ec184ffa701127f8398af60474a7b830cf6d2317d2cc68860479083d4daaa21cf168ac77be70fd2e5073be2197ee05890bf528698a4bc24328f8
7
- data.tar.gz: 5c92c334266fdc7c8d5155918e556f071aabc07c3b2db316c87afa8e21d46173cb9bc14d0fa73108131462e9703814212dd75abbfbe8ce557280d7f37866a6cd
6
+ metadata.gz: b6bbf82746d164940dd0781b512623fc22101c12240dc32b8745007f8ce04079d4fd07e6d1c25dea78f96bfaed8202c85ed18fb766041b4050a4dd3339bf46a1
7
+ data.tar.gz: f5415a40dee71d25d4cfd8279ccf5ec6ce3269551055be2dfddc8c375635481e39fbfdebc9f7547928631762a67dcada8e99c8da33cb669734bd2a218ff809e7
@@ -0,0 +1,35 @@
1
+ name: Ruby
2
+
3
+ on: [pull_request]
4
+
5
+ jobs:
6
+ build:
7
+ strategy:
8
+ fail-fast: false
9
+ matrix:
10
+ ruby: [2.5, 2.6, 2.7, 3.0]
11
+ runs-on: ubuntu-latest
12
+ steps:
13
+ - uses: actions/checkout@v2
14
+ with:
15
+ submodules: true
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: ${{ matrix.ruby }}
20
+ bundler-cache: true
21
+ - name: Run the default task
22
+ run: |
23
+ bundle exec rake clobber test build
24
+ gem install --no-document "$(ls pkg/zopfli-*.gem)"
25
+ cat <<EOF | ruby
26
+ require "zopfli"
27
+ require "zlib"
28
+ if Zlib::Inflate.inflate(Zopfli.deflate(File.read("README.md"))) == File.read("README.md")
29
+ puts "OK"
30
+ exit 0
31
+ else
32
+ puts "NG"
33
+ exit 0
34
+ end
35
+ EOF
@@ -0,0 +1,34 @@
1
+ name: Publish Gem
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ jobs:
9
+ build:
10
+ strategy:
11
+ fail-fast: false
12
+ matrix:
13
+ ruby: [3.0]
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v2
17
+ with:
18
+ submodules: true
19
+ - name: Set up Ruby
20
+ uses: ruby/setup-ruby@v1
21
+ with:
22
+ ruby-version: ${{ matrix.ruby }}
23
+ bundler-cache: true
24
+ - name: Run release task
25
+ run: |
26
+ mkdir -p ~/.gem
27
+ cat << EOF > ~/.gem/credentials
28
+ ---
29
+ :github: Bearer ${{secrets.GITHUB_TOKEN}}
30
+ :rubygems_api_key: ${{secrets.RUBYGEMS_API_KEY}}
31
+ EOF
32
+ chmod 600 ~/.gem/credentials
33
+ bundle exec rake release[remote]
34
+ rm -f ~/.gem/credentials
@@ -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
data/Gemfile CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in zopfli.gemspec
4
4
  gemspec
5
+
6
+ gem "rake", "~> 13.0"
7
+ gem "test-unit", "~> 3.0"
8
+ gem "test-unit-rr"
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,29 @@
1
+ require "bundler/setup"
1
2
  require "bundler/gem_tasks"
3
+ require "rake/clean"
2
4
  require "rake/testtask"
3
5
  require "rbconfig"
4
6
 
5
7
  DLEXT = RbConfig::CONFIG["DLEXT"]
6
8
 
7
- file "ext/zopfli.#{DLEXT}" => Dir.glob("ext/*{.rb,.c}") do
9
+ file "ext/zopfli.#{DLEXT}" => Dir.glob("ext/*{.rb,.c,.h}") do
8
10
  Dir.chdir("ext") do
9
- ruby "extconf.rb"
10
- sh "make"
11
+ ruby "extconf.rb"
12
+ sh "make"
11
13
  end
12
14
  cp "ext/zopfli.#{DLEXT}", "lib"
13
15
  end
14
16
 
15
- task :clean do
16
- files = Dir["ext/*"] - ["ext/extconf.rb", "ext/zopfli.c"]
17
- files+= ["ext/zopfli.#{DLEXT}", "lib/zopfli.#{DLEXT}"]
18
- rm_rf(files) unless files.empty?
19
- end
20
-
21
- Rake::TestTask.new do |t|
17
+ Rake::TestTask.new(:test) do |t|
18
+ t.libs << "test"
19
+ t.test_files = FileList["test/**/*_test.rb"]
22
20
  t.warning = true
23
21
  t.verbose = true
24
22
  end
23
+
24
+ CLEAN.include "ext/zopfli.#{DLEXT}", "lib/zopfli.#{DLEXT}"
25
+ CLEAN.include "ext/*"
26
+ CLEAN.exclude "ext/extconf.rb", "ext/zopfli.c"
27
+
25
28
  task :test => "ext/zopfli.#{DLEXT}"
29
+ task :default => :test
@@ -8,36 +8,40 @@
8
8
  # the ZopfliOptions first.
9
9
  require "mkmf"
10
10
 
11
- dst = File.dirname File.expand_path __FILE__
12
- src = File.join dst, "..", "vendor", "zopfli", "src", "zopfli"
13
-
14
- %w(
15
- blocksplitter.c
16
- blocksplitter.h
17
- cache.c
18
- cache.h
19
- deflate.c
20
- deflate.h
21
- gzip_container.c
22
- gzip_container.h
23
- hash.c
24
- hash.h
25
- katajainen.c
26
- katajainen.h
27
- lz77.c
28
- lz77.h
29
- squeeze.c
30
- squeeze.h
31
- tree.c
32
- tree.h
33
- util.c
34
- util.h
35
- zlib_container.c
36
- zlib_container.h
37
- zopfli.h
38
- zopfli_lib.c
39
- ).each do |file|
40
- FileUtils.copy File.join(src, file), File.join(dst, file) if FileTest.exist? File.join(src, file)
11
+ dir_config("zopfli")
12
+ if have_header("zopfli/zopfli.h") && have_library("zopfli", "ZopfliCompress", "zopfli/zopfli.h")
13
+ create_makefile "zopfli"
14
+ else
15
+ dst = File.dirname File.expand_path __FILE__
16
+ src = File.join dst, "..", "vendor", "zopfli", "src", "zopfli"
17
+ %w[
18
+ blocksplitter.c
19
+ blocksplitter.h
20
+ cache.c
21
+ cache.h
22
+ deflate.c
23
+ deflate.h
24
+ gzip_container.c
25
+ gzip_container.h
26
+ hash.c
27
+ hash.h
28
+ katajainen.c
29
+ katajainen.h
30
+ lz77.c
31
+ lz77.h
32
+ squeeze.c
33
+ squeeze.h
34
+ symbols.h
35
+ tree.c
36
+ tree.h
37
+ util.c
38
+ util.h
39
+ zlib_container.c
40
+ zlib_container.h
41
+ zopfli.h
42
+ zopfli_lib.c
43
+ ].each do |file|
44
+ FileUtils.copy File.join(src, file), File.join(dst, file) if FileTest.exist? File.join(src, file)
45
+ end
46
+ create_makefile "zopfli"
41
47
  end
42
-
43
- create_makefile "zopfli"
@@ -1,12 +1,17 @@
1
1
  #include "ruby.h"
2
+ #ifdef HAVE_RUBY_THREAD_H
3
+ #include "ruby/thread.h"
4
+ #endif
5
+ #ifdef HAVE_ZOPFLI_ZOPFLI_H
6
+ #include "zopfli/zopfli.h"
7
+ #else
2
8
  #include "zopfli.h"
9
+ #endif
3
10
 
4
11
  #define CSTR2SYM(x) ID2SYM(rb_intern(x))
5
12
  #define DEFAULT_FORMAT ZOPFLI_FORMAT_ZLIB
6
13
 
7
- static VALUE rb_mZopfli;
8
-
9
- ZopfliFormat
14
+ static ZopfliFormat
10
15
  zopfli_deflate_parse_options(ZopfliOptions *options, VALUE opts)
11
16
  {
12
17
  ZopfliFormat format;
@@ -50,35 +55,60 @@ zopfli_deflate_parse_options(ZopfliOptions *options, VALUE opts)
50
55
  return format;
51
56
  }
52
57
 
53
- VALUE
54
- zopfli_deflate(int argc, VALUE *argv, VALUE self)
55
- {
56
- VALUE in, out, opts;
58
+ typedef struct {
57
59
  ZopfliOptions options;
58
60
  ZopfliFormat format;
59
- unsigned char *tmp = NULL;
60
- size_t tmpsize = 0;
61
+ unsigned char *in;
62
+ size_t insize;
63
+ unsigned char *out;
64
+ size_t outsize;
65
+ } zopfli_deflate_args_t;
66
+
67
+ static void*
68
+ zopfli_deflate_no_gvl(void* arg)
69
+ {
70
+ zopfli_deflate_args_t *args = (zopfli_deflate_args_t*)arg;
61
71
 
62
- ZopfliInitOptions(&options);
72
+ ZopfliCompress(&args->options, args->format,
73
+ args->in, args->insize,
74
+ &args->out, &args->outsize);
75
+
76
+ return arg;
77
+ }
78
+
79
+ static VALUE
80
+ zopfli_deflate(int argc, VALUE *argv, VALUE self)
81
+ {
82
+ zopfli_deflate_args_t args;
83
+ VALUE in, out, opts;
84
+
85
+ ZopfliInitOptions(&args.options);
63
86
 
64
87
  rb_scan_args(argc, argv, "11", &in, &opts);
65
88
 
66
89
  if (!NIL_P(opts)) {
67
- format = zopfli_deflate_parse_options(&options, opts);
90
+ args.format = zopfli_deflate_parse_options(&args.options, opts);
68
91
  } else {
69
- format = DEFAULT_FORMAT;
92
+ args.format = DEFAULT_FORMAT;
70
93
  }
71
94
 
72
95
  StringValue(in);
73
96
 
74
- ZopfliCompress(&options,
75
- format,
76
- RSTRING_PTR(in), RSTRING_LEN(in),
77
- &tmp, &tmpsize);
97
+ args.in = (unsigned char*)RSTRING_PTR(in);
98
+ args.insize = RSTRING_LEN(in);
99
+
100
+ args.out = NULL;
101
+ args.outsize = 0;
102
+
103
+ #ifdef HAVE_RUBY_THREAD_H
104
+ rb_thread_call_without_gvl(zopfli_deflate_no_gvl, (void *)&args, NULL, NULL);
105
+ #else
106
+ zopfli_deflate_no_gvl((void *)&args);
107
+ #endif
78
108
 
79
- out = rb_str_new(tmp, tmpsize);
109
+ out = rb_str_new((const char*)args.out, args.outsize);
80
110
 
81
- free(tmp);
111
+ free(args.out);
82
112
 
83
113
  return out;
84
114
  }
@@ -86,7 +116,9 @@ zopfli_deflate(int argc, VALUE *argv, VALUE self)
86
116
  void
87
117
  Init_zopfli()
88
118
  {
89
- rb_mZopfli = rb_define_module("Zopfli");
119
+ #if HAVE_RB_EXT_RACTOR_SAFE
120
+ rb_ext_ractor_safe(true);
121
+ #endif
122
+ VALUE rb_mZopfli = rb_define_module("Zopfli");
90
123
  rb_define_singleton_method(rb_mZopfli, "deflate", zopfli_deflate, -1);
91
- rb_require("zopfli/version");
92
124
  }
@@ -1,3 +1,3 @@
1
1
  module Zopfli
2
- VERSION = "0.0.3"
2
+ VERSION = "0.1.0"
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
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+ require "zopfli"
5
+
6
+ require "test-unit"
7
+ require "test/unit/rr"
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "test_helper"
4
+ require "zlib"
5
+ require "stringio"
6
+
7
+ class ZopfliTest < Test::Unit::TestCase
8
+ T = [*"a".."z", *"A".."Z", *"0".."9"].freeze
9
+
10
+ def random_data(length = 1024)
11
+ Array.new(length) { T.sample }.join
12
+ end
13
+
14
+ test "VERSION" do
15
+ assert do
16
+ ::Zopfli.const_defined?(:VERSION)
17
+ end
18
+ end
19
+
20
+ test "well done" do
21
+ s = random_data
22
+ assert_equal s, Zlib::Inflate.inflate(Zopfli.deflate(s, format: :zlib))
23
+ end
24
+
25
+ test "well done(default format is zlib)" do
26
+ s = random_data
27
+ assert_equal Zopfli.deflate(s, format: :zlib), Zopfli.deflate(s)
28
+ end
29
+
30
+ test "well done(gzip format)" do
31
+ s = random_data
32
+ assert_equal s, Zlib::GzipReader.wrap(StringIO.new(Zopfli.deflate(s, format: :gzip)), &:read)
33
+ end
34
+
35
+ test "well done(deflate)" do
36
+ s = random_data
37
+ assert_nothing_raised do
38
+ Zopfli.deflate(s, format: :deflate)
39
+ end
40
+ end
41
+
42
+ test "raise error when pass invalid format" do
43
+ s = random_data
44
+ assert_raise ArgumentError do
45
+ Zopfli.deflate(s, format: :lzma)
46
+ end
47
+ end
48
+
49
+ sub_test_case "Ractor safe" do
50
+ test "able to invoke non-main ractor" do
51
+ unless defined? ::Ractor
52
+ notify "Ractor not defined"
53
+ omit
54
+ end
55
+ a = Array.new(2) do
56
+ Ractor.new(random_data) do |s|
57
+ Zlib::Inflate.inflate(Zopfli.deflate(s)) == s
58
+ end
59
+ end
60
+ assert_equal [true, true], a.map(&:take)
61
+ end
62
+ end
63
+ 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,