snappy-ruby 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 (42) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +77 -0
  4. data/Rakefile +12 -0
  5. data/ext/snappy/extconf.rb +83 -0
  6. data/ext/snappy/snappy-src/AUTHORS +1 -0
  7. data/ext/snappy/snappy-src/BUILD.bazel +211 -0
  8. data/ext/snappy/snappy-src/CMakeLists.txt +467 -0
  9. data/ext/snappy/snappy-src/CONTRIBUTING.md +31 -0
  10. data/ext/snappy/snappy-src/COPYING +54 -0
  11. data/ext/snappy/snappy-src/MODULE.bazel +23 -0
  12. data/ext/snappy/snappy-src/NEWS +215 -0
  13. data/ext/snappy/snappy-src/README.md +165 -0
  14. data/ext/snappy/snappy-src/WORKSPACE +27 -0
  15. data/ext/snappy/snappy-src/WORKSPACE.bzlmod +0 -0
  16. data/ext/snappy/snappy-src/cmake/SnappyConfig.cmake.in +33 -0
  17. data/ext/snappy/snappy-src/cmake/config.h.in +75 -0
  18. data/ext/snappy/snappy-src/config.h +78 -0
  19. data/ext/snappy/snappy-src/docs/README.md +72 -0
  20. data/ext/snappy/snappy-src/format_description.txt +110 -0
  21. data/ext/snappy/snappy-src/framing_format.txt +135 -0
  22. data/ext/snappy/snappy-src/snappy-c.cc +90 -0
  23. data/ext/snappy/snappy-src/snappy-c.h +138 -0
  24. data/ext/snappy/snappy-src/snappy-internal.h +444 -0
  25. data/ext/snappy/snappy-src/snappy-sinksource.cc +121 -0
  26. data/ext/snappy/snappy-src/snappy-sinksource.h +182 -0
  27. data/ext/snappy/snappy-src/snappy-stubs-internal.cc +42 -0
  28. data/ext/snappy/snappy-src/snappy-stubs-internal.h +531 -0
  29. data/ext/snappy/snappy-src/snappy-stubs-public.h +60 -0
  30. data/ext/snappy/snappy-src/snappy-stubs-public.h.in +63 -0
  31. data/ext/snappy/snappy-src/snappy-test.cc +503 -0
  32. data/ext/snappy/snappy-src/snappy-test.h +342 -0
  33. data/ext/snappy/snappy-src/snappy.cc +2666 -0
  34. data/ext/snappy/snappy-src/snappy.h +257 -0
  35. data/ext/snappy/snappy-src/snappy_test_data.cc +57 -0
  36. data/ext/snappy/snappy-src/snappy_test_data.h +68 -0
  37. data/ext/snappy/snappy-src/snappy_test_tool.cc +471 -0
  38. data/ext/snappy/snappy-src/snappy_unittest.cc +1023 -0
  39. data/ext/snappy/snappy.c +282 -0
  40. data/lib/snappy/snappy.so +0 -0
  41. data/lib/snappy.rb +5 -0
  42. metadata +142 -0
