brotli 0.7.0 → 0.9.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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +113 -1
  3. data/ext/brotli/brotli.c +908 -288
  4. data/ext/brotli/brotli.h +0 -5
  5. data/ext/brotli/buffer.c +43 -65
  6. data/ext/brotli/buffer.h +6 -9
  7. data/ext/brotli/extconf.rb +115 -50
  8. data/lib/brotli/reader.rb +167 -0
  9. data/lib/brotli/version.rb +1 -1
  10. data/lib/brotli/writer.rb +81 -0
  11. data/lib/brotli.rb +2 -0
  12. data/vendor/brotli/c/common/constants.c +7 -7
  13. data/vendor/brotli/c/common/constants.h +2 -5
  14. data/vendor/brotli/c/common/context.c +2 -2
  15. data/vendor/brotli/c/common/context.h +1 -2
  16. data/vendor/brotli/c/common/dictionary.c +4 -5856
  17. data/vendor/brotli/c/common/dictionary.h +1 -2
  18. data/vendor/brotli/c/common/dictionary_inc.h +5847 -0
  19. data/vendor/brotli/c/common/platform.c +0 -4
  20. data/vendor/brotli/c/common/platform.h +182 -43
  21. data/vendor/brotli/c/common/shared_dictionary.c +3 -7
  22. data/vendor/brotli/c/common/shared_dictionary_internal.h +1 -1
  23. data/vendor/brotli/c/common/static_init.h +56 -0
  24. data/vendor/brotli/c/common/transform.c +6 -4
  25. data/vendor/brotli/c/common/transform.h +1 -2
  26. data/vendor/brotli/c/common/version.h +3 -3
  27. data/vendor/brotli/c/dec/bit_reader.c +2 -3
  28. data/vendor/brotli/c/dec/bit_reader.h +0 -4
  29. data/vendor/brotli/c/dec/decode.c +128 -39
  30. data/vendor/brotli/c/dec/huffman.c +2 -5
  31. data/vendor/brotli/c/dec/huffman.h +0 -2
  32. data/vendor/brotli/c/dec/prefix.c +67 -0
  33. data/vendor/brotli/c/dec/prefix.h +18 -708
  34. data/vendor/brotli/c/dec/prefix_inc.h +707 -0
  35. data/vendor/brotli/c/dec/state.c +18 -15
  36. data/vendor/brotli/c/dec/state.h +2 -6
  37. data/vendor/brotli/c/dec/static_init.c +53 -0
  38. data/vendor/brotli/c/dec/static_init.h +30 -0
  39. data/vendor/brotli/c/enc/backward_references.c +32 -8
  40. data/vendor/brotli/c/enc/backward_references.h +1 -5
  41. data/vendor/brotli/c/enc/backward_references_hq.c +15 -15
  42. data/vendor/brotli/c/enc/backward_references_hq.h +1 -5
  43. data/vendor/brotli/c/enc/bit_cost.c +28 -4
  44. data/vendor/brotli/c/enc/bit_cost.h +8 -40
  45. data/vendor/brotli/c/enc/bit_cost_inc.h +1 -1
  46. data/vendor/brotli/c/enc/block_splitter.c +9 -12
  47. data/vendor/brotli/c/enc/block_splitter.h +0 -3
  48. data/vendor/brotli/c/enc/block_splitter_inc.h +14 -8
  49. data/vendor/brotli/c/enc/brotli_bit_stream.c +10 -9
  50. data/vendor/brotli/c/enc/brotli_bit_stream.h +0 -6
  51. data/vendor/brotli/c/enc/cluster.c +0 -2
  52. data/vendor/brotli/c/enc/cluster.h +0 -2
  53. data/vendor/brotli/c/enc/command.c +1 -1
  54. data/vendor/brotli/c/enc/command.h +8 -10
  55. data/vendor/brotli/c/enc/compound_dictionary.c +3 -5
  56. data/vendor/brotli/c/enc/compound_dictionary.h +1 -4
  57. data/vendor/brotli/c/enc/compress_fragment.c +3 -13
  58. data/vendor/brotli/c/enc/compress_fragment.h +0 -2
  59. data/vendor/brotli/c/enc/compress_fragment_two_pass.c +5 -15
  60. data/vendor/brotli/c/enc/compress_fragment_two_pass.h +0 -2
  61. data/vendor/brotli/c/enc/dictionary_hash.c +127 -1830
  62. data/vendor/brotli/c/enc/dictionary_hash.h +23 -3
  63. data/vendor/brotli/c/enc/dictionary_hash_inc.h +1829 -0
  64. data/vendor/brotli/c/enc/encode.c +77 -52
  65. data/vendor/brotli/c/enc/encoder_dict.c +9 -7
  66. data/vendor/brotli/c/enc/encoder_dict.h +2 -4
  67. data/vendor/brotli/c/enc/entropy_encode.c +3 -6
  68. data/vendor/brotli/c/enc/entropy_encode.h +2 -4
  69. data/vendor/brotli/c/enc/entropy_encode_static.h +18 -12
  70. data/vendor/brotli/c/enc/fast_log.c +1 -1
  71. data/vendor/brotli/c/enc/fast_log.h +2 -3
  72. data/vendor/brotli/c/enc/find_match_length.h +0 -2
  73. data/vendor/brotli/c/enc/hash.h +38 -31
  74. data/vendor/brotli/c/enc/hash_base.h +38 -0
  75. data/vendor/brotli/c/enc/hash_forgetful_chain_inc.h +11 -1
  76. data/vendor/brotli/c/enc/hash_longest_match64_inc.h +24 -7
  77. data/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h +304 -0
  78. data/vendor/brotli/c/enc/hash_longest_match_inc.h +30 -11
  79. data/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h +4 -0
  80. data/vendor/brotli/c/enc/hash_longest_match_simd_inc.h +278 -0
  81. data/vendor/brotli/c/enc/histogram.c +1 -0
  82. data/vendor/brotli/c/enc/histogram.h +0 -4
  83. data/vendor/brotli/c/enc/literal_cost.c +4 -6
  84. data/vendor/brotli/c/enc/literal_cost.h +0 -2
  85. data/vendor/brotli/c/enc/matching_tag_mask.h +69 -0
  86. data/vendor/brotli/c/enc/memory.c +0 -5
  87. data/vendor/brotli/c/enc/memory.h +0 -4
  88. data/vendor/brotli/c/enc/metablock.c +7 -9
  89. data/vendor/brotli/c/enc/metablock.h +3 -3
  90. data/vendor/brotli/c/enc/metablock_inc.h +4 -4
  91. data/vendor/brotli/c/enc/params.h +0 -1
  92. data/vendor/brotli/c/enc/prefix.h +0 -2
  93. data/vendor/brotli/c/enc/quality.h +17 -10
  94. data/vendor/brotli/c/enc/ringbuffer.h +1 -4
  95. data/vendor/brotli/c/enc/state.h +2 -2
  96. data/vendor/brotli/c/enc/static_dict.c +5 -11
  97. data/vendor/brotli/c/enc/static_dict.h +1 -3
  98. data/vendor/brotli/c/enc/static_dict_lut.c +224 -0
  99. data/vendor/brotli/c/enc/static_dict_lut.h +20 -5837
  100. data/vendor/brotli/c/enc/static_dict_lut_inc.h +5830 -0
  101. data/vendor/brotli/c/enc/static_init.c +59 -0
  102. data/vendor/brotli/c/enc/static_init.h +30 -0
  103. data/vendor/brotli/c/enc/utf8_util.c +1 -1
  104. data/vendor/brotli/c/enc/utf8_util.h +0 -2
  105. data/vendor/brotli/c/enc/write_bits.h +0 -2
  106. data/vendor/brotli/c/include/brotli/decode.h +1 -1
  107. data/vendor/brotli/c/include/brotli/encode.h +5 -1
  108. data/vendor/brotli/c/include/brotli/port.h +4 -7
  109. data/vendor/brotli/c/include/brotli/types.h +2 -2
  110. metadata +24 -28
  111. data/.github/workflows/main.yml +0 -37
  112. data/.github/workflows/publish.yml +0 -24
  113. data/.gitignore +0 -18
  114. data/.gitmodules +0 -3
  115. data/.rspec +0 -2
  116. data/Dockerfile +0 -38
  117. data/Gemfile +0 -10
  118. data/Rakefile +0 -42
  119. data/bin/before_install.sh +0 -9
  120. data/bin/console +0 -14
  121. data/bin/setup +0 -8
  122. data/brotli.gemspec +0 -27
  123. data/smoke.sh +0 -8
  124. data/test/brotli_test.rb +0 -183
  125. data/test/brotli_writer_test.rb +0 -93
  126. data/test/test_helper.rb +0 -9
  127. data/vendor/brotli/c/common/dictionary.bin +0 -432
  128. data/vendor/brotli/c/common/dictionary.bin.br +0 -0
data/ext/brotli/brotli.h CHANGED
@@ -3,16 +3,11 @@
3
3
 
4
4
  #include "ruby.h"
5
5
 
6
- // ruby/thread.h is ruby 2.x
7
- #ifdef HAVE_RUBY_THREAD_H
8
6
  #include "ruby/thread.h"
9
- #endif
10
7
 
11
8
  #include "brotli/encode.h"
12
9
  #include "brotli/decode.h"
13
- #ifdef HAVE_BROTLI_SHARED_DICTIONARY_H
14
10
  #include "brotli/shared_dictionary.h"
15
- #endif
16
11
  #include "buffer.h"
17
12
 
18
13
  #endif /* BROTLI_H */
data/ext/brotli/buffer.c CHANGED
@@ -1,90 +1,68 @@
1
1
  #include "buffer.h"
2
2
  #include "ruby/ruby.h"
3
- #define INITIAL (1024)
4
3
 
5
- buffer_t*
6
- create_buffer(const size_t initial) {
7
- buffer_t *buffer = ruby_xmalloc(sizeof(buffer_t));
8
- if (buffer == NULL) {
9
- return NULL;
10
- }
4
+ #include <stdint.h>
5
+ #include <string.h>
11
6
 
7
+ #define BUFFER_INITIAL_SIZE 1024
8
+
9
+ buffer_t*
10
+ create_buffer(size_t initial)
11
+ {
12
+ buffer_t *buffer = ruby_xmalloc(sizeof(*buffer));
12
13
  buffer->used = 0;
13
- buffer->expand_count = 0;
14
- buffer->expand_ratio = 130;
15
- buffer->size = (size_t) (initial > 0 ? initial : INITIAL);
14
+ buffer->size = initial > 0 ? initial : BUFFER_INITIAL_SIZE;
16
15
  buffer->ptr = ruby_xmalloc(buffer->size);
17
- if (buffer->ptr == NULL) {
18
- delete_buffer(buffer);
19
- return NULL;
20
- }
21
-
22
16
  return buffer;
23
17
  }
24
18
 
25
19
  void
26
- delete_buffer(buffer_t* buffer) {
27
- if (buffer->ptr != NULL) {
28
- ruby_xfree(buffer->ptr);
29
- buffer->ptr = NULL;
20
+ delete_buffer(buffer_t* buffer)
21
+ {
22
+ if (!buffer) {
23
+ return;
30
24
  }
25
+
26
+ ruby_xfree(buffer->ptr);
31
27
  ruby_xfree(buffer);
32
28
  }
33
29
 
34
- static
35
- buffer_t*
36
- expand_buffer(buffer_t* const buffer, const size_t need) {
37
- size_t size = need * buffer->expand_ratio / 100;
38
- buffer->ptr = ruby_xrealloc(buffer->ptr, size);
39
- buffer->size = size;
40
- buffer->expand_count += 1;
41
- return buffer;
42
- }
30
+ static size_t
31
+ buffer_size_for(size_t current, size_t required)
32
+ {
33
+ size_t size = current > 0 ? current : BUFFER_INITIAL_SIZE;
43
34
 
44
- buffer_t*
45
- append_buffer(buffer_t* buffer, const void* ptr, const size_t size) {
46
- if (buffer->used + size > buffer->size) {
47
- if (expand_buffer(buffer, buffer->used + size) == NULL) {
48
- return NULL;
35
+ while (size < required) {
36
+ if (size > SIZE_MAX / 2) {
37
+ return required;
49
38
  }
39
+ size *= 2;
50
40
  }
51
- memcpy(buffer->ptr + buffer->used, ptr, size);
52
- buffer->used += size;
53
- return buffer;
54
- }
55
41
 
56
- #if 0
57
- #include <stdio.h>
42
+ return size;
43
+ }
58
44
 
59
- void
60
- inspect_buffer(buffer_t* buffer) {
61
- printf("ptr=%p size=%d used=%d expc=%d\n",
62
- buffer->ptr,
63
- buffer->size,
64
- buffer->used,
65
- buffer->expand_count);
45
+ static void
46
+ expand_buffer(buffer_t* buffer, size_t required)
47
+ {
48
+ buffer->size = buffer_size_for(buffer->size, required);
49
+ buffer->ptr = ruby_xrealloc(buffer->ptr, buffer->size);
66
50
  }
67
51
 
68
- int
69
- main(int argc, char *argv[])
52
+ void
53
+ append_buffer(buffer_t* buffer, const void* ptr, size_t size)
70
54
  {
71
- buffer_t* b = create_buffer(8);
55
+ size_t required;
56
+
57
+ if (size == 0) {
58
+ return;
59
+ }
72
60
 
73
- inspect_buffer(b);
74
- append_buffer(b, "1111", 4);
75
- inspect_buffer(b);
76
- append_buffer(b, "2222", 4);
77
- inspect_buffer(b);
78
- append_buffer(b, "3333", 4);
79
- inspect_buffer(b);
80
- append_buffer(b, "4444", 4);
81
- inspect_buffer(b);
82
- append_buffer(b, "5555", 4);
83
- inspect_buffer(b);
84
- append_buffer(b, "66", 2);
85
- inspect_buffer(b);
61
+ required = buffer->used + size;
62
+ if (required > buffer->size) {
63
+ expand_buffer(buffer, required);
64
+ }
86
65
 
87
- delete_buffer(b);
88
- return 0;
66
+ memcpy(buffer->ptr + buffer->used, ptr, size);
67
+ buffer->used += size;
89
68
  }
90
- #endif
data/ext/brotli/buffer.h CHANGED
@@ -1,19 +1,16 @@
1
- #ifndef __BUFFER_HEADER__
2
- #include <stdint.h>
3
- #include <stdlib.h>
1
+ #ifndef BUFFER_H
2
+ #define BUFFER_H 1
3
+
4
4
  #include <stddef.h>
5
- #include <string.h>
6
5
 
7
6
  typedef struct {
8
7
  char* ptr;
9
8
  size_t size;
10
9
  size_t used;
11
- size_t expand_ratio;
12
- size_t expand_count;
13
10
  } buffer_t;
14
11
 
15
- buffer_t* create_buffer(const size_t initial);
12
+ buffer_t* create_buffer(size_t initial);
16
13
  void delete_buffer(buffer_t* buffer);
17
- buffer_t* append_buffer(buffer_t* buffer, const void* ptr, const size_t size);
14
+ void append_buffer(buffer_t* buffer, const void* ptr, size_t size);
18
15
 
19
- #endif // __BUFFER_HEADER__
16
+ #endif /* BUFFER_H */
@@ -1,66 +1,131 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "mkmf"
2
4
  require "fileutils"
3
5
  require "rbconfig"
6
+ require "rubygems/version"
4
7
 
5
- dir_config("brotli")
8
+ VENDORED_DIRS = %w[common dec enc include].freeze
9
+ MINIMUM_BROTLI_VERSION = Gem::Version.new("1.2.0")
10
+ BUILD_DIR = Dir.pwd
11
+ VENDORED_SOURCE_DIR = File.expand_path("../../vendor/brotli/c", __dir__)
6
12
 
7
- # libbrotli-dev
8
- have_dev_pkg = [
9
- have_header("brotli/decode.h"),
10
- have_header("brotli/encode.h"),
11
- pkg_config("libbrotlicommon"),
12
- pkg_config("libbrotlidec"),
13
- pkg_config("libbrotlienc")
14
- ].all? { |e| e }
15
-
16
- have_header("brotli/shared_dictionary.h")
17
- have_func("BrotliEncoderPrepareDictionary", "brotli/encode.h")
18
- have_func("BrotliEncoderAttachPreparedDictionary", "brotli/encode.h")
19
- have_func("BrotliDecoderAttachDictionary", "brotli/decode.h")
20
-
21
- if enable_config("vendor")
22
- have_dev_pkg = false
23
- Logging::message "Use vendor brotli\n"
24
- $defs << "-DHAVE_BROTLI_SHARED_DICTIONARY_H"
25
- $defs << "-DHAVE_BROTLIENCODERPREPAREDICTIONARY"
26
- $defs << "-DHAVE_BROTLIENCODERATTACHPREPAREDDICTIONARY"
27
- $defs << "-DHAVE_BROTLIDECODERATTACHDICTIONARY"
13
+ def generated_vendored_dirs
14
+ VENDORED_DIRS.map { |dirname| File.join(BUILD_DIR, dirname) }
28
15
  end
29
16
 
30
- $CPPFLAGS << " -DOS_MACOSX" if RbConfig::CONFIG["host_os"] =~ /darwin|mac os/
31
- $INCFLAGS << " -I$(srcdir)/enc -I$(srcdir)/dec -I$(srcdir)/common -I$(srcdir)/include" unless have_dev_pkg
17
+ def remove_generated_vendored_dirs
18
+ generated_vendored_dirs.each { |path| FileUtils.rm_rf(path) }
19
+ end
32
20
 
33
- create_makefile("brotli/brotli")
21
+ def copy_vendored_sources
22
+ sources = Dir[File.join(VENDORED_SOURCE_DIR, "{common,dec,enc,include}", "**", "*.{c,h}")].sort
34
23
 
35
- unless have_dev_pkg
36
- __DIR__ = File.expand_path(File.dirname(__FILE__))
24
+ if sources.empty?
25
+ abort "ERROR: Vendored Brotli sources not found at #{VENDORED_SOURCE_DIR}.\n" \
26
+ "Install system libbrotli-dev >= #{MINIMUM_BROTLI_VERSION} or ensure vendor sources are present."
27
+ end
37
28
 
38
- %w[enc dec common include].each do |dirname|
39
- FileUtils.rm_rf dirname
40
- FileUtils.mkdir_p dirname
41
- FileUtils.cp_r(
42
- File.expand_path(File.join(__DIR__, "..", "..", "vendor", "brotli", "c", dirname), __DIR__),
43
- __DIR__,
44
- verbose: true
45
- )
29
+ sources.each do |source|
30
+ relative_path = source.delete_prefix("#{VENDORED_SOURCE_DIR}/")
31
+ destination = File.join(BUILD_DIR, relative_path)
32
+
33
+ FileUtils.mkdir_p(File.dirname(destination))
34
+ FileUtils.cp(source, destination)
46
35
  end
36
+ end
47
37
 
48
- srcs = []
49
- objs = []
50
- Dir[File.expand_path(File.join("{enc,dec,common,include}", "**", "*.c"), __DIR__)].sort.each do |file|
51
- file[__DIR__ + File::SEPARATOR] = ""
52
- srcs << file
53
- objs << file.sub(/\.c\z/, "." + RbConfig::CONFIG["OBJEXT"])
38
+ def vendored_source_files
39
+ Dir[File.join(BUILD_DIR, "{common,dec,enc,include}", "**", "*.c")].sort.map do |path|
40
+ path.delete_prefix("#{BUILD_DIR}/")
54
41
  end
42
+ end
43
+
44
+ def add_vendored_sources_to_makefile
45
+ objext = RbConfig::CONFIG["OBJEXT"]
46
+ source_files = vendored_source_files
47
+ object_files = source_files.map { |path| path.sub(/\.c\z/, ".#{objext}") }
48
+
49
+ makefile = File.read("Makefile")
50
+ makefile = makefile
51
+ .sub(/^ORIG_SRCS = .*$/, "ORIG_SRCS = brotli.c buffer.c #{source_files.join(" ")}")
52
+ .sub(/^OBJS = .*$/, "OBJS = brotli.#{objext} buffer.#{objext} #{object_files.join(" ")}")
53
+ File.write("Makefile", makefile)
54
+ end
55
+
56
+ def mkmf_flags
57
+ {
58
+ cflags: $CFLAGS.dup,
59
+ cxxflags: $CXXFLAGS.dup,
60
+ cppflags: $CPPFLAGS.dup,
61
+ defs: $defs.dup,
62
+ incflags: $INCFLAGS.dup,
63
+ ldflags: $LDFLAGS.dup,
64
+ libs: $libs.dup,
65
+ local_libs: $LOCAL_LIBS.dup
66
+ }
67
+ end
68
+
69
+ def restore_mkmf_flags(flags)
70
+ $CFLAGS = flags[:cflags]
71
+ $CXXFLAGS = flags[:cxxflags]
72
+ $CPPFLAGS = flags[:cppflags]
73
+ $defs = flags[:defs]
74
+ $INCFLAGS = flags[:incflags]
75
+ $LDFLAGS = flags[:ldflags]
76
+ $libs = flags[:libs]
77
+ $LOCAL_LIBS = flags[:local_libs]
78
+ end
55
79
 
56
- File.open("Makefile", "r+") do |f|
57
- obj_ext = RbConfig::CONFIG["OBJEXT"]
58
- src = "ORIG_SRCS = brotli.c buffer.c"
59
- obj = "OBJS = brotli.#{obj_ext} buffer.#{obj_ext}"
60
- txt = f.read
61
- .sub(/^ORIG_SRCS = .*$/, "#{src} #{srcs.join(" ")}")
62
- .sub(/^OBJS = .*$/, "#{obj} #{objs.join(" ")}")
63
- f.rewind
64
- f.write txt
80
+ def system_brotli_version
81
+ version = pkg_config("libbrotlicommon", "modversion")
82
+ Gem::Version.new(version) if version
83
+ rescue ArgumentError
84
+ nil
85
+ end
86
+
87
+ def system_brotli_available?
88
+ flags = mkmf_flags
89
+ version = system_brotli_version
90
+
91
+ unless version && version >= MINIMUM_BROTLI_VERSION
92
+ Logging.message(
93
+ "System Brotli version %s is too old; need >= %s\n",
94
+ version || "unknown",
95
+ MINIMUM_BROTLI_VERSION
96
+ )
97
+ restore_mkmf_flags(flags)
98
+ return false
65
99
  end
100
+
101
+ available = pkg_config("libbrotlicommon") &&
102
+ pkg_config("libbrotlidec") &&
103
+ pkg_config("libbrotlienc") &&
104
+ have_header("brotli/decode.h") &&
105
+ have_header("brotli/encode.h") &&
106
+ have_header("brotli/shared_dictionary.h") &&
107
+ have_func("BrotliEncoderPrepareDictionary", "brotli/encode.h") &&
108
+ have_func("BrotliEncoderAttachPreparedDictionary", "brotli/encode.h") &&
109
+ have_func("BrotliDecoderAttachDictionary", "brotli/decode.h")
110
+
111
+ restore_mkmf_flags(flags) unless available
112
+ available
113
+ end
114
+
115
+ dir_config("brotli")
116
+ have_func("rb_gc_mark_movable")
117
+
118
+ $CPPFLAGS << " -DOS_MACOSX" if RbConfig::CONFIG["host_os"] =~ /darwin|mac os/
119
+
120
+ remove_generated_vendored_dirs
121
+
122
+ use_vendored_brotli = enable_config("vendor", false) || !system_brotli_available?
123
+
124
+ if use_vendored_brotli
125
+ Logging.message "Using vendored Brotli sources\n"
126
+ copy_vendored_sources
127
+ $INCFLAGS << " -Ienc -Idec -Icommon -Iinclude"
66
128
  end
129
+
130
+ create_makefile("brotli/brotli")
131
+ add_vendored_sources_to_makefile if use_vendored_brotli
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brotli
4
+ class Reader
5
+ DEFAULT_READ_SIZE = 8192
6
+
7
+ def initialize(io, options = nil, **kwargs)
8
+ raise ArgumentError, "io should not be nil" if io.nil?
9
+
10
+ @io = io
11
+ @decompressor = Decompressor.new(normalize_options(options, kwargs))
12
+ @output_buffer = +""
13
+ @closed = false
14
+ @finished = false
15
+ end
16
+
17
+ def read(length = nil, outbuf = nil)
18
+ ensure_open
19
+
20
+ if length.nil?
21
+ drain_stream
22
+ return replace_outbuf(outbuf, take_output)
23
+ end
24
+
25
+ len = Integer(length)
26
+ raise ArgumentError, "negative length #{len} given" if len.negative?
27
+ return replace_outbuf(outbuf, +"") if len.zero?
28
+
29
+ fill_buffer(len, output_limit: len)
30
+ if @output_buffer.empty? && @finished
31
+ replace_outbuf(outbuf, +"") if outbuf
32
+ return nil
33
+ end
34
+
35
+ replace_outbuf(outbuf, take_output(len))
36
+ end
37
+
38
+ def readpartial(maxlen, outbuf = nil)
39
+ ensure_open
40
+
41
+ len = Integer(maxlen)
42
+ raise ArgumentError, "max length must be positive" unless len.positive?
43
+
44
+ until @finished || !@output_buffer.empty?
45
+ fill_buffer(1, output_limit: len, stop_after_output: true)
46
+ end
47
+
48
+ if @output_buffer.empty?
49
+ replace_outbuf(outbuf, +"") if outbuf
50
+ raise EOFError, "end of file reached"
51
+ end
52
+
53
+ replace_outbuf(outbuf, take_output(len))
54
+ end
55
+
56
+ def eof?
57
+ ensure_open
58
+
59
+ return false unless @output_buffer.empty?
60
+
61
+ fill_buffer(1, output_limit: 1, stop_after_output: true) unless @finished
62
+ @output_buffer.empty? && @finished
63
+ end
64
+
65
+ def close
66
+ return @io if @closed
67
+
68
+ begin
69
+ @io.close if @io.respond_to?(:close)
70
+ ensure
71
+ @closed = true
72
+ @finished = true
73
+ @decompressor = nil
74
+ @output_buffer.clear
75
+ end
76
+
77
+ @io
78
+ end
79
+
80
+ def closed?
81
+ @closed
82
+ end
83
+
84
+ private
85
+
86
+ def ensure_open
87
+ raise Error, "Reader is closed" if @closed
88
+ end
89
+
90
+ def replace_outbuf(outbuf, string)
91
+ return string unless outbuf
92
+
93
+ buffer = coerce_string(outbuf)
94
+ buffer.replace(string)
95
+ buffer
96
+ end
97
+
98
+ def take_output(length = @output_buffer.bytesize)
99
+ return +"".b if length <= 0 || @output_buffer.empty?
100
+
101
+ if length >= @output_buffer.bytesize
102
+ output = @output_buffer
103
+ @output_buffer = +""
104
+ return output
105
+ end
106
+
107
+ @output_buffer.slice!(0, length)
108
+ end
109
+
110
+ def drain_stream
111
+ fill_buffer(@output_buffer.bytesize + 1) until @finished
112
+ end
113
+
114
+ def fill_buffer(wanted, output_limit: nil, stop_after_output: false)
115
+ while @output_buffer.bytesize < wanted && !@finished
116
+ buffered = @output_buffer.bytesize
117
+ chunk = next_chunk
118
+ feed_chunk(chunk || +"", output_limit: remaining_output_limit(output_limit))
119
+ break if stop_after_output && !@output_buffer.empty?
120
+
121
+ next unless chunk.nil? || chunk.empty?
122
+ next if @finished || @output_buffer.bytesize > buffered || !@decompressor.can_accept_more_data
123
+
124
+ raise Error, "Unexpected end of compressed stream"
125
+ end
126
+ end
127
+
128
+ def feed_chunk(chunk, output_limit: nil)
129
+ output = if output_limit&.positive?
130
+ @decompressor.process(chunk, output_buffer_limit: output_limit)
131
+ else
132
+ @decompressor.process(chunk)
133
+ end
134
+
135
+ @output_buffer << output unless output.empty?
136
+ @finished = @decompressor.finished?
137
+ end
138
+
139
+ def next_chunk
140
+ return +"".b unless @decompressor.can_accept_more_data
141
+
142
+ @io.respond_to?(:readpartial) ? @io.readpartial(DEFAULT_READ_SIZE) : @io.read(DEFAULT_READ_SIZE)
143
+ rescue EOFError
144
+ nil
145
+ end
146
+
147
+ def remaining_output_limit(output_limit)
148
+ return unless output_limit
149
+
150
+ [output_limit - @output_buffer.bytesize, 0].max
151
+ end
152
+
153
+ def normalize_options(options, kwargs)
154
+ return kwargs if options.nil?
155
+
156
+ unless options.is_a?(Hash)
157
+ raise TypeError, "no implicit conversion of #{options.class} into Hash"
158
+ end
159
+
160
+ kwargs.empty? ? options : options.merge(kwargs)
161
+ end
162
+
163
+ def coerce_string(value)
164
+ String.try_convert(value) || raise(TypeError, "no implicit conversion of #{value.class} into String")
165
+ end
166
+ end
167
+ end
@@ -1,3 +1,3 @@
1
1
  module Brotli
2
- VERSION = '0.7.0'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -0,0 +1,81 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brotli
4
+ class Writer
5
+ def initialize(io, options = nil, **kwargs)
6
+ raise ArgumentError, "io should not be nil" if io.nil?
7
+
8
+ @io = io
9
+ @compressor = Compressor.new(normalize_options(options, kwargs))
10
+ @closed = false
11
+ end
12
+
13
+ def write(data)
14
+ ensure_open
15
+
16
+ data = coerce_string(data)
17
+ write_output(@compressor.process(data))
18
+ data.bytesize
19
+ end
20
+
21
+ def finish
22
+ ensure_open
23
+
24
+ write_output(@compressor.finish)
25
+ @io
26
+ end
27
+
28
+ def flush
29
+ ensure_open
30
+
31
+ write_output(@compressor.flush)
32
+ @io.flush if @io.respond_to?(:flush)
33
+ self
34
+ end
35
+
36
+ def close
37
+ return @io if @closed
38
+
39
+ begin
40
+ finish
41
+ ensure
42
+ begin
43
+ @io.close if @io.respond_to?(:close)
44
+ ensure
45
+ @closed = true
46
+ @compressor = nil
47
+ end
48
+ end
49
+
50
+ @io
51
+ end
52
+
53
+ def closed?
54
+ @closed
55
+ end
56
+
57
+ private
58
+
59
+ def ensure_open
60
+ raise Error, "Writer is closed" if @closed
61
+ end
62
+
63
+ def write_output(output)
64
+ @io.write(output) unless output.empty?
65
+ end
66
+
67
+ def normalize_options(options, kwargs)
68
+ return kwargs if options.nil?
69
+
70
+ unless options.is_a?(Hash)
71
+ raise TypeError, "no implicit conversion of #{options.class} into Hash"
72
+ end
73
+
74
+ kwargs.empty? ? options : options.merge(kwargs)
75
+ end
76
+
77
+ def coerce_string(value)
78
+ String.try_convert(value) || raise(TypeError, "no implicit conversion of #{value.class} into String")
79
+ end
80
+ end
81
+ end
data/lib/brotli.rb CHANGED
@@ -1,2 +1,4 @@
1
1
  require 'brotli/version'
2
2
  require 'brotli/brotli'
3
+ require 'brotli/writer'
4
+ require 'brotli/reader'
@@ -6,10 +6,10 @@
6
6
 
7
7
  #include "constants.h"
8
8
 
9
- const BrotliPrefixCodeRange
10
- _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
11
- {1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
12
- {33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
13
- {113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
14
- {369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
15
- {8433, 13}, {16625, 24}};
9
+ const BROTLI_MODEL("small")
10
+ BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
11
+ {1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
12
+ {33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
13
+ {113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
14
+ {369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
15
+ {8433, 13}, {16625, 24}};
@@ -12,9 +12,6 @@
12
12
  #ifndef BROTLI_COMMON_CONSTANTS_H_
13
13
  #define BROTLI_COMMON_CONSTANTS_H_
14
14
 
15
- #include <brotli/port.h>
16
- #include <brotli/types.h>
17
-
18
15
  #include "platform.h"
19
16
 
20
17
  /* Specification: 7.3. Encoding of the context map */
@@ -195,7 +192,7 @@ typedef struct {
195
192
  } BrotliPrefixCodeRange;
196
193
 
197
194
  /* "Soft-private", it is exported, but not "advertised" as API. */
198
- BROTLI_COMMON_API extern const BrotliPrefixCodeRange
199
- _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
195
+ BROTLI_COMMON_API extern const BROTLI_MODEL("small")
196
+ BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
200
197
 
201
198
  #endif /* BROTLI_COMMON_CONSTANTS_H_ */
@@ -1,9 +1,9 @@
1
1
  #include "context.h"
2
2
 
3
- #include <brotli/types.h>
3
+ #include "platform.h"
4
4
 
5
5
  /* Common context lookup table for all context modes. */
6
- const uint8_t _kBrotliContextLookupTable[2048] = {
6
+ const BROTLI_MODEL("small") uint8_t _kBrotliContextLookupTable[2048] = {
7
7
  /* CONTEXT_LSB6, last byte. */
8
8
  0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
9
9
  16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
@@ -88,8 +88,7 @@
88
88
  #ifndef BROTLI_COMMON_CONTEXT_H_
89
89
  #define BROTLI_COMMON_CONTEXT_H_
90
90
 
91
- #include <brotli/port.h>
92
- #include <brotli/types.h>
91
+ #include "platform.h"
93
92
 
94
93
  typedef enum ContextType {
95
94
  CONTEXT_LSB6 = 0,