multi_compress 0.6.0 → 0.6.1
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/GET_STARTED.md +1 -1
- data/README.md +1 -1
- data/THIRD_PARTY_NOTICES.md +1 -1
- data/ext/multi_compress/multi_compress.c +230 -77
- data/ext/multi_compress/vendor/.vendored +1 -1
- data/ext/multi_compress/vendor/brotli/c/common/version.h +2 -2
- data/ext/multi_compress/vendor/brotli/c/dec/decode.c +59 -30
- data/ext/multi_compress/vendor/brotli/c/include/brotli/decode.h +1 -3
- data/lib/multi_compress/active_record.rb +11 -5
- data/lib/multi_compress/codec.rb +164 -94
- data/lib/multi_compress/database/api.rb +42 -0
- data/lib/multi_compress/database/decoding.rb +42 -0
- data/lib/multi_compress/database/dictionary.rb +72 -0
- data/lib/multi_compress/database/encoding.rb +31 -0
- data/lib/multi_compress/database/header.rb +71 -0
- data/lib/multi_compress/database/operations.rb +73 -0
- data/lib/multi_compress/database/validation.rb +95 -0
- data/lib/multi_compress/database.rb +10 -282
- data/lib/multi_compress/db_deployment/bundle_archiver.rb +70 -0
- data/lib/multi_compress/db_deployment/bundle_metadata.rb +56 -0
- data/lib/multi_compress/db_deployment/bundle_stager.rb +62 -0
- data/lib/multi_compress/db_deployment/commands.rb +309 -0
- data/lib/multi_compress/db_deployment/deployment_bundle.rb +80 -0
- data/lib/multi_compress/db_deployment/deterministic_tar_writer.rb +76 -0
- data/lib/multi_compress/db_deployment/dictionary_registry.rb +244 -0
- data/lib/multi_compress/db_deployment/readable_view.rb +112 -0
- data/lib/multi_compress/db_deployment/readable_view_options.rb +51 -0
- data/lib/multi_compress/db_deployment/sql_identifiers.rb +45 -0
- data/lib/multi_compress/db_deployment.rb +10 -844
- data/lib/multi_compress/reader/buffer_operations.rb +57 -0
- data/lib/multi_compress/reader/read_operations.rb +67 -0
- data/lib/multi_compress/reader.rb +97 -0
- data/lib/multi_compress/stream_io.rb +13 -0
- data/lib/multi_compress/version.rb +1 -1
- data/lib/multi_compress/writer.rb +85 -0
- data/lib/multi_compress.rb +42 -333
- metadata +25 -6
|
@@ -8,8 +8,9 @@
|
|
|
8
8
|
#include <brotli/decode.h>
|
|
9
9
|
#include <brotli/encode.h>
|
|
10
10
|
#include <lz4.h>
|
|
11
|
-
#include <
|
|
11
|
+
#include <limits.h>
|
|
12
12
|
#include <lz4frame.h>
|
|
13
|
+
#include <lz4hc.h>
|
|
13
14
|
#include <pthread.h>
|
|
14
15
|
#include <stdio.h>
|
|
15
16
|
#include <stdint.h>
|
|
@@ -518,30 +519,42 @@ static compress_algo_t detect_algo(const uint8_t *data, size_t len) {
|
|
|
518
519
|
return ALGO_ZSTD;
|
|
519
520
|
}
|
|
520
521
|
|
|
521
|
-
static inline
|
|
522
|
-
|
|
522
|
+
static inline long rb_checked_string_length(size_t len) {
|
|
523
|
+
if ((uintmax_t)len > (uintmax_t)LONG_MAX)
|
|
524
|
+
rb_raise(eDataError, "string size exceeds Ruby's maximum length");
|
|
525
|
+
|
|
526
|
+
return (long)len;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
static inline VALUE rb_binary_str_new(const char *ptr, size_t len) {
|
|
530
|
+
VALUE str = rb_str_new(ptr, rb_checked_string_length(len));
|
|
523
531
|
rb_enc_associate(str, binary_encoding);
|
|
524
532
|
return str;
|
|
525
533
|
}
|
|
526
534
|
|
|
527
|
-
static inline VALUE rb_binary_str_buf_new(
|
|
528
|
-
VALUE str = rb_str_buf_new(capa);
|
|
535
|
+
static inline VALUE rb_binary_str_buf_new(size_t capa) {
|
|
536
|
+
VALUE str = rb_str_buf_new(rb_checked_string_length(capa));
|
|
529
537
|
rb_enc_associate(str, binary_encoding);
|
|
530
538
|
return str;
|
|
531
539
|
}
|
|
532
540
|
|
|
533
|
-
static inline VALUE rb_binary_str_buf_reserve(
|
|
534
|
-
VALUE str = rb_str_buf_new(capa);
|
|
541
|
+
static inline VALUE rb_binary_str_buf_reserve(size_t capa) {
|
|
542
|
+
VALUE str = rb_str_buf_new(rb_checked_string_length(capa));
|
|
535
543
|
rb_enc_associate(str, binary_encoding);
|
|
536
544
|
return str;
|
|
537
545
|
}
|
|
538
546
|
|
|
547
|
+
static inline void rb_binary_str_set_len(VALUE str, size_t len) {
|
|
548
|
+
rb_str_set_len(str, rb_checked_string_length(len));
|
|
549
|
+
}
|
|
550
|
+
|
|
539
551
|
static inline void grow_binary_str(VALUE str, size_t cur_len, size_t new_cap) {
|
|
540
552
|
size_t cur_cap = (size_t)rb_str_capacity(str);
|
|
541
553
|
if (new_cap <= cur_cap)
|
|
542
554
|
return;
|
|
543
|
-
|
|
544
|
-
|
|
555
|
+
(void)rb_checked_string_length(new_cap);
|
|
556
|
+
rb_binary_str_set_len(str, cur_len);
|
|
557
|
+
rb_str_modify_expand(str, rb_checked_string_length(new_cap - cur_len));
|
|
545
558
|
}
|
|
546
559
|
|
|
547
560
|
typedef struct {
|
|
@@ -562,6 +575,8 @@ static void limits_config_apply_parsed(const mc_opts_t *opts, limits_config_t *l
|
|
|
562
575
|
size_t max_output_size = NUM2SIZET(val);
|
|
563
576
|
if (max_output_size == 0)
|
|
564
577
|
rb_raise(rb_eArgError, "max_output_size must be greater than 0");
|
|
578
|
+
if ((uintmax_t)max_output_size > (uintmax_t)LONG_MAX)
|
|
579
|
+
rb_raise(rb_eArgError, "max_output_size exceeds Ruby's maximum string length");
|
|
565
580
|
limits->max_output_size = max_output_size;
|
|
566
581
|
}
|
|
567
582
|
|
|
@@ -1306,7 +1321,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1306
1321
|
rb_raise(eMemError, "zstd: failed to create context");
|
|
1307
1322
|
if (ZSTD_isError(csize))
|
|
1308
1323
|
rb_raise(eError, "zstd compress: %s", ZSTD_getErrorName(csize));
|
|
1309
|
-
|
|
1324
|
+
rb_binary_str_set_len(dst, csize);
|
|
1310
1325
|
RB_GC_GUARD(data);
|
|
1311
1326
|
RB_GC_GUARD(dict_val);
|
|
1312
1327
|
return dst;
|
|
@@ -1343,7 +1358,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1343
1358
|
rb_raise(eError, "zstd compress: %s", ZSTD_getErrorName(fargs.result));
|
|
1344
1359
|
}
|
|
1345
1360
|
|
|
1346
|
-
VALUE result = rb_binary_str_new(out_buf,
|
|
1361
|
+
VALUE result = rb_binary_str_new(out_buf, fargs.result);
|
|
1347
1362
|
free(out_buf);
|
|
1348
1363
|
RB_GC_GUARD(data);
|
|
1349
1364
|
RB_GC_GUARD(dict_val);
|
|
@@ -1370,7 +1385,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1370
1385
|
if (ZSTD_isError(args.result))
|
|
1371
1386
|
rb_raise(eError, "zstd compress: %s", ZSTD_getErrorName(args.result));
|
|
1372
1387
|
|
|
1373
|
-
|
|
1388
|
+
rb_binary_str_set_len(dst, args.result);
|
|
1374
1389
|
RB_GC_GUARD(data);
|
|
1375
1390
|
RB_GC_GUARD(dict_val);
|
|
1376
1391
|
return dst;
|
|
@@ -1383,7 +1398,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1383
1398
|
prefs.frameInfo.blockChecksumFlag = LZ4F_blockChecksumEnabled;
|
|
1384
1399
|
prefs.frameInfo.contentChecksumFlag = LZ4F_contentChecksumEnabled;
|
|
1385
1400
|
size_t bound = LZ4F_compressFrameBound(slen, &prefs);
|
|
1386
|
-
VALUE dst = rb_binary_str_buf_reserve(
|
|
1401
|
+
VALUE dst = rb_binary_str_buf_reserve(bound);
|
|
1387
1402
|
lz4frame_compress_args_t args = {
|
|
1388
1403
|
.src = src,
|
|
1389
1404
|
.src_len = slen,
|
|
@@ -1401,7 +1416,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1401
1416
|
if (args.error_code)
|
|
1402
1417
|
rb_raise(eError, "lz4 frame compress failed: %s",
|
|
1403
1418
|
LZ4F_getErrorName(args.error_code));
|
|
1404
|
-
|
|
1419
|
+
rb_binary_str_set_len(dst, args.result);
|
|
1405
1420
|
RB_GC_GUARD(data);
|
|
1406
1421
|
return dst;
|
|
1407
1422
|
}
|
|
@@ -1438,7 +1453,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1438
1453
|
size_t total = 8 + (size_t)csize;
|
|
1439
1454
|
write_le_u32((uint8_t *)out + total, 0);
|
|
1440
1455
|
|
|
1441
|
-
|
|
1456
|
+
rb_binary_str_set_len(dst, total + 4);
|
|
1442
1457
|
RB_GC_GUARD(data);
|
|
1443
1458
|
return dst;
|
|
1444
1459
|
} else {
|
|
@@ -1460,7 +1475,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1460
1475
|
size_t total = 8 + csize;
|
|
1461
1476
|
write_le_u32((uint8_t *)out + total, 0);
|
|
1462
1477
|
|
|
1463
|
-
|
|
1478
|
+
rb_binary_str_set_len(dst, total + 4);
|
|
1464
1479
|
RB_GC_GUARD(data);
|
|
1465
1480
|
return dst;
|
|
1466
1481
|
}
|
|
@@ -1516,7 +1531,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1516
1531
|
if (!ok)
|
|
1517
1532
|
rb_raise(eError, "brotli compress with dict failed");
|
|
1518
1533
|
|
|
1519
|
-
|
|
1534
|
+
rb_binary_str_set_len(dst, initial_out - available_out);
|
|
1520
1535
|
RB_GC_GUARD(data);
|
|
1521
1536
|
RB_GC_GUARD(dict_val);
|
|
1522
1537
|
return dst;
|
|
@@ -1540,7 +1555,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1540
1555
|
if (!args.result)
|
|
1541
1556
|
rb_raise(eError, "brotli compress failed");
|
|
1542
1557
|
|
|
1543
|
-
|
|
1558
|
+
rb_binary_str_set_len(dst, actual_out_len);
|
|
1544
1559
|
RB_GC_GUARD(data);
|
|
1545
1560
|
return dst;
|
|
1546
1561
|
} else {
|
|
@@ -1550,7 +1565,7 @@ static VALUE compress_compress(int argc, VALUE *argv, VALUE self) {
|
|
|
1550
1565
|
(const uint8_t *)src, &out_len, (uint8_t *)RSTRING_PTR(dst));
|
|
1551
1566
|
if (!ok)
|
|
1552
1567
|
rb_raise(eError, "brotli compress failed");
|
|
1553
|
-
|
|
1568
|
+
rb_binary_str_set_len(dst, out_len);
|
|
1554
1569
|
RB_GC_GUARD(data);
|
|
1555
1570
|
return dst;
|
|
1556
1571
|
}
|
|
@@ -1690,7 +1705,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1690
1705
|
|
|
1691
1706
|
enforce_output_and_ratio_limits(dsize, slen, limits.max_output_size,
|
|
1692
1707
|
limits.max_ratio_enabled, limits.max_ratio);
|
|
1693
|
-
|
|
1708
|
+
rb_binary_str_set_len(dst, dsize);
|
|
1694
1709
|
RB_GC_GUARD(data);
|
|
1695
1710
|
RB_GC_GUARD(dict_val);
|
|
1696
1711
|
return dst;
|
|
@@ -1714,7 +1729,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1714
1729
|
rb_raise(eDataError, "zstd decompress: %s", ZSTD_getErrorName(dsize));
|
|
1715
1730
|
enforce_output_and_ratio_limits(dsize, slen, limits.max_output_size,
|
|
1716
1731
|
limits.max_ratio_enabled, limits.max_ratio);
|
|
1717
|
-
|
|
1732
|
+
rb_binary_str_set_len(dst, dsize);
|
|
1718
1733
|
RB_GC_GUARD(data);
|
|
1719
1734
|
RB_GC_GUARD(dict_val);
|
|
1720
1735
|
return dst;
|
|
@@ -1787,7 +1802,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1787
1802
|
break;
|
|
1788
1803
|
}
|
|
1789
1804
|
|
|
1790
|
-
|
|
1805
|
+
rb_binary_str_set_len(dst, total_out);
|
|
1791
1806
|
RB_GC_GUARD(data);
|
|
1792
1807
|
RB_GC_GUARD(dict_val);
|
|
1793
1808
|
return dst;
|
|
@@ -1800,7 +1815,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1800
1815
|
alloc_size = limits.max_output_size < 4096 ? limits.max_output_size : 4096;
|
|
1801
1816
|
if (alloc_size == 0)
|
|
1802
1817
|
alloc_size = limits.max_output_size;
|
|
1803
|
-
VALUE dst = rb_binary_str_buf_reserve(
|
|
1818
|
+
VALUE dst = rb_binary_str_buf_reserve(alloc_size);
|
|
1804
1819
|
while (1) {
|
|
1805
1820
|
lz4frame_decompress_args_t args = {
|
|
1806
1821
|
.src = src,
|
|
@@ -1835,7 +1850,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1835
1850
|
LZ4F_getErrorName(args.error_code));
|
|
1836
1851
|
enforce_output_and_ratio_limits(args.result, slen, limits.max_output_size,
|
|
1837
1852
|
limits.max_ratio_enabled, limits.max_ratio);
|
|
1838
|
-
|
|
1853
|
+
rb_binary_str_set_len(dst, args.result);
|
|
1839
1854
|
RB_GC_GUARD(data);
|
|
1840
1855
|
return dst;
|
|
1841
1856
|
}
|
|
@@ -1890,7 +1905,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1890
1905
|
|
|
1891
1906
|
enforce_output_and_ratio_limits(args.out_offset, slen, limits.max_output_size,
|
|
1892
1907
|
limits.max_ratio_enabled, limits.max_ratio);
|
|
1893
|
-
|
|
1908
|
+
rb_binary_str_set_len(result, args.out_offset);
|
|
1894
1909
|
RB_GC_GUARD(data);
|
|
1895
1910
|
return result;
|
|
1896
1911
|
}
|
|
@@ -1976,7 +1991,7 @@ static VALUE compress_decompress(int argc, VALUE *argv, VALUE self) {
|
|
|
1976
1991
|
if (res != BROTLI_DECODER_RESULT_SUCCESS) {
|
|
1977
1992
|
rb_raise(eDataError, "brotli decompress failed");
|
|
1978
1993
|
}
|
|
1979
|
-
|
|
1994
|
+
rb_binary_str_set_len(dst, total_out);
|
|
1980
1995
|
RB_GC_GUARD(data);
|
|
1981
1996
|
RB_GC_GUARD(dict_val);
|
|
1982
1997
|
return dst;
|
|
@@ -2131,11 +2146,45 @@ static VALUE compress_version(VALUE self, VALUE algo_sym) {
|
|
|
2131
2146
|
_Static_assert(LZ4_RING_BUFFER_TOTAL == 2 * LZ4_RING_BUFFER_SIZE,
|
|
2132
2147
|
"ring buffer total must be exactly twice the window size");
|
|
2133
2148
|
|
|
2149
|
+
typedef struct {
|
|
2150
|
+
int *active;
|
|
2151
|
+
VALUE self;
|
|
2152
|
+
VALUE argument;
|
|
2153
|
+
VALUE (*operation)(VALUE, VALUE);
|
|
2154
|
+
} stream_operation_t;
|
|
2155
|
+
|
|
2156
|
+
static VALUE stream_operation_body(VALUE opaque) {
|
|
2157
|
+
stream_operation_t *call = (stream_operation_t *)(uintptr_t)opaque;
|
|
2158
|
+
return call->operation(call->self, call->argument);
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
static VALUE stream_operation_ensure(VALUE opaque) {
|
|
2162
|
+
stream_operation_t *call = (stream_operation_t *)(uintptr_t)opaque;
|
|
2163
|
+
*call->active = 0;
|
|
2164
|
+
return Qnil;
|
|
2165
|
+
}
|
|
2166
|
+
|
|
2167
|
+
static VALUE stream_operation_call(int *active, VALUE self, VALUE argument,
|
|
2168
|
+
VALUE (*operation)(VALUE, VALUE)) {
|
|
2169
|
+
if (*active)
|
|
2170
|
+
rb_raise(eStreamError, "stream operation already in progress");
|
|
2171
|
+
|
|
2172
|
+
stream_operation_t call = {
|
|
2173
|
+
.active = active, .self = self, .argument = argument, .operation = operation};
|
|
2174
|
+
*active = 1;
|
|
2175
|
+
VALUE result = rb_ensure(stream_operation_body, (VALUE)(uintptr_t)&call,
|
|
2176
|
+
stream_operation_ensure, (VALUE)(uintptr_t)&call);
|
|
2177
|
+
RB_GC_GUARD(self);
|
|
2178
|
+
RB_GC_GUARD(argument);
|
|
2179
|
+
return result;
|
|
2180
|
+
}
|
|
2181
|
+
|
|
2134
2182
|
typedef struct {
|
|
2135
2183
|
compress_algo_t algo;
|
|
2136
2184
|
int level;
|
|
2137
2185
|
int closed;
|
|
2138
2186
|
int finished;
|
|
2187
|
+
int operation_active;
|
|
2139
2188
|
|
|
2140
2189
|
union {
|
|
2141
2190
|
ZSTD_CStream *zstd;
|
|
@@ -2179,6 +2228,9 @@ static size_t deflater_memsize(const void *ptr) {
|
|
|
2179
2228
|
return 0;
|
|
2180
2229
|
|
|
2181
2230
|
size_t s = sizeof(deflater_t);
|
|
2231
|
+
if (d->operation_active)
|
|
2232
|
+
return s;
|
|
2233
|
+
|
|
2182
2234
|
switch (d->algo) {
|
|
2183
2235
|
case ALGO_ZSTD:
|
|
2184
2236
|
if (d->ctx.zstd)
|
|
@@ -2325,7 +2377,7 @@ static VALUE lz4_compress_ring_block(deflater_t *d) {
|
|
|
2325
2377
|
|
|
2326
2378
|
write_le_u32((uint8_t *)out + 4, (uint32_t)csize);
|
|
2327
2379
|
|
|
2328
|
-
|
|
2380
|
+
rb_binary_str_set_len(output, 8 + csize);
|
|
2329
2381
|
d->lz4_ring.pending = 0;
|
|
2330
2382
|
|
|
2331
2383
|
if (d->lz4_ring.ring_offset >= LZ4_RING_BUFFER_SIZE) {
|
|
@@ -2335,7 +2387,7 @@ static VALUE lz4_compress_ring_block(deflater_t *d) {
|
|
|
2335
2387
|
return output;
|
|
2336
2388
|
}
|
|
2337
2389
|
|
|
2338
|
-
static VALUE
|
|
2390
|
+
static VALUE deflater_write_impl(VALUE self, VALUE chunk) {
|
|
2339
2391
|
deflater_t *d;
|
|
2340
2392
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2341
2393
|
if (d->closed)
|
|
@@ -2405,7 +2457,7 @@ static VALUE deflater_write(VALUE self, VALUE chunk) {
|
|
|
2405
2457
|
}
|
|
2406
2458
|
result_len += output.pos;
|
|
2407
2459
|
}
|
|
2408
|
-
|
|
2460
|
+
rb_binary_str_set_len(result, result_len);
|
|
2409
2461
|
RB_GC_GUARD(chunk);
|
|
2410
2462
|
return result;
|
|
2411
2463
|
}
|
|
@@ -2471,7 +2523,7 @@ static VALUE deflater_write(VALUE self, VALUE chunk) {
|
|
|
2471
2523
|
}
|
|
2472
2524
|
}
|
|
2473
2525
|
}
|
|
2474
|
-
|
|
2526
|
+
rb_binary_str_set_len(result, result_len);
|
|
2475
2527
|
RB_GC_GUARD(chunk);
|
|
2476
2528
|
return result;
|
|
2477
2529
|
}
|
|
@@ -2517,7 +2569,7 @@ static VALUE deflater_write(VALUE self, VALUE chunk) {
|
|
|
2517
2569
|
}
|
|
2518
2570
|
}
|
|
2519
2571
|
}
|
|
2520
|
-
|
|
2572
|
+
rb_binary_str_set_len(result, result_len);
|
|
2521
2573
|
RB_GC_GUARD(chunk);
|
|
2522
2574
|
return result;
|
|
2523
2575
|
}
|
|
@@ -2525,7 +2577,14 @@ static VALUE deflater_write(VALUE self, VALUE chunk) {
|
|
|
2525
2577
|
return rb_binary_str_new("", 0);
|
|
2526
2578
|
}
|
|
2527
2579
|
|
|
2528
|
-
static VALUE
|
|
2580
|
+
static VALUE deflater_write(VALUE self, VALUE chunk) {
|
|
2581
|
+
deflater_t *d;
|
|
2582
|
+
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2583
|
+
return stream_operation_call(&d->operation_active, self, chunk, deflater_write_impl);
|
|
2584
|
+
}
|
|
2585
|
+
|
|
2586
|
+
static VALUE deflater_flush_impl(VALUE self, VALUE unused) {
|
|
2587
|
+
(void)unused;
|
|
2529
2588
|
deflater_t *d;
|
|
2530
2589
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2531
2590
|
if (d->closed)
|
|
@@ -2554,7 +2613,7 @@ static VALUE deflater_flush(VALUE self) {
|
|
|
2554
2613
|
result_len += output.pos;
|
|
2555
2614
|
} while (ret > 0);
|
|
2556
2615
|
|
|
2557
|
-
|
|
2616
|
+
rb_binary_str_set_len(result, result_len);
|
|
2558
2617
|
return result;
|
|
2559
2618
|
}
|
|
2560
2619
|
case ALGO_BROTLI: {
|
|
@@ -2586,7 +2645,7 @@ static VALUE deflater_flush(VALUE self) {
|
|
|
2586
2645
|
}
|
|
2587
2646
|
} while (BrotliEncoderHasMoreOutput(d->ctx.brotli));
|
|
2588
2647
|
|
|
2589
|
-
|
|
2648
|
+
rb_binary_str_set_len(result, result_len);
|
|
2590
2649
|
return result;
|
|
2591
2650
|
}
|
|
2592
2651
|
case ALGO_LZ4:
|
|
@@ -2595,7 +2654,14 @@ static VALUE deflater_flush(VALUE self) {
|
|
|
2595
2654
|
return rb_binary_str_new("", 0);
|
|
2596
2655
|
}
|
|
2597
2656
|
|
|
2598
|
-
static VALUE
|
|
2657
|
+
static VALUE deflater_flush(VALUE self) {
|
|
2658
|
+
deflater_t *d;
|
|
2659
|
+
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2660
|
+
return stream_operation_call(&d->operation_active, self, Qnil, deflater_flush_impl);
|
|
2661
|
+
}
|
|
2662
|
+
|
|
2663
|
+
static VALUE deflater_finish_impl(VALUE self, VALUE unused) {
|
|
2664
|
+
(void)unused;
|
|
2599
2665
|
deflater_t *d;
|
|
2600
2666
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2601
2667
|
if (d->closed)
|
|
@@ -2625,7 +2691,7 @@ static VALUE deflater_finish(VALUE self) {
|
|
|
2625
2691
|
result_len += output.pos;
|
|
2626
2692
|
} while (ret > 0);
|
|
2627
2693
|
|
|
2628
|
-
|
|
2694
|
+
rb_binary_str_set_len(result, result_len);
|
|
2629
2695
|
return result;
|
|
2630
2696
|
}
|
|
2631
2697
|
case ALGO_BROTLI: {
|
|
@@ -2658,7 +2724,7 @@ static VALUE deflater_finish(VALUE self) {
|
|
|
2658
2724
|
} while (BrotliEncoderHasMoreOutput(d->ctx.brotli) ||
|
|
2659
2725
|
!BrotliEncoderIsFinished(d->ctx.brotli));
|
|
2660
2726
|
|
|
2661
|
-
|
|
2727
|
+
rb_binary_str_set_len(result, result_len);
|
|
2662
2728
|
return result;
|
|
2663
2729
|
}
|
|
2664
2730
|
case ALGO_LZ4: {
|
|
@@ -2689,14 +2755,21 @@ static VALUE deflater_finish(VALUE self) {
|
|
|
2689
2755
|
write_le_u32((uint8_t *)out, 0);
|
|
2690
2756
|
result_len += 4;
|
|
2691
2757
|
|
|
2692
|
-
|
|
2758
|
+
rb_binary_str_set_len(result, result_len);
|
|
2693
2759
|
return result;
|
|
2694
2760
|
}
|
|
2695
2761
|
}
|
|
2696
2762
|
return rb_binary_str_new("", 0);
|
|
2697
2763
|
}
|
|
2698
2764
|
|
|
2699
|
-
static VALUE
|
|
2765
|
+
static VALUE deflater_finish(VALUE self) {
|
|
2766
|
+
deflater_t *d;
|
|
2767
|
+
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2768
|
+
return stream_operation_call(&d->operation_active, self, Qnil, deflater_finish_impl);
|
|
2769
|
+
}
|
|
2770
|
+
|
|
2771
|
+
static VALUE deflater_reset_impl(VALUE self, VALUE unused) {
|
|
2772
|
+
(void)unused;
|
|
2700
2773
|
deflater_t *d;
|
|
2701
2774
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2702
2775
|
|
|
@@ -2752,7 +2825,14 @@ static VALUE deflater_reset(VALUE self) {
|
|
|
2752
2825
|
return self;
|
|
2753
2826
|
}
|
|
2754
2827
|
|
|
2755
|
-
static VALUE
|
|
2828
|
+
static VALUE deflater_reset(VALUE self) {
|
|
2829
|
+
deflater_t *d;
|
|
2830
|
+
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2831
|
+
return stream_operation_call(&d->operation_active, self, Qnil, deflater_reset_impl);
|
|
2832
|
+
}
|
|
2833
|
+
|
|
2834
|
+
static VALUE deflater_close_impl(VALUE self, VALUE unused) {
|
|
2835
|
+
(void)unused;
|
|
2756
2836
|
deflater_t *d;
|
|
2757
2837
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2758
2838
|
if (d->closed)
|
|
@@ -2782,6 +2862,12 @@ static VALUE deflater_close(VALUE self) {
|
|
|
2782
2862
|
return Qnil;
|
|
2783
2863
|
}
|
|
2784
2864
|
|
|
2865
|
+
static VALUE deflater_close(VALUE self) {
|
|
2866
|
+
deflater_t *d;
|
|
2867
|
+
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
2868
|
+
return stream_operation_call(&d->operation_active, self, Qnil, deflater_close_impl);
|
|
2869
|
+
}
|
|
2870
|
+
|
|
2785
2871
|
static VALUE deflater_closed_p(VALUE self) {
|
|
2786
2872
|
deflater_t *d;
|
|
2787
2873
|
TypedData_Get_Struct(self, deflater_t, &deflater_type, d);
|
|
@@ -2792,6 +2878,7 @@ typedef struct {
|
|
|
2792
2878
|
compress_algo_t algo;
|
|
2793
2879
|
int closed;
|
|
2794
2880
|
int finished;
|
|
2881
|
+
int operation_active;
|
|
2795
2882
|
size_t max_output_size;
|
|
2796
2883
|
size_t total_output;
|
|
2797
2884
|
size_t total_input;
|
|
@@ -2838,6 +2925,9 @@ static size_t inflater_memsize(const void *ptr) {
|
|
|
2838
2925
|
return 0;
|
|
2839
2926
|
|
|
2840
2927
|
size_t s = sizeof(inflater_t);
|
|
2928
|
+
if (inf->operation_active)
|
|
2929
|
+
return s;
|
|
2930
|
+
|
|
2841
2931
|
switch (inf->algo) {
|
|
2842
2932
|
case ALGO_ZSTD:
|
|
2843
2933
|
if (inf->ctx.zstd)
|
|
@@ -2932,7 +3022,7 @@ static VALUE inflater_initialize(int argc, VALUE *argv, VALUE self) {
|
|
|
2932
3022
|
return self;
|
|
2933
3023
|
}
|
|
2934
3024
|
|
|
2935
|
-
static VALUE
|
|
3025
|
+
static VALUE inflater_write_impl(VALUE self, VALUE chunk) {
|
|
2936
3026
|
inflater_t *inf;
|
|
2937
3027
|
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
2938
3028
|
if (inf->closed)
|
|
@@ -3017,7 +3107,7 @@ static VALUE inflater_write(VALUE self, VALUE chunk) {
|
|
|
3017
3107
|
"compressed input exceeds representable size");
|
|
3018
3108
|
inf->total_output = checked_add_size(inf->total_output, result_len,
|
|
3019
3109
|
"decompressed output exceeds representable size");
|
|
3020
|
-
|
|
3110
|
+
rb_binary_str_set_len(result, result_len);
|
|
3021
3111
|
RB_GC_GUARD(chunk);
|
|
3022
3112
|
return result;
|
|
3023
3113
|
}
|
|
@@ -3098,7 +3188,7 @@ static VALUE inflater_write(VALUE self, VALUE chunk) {
|
|
|
3098
3188
|
"compressed input exceeds representable size");
|
|
3099
3189
|
inf->total_output = checked_add_size(inf->total_output, result_len,
|
|
3100
3190
|
"decompressed output exceeds representable size");
|
|
3101
|
-
|
|
3191
|
+
rb_binary_str_set_len(result, result_len);
|
|
3102
3192
|
RB_GC_GUARD(chunk);
|
|
3103
3193
|
return result;
|
|
3104
3194
|
}
|
|
@@ -3201,7 +3291,7 @@ static VALUE inflater_write(VALUE self, VALUE chunk) {
|
|
|
3201
3291
|
inf->lz4_buf.offset = pos;
|
|
3202
3292
|
inf->total_output = checked_add_size(inf->total_output, result_len,
|
|
3203
3293
|
"decompressed output exceeds representable size");
|
|
3204
|
-
|
|
3294
|
+
rb_binary_str_set_len(result, result_len);
|
|
3205
3295
|
RB_GC_GUARD(chunk);
|
|
3206
3296
|
return result;
|
|
3207
3297
|
}
|
|
@@ -3209,7 +3299,14 @@ static VALUE inflater_write(VALUE self, VALUE chunk) {
|
|
|
3209
3299
|
return rb_binary_str_new("", 0);
|
|
3210
3300
|
}
|
|
3211
3301
|
|
|
3212
|
-
static VALUE
|
|
3302
|
+
static VALUE inflater_write(VALUE self, VALUE chunk) {
|
|
3303
|
+
inflater_t *inf;
|
|
3304
|
+
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3305
|
+
return stream_operation_call(&inf->operation_active, self, chunk, inflater_write_impl);
|
|
3306
|
+
}
|
|
3307
|
+
|
|
3308
|
+
static VALUE inflater_finish_impl(VALUE self, VALUE unused) {
|
|
3309
|
+
(void)unused;
|
|
3213
3310
|
inflater_t *inf;
|
|
3214
3311
|
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3215
3312
|
if (inf->closed)
|
|
@@ -3218,7 +3315,14 @@ static VALUE inflater_finish(VALUE self) {
|
|
|
3218
3315
|
return rb_binary_str_new("", 0);
|
|
3219
3316
|
}
|
|
3220
3317
|
|
|
3221
|
-
static VALUE
|
|
3318
|
+
static VALUE inflater_finish(VALUE self) {
|
|
3319
|
+
inflater_t *inf;
|
|
3320
|
+
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3321
|
+
return stream_operation_call(&inf->operation_active, self, Qnil, inflater_finish_impl);
|
|
3322
|
+
}
|
|
3323
|
+
|
|
3324
|
+
static VALUE inflater_reset_impl(VALUE self, VALUE unused) {
|
|
3325
|
+
(void)unused;
|
|
3222
3326
|
inflater_t *inf;
|
|
3223
3327
|
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3224
3328
|
|
|
@@ -3263,7 +3367,14 @@ static VALUE inflater_reset(VALUE self) {
|
|
|
3263
3367
|
return self;
|
|
3264
3368
|
}
|
|
3265
3369
|
|
|
3266
|
-
static VALUE
|
|
3370
|
+
static VALUE inflater_reset(VALUE self) {
|
|
3371
|
+
inflater_t *inf;
|
|
3372
|
+
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3373
|
+
return stream_operation_call(&inf->operation_active, self, Qnil, inflater_reset_impl);
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3376
|
+
static VALUE inflater_close_impl(VALUE self, VALUE unused) {
|
|
3377
|
+
(void)unused;
|
|
3267
3378
|
inflater_t *inf;
|
|
3268
3379
|
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3269
3380
|
if (inf->closed)
|
|
@@ -3289,6 +3400,12 @@ static VALUE inflater_close(VALUE self) {
|
|
|
3289
3400
|
return Qnil;
|
|
3290
3401
|
}
|
|
3291
3402
|
|
|
3403
|
+
static VALUE inflater_close(VALUE self) {
|
|
3404
|
+
inflater_t *inf;
|
|
3405
|
+
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
3406
|
+
return stream_operation_call(&inf->operation_active, self, Qnil, inflater_close_impl);
|
|
3407
|
+
}
|
|
3408
|
+
|
|
3292
3409
|
static VALUE inflater_closed_p(VALUE self) {
|
|
3293
3410
|
inflater_t *inf;
|
|
3294
3411
|
TypedData_Get_Struct(self, inflater_t, &inflater_type, inf);
|
|
@@ -3409,6 +3526,59 @@ static VALUE brotli_train_dictionary(int argc, VALUE *argv, VALUE self) {
|
|
|
3409
3526
|
return train_dictionary_internal(samples, parsed_opts.size, ALGO_BROTLI);
|
|
3410
3527
|
}
|
|
3411
3528
|
|
|
3529
|
+
typedef struct {
|
|
3530
|
+
FILE *file;
|
|
3531
|
+
VALUE path_value;
|
|
3532
|
+
const char *path;
|
|
3533
|
+
uint8_t *data;
|
|
3534
|
+
size_t size;
|
|
3535
|
+
int loaded;
|
|
3536
|
+
} dict_file_read_t;
|
|
3537
|
+
|
|
3538
|
+
static VALUE dict_file_read_body(VALUE opaque) {
|
|
3539
|
+
dict_file_read_t *read = (dict_file_read_t *)(uintptr_t)opaque;
|
|
3540
|
+
|
|
3541
|
+
if (fseek(read->file, 0, SEEK_END) != 0)
|
|
3542
|
+
rb_sys_fail(read->path);
|
|
3543
|
+
|
|
3544
|
+
long file_size = ftell(read->file);
|
|
3545
|
+
if (file_size < 0)
|
|
3546
|
+
rb_sys_fail(read->path);
|
|
3547
|
+
if (file_size == 0)
|
|
3548
|
+
rb_raise(eDataError, "dictionary file is empty: %s", read->path);
|
|
3549
|
+
if ((unsigned long long)file_size > DICT_FILE_MAX_SIZE)
|
|
3550
|
+
rb_raise(eDataError, "dictionary file too large (%ld bytes, max=%d)", file_size,
|
|
3551
|
+
(int)DICT_FILE_MAX_SIZE);
|
|
3552
|
+
if (fseek(read->file, 0, SEEK_SET) != 0)
|
|
3553
|
+
rb_sys_fail(read->path);
|
|
3554
|
+
|
|
3555
|
+
read->data = ALLOC_N(uint8_t, file_size);
|
|
3556
|
+
read->path = RSTRING_PTR(read->path_value);
|
|
3557
|
+
read->size = (size_t)file_size;
|
|
3558
|
+
size_t read_bytes = fread(read->data, 1, read->size, read->file);
|
|
3559
|
+
if (read_bytes != read->size) {
|
|
3560
|
+
xfree(read->data);
|
|
3561
|
+
read->data = NULL;
|
|
3562
|
+
rb_raise(eDataError, "failed to read dictionary: %s", read->path);
|
|
3563
|
+
}
|
|
3564
|
+
|
|
3565
|
+
read->loaded = 1;
|
|
3566
|
+
return Qnil;
|
|
3567
|
+
}
|
|
3568
|
+
|
|
3569
|
+
static VALUE dict_file_read_ensure(VALUE opaque) {
|
|
3570
|
+
dict_file_read_t *read = (dict_file_read_t *)(uintptr_t)opaque;
|
|
3571
|
+
if (read->file) {
|
|
3572
|
+
fclose(read->file);
|
|
3573
|
+
read->file = NULL;
|
|
3574
|
+
}
|
|
3575
|
+
if (!read->loaded && read->data) {
|
|
3576
|
+
xfree(read->data);
|
|
3577
|
+
read->data = NULL;
|
|
3578
|
+
}
|
|
3579
|
+
return Qnil;
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3412
3582
|
static VALUE dict_load(int argc, VALUE *argv, VALUE self) {
|
|
3413
3583
|
VALUE path, opts;
|
|
3414
3584
|
scan_one_required_keywords(argc, argv, &path, &opts);
|
|
@@ -3425,40 +3595,23 @@ static VALUE dict_load(int argc, VALUE *argv, VALUE self) {
|
|
|
3425
3595
|
if (algo == ALGO_LZ4)
|
|
3426
3596
|
rb_raise(eUnsupportedError, "LZ4 does not support dictionaries");
|
|
3427
3597
|
|
|
3598
|
+
VALUE dict_obj = dict_alloc(cDictionary);
|
|
3599
|
+
dictionary_t *d;
|
|
3600
|
+
TypedData_Get_Struct(dict_obj, dictionary_t, &dictionary_type, d);
|
|
3601
|
+
|
|
3428
3602
|
const char *cpath = RSTRING_PTR(path);
|
|
3429
|
-
FILE *
|
|
3430
|
-
if (!
|
|
3603
|
+
FILE *file = fopen(cpath, "rb");
|
|
3604
|
+
if (!file)
|
|
3431
3605
|
rb_sys_fail(cpath);
|
|
3432
3606
|
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3607
|
+
dict_file_read_t read = {.file = file, .path_value = path, .path = cpath};
|
|
3608
|
+
rb_ensure(dict_file_read_body, (VALUE)(uintptr_t)&read, dict_file_read_ensure,
|
|
3609
|
+
(VALUE)(uintptr_t)&read);
|
|
3436
3610
|
|
|
3437
|
-
if (file_size <= 0) {
|
|
3438
|
-
fclose(f);
|
|
3439
|
-
rb_raise(eDataError, "dictionary file is empty: %s", cpath);
|
|
3440
|
-
}
|
|
3441
|
-
if ((unsigned long long)file_size > DICT_FILE_MAX_SIZE) {
|
|
3442
|
-
fclose(f);
|
|
3443
|
-
rb_raise(eDataError, "dictionary file too large (%ld bytes, max=%d)", file_size,
|
|
3444
|
-
(int)DICT_FILE_MAX_SIZE);
|
|
3445
|
-
}
|
|
3446
|
-
|
|
3447
|
-
uint8_t *buf = ALLOC_N(uint8_t, file_size);
|
|
3448
|
-
size_t read_bytes = fread(buf, 1, file_size, f);
|
|
3449
|
-
fclose(f);
|
|
3450
|
-
|
|
3451
|
-
if ((long)read_bytes != file_size) {
|
|
3452
|
-
xfree(buf);
|
|
3453
|
-
rb_raise(eDataError, "failed to read dictionary: %s", cpath);
|
|
3454
|
-
}
|
|
3455
|
-
|
|
3456
|
-
VALUE dict_obj = dict_alloc(cDictionary);
|
|
3457
|
-
dictionary_t *d;
|
|
3458
|
-
TypedData_Get_Struct(dict_obj, dictionary_t, &dictionary_type, d);
|
|
3459
3611
|
d->algo = algo;
|
|
3460
|
-
d->data =
|
|
3461
|
-
d->size =
|
|
3612
|
+
d->data = read.data;
|
|
3613
|
+
d->size = read.size;
|
|
3614
|
+
read.data = NULL;
|
|
3462
3615
|
return dict_obj;
|
|
3463
3616
|
}
|
|
3464
3617
|
|
|
@@ -3488,7 +3641,7 @@ static VALUE dict_algo(VALUE self) {
|
|
|
3488
3641
|
static VALUE dict_bytes(VALUE self) {
|
|
3489
3642
|
dictionary_t *d;
|
|
3490
3643
|
TypedData_Get_Struct(self, dictionary_t, &dictionary_type, d);
|
|
3491
|
-
return rb_binary_str_new((const char *)d->data,
|
|
3644
|
+
return rb_binary_str_new((const char *)d->data, d->size);
|
|
3492
3645
|
}
|
|
3493
3646
|
|
|
3494
3647
|
static VALUE dict_zstd_id(VALUE self) {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
|
|
20
20
|
#define BROTLI_VERSION_MAJOR 1
|
|
21
21
|
#define BROTLI_VERSION_MINOR 2
|
|
22
|
-
#define BROTLI_VERSION_PATCH
|
|
22
|
+
#define BROTLI_VERSION_PATCH 1
|
|
23
23
|
|
|
24
24
|
#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \
|
|
25
25
|
BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH)
|
|
@@ -33,7 +33,7 @@
|
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
35
|
#define BROTLI_ABI_CURRENT 3
|
|
36
|
-
#define BROTLI_ABI_REVISION
|
|
36
|
+
#define BROTLI_ABI_REVISION 1
|
|
37
37
|
#define BROTLI_ABI_AGE 2
|
|
38
38
|
|
|
39
39
|
#if BROTLI_VERSION_MAJOR != (BROTLI_ABI_CURRENT - BROTLI_ABI_AGE)
|