@@ -0,0 +1,282 @@
1
+ #include <ruby.h>
2
+ #include <ruby/encoding.h>
3
+ #include <snappy-c.h>
4
+ #include <errno.h>
5
+
6
+ static VALUE rb_mSnappy;
7
+ static VALUE rb_eSnappyError;
8
+
9
+ // Compression level validation
10
+ #define MIN_COMPRESSION_LEVEL 1
11
+ #define MAX_COMPRESSION_LEVEL 9
12
+ #define DEFAULT_COMPRESSION_LEVEL 6
13
+
14
+ /*
15
+ * Compress a string using Snappy compression
16
+ *
17
+ * @param data [String] the data to compress
18
+ * @param options [Hash] options hash
19
+ * @option options [Integer] :level compression level (1-9, default: 6)
20
+ * @return [String] compressed data
21
+ */
22
+ static VALUE rb_snappy_compress(int argc, VALUE *argv, VALUE self) {
23
+ VALUE data, options;
24
+ int level = DEFAULT_COMPRESSION_LEVEL;
25
+
26
+ rb_scan_args(argc, argv, "11", &data, &options);
27
+
28
+ // Validate input
29
+ Check_Type(data, T_STRING);
30
+
31
+ // Parse options
32
+ if (!NIL_P(options)) {
33
+ Check_Type(options, T_HASH);
34
+ VALUE level_val = rb_hash_aref(options, ID2SYM(rb_intern("level")));
35
+ if (!NIL_P(level_val)) {
36
+ level = NUM2INT(level_val);
37
+ if (level < MIN_COMPRESSION_LEVEL || level > MAX_COMPRESSION_LEVEL) {
38
+ rb_raise(rb_eArgError, "compression level must be between %d and %d",
39
+ MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
40
+ }
41
+ }
42
+ }
43
+
44
+ const char *input = RSTRING_PTR(data);
45
+ size_t input_length = RSTRING_LEN(data);
46
+
47
+ // Get maximum compressed length
48
+ size_t max_compressed_length = snappy_max_compressed_length(input_length);
49
+
50
+ // Allocate buffer for compressed data
51
+ char *compressed = ALLOC_N(char, max_compressed_length);
52
+ size_t compressed_length = max_compressed_length;
53
+
54
+ // Perform compression
55
+ snappy_status status = snappy_compress(input, input_length, compressed, &compressed_length);
56
+
57
+ if (status != SNAPPY_OK) {
58
+ xfree(compressed);
59
+ rb_raise(rb_eSnappyError, "compression failed with status: %d", status);
60
+ }
61
+
62
+ // Create Ruby string with compressed data
63
+ VALUE result = rb_str_new(compressed, compressed_length);
64
+ xfree(compressed);
65
+
66
+ return result;
67
+ }
68
+
69
+ /*
70
+ * Decompress Snappy compressed data
71
+ *
72
+ * @param data [String] the compressed data
73
+ * @return [String] decompressed data
74
+ */
75
+ static VALUE rb_snappy_decompress(VALUE self, VALUE data) {
76
+ Check_Type(data, T_STRING);
77
+
78
+ const char *compressed = RSTRING_PTR(data);
79
+ size_t compressed_length = RSTRING_LEN(data);
80
+
81
+ // Get uncompressed length
82
+ size_t uncompressed_length;
83
+ snappy_status status = snappy_uncompressed_length(compressed, compressed_length, &uncompressed_length);
84
+
85
+ if (status != SNAPPY_OK) {
86
+ rb_raise(rb_eSnappyError, "failed to get uncompressed length, status: %d", status);
87
+ }
88
+
89
+ // Allocate buffer for decompressed data
90
+ char *uncompressed = ALLOC_N(char, uncompressed_length);
91
+
92
+ // Perform decompression
93
+ status = snappy_uncompress(compressed, compressed_length, uncompressed, &uncompressed_length);
94
+
95
+ if (status != SNAPPY_OK) {
96
+ xfree(uncompressed);
97
+ rb_raise(rb_eSnappyError, "decompression failed with status: %d", status);
98
+ }
99
+
100
+ // Create Ruby string with decompressed data
101
+ VALUE result = rb_str_new(uncompressed, uncompressed_length);
102
+ xfree(uncompressed);
103
+
104
+ // Try to set UTF-8 encoding if the data is valid UTF-8
105
+ // Otherwise, keep it as binary (ASCII-8BIT)
106
+ int utf8_index = rb_utf8_encindex();
107
+ rb_enc_associate_index(result, utf8_index);
108
+
109
+ // Check if the string is valid in the UTF-8 encoding
110
+ // If not, fall back to binary encoding
111
+ if (rb_enc_str_coderange(result) == ENC_CODERANGE_BROKEN) {
112
+ rb_enc_associate_index(result, rb_ascii8bit_encindex());
113
+ }
114
+
115
+ return result;
116
+ }
117
+
118
+ /*
119
+ * Compress a file using Snappy compression
120
+ *
121
+ * @param input_path [String] path to input file
122
+ * @param output_path [String] path to output file
123
+ * @param options [Hash] options hash
124
+ * @option options [Integer] :level compression level (1-9, default: 6)
125
+ */
126
+ static VALUE rb_snappy_compress_file(int argc, VALUE *argv, VALUE self) {
127
+ VALUE input_path, output_path, options;
128
+ int level = DEFAULT_COMPRESSION_LEVEL;
129
+
130
+ rb_scan_args(argc, argv, "21", &input_path, &output_path, &options);
131
+
132
+ Check_Type(input_path, T_STRING);
133
+ Check_Type(output_path, T_STRING);
134
+
135
+ // Parse options
136
+ if (!NIL_P(options)) {
137
+ Check_Type(options, T_HASH);
138
+ VALUE level_val = rb_hash_aref(options, ID2SYM(rb_intern("level")));
139
+ if (!NIL_P(level_val)) {
140
+ level = NUM2INT(level_val);
141
+ if (level < MIN_COMPRESSION_LEVEL || level > MAX_COMPRESSION_LEVEL) {
142
+ rb_raise(rb_eArgError, "compression level must be between %d and %d",
143
+ MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL);
144
+ }
145
+ }
146
+ }
147
+
148
+ const char *input_file = StringValueCStr(input_path);
149
+ const char *output_file = StringValueCStr(output_path);
150
+
151
+ // Open input file
152
+ FILE *in = fopen(input_file, "rb");
153
+ if (!in) {
154
+ rb_sys_fail(input_file);
155
+ }
156
+
157
+ // Get file size
158
+ fseek(in, 0, SEEK_END);
159
+ long file_size = ftell(in);
160
+ fseek(in, 0, SEEK_SET);
161
+
162
+ // Read file contents
163
+ char *input_data = ALLOC_N(char, file_size);
164
+ size_t bytes_read = fread(input_data, 1, file_size, in);
165
+ fclose(in);
166
+
167
+ if (bytes_read != file_size) {
168
+ xfree(input_data);
169
+ rb_raise(rb_eIOError, "failed to read complete file");
170
+ }
171
+
172
+ // Compress data
173
+ size_t max_compressed_length = snappy_max_compressed_length(file_size);
174
+ char *compressed = ALLOC_N(char, max_compressed_length);
175
+ size_t compressed_length = max_compressed_length;
176
+
177
+ snappy_status status = snappy_compress(input_data, file_size, compressed, &compressed_length);
178
+ xfree(input_data);
179
+
180
+ if (status != SNAPPY_OK) {
181
+ xfree(compressed);
182
+ rb_raise(rb_eSnappyError, "compression failed with status: %d", status);
183
+ }
184
+
185
+ // Write compressed data to output file
186
+ FILE *out = fopen(output_file, "wb");
187
+ if (!out) {
188
+ xfree(compressed);
189
+ rb_sys_fail(output_file);
190
+ }
191
+
192
+ size_t bytes_written = fwrite(compressed, 1, compressed_length, out);
193
+ fclose(out);
194
+ xfree(compressed);
195
+
196
+ if (bytes_written != compressed_length) {
197
+ rb_raise(rb_eIOError, "failed to write complete compressed data");
198
+ }
199
+
200
+ return Qnil;
201
+ }
202
+
203
+ /*
204
+ * Decompress a Snappy compressed file
205
+ *
206
+ * @param input_path [String] path to compressed input file
207
+ * @param output_path [String] path to decompressed output file
208
+ */
209
+ static VALUE rb_snappy_decompress_file(VALUE self, VALUE input_path, VALUE output_path) {
210
+ Check_Type(input_path, T_STRING);
211
+ Check_Type(output_path, T_STRING);
212
+
213
+ const char *input_file = StringValueCStr(input_path);
214
+ const char *output_file = StringValueCStr(output_path);
215
+
216
+ // Open input file
217
+ FILE *in = fopen(input_file, "rb");
218
+ if (!in) {
219
+ rb_sys_fail(input_file);
220
+ }
221
+
222
+ // Get file size
223
+ fseek(in, 0, SEEK_END);
224
+ long file_size = ftell(in);
225
+ fseek(in, 0, SEEK_SET);
226
+
227
+ // Read compressed file contents
228
+ char *compressed_data = ALLOC_N(char, file_size);
229
+ size_t bytes_read = fread(compressed_data, 1, file_size, in);
230
+ fclose(in);
231
+
232
+ if (bytes_read != file_size) {
233
+ xfree(compressed_data);
234
+ rb_raise(rb_eIOError, "failed to read complete file");
235
+ }
236
+
237
+ // Get uncompressed length
238
+ size_t uncompressed_length;
239
+ snappy_status status = snappy_uncompressed_length(compressed_data, file_size, &uncompressed_length);
240
+
241
+ if (status != SNAPPY_OK) {
242
+ xfree(compressed_data);
243
+ rb_raise(rb_eSnappyError, "failed to get uncompressed length, status: %d", status);
244
+ }
245
+
246
+ // Decompress data
247
+ char *uncompressed = ALLOC_N(char, uncompressed_length);
248
+ status = snappy_uncompress(compressed_data, file_size, uncompressed, &uncompressed_length);
249
+ xfree(compressed_data);
250
+
251
+ if (status != SNAPPY_OK) {
252
+ xfree(uncompressed);
253
+ rb_raise(rb_eSnappyError, "decompression failed with status: %d", status);
254
+ }
255
+
256
+ // Write decompressed data to output file
257
+ FILE *out = fopen(output_file, "wb");
258
+ if (!out) {
259
+ xfree(uncompressed);
260
+ rb_sys_fail(output_file);
261
+ }
262
+
263
+ size_t bytes_written = fwrite(uncompressed, 1, uncompressed_length, out);
264
+ fclose(out);
265
+ xfree(uncompressed);
266
+
267
+ if (bytes_written != uncompressed_length) {
268
+ rb_raise(rb_eIOError, "failed to write complete decompressed data");
269
+ }
270
+
271
+ return Qnil;
272
+ }
273
+
274
+ void Init_snappy(void) {
275
+ rb_mSnappy = rb_define_module("Snappy");
276
+ rb_eSnappyError = rb_define_class_under(rb_mSnappy, "Error", rb_eStandardError);
277
+
278
+ rb_define_singleton_method(rb_mSnappy, "compress", rb_snappy_compress, -1);
279
+ rb_define_singleton_method(rb_mSnappy, "decompress", rb_snappy_decompress, 1);
280
+ rb_define_singleton_method(rb_mSnappy, "compress_file", rb_snappy_compress_file, -1);
281
+ rb_define_singleton_method(rb_mSnappy, "decompress_file", rb_snappy_decompress_file, 2);
282
+ }
Binary file
data/lib/snappy.rb ADDED
@@ -0,0 +1,5 @@
1
+ require "snappy/snappy"
2
+
3
+ module Snappy
4
+ VERSION = "0.1.0"
5
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: snappy-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - John Greninger
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2025-11-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake-compiler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: Ruby bindings for Google's Snappy compression library with bundled libsnappy.
70
+ Provides fast compression and decompression with support for file I/O. No system
71
+ dependencies required.
72
+ email:
73
+ - v-greningerj@microsoft.com
74
+ executables: []
75
+ extensions:
76
+ - ext/snappy/extconf.rb
77
+ extra_rdoc_files: []
78
+ files:
79
+ - LICENSE
80
+ - README.md
81
+ - Rakefile
82
+ - ext/snappy/extconf.rb
83
+ - ext/snappy/snappy-src/AUTHORS
84
+ - ext/snappy/snappy-src/BUILD.bazel
85
+ - ext/snappy/snappy-src/CMakeLists.txt
86
+ - ext/snappy/snappy-src/CONTRIBUTING.md
87
+ - ext/snappy/snappy-src/COPYING
88
+ - ext/snappy/snappy-src/MODULE.bazel
89
+ - ext/snappy/snappy-src/NEWS
90
+ - ext/snappy/snappy-src/README.md
91
+ - ext/snappy/snappy-src/WORKSPACE
92
+ - ext/snappy/snappy-src/WORKSPACE.bzlmod
93
+ - ext/snappy/snappy-src/cmake/SnappyConfig.cmake.in
94
+ - ext/snappy/snappy-src/cmake/config.h.in
95
+ - ext/snappy/snappy-src/config.h
96
+ - ext/snappy/snappy-src/docs/README.md
97
+ - ext/snappy/snappy-src/format_description.txt
98
+ - ext/snappy/snappy-src/framing_format.txt
99
+ - ext/snappy/snappy-src/snappy-c.cc
100
+ - ext/snappy/snappy-src/snappy-c.h
101
+ - ext/snappy/snappy-src/snappy-internal.h
102
+ - ext/snappy/snappy-src/snappy-sinksource.cc
103
+ - ext/snappy/snappy-src/snappy-sinksource.h
104
+ - ext/snappy/snappy-src/snappy-stubs-internal.cc
105
+ - ext/snappy/snappy-src/snappy-stubs-internal.h
106
+ - ext/snappy/snappy-src/snappy-stubs-public.h
107
+ - ext/snappy/snappy-src/snappy-stubs-public.h.in
108
+ - ext/snappy/snappy-src/snappy-test.cc
109
+ - ext/snappy/snappy-src/snappy-test.h
110
+ - ext/snappy/snappy-src/snappy.cc
111
+ - ext/snappy/snappy-src/snappy.h
112
+ - ext/snappy/snappy-src/snappy_test_data.cc
113
+ - ext/snappy/snappy-src/snappy_test_data.h
114
+ - ext/snappy/snappy-src/snappy_test_tool.cc
115
+ - ext/snappy/snappy-src/snappy_unittest.cc
116
+ - ext/snappy/snappy.c
117
+ - lib/snappy.rb
118
+ - lib/snappy/snappy.so
119
+ homepage: https://github.com/jgreninger/snappy-ruby
120
+ licenses:
121
+ - MIT
122
+ metadata: {}
123
+ post_install_message:
124
+ rdoc_options: []
125
+ require_paths:
126
+ - lib
127
+ required_ruby_version: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: 3.0.0
132
+ required_rubygems_version: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: '0'
137
+ requirements: []
138
+ rubygems_version: 3.4.20
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Ruby bindings for the Snappy compression library
142
+ test_files: []