brotli 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -4
- data/lib/brotli/version.rb +1 -1
- data/vendor/brotli/c/common/platform.h +70 -11
- data/vendor/brotli/c/common/transform.c +4 -4
- data/vendor/brotli/c/common/version.h +2 -2
- data/vendor/brotli/c/dec/decode.c +50 -41
- data/vendor/brotli/c/dec/huffman.c +30 -47
- data/vendor/brotli/c/dec/huffman.h +55 -0
- data/vendor/brotli/c/enc/backward_references_hq.c +50 -55
- data/vendor/brotli/c/enc/backward_references_hq.h +6 -7
- data/vendor/brotli/c/enc/backward_references_inc.h +9 -9
- data/vendor/brotli/c/enc/encode.c +16 -18
- data/vendor/brotli/c/enc/hash.h +5 -4
- data/vendor/brotli/c/enc/hash_composite_inc.h +7 -4
- data/vendor/brotli/c/enc/hash_longest_match64_inc.h +3 -2
- data/vendor/brotli/c/enc/hash_longest_match_inc.h +3 -2
- data/vendor/brotli/c/enc/hash_rolling_inc.h +3 -2
- data/vendor/brotli/c/enc/hash_to_binary_tree_inc.h +3 -2
- data/vendor/brotli/c/enc/metablock.c +2 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 81b3e01265c409832de742771d83abbfa21c0445a0ad3fa44d8ae646998786d5
|
4
|
+
data.tar.gz: 79d4545e4c507a0ef774412c005fe8ac999a31457347fbea31e21533c194b0ba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9380345b150e5d8e2de3d9c58e4a1b5e6e4ac293f247c9a86caf5b9d1e9026b9b3a89d91254d91edf12212e553fe979894c1a01d6e0d1bfbf5cb1fd37571a7af
|
7
|
+
data.tar.gz: 64bb2538e6d712929a8fdfb2511f612b638c0f33d47eb38b973c9a26876e8ed44642ab1198dcc9f92614716e2b2d5b519705287897dca3ecd66e102d21a41b4e
|
data/.travis.yml
CHANGED
@@ -9,7 +9,7 @@ rvm:
|
|
9
9
|
- 2.2.8
|
10
10
|
- 2.3.5
|
11
11
|
- 2.4.2
|
12
|
-
- 2.5.
|
12
|
+
- 2.5.3
|
13
13
|
env:
|
14
14
|
global:
|
15
15
|
- RANTLY_COUNT=10000
|
@@ -25,6 +25,3 @@ deploy:
|
|
25
25
|
tags: true
|
26
26
|
repo: miyucy/brotli
|
27
27
|
script: bundle exec rake && ./smoke.sh
|
28
|
-
matrix:
|
29
|
-
allow_failures:
|
30
|
-
- rvm: 2.5.0-preview1
|
data/lib/brotli/version.rb
CHANGED
@@ -71,7 +71,7 @@ OR:
|
|
71
71
|
*/
|
72
72
|
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
|
73
73
|
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
74
|
-
BROTLI_SUNPRO_VERSION_CHECK(5,
|
74
|
+
BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) || \
|
75
75
|
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
76
76
|
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
|
77
77
|
BROTLI_TI_VERSION_CHECK(7, 3, 0) || \
|
@@ -180,6 +180,12 @@ OR:
|
|
180
180
|
#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE
|
181
181
|
#endif
|
182
182
|
|
183
|
+
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
|
184
|
+
#define BROTLI_ALIGNED(N) __attribute__((aligned(N)))
|
185
|
+
#else
|
186
|
+
#define BROTLI_ALIGNED(N)
|
187
|
+
#endif
|
188
|
+
|
183
189
|
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
|
184
190
|
(defined(M_ARM) && (M_ARM == 7))
|
185
191
|
#define BROTLI_TARGET_ARMV7
|
@@ -187,9 +193,20 @@ OR:
|
|
187
193
|
|
188
194
|
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \
|
189
195
|
defined(__aarch64__) || defined(__ARM64_ARCH_8__)
|
190
|
-
#define
|
196
|
+
#define BROTLI_TARGET_ARMV8_ANY
|
197
|
+
|
198
|
+
#if defined(__ARM_32BIT_STATE)
|
199
|
+
#define BROTLI_TARGET_ARMV8_32
|
200
|
+
#elif defined(__ARM_64BIT_STATE)
|
201
|
+
#define BROTLI_TARGET_ARMV8_64
|
202
|
+
#endif
|
203
|
+
|
191
204
|
#endif /* ARMv8 */
|
192
205
|
|
206
|
+
#if defined(__ARM_NEON__) || defined(__ARM_NEON)
|
207
|
+
#define BROTLI_TARGET_NEON
|
208
|
+
#endif
|
209
|
+
|
193
210
|
#if defined(__i386) || defined(_M_IX86)
|
194
211
|
#define BROTLI_TARGET_X86
|
195
212
|
#endif
|
@@ -210,7 +227,7 @@ OR:
|
|
210
227
|
#define BROTLI_64_BITS 1
|
211
228
|
#elif defined(BROTLI_BUILD_32_BIT)
|
212
229
|
#define BROTLI_64_BITS 0
|
213
|
-
#elif defined(BROTLI_TARGET_X64) || defined(
|
230
|
+
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
|
214
231
|
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
|
215
232
|
#define BROTLI_64_BITS 1
|
216
233
|
#else
|
@@ -261,7 +278,7 @@ OR:
|
|
261
278
|
#if defined(BROTLI_BUILD_PORTABLE)
|
262
279
|
#define BROTLI_ALIGNED_READ (!!1)
|
263
280
|
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
|
264
|
-
defined(BROTLI_TARGET_ARMV7) || defined(
|
281
|
+
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
|
265
282
|
defined(BROTLI_TARGET_RISCV64)
|
266
283
|
/* Allow unaligned read only for white-listed CPUs. */
|
267
284
|
#define BROTLI_ALIGNED_READ (!!0)
|
@@ -291,6 +308,33 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
|
291
308
|
}
|
292
309
|
#else /* BROTLI_ALIGNED_READ */
|
293
310
|
/* Unaligned memory access is allowed: just cast pointer to requested type. */
|
311
|
+
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
|
312
|
+
defined(MEMORY_SANITIZER)
|
313
|
+
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
|
314
|
+
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
|
315
|
+
will miss a bug if 08 is the first unaddressable byte.
|
316
|
+
ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
|
317
|
+
miss a race between this access and some other accesses to 08.
|
318
|
+
MemorySanitizer will correctly propagate the shadow on unaligned stores
|
319
|
+
and correctly report bugs on unaligned loads, but it may not properly
|
320
|
+
update and report the origin of the uninitialized memory.
|
321
|
+
For all three tools, replacing an unaligned access with a tool-specific
|
322
|
+
callback solves the problem. */
|
323
|
+
#if defined(__cplusplus)
|
324
|
+
extern "C" {
|
325
|
+
#endif /* __cplusplus */
|
326
|
+
uint16_t __sanitizer_unaligned_load16(const void* p);
|
327
|
+
uint32_t __sanitizer_unaligned_load32(const void* p);
|
328
|
+
uint64_t __sanitizer_unaligned_load64(const void* p);
|
329
|
+
void __sanitizer_unaligned_store64(void* p, uint64_t v);
|
330
|
+
#if defined(__cplusplus)
|
331
|
+
} /* extern "C" */
|
332
|
+
#endif /* __cplusplus */
|
333
|
+
#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
|
334
|
+
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
|
335
|
+
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
|
336
|
+
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
|
337
|
+
#else
|
294
338
|
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
295
339
|
return *(const uint16_t*)p;
|
296
340
|
}
|
@@ -306,16 +350,31 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
|
306
350
|
}
|
307
351
|
#else /* BROTLI_64_BITS */
|
308
352
|
/* Avoid emitting LDRD / STRD, which require properly aligned address. */
|
353
|
+
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
|
354
|
+
|
355
|
+
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
|
356
|
+
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
|
357
|
+
|
358
|
+
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
359
|
+
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
|
360
|
+
}
|
361
|
+
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
362
|
+
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
|
363
|
+
dwords[0] = (brotli_unaligned_uint64_t) v;
|
364
|
+
}
|
365
|
+
#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
309
366
|
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
310
|
-
|
311
|
-
|
367
|
+
uint64_t v;
|
368
|
+
memcpy(&v, p, sizeof(uint64_t));
|
369
|
+
return v;
|
312
370
|
}
|
371
|
+
|
313
372
|
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
314
|
-
|
315
|
-
dwords[0] = (uint32_t)v;
|
316
|
-
dwords[1] = (uint32_t)(v >> 32);
|
373
|
+
memcpy(p, &v, sizeof(uint64_t));
|
317
374
|
}
|
375
|
+
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
|
318
376
|
#endif /* BROTLI_64_BITS */
|
377
|
+
#endif /* ASAN / TSAN / MSAN */
|
319
378
|
#endif /* BROTLI_ALIGNED_READ */
|
320
379
|
|
321
380
|
#if BROTLI_LITTLE_ENDIAN
|
@@ -400,7 +459,7 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
|
400
459
|
#define BROTLI_IS_CONSTANT(x) (!!0)
|
401
460
|
#endif
|
402
461
|
|
403
|
-
#if defined(BROTLI_TARGET_ARMV7) || defined(
|
462
|
+
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
|
404
463
|
#define BROTLI_HAS_UBFX (!!1)
|
405
464
|
#else
|
406
465
|
#define BROTLI_HAS_UBFX (!!0)
|
@@ -427,7 +486,7 @@ static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
|
427
486
|
/* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */
|
428
487
|
#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \
|
429
488
|
!defined(BROTLI_BUILD_NO_RBIT)
|
430
|
-
#if defined(BROTLI_TARGET_ARMV7) || defined(
|
489
|
+
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
|
431
490
|
/* TODO: detect ARMv6T2 and enable this code for it. */
|
432
491
|
static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
|
433
492
|
brotli_reg_t output;
|
@@ -191,11 +191,11 @@ static int ToUpperCase(uint8_t* p) {
|
|
191
191
|
}
|
192
192
|
|
193
193
|
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
|
194
|
-
const BrotliTransforms* transforms, int
|
194
|
+
const BrotliTransforms* transforms, int transform_idx) {
|
195
195
|
int idx = 0;
|
196
|
-
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms,
|
197
|
-
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms,
|
198
|
-
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms,
|
196
|
+
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transform_idx);
|
197
|
+
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transform_idx);
|
198
|
+
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transform_idx);
|
199
199
|
{
|
200
200
|
int prefix_len = *prefix++;
|
201
201
|
while (prefix_len--) { dst[idx++] = *prefix++; }
|
@@ -14,13 +14,13 @@
|
|
14
14
|
BrotliEncoderVersion methods. */
|
15
15
|
|
16
16
|
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
17
|
-
#define BROTLI_VERSION
|
17
|
+
#define BROTLI_VERSION 0x1000007
|
18
18
|
|
19
19
|
/* This macro is used by build system to produce Libtool-friendly soname. See
|
20
20
|
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
21
21
|
*/
|
22
22
|
|
23
23
|
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
|
24
|
-
#define BROTLI_ABI_VERSION
|
24
|
+
#define BROTLI_ABI_VERSION 0x1007000
|
25
25
|
|
26
26
|
#endif /* BROTLI_COMMON_VERSION_H_ */
|
@@ -6,10 +6,6 @@
|
|
6
6
|
|
7
7
|
#include <brotli/decode.h>
|
8
8
|
|
9
|
-
#if defined(__ARM_NEON__)
|
10
|
-
#include <arm_neon.h>
|
11
|
-
#endif
|
12
|
-
|
13
9
|
#include <stdlib.h> /* free, malloc */
|
14
10
|
#include <string.h> /* memcpy, memset */
|
15
11
|
|
@@ -24,6 +20,10 @@
|
|
24
20
|
#include "./prefix.h"
|
25
21
|
#include "./state.h"
|
26
22
|
|
23
|
+
#if defined(BROTLI_TARGET_NEON)
|
24
|
+
#include <arm_neon.h>
|
25
|
+
#endif
|
26
|
+
|
27
27
|
#if defined(__cplusplus) || defined(c_plusplus)
|
28
28
|
extern "C" {
|
29
29
|
#endif
|
@@ -167,7 +167,7 @@ static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s,
|
|
167
167
|
}
|
168
168
|
|
169
169
|
static BROTLI_INLINE void memmove16(uint8_t* dst, uint8_t* src) {
|
170
|
-
#if defined(
|
170
|
+
#if defined(BROTLI_TARGET_NEON)
|
171
171
|
vst1q_u8(dst, vld1q_u8(src));
|
172
172
|
#else
|
173
173
|
uint32_t buffer[4];
|
@@ -347,15 +347,17 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
|
|
347
347
|
static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits,
|
348
348
|
const HuffmanCode* table,
|
349
349
|
BrotliBitReader* br) {
|
350
|
-
table
|
351
|
-
|
352
|
-
|
350
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
351
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(table, bits & HUFFMAN_TABLE_MASK);
|
352
|
+
if (BROTLI_HC_FAST_LOAD_BITS(table) > HUFFMAN_TABLE_BITS) {
|
353
|
+
uint32_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS;
|
353
354
|
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
|
354
|
-
table
|
355
|
-
|
355
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(table,
|
356
|
+
BROTLI_HC_FAST_LOAD_VALUE(table) +
|
357
|
+
((bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits)));
|
356
358
|
}
|
357
|
-
BrotliDropBits(br, table
|
358
|
-
return table
|
359
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
|
360
|
+
return BROTLI_HC_FAST_LOAD_VALUE(table);
|
359
361
|
}
|
360
362
|
|
361
363
|
/* Reads and decodes the next Huffman code from bit-stream.
|
@@ -371,19 +373,20 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol(
|
|
371
373
|
const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) {
|
372
374
|
uint32_t val;
|
373
375
|
uint32_t available_bits = BrotliGetAvailableBits(br);
|
376
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
374
377
|
if (available_bits == 0) {
|
375
|
-
if (table
|
376
|
-
*result = table
|
378
|
+
if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) {
|
379
|
+
*result = BROTLI_HC_FAST_LOAD_VALUE(table);
|
377
380
|
return BROTLI_TRUE;
|
378
381
|
}
|
379
382
|
return BROTLI_FALSE; /* No valid bits at all. */
|
380
383
|
}
|
381
384
|
val = (uint32_t)BrotliGetBitsUnmasked(br);
|
382
|
-
table
|
383
|
-
if (table
|
384
|
-
if (table
|
385
|
-
BrotliDropBits(br, table
|
386
|
-
*result = table
|
385
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK);
|
386
|
+
if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) {
|
387
|
+
if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) {
|
388
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
|
389
|
+
*result = BROTLI_HC_FAST_LOAD_VALUE(table);
|
387
390
|
return BROTLI_TRUE;
|
388
391
|
} else {
|
389
392
|
return BROTLI_FALSE; /* Not enough bits for the first level. */
|
@@ -394,15 +397,15 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol(
|
|
394
397
|
}
|
395
398
|
|
396
399
|
/* Speculatively drop HUFFMAN_TABLE_BITS. */
|
397
|
-
val = (val & BitMask(table
|
400
|
+
val = (val & BitMask(BROTLI_HC_FAST_LOAD_BITS(table))) >> HUFFMAN_TABLE_BITS;
|
398
401
|
available_bits -= HUFFMAN_TABLE_BITS;
|
399
|
-
table
|
400
|
-
if (available_bits < table
|
402
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + val);
|
403
|
+
if (available_bits < BROTLI_HC_FAST_LOAD_BITS(table)) {
|
401
404
|
return BROTLI_FALSE; /* Not enough bits for the second level. */
|
402
405
|
}
|
403
406
|
|
404
|
-
BrotliDropBits(br, HUFFMAN_TABLE_BITS + table
|
405
|
-
*result = table
|
407
|
+
BrotliDropBits(br, HUFFMAN_TABLE_BITS + BROTLI_HC_FAST_LOAD_BITS(table));
|
408
|
+
*result = BROTLI_HC_FAST_LOAD_VALUE(table);
|
406
409
|
return BROTLI_TRUE;
|
407
410
|
}
|
408
411
|
|
@@ -425,9 +428,10 @@ static BROTLI_INLINE void PreloadSymbol(int safe,
|
|
425
428
|
if (safe) {
|
426
429
|
return;
|
427
430
|
}
|
428
|
-
table
|
429
|
-
|
430
|
-
*
|
431
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
432
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(table, BrotliGetBits(br, HUFFMAN_TABLE_BITS));
|
433
|
+
*bits = BROTLI_HC_FAST_LOAD_BITS(table);
|
434
|
+
*value = BROTLI_HC_FAST_LOAD_VALUE(table);
|
431
435
|
}
|
432
436
|
|
433
437
|
/* Decodes the next Huffman code using data prepared by PreloadSymbol.
|
@@ -441,10 +445,11 @@ static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table,
|
|
441
445
|
uint32_t val = BrotliGet16BitsUnmasked(br);
|
442
446
|
const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
|
443
447
|
uint32_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS));
|
448
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext);
|
444
449
|
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
|
445
|
-
ext
|
446
|
-
BrotliDropBits(br, ext
|
447
|
-
result = ext
|
450
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask);
|
451
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(ext));
|
452
|
+
result = BROTLI_HC_FAST_LOAD_VALUE(ext);
|
448
453
|
} else {
|
449
454
|
BrotliDropBits(br, *bits);
|
450
455
|
}
|
@@ -597,6 +602,7 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
|
597
602
|
while (symbol < alphabet_size && space > 0) {
|
598
603
|
const HuffmanCode* p = s->table;
|
599
604
|
uint32_t code_len;
|
605
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
|
600
606
|
if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
|
601
607
|
s->symbol = symbol;
|
602
608
|
s->repeat = repeat;
|
@@ -606,10 +612,10 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
|
|
606
612
|
return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
607
613
|
}
|
608
614
|
BrotliFillBitWindow16(br);
|
609
|
-
p
|
610
|
-
BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
|
611
|
-
BrotliDropBits(br, p
|
612
|
-
code_len = p
|
615
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(p, BrotliGetBitsUnmasked(br) &
|
616
|
+
BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
|
617
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); /* Use 1..5 bits. */
|
618
|
+
code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
|
613
619
|
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
|
614
620
|
ProcessSingleCodeLength(code_len, &symbol, &repeat, &space,
|
615
621
|
&prev_code_len, symbol_lists, code_length_histo, next_symbol);
|
@@ -637,31 +643,34 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
|
|
637
643
|
uint32_t code_len;
|
638
644
|
uint32_t available_bits;
|
639
645
|
uint32_t bits = 0;
|
646
|
+
BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
|
640
647
|
if (get_byte && !BrotliPullByte(br)) return BROTLI_DECODER_NEEDS_MORE_INPUT;
|
641
648
|
get_byte = BROTLI_FALSE;
|
642
649
|
available_bits = BrotliGetAvailableBits(br);
|
643
650
|
if (available_bits != 0) {
|
644
651
|
bits = (uint32_t)BrotliGetBitsUnmasked(br);
|
645
652
|
}
|
646
|
-
p
|
647
|
-
|
653
|
+
BROTLI_HC_ADJUST_TABLE_INDEX(p,
|
654
|
+
bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
|
655
|
+
if (BROTLI_HC_FAST_LOAD_BITS(p) > available_bits) {
|
648
656
|
get_byte = BROTLI_TRUE;
|
649
657
|
continue;
|
650
658
|
}
|
651
|
-
code_len = p
|
659
|
+
code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
|
652
660
|
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
|
653
|
-
BrotliDropBits(br, p
|
661
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
|
654
662
|
ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
|
655
663
|
&s->prev_code_len, s->symbol_lists, s->code_length_histo,
|
656
664
|
s->next_symbol);
|
657
665
|
} else { /* code_len == 16..17, extra_bits == 2..3 */
|
658
666
|
uint32_t extra_bits = code_len - 14U;
|
659
|
-
uint32_t repeat_delta = (bits >> p
|
660
|
-
|
667
|
+
uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
|
668
|
+
BitMask(extra_bits);
|
669
|
+
if (available_bits < BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits) {
|
661
670
|
get_byte = BROTLI_TRUE;
|
662
671
|
continue;
|
663
672
|
}
|
664
|
-
BrotliDropBits(br, p
|
673
|
+
BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
|
665
674
|
ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
|
666
675
|
&s->symbol, &s->repeat, &s->space, &s->prev_code_len,
|
667
676
|
&s->repeat_code_len, s->symbol_lists, s->code_length_histo,
|
@@ -142,8 +142,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
|
142
142
|
|
143
143
|
/* Special case: all symbols but one have 0 code length. */
|
144
144
|
if (offset[0] == 0) {
|
145
|
-
code
|
146
|
-
code.value = (uint16_t)sorted[0];
|
145
|
+
code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
|
147
146
|
for (key = 0; key < (brotli_reg_t)table_size; ++key) {
|
148
147
|
table[key] = code;
|
149
148
|
}
|
@@ -157,9 +156,8 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
|
|
157
156
|
bits = 1;
|
158
157
|
step = 2;
|
159
158
|
do {
|
160
|
-
code.bits = (uint8_t)bits;
|
161
159
|
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
162
|
-
code
|
160
|
+
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]);
|
163
161
|
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
164
162
|
key += key_step;
|
165
163
|
}
|
@@ -211,11 +209,10 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
|
211
209
|
bits = 1;
|
212
210
|
step = 2;
|
213
211
|
do {
|
214
|
-
code.bits = (uint8_t)bits;
|
215
212
|
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
|
216
213
|
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
|
217
214
|
symbol = symbol_lists[symbol];
|
218
|
-
code
|
215
|
+
code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol);
|
219
216
|
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
|
220
217
|
key += key_step;
|
221
218
|
}
|
@@ -244,14 +241,13 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
|
|
244
241
|
total_size += table_size;
|
245
242
|
sub_key = BrotliReverseBits(key);
|
246
243
|
key += key_step;
|
247
|
-
root_table[sub_key]
|
248
|
-
|
249
|
-
(uint16_t)(((size_t)(table - root_table)) - sub_key);
|
244
|
+
root_table[sub_key] = ConstructHuffmanCode(
|
245
|
+
(uint8_t)(table_bits + root_bits),
|
246
|
+
(uint16_t)(((size_t)(table - root_table)) - sub_key));
|
250
247
|
sub_key = 0;
|
251
248
|
}
|
252
|
-
code.bits = (uint8_t)(len - root_bits);
|
253
249
|
symbol = symbol_lists[symbol];
|
254
|
-
code
|
250
|
+
code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol);
|
255
251
|
ReplicateValue(
|
256
252
|
&table[BrotliReverseBits(sub_key)], step, table_size, code);
|
257
253
|
sub_key += sub_key_step;
|
@@ -270,35 +266,28 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
|
270
266
|
const uint32_t goal_size = 1U << root_bits;
|
271
267
|
switch (num_symbols) {
|
272
268
|
case 0:
|
273
|
-
table[0]
|
274
|
-
table[0].value = val[0];
|
269
|
+
table[0] = ConstructHuffmanCode(0, val[0]);
|
275
270
|
break;
|
276
271
|
case 1:
|
277
|
-
table[0].bits = 1;
|
278
|
-
table[1].bits = 1;
|
279
272
|
if (val[1] > val[0]) {
|
280
|
-
table[0]
|
281
|
-
table[1]
|
273
|
+
table[0] = ConstructHuffmanCode(1, val[0]);
|
274
|
+
table[1] = ConstructHuffmanCode(1, val[1]);
|
282
275
|
} else {
|
283
|
-
table[0]
|
284
|
-
table[1]
|
276
|
+
table[0] = ConstructHuffmanCode(1, val[1]);
|
277
|
+
table[1] = ConstructHuffmanCode(1, val[0]);
|
285
278
|
}
|
286
279
|
table_size = 2;
|
287
280
|
break;
|
288
281
|
case 2:
|
289
|
-
table[0]
|
290
|
-
table[
|
291
|
-
table[2].bits = 1;
|
292
|
-
table[2].value = val[0];
|
282
|
+
table[0] = ConstructHuffmanCode(1, val[0]);
|
283
|
+
table[2] = ConstructHuffmanCode(1, val[0]);
|
293
284
|
if (val[2] > val[1]) {
|
294
|
-
table[1]
|
295
|
-
table[3]
|
285
|
+
table[1] = ConstructHuffmanCode(2, val[1]);
|
286
|
+
table[3] = ConstructHuffmanCode(2, val[2]);
|
296
287
|
} else {
|
297
|
-
table[1]
|
298
|
-
table[3]
|
288
|
+
table[1] = ConstructHuffmanCode(2, val[2]);
|
289
|
+
table[3] = ConstructHuffmanCode(2, val[1]);
|
299
290
|
}
|
300
|
-
table[1].bits = 2;
|
301
|
-
table[3].bits = 2;
|
302
291
|
table_size = 4;
|
303
292
|
break;
|
304
293
|
case 3: {
|
@@ -312,33 +301,27 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
|
|
312
301
|
}
|
313
302
|
}
|
314
303
|
}
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
table[
|
319
|
-
table[2].value = val[1];
|
320
|
-
table[1].value = val[2];
|
321
|
-
table[3].value = val[3];
|
304
|
+
table[0] = ConstructHuffmanCode(2, val[0]);
|
305
|
+
table[2] = ConstructHuffmanCode(2, val[1]);
|
306
|
+
table[1] = ConstructHuffmanCode(2, val[2]);
|
307
|
+
table[3] = ConstructHuffmanCode(2, val[3]);
|
322
308
|
table_size = 4;
|
323
309
|
break;
|
324
310
|
}
|
325
311
|
case 4: {
|
326
|
-
int i;
|
327
312
|
if (val[3] < val[2]) {
|
328
313
|
uint16_t t = val[3];
|
329
314
|
val[3] = val[2];
|
330
315
|
val[2] = t;
|
331
316
|
}
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
table[
|
337
|
-
table[
|
338
|
-
table[
|
339
|
-
table[7]
|
340
|
-
table[3].bits = 3;
|
341
|
-
table[7].bits = 3;
|
317
|
+
table[0] = ConstructHuffmanCode(1, val[0]);
|
318
|
+
table[1] = ConstructHuffmanCode(2, val[1]);
|
319
|
+
table[2] = ConstructHuffmanCode(1, val[0]);
|
320
|
+
table[3] = ConstructHuffmanCode(3, val[2]);
|
321
|
+
table[4] = ConstructHuffmanCode(1, val[0]);
|
322
|
+
table[5] = ConstructHuffmanCode(2, val[1]);
|
323
|
+
table[6] = ConstructHuffmanCode(1, val[0]);
|
324
|
+
table[7] = ConstructHuffmanCode(3, val[3]);
|
342
325
|
table_size = 8;
|
343
326
|
break;
|
344
327
|
}
|
@@ -33,11 +33,66 @@ static const uint16_t kMaxHuffmanTableSize[] = {
|
|
33
33
|
|
34
34
|
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
|
35
35
|
|
36
|
+
#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \
|
37
|
+
BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0))
|
38
|
+
#define BROTLI_HUFFMAN_CODE_FAST_LOAD
|
39
|
+
#endif
|
40
|
+
|
41
|
+
#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD)
|
42
|
+
/* Do not create this struct directly - use the ConstructHuffmanCode
|
43
|
+
* constructor below! */
|
36
44
|
typedef struct {
|
37
45
|
uint8_t bits; /* number of bits used for this symbol */
|
38
46
|
uint16_t value; /* symbol value or table offset */
|
39
47
|
} HuffmanCode;
|
40
48
|
|
49
|
+
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
50
|
+
const uint16_t value) {
|
51
|
+
HuffmanCode h;
|
52
|
+
h.bits = bits;
|
53
|
+
h.value = value;
|
54
|
+
return h;
|
55
|
+
}
|
56
|
+
|
57
|
+
/* Please use the following macros to optimize HuffmanCode accesses in hot
|
58
|
+
* paths.
|
59
|
+
*
|
60
|
+
* For example, assuming |table| contains a HuffmanCode pointer:
|
61
|
+
*
|
62
|
+
* BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
|
63
|
+
* BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table);
|
64
|
+
* *bits = BROTLI_HC_GET_BITS(table);
|
65
|
+
* *value = BROTLI_HC_GET_VALUE(table);
|
66
|
+
* BROTLI_HC_ADJUST_TABLE_INDEX(table, offset);
|
67
|
+
* *bits2 = BROTLI_HC_GET_BITS(table);
|
68
|
+
* *value2 = BROTLI_HC_GET_VALUE(table);
|
69
|
+
*
|
70
|
+
*/
|
71
|
+
|
72
|
+
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H)
|
73
|
+
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V)
|
74
|
+
|
75
|
+
/* These must be given a HuffmanCode pointer! */
|
76
|
+
#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits)
|
77
|
+
#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value)
|
78
|
+
|
79
|
+
#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
80
|
+
|
81
|
+
typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
|
82
|
+
|
83
|
+
static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
|
84
|
+
const uint16_t value) {
|
85
|
+
return ((value & 0xFFFF) << 16) | (bits & 0xFF);
|
86
|
+
}
|
87
|
+
|
88
|
+
#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
|
89
|
+
#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H)
|
90
|
+
|
91
|
+
/* These must be given a HuffmanCode pointer! */
|
92
|
+
#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF)
|
93
|
+
#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16)
|
94
|
+
#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
|
95
|
+
|
41
96
|
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
|
42
97
|
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
|
43
98
|
const uint8_t* const code_lengths, uint16_t* count);
|
@@ -330,7 +330,7 @@ static size_t ComputeMinimumCopyLength(const float start_cost,
|
|
330
330
|
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
|
331
331
|
static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
332
332
|
const size_t pos,
|
333
|
-
const size_t
|
333
|
+
const size_t max_backward_limit,
|
334
334
|
const size_t gap,
|
335
335
|
const ZopfliNode* nodes) {
|
336
336
|
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
|
@@ -338,13 +338,13 @@ static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
|
338
338
|
const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
|
339
339
|
/* Since |block_start + pos| is the end position of the command, the copy part
|
340
340
|
starts from |block_start + pos - clen|. Distances that are greater than
|
341
|
-
this or greater than |
|
342
|
-
do not update the last distances.
|
343
|
-
does not update the last distances. */
|
341
|
+
this or greater than |max_backward_limit| + |gap| are static dictionary
|
342
|
+
references, and do not update the last distances.
|
343
|
+
Also distance code 0 (last distance) does not update the last distances. */
|
344
344
|
if (pos == 0) {
|
345
345
|
return 0;
|
346
346
|
} else if (dist + clen <= block_start + pos + gap &&
|
347
|
-
dist <=
|
347
|
+
dist <= max_backward_limit + gap &&
|
348
348
|
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
|
349
349
|
return (uint32_t)pos;
|
350
350
|
} else {
|
@@ -454,9 +454,11 @@ static size_t UpdateNodes(
|
|
454
454
|
break;
|
455
455
|
}
|
456
456
|
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
|
457
|
+
/* Word dictionary -> ignore. */
|
457
458
|
continue;
|
458
459
|
}
|
459
460
|
if (backward <= max_distance) {
|
461
|
+
/* Regular backward reference. */
|
460
462
|
if (prev_ix >= cur_ix) {
|
461
463
|
continue;
|
462
464
|
}
|
@@ -564,14 +566,10 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
|
|
564
566
|
|
565
567
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
566
568
|
void BrotliZopfliCreateCommands(const size_t num_bytes,
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
size_t* last_insert_len,
|
572
|
-
const BrotliEncoderParams* params,
|
573
|
-
Command* commands,
|
574
|
-
size_t* num_literals) {
|
569
|
+
const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
|
570
|
+
size_t* last_insert_len, const BrotliEncoderParams* params,
|
571
|
+
Command* commands, size_t* num_literals) {
|
572
|
+
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
575
573
|
size_t pos = 0;
|
576
574
|
uint32_t offset = nodes[0].u.next;
|
577
575
|
size_t i;
|
@@ -610,18 +608,12 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
|
610
608
|
*last_insert_len += num_bytes - pos;
|
611
609
|
}
|
612
610
|
|
613
|
-
static size_t ZopfliIterate(size_t num_bytes,
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
const size_t gap,
|
620
|
-
const int* dist_cache,
|
621
|
-
const ZopfliCostModel* model,
|
622
|
-
const uint32_t* num_matches,
|
623
|
-
const BackwardMatch* matches,
|
624
|
-
ZopfliNode* nodes) {
|
611
|
+
static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
612
|
+
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
613
|
+
const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
|
614
|
+
const ZopfliCostModel* model, const uint32_t* num_matches,
|
615
|
+
const BackwardMatch* matches, ZopfliNode* nodes) {
|
616
|
+
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
625
617
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
626
618
|
StartPosQueue queue;
|
627
619
|
size_t cur_match_pos = 0;
|
@@ -645,8 +637,8 @@ static size_t ZopfliIterate(size_t num_bytes,
|
|
645
637
|
while (skip) {
|
646
638
|
i++;
|
647
639
|
if (i + 3 >= num_bytes) break;
|
648
|
-
EvaluateNode(position, i, max_backward_limit, gap,
|
649
|
-
&queue, nodes);
|
640
|
+
EvaluateNode(position, i, max_backward_limit, gap,
|
641
|
+
dist_cache, model, &queue, nodes);
|
650
642
|
cur_match_pos += num_matches[i];
|
651
643
|
skip--;
|
652
644
|
}
|
@@ -656,11 +648,11 @@ static size_t ZopfliIterate(size_t num_bytes,
|
|
656
648
|
}
|
657
649
|
|
658
650
|
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
659
|
-
size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
660
|
-
size_t
|
661
|
-
|
662
|
-
const
|
663
|
-
|
651
|
+
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
652
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
653
|
+
const BrotliEncoderParams* params,
|
654
|
+
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
|
655
|
+
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
664
656
|
const size_t max_zopfli_len = MaxZopfliLen(params);
|
665
657
|
ZopfliCostModel model;
|
666
658
|
StartPosQueue queue;
|
@@ -681,9 +673,11 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
|
681
673
|
const size_t pos = position + i;
|
682
674
|
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
|
683
675
|
size_t skip;
|
684
|
-
size_t num_matches
|
685
|
-
|
686
|
-
params,
|
676
|
+
size_t num_matches;
|
677
|
+
num_matches = FindAllMatchesH10(hasher,
|
678
|
+
¶ms->dictionary,
|
679
|
+
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
680
|
+
gap, params, &matches[lz_matches_offset]);
|
687
681
|
if (num_matches > 0 &&
|
688
682
|
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
689
683
|
matches[0] = matches[num_matches - 1];
|
@@ -704,8 +698,8 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
|
704
698
|
while (skip) {
|
705
699
|
i++;
|
706
700
|
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
707
|
-
EvaluateNode(position, i, max_backward_limit, gap,
|
708
|
-
&queue, nodes);
|
701
|
+
EvaluateNode(position, i, max_backward_limit, gap,
|
702
|
+
dist_cache, &model, &queue, nodes);
|
709
703
|
skip--;
|
710
704
|
}
|
711
705
|
}
|
@@ -714,28 +708,27 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
|
|
714
708
|
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
715
709
|
}
|
716
710
|
|
717
|
-
void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
|
718
|
-
size_t
|
719
|
-
|
711
|
+
void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
712
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
713
|
+
const BrotliEncoderParams* params,
|
720
714
|
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
721
715
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
722
|
-
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
723
716
|
ZopfliNode* nodes;
|
724
717
|
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
725
718
|
if (BROTLI_IS_OOM(m)) return;
|
726
719
|
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
727
|
-
*num_commands += BrotliZopfliComputeShortestPath(m,
|
728
|
-
|
729
|
-
|
720
|
+
*num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
|
721
|
+
position, ringbuffer, ringbuffer_mask, params,
|
722
|
+
dist_cache, hasher, nodes);
|
730
723
|
if (BROTLI_IS_OOM(m)) return;
|
731
|
-
BrotliZopfliCreateCommands(num_bytes, position,
|
732
|
-
|
724
|
+
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
725
|
+
last_insert_len, params, commands, num_literals);
|
733
726
|
BROTLI_FREE(m, nodes);
|
734
727
|
}
|
735
728
|
|
736
|
-
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
737
|
-
size_t
|
738
|
-
|
729
|
+
void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
730
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
731
|
+
const BrotliEncoderParams* params,
|
739
732
|
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
740
733
|
Command* commands, size_t* num_commands, size_t* num_literals) {
|
741
734
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
@@ -767,8 +760,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
|
767
760
|
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
768
761
|
if (BROTLI_IS_OOM(m)) return;
|
769
762
|
num_found_matches = FindAllMatchesH10(hasher,
|
770
|
-
¶ms->dictionary,
|
771
|
-
|
763
|
+
¶ms->dictionary,
|
764
|
+
ringbuffer, ringbuffer_mask, pos, max_length,
|
765
|
+
max_distance, gap, params,
|
766
|
+
&matches[cur_match_pos + shadow_matches]);
|
772
767
|
cur_match_end = cur_match_pos + num_found_matches;
|
773
768
|
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
774
769
|
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
@@ -814,10 +809,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
|
|
814
809
|
*last_insert_len = orig_last_insert_len;
|
815
810
|
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
816
811
|
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
817
|
-
ringbuffer_mask, params,
|
818
|
-
|
819
|
-
BrotliZopfliCreateCommands(num_bytes, position,
|
820
|
-
|
812
|
+
ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
|
813
|
+
nodes);
|
814
|
+
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
815
|
+
last_insert_len, params, commands, num_literals);
|
821
816
|
}
|
822
817
|
CleanupZopfliCostModel(m, &model);
|
823
818
|
BROTLI_FREE(m, nodes);
|
@@ -74,15 +74,14 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
|
|
74
74
|
(1) nodes[i].copy_length() >= 2
|
75
75
|
(2) nodes[i].command_length() <= i and
|
76
76
|
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
|
77
|
-
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
78
|
-
|
79
|
-
size_t
|
80
|
-
const
|
81
|
-
ZopfliNode* nodes);
|
77
|
+
BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
|
78
|
+
MemoryManager* m, size_t num_bytes,
|
79
|
+
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
80
|
+
const BrotliEncoderParams* params,
|
81
|
+
const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
|
82
82
|
|
83
83
|
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
|
84
|
-
const size_t num_bytes, const size_t block_start,
|
85
|
-
const size_t max_backward_limit, const ZopfliNode* nodes,
|
84
|
+
const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
|
86
85
|
int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
|
87
86
|
Command* commands, size_t* num_literals);
|
88
87
|
|
@@ -10,9 +10,9 @@
|
|
10
10
|
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
11
11
|
size_t num_bytes, size_t position,
|
12
12
|
const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
13
|
-
const BrotliEncoderParams* params,
|
14
|
-
|
15
|
-
size_t* num_literals) {
|
13
|
+
const BrotliEncoderParams* params,
|
14
|
+
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
|
15
|
+
Command* commands, size_t* num_commands, size_t* num_literals) {
|
16
16
|
/* Set maximum distance, see section 9.1. of the spec. */
|
17
17
|
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
18
18
|
|
@@ -42,9 +42,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
42
42
|
sr.distance = 0;
|
43
43
|
sr.score = kMinScore;
|
44
44
|
FN(FindLongestMatch)(hasher, ¶ms->dictionary,
|
45
|
-
|
46
|
-
|
47
|
-
params->dist.max_distance, &sr);
|
45
|
+
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
46
|
+
max_distance, gap, params->dist.max_distance, &sr);
|
48
47
|
if (sr.score > kMinScore) {
|
49
48
|
/* Found a match. Let's look for something even better ahead. */
|
50
49
|
int delayed_backward_references_in_row = 0;
|
@@ -58,7 +57,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
58
57
|
sr2.distance = 0;
|
59
58
|
sr2.score = kMinScore;
|
60
59
|
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
61
|
-
FN(FindLongestMatch)(hasher,
|
60
|
+
FN(FindLongestMatch)(hasher,
|
61
|
+
¶ms->dictionary,
|
62
62
|
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
63
63
|
max_distance, gap, params->dist.max_distance, &sr2);
|
64
64
|
if (sr2.score >= sr.score + cost_diff_lazy) {
|
@@ -80,8 +80,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
|
80
80
|
{
|
81
81
|
/* The first 16 codes are special short-codes,
|
82
82
|
and the minimum offset is 1. */
|
83
|
-
size_t distance_code =
|
84
|
-
|
83
|
+
size_t distance_code = ComputeDistanceCode(
|
84
|
+
sr.distance, max_distance + gap, dist_cache);
|
85
85
|
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
|
86
86
|
dist_cache[3] = dist_cache[2];
|
87
87
|
dist_cache[2] = dist_cache[1];
|
@@ -496,6 +496,8 @@ static void DecideOverLiteralContextModeling(const uint8_t* input,
|
|
496
496
|
static BROTLI_BOOL ShouldCompress(
|
497
497
|
const uint8_t* data, const size_t mask, const uint64_t last_flush_pos,
|
498
498
|
const size_t bytes, const size_t num_literals, const size_t num_commands) {
|
499
|
+
/* TODO: find more precise minimal block overhead. */
|
500
|
+
if (bytes <= 2) return BROTLI_FALSE;
|
499
501
|
if (num_commands < (bytes >> 8) + 2) {
|
500
502
|
if (num_literals > 0.99 * (double)bytes) {
|
501
503
|
uint32_t literal_histo[256] = { 0 };
|
@@ -674,12 +676,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
|
|
674
676
|
if (BROTLI_IS_OOM(&s->memory_manager_)) return BROTLI_FALSE;
|
675
677
|
if (s->is_initialized_) return BROTLI_TRUE;
|
676
678
|
|
679
|
+
s->last_bytes_bits_ = 0;
|
680
|
+
s->last_bytes_ = 0;
|
681
|
+
s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
|
682
|
+
|
677
683
|
SanitizeParams(&s->params);
|
678
684
|
s->params.lgblock = ComputeLgBlock(&s->params);
|
679
685
|
ChooseDistanceParams(&s->params);
|
680
686
|
|
681
|
-
s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
|
682
|
-
|
683
687
|
RingBufferSetup(&s->params, &s->ringbuffer_);
|
684
688
|
|
685
689
|
/* Initialize last byte with stream header. */
|
@@ -1029,23 +1033,20 @@ static BROTLI_BOOL EncodeData(
|
|
1029
1033
|
|
1030
1034
|
if (s->params.quality == ZOPFLIFICATION_QUALITY) {
|
1031
1035
|
BROTLI_DCHECK(s->params.hasher.type == 10);
|
1032
|
-
BrotliCreateZopfliBackwardReferences(m,
|
1033
|
-
bytes, wrapped_last_processed_pos,
|
1036
|
+
BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
|
1034
1037
|
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
1035
1038
|
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
1036
1039
|
&s->num_commands_, &s->num_literals_);
|
1037
1040
|
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
1038
1041
|
} else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
|
1039
1042
|
BROTLI_DCHECK(s->params.hasher.type == 10);
|
1040
|
-
BrotliCreateHqZopfliBackwardReferences(m,
|
1041
|
-
bytes, wrapped_last_processed_pos,
|
1043
|
+
BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
|
1042
1044
|
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
1043
1045
|
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
1044
1046
|
&s->num_commands_, &s->num_literals_);
|
1045
1047
|
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
1046
1048
|
} else {
|
1047
|
-
BrotliCreateBackwardReferences(
|
1048
|
-
bytes, wrapped_last_processed_pos,
|
1049
|
+
BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
|
1049
1050
|
data, mask, &s->params, s->hasher_, s->dist_cache_,
|
1050
1051
|
&s->last_insert_len_, &s->commands_[s->num_commands_],
|
1051
1052
|
&s->num_commands_, &s->num_literals_);
|
@@ -1166,7 +1167,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|
1166
1167
|
MemoryManager* m = &memory_manager;
|
1167
1168
|
|
1168
1169
|
const size_t mask = BROTLI_SIZE_MAX >> 1;
|
1169
|
-
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(lgwin);
|
1170
1170
|
int dist_cache[4] = { 4, 11, 15, 16 };
|
1171
1171
|
int saved_dist_cache[4] = { 4, 11, 15, 16 };
|
1172
1172
|
BROTLI_BOOL ok = BROTLI_TRUE;
|
@@ -1176,8 +1176,8 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|
1176
1176
|
uint8_t last_bytes_bits;
|
1177
1177
|
HasherHandle hasher = NULL;
|
1178
1178
|
|
1179
|
-
const size_t hasher_eff_size =
|
1180
|
-
|
1179
|
+
const size_t hasher_eff_size = BROTLI_MIN(size_t,
|
1180
|
+
input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
|
1181
1181
|
|
1182
1182
|
BrotliEncoderParams params;
|
1183
1183
|
|
@@ -1238,9 +1238,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|
1238
1238
|
BrotliInitZopfliNodes(nodes, block_size + 1);
|
1239
1239
|
StitchToPreviousBlockH10(hasher, block_size, block_start,
|
1240
1240
|
input_buffer, mask);
|
1241
|
-
path_size = BrotliZopfliComputeShortestPath(m,
|
1242
|
-
|
1243
|
-
|
1241
|
+
path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
|
1242
|
+
input_buffer, mask, ¶ms, dist_cache, hasher,
|
1243
|
+
nodes);
|
1244
1244
|
if (BROTLI_IS_OOM(m)) goto oom;
|
1245
1245
|
/* We allocate a command buffer in the first iteration of this loop that
|
1246
1246
|
will be likely big enough for the whole metablock, so that for most
|
@@ -1262,10 +1262,8 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
|
|
1262
1262
|
}
|
1263
1263
|
commands = new_commands;
|
1264
1264
|
}
|
1265
|
-
BrotliZopfliCreateCommands(block_size, block_start,
|
1266
|
-
|
1267
|
-
¶ms, &commands[num_commands],
|
1268
|
-
&num_literals);
|
1265
|
+
BrotliZopfliCreateCommands(block_size, block_start, &nodes[0], dist_cache,
|
1266
|
+
&last_insert_len, ¶ms, &commands[num_commands], &num_literals);
|
1269
1267
|
num_commands += path_size;
|
1270
1268
|
block_start += block_size;
|
1271
1269
|
metablock_size += block_size;
|
data/vendor/brotli/c/enc/hash.h
CHANGED
@@ -149,9 +149,9 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
|
|
149
149
|
}
|
150
150
|
|
151
151
|
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
|
152
|
-
const BrotliEncoderDictionary* dictionary, size_t item,
|
153
|
-
|
154
|
-
HasherSearchResult* out) {
|
152
|
+
const BrotliEncoderDictionary* dictionary, size_t item,
|
153
|
+
const uint8_t* data, size_t max_length, size_t max_backward,
|
154
|
+
size_t max_distance, HasherSearchResult* out) {
|
155
155
|
size_t len;
|
156
156
|
size_t word_idx;
|
157
157
|
size_t offset;
|
@@ -208,7 +208,8 @@ static BROTLI_INLINE void SearchInStaticDictionary(
|
|
208
208
|
self->dict_num_lookups++;
|
209
209
|
if (item != 0) {
|
210
210
|
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
|
211
|
-
dictionary, item, data,
|
211
|
+
dictionary, item, data,
|
212
|
+
max_length, max_backward, max_distance, out);
|
212
213
|
if (item_matches) {
|
213
214
|
self->dict_num_matches++;
|
214
215
|
}
|
@@ -121,13 +121,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
121
121
|
const BrotliEncoderDictionary* dictionary,
|
122
122
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
123
123
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
124
|
-
const size_t max_length, const size_t max_backward,
|
125
|
-
const size_t
|
124
|
+
const size_t max_length, const size_t max_backward,
|
125
|
+
const size_t gap, const size_t max_distance,
|
126
|
+
HasherSearchResult* BROTLI_RESTRICT out) {
|
126
127
|
HashComposite* self = FN(Self)(handle);
|
127
128
|
FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
|
128
|
-
distance_cache, cur_ix, max_length, max_backward, gap,
|
129
|
+
distance_cache, cur_ix, max_length, max_backward, gap,
|
130
|
+
max_distance, out);
|
129
131
|
FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
|
130
|
-
distance_cache, cur_ix, max_length, max_backward, gap,
|
132
|
+
distance_cache, cur_ix, max_length, max_backward, gap,
|
133
|
+
max_distance, out);
|
131
134
|
}
|
132
135
|
|
133
136
|
#undef HashComposite
|
@@ -161,8 +161,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
161
161
|
const BrotliEncoderDictionary* dictionary,
|
162
162
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
163
163
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
164
|
-
const size_t max_length, const size_t max_backward,
|
165
|
-
const size_t
|
164
|
+
const size_t max_length, const size_t max_backward,
|
165
|
+
const size_t gap, const size_t max_distance,
|
166
|
+
HasherSearchResult* BROTLI_RESTRICT out) {
|
166
167
|
HasherCommon* common = GetHasherCommon(handle);
|
167
168
|
HashLongestMatch* self = FN(Self)(handle);
|
168
169
|
uint16_t* num = FN(Num)(self);
|
@@ -154,8 +154,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
154
154
|
const BrotliEncoderDictionary* dictionary,
|
155
155
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
156
156
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
157
|
-
const size_t max_length, const size_t max_backward,
|
158
|
-
const size_t
|
157
|
+
const size_t max_length, const size_t max_backward,
|
158
|
+
const size_t gap, const size_t max_distance,
|
159
|
+
HasherSearchResult* BROTLI_RESTRICT out) {
|
159
160
|
HasherCommon* common = GetHasherCommon(handle);
|
160
161
|
HashLongestMatch* self = FN(Self)(handle);
|
161
162
|
uint16_t* num = FN(Num)(self);
|
@@ -155,8 +155,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
|
|
155
155
|
const BrotliEncoderDictionary* dictionary,
|
156
156
|
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
157
157
|
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
158
|
-
const size_t max_length, const size_t max_backward,
|
159
|
-
const size_t
|
158
|
+
const size_t max_length, const size_t max_backward,
|
159
|
+
const size_t gap, const size_t max_distance,
|
160
|
+
HasherSearchResult* BROTLI_RESTRICT out) {
|
160
161
|
HashRolling* self = FN(Self)(handle);
|
161
162
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
162
163
|
size_t pos = self->next_ix;
|
@@ -202,8 +202,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
|
|
202
202
|
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
|
203
203
|
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
|
204
204
|
const size_t ring_buffer_mask, const size_t cur_ix,
|
205
|
-
const size_t max_length, const size_t max_backward,
|
206
|
-
const BrotliEncoderParams* params,
|
205
|
+
const size_t max_length, const size_t max_backward,
|
206
|
+
const size_t gap, const BrotliEncoderParams* params,
|
207
|
+
BackwardMatch* matches) {
|
207
208
|
BackwardMatch* const orig_matches = matches;
|
208
209
|
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
209
210
|
size_t best_len = 1;
|
@@ -181,7 +181,8 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
|
181
181
|
ComputeDistanceCost(cmds, num_commands,
|
182
182
|
&orig_params.dist, &orig_params.dist, &dist_cost);
|
183
183
|
if (dist_cost < best_dist_cost) {
|
184
|
-
|
184
|
+
/* NB: currently unused; uncomment when more param tuning is added. */
|
185
|
+
/* best_dist_cost = dist_cost; */
|
185
186
|
params->dist = orig_params.dist;
|
186
187
|
}
|
187
188
|
}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: brotli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- miyucy
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -229,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
229
229
|
version: '0'
|
230
230
|
requirements: []
|
231
231
|
rubyforge_project:
|
232
|
-
rubygems_version: 2.7.
|
232
|
+
rubygems_version: 2.7.7
|
233
233
|
signing_key:
|
234
234
|
specification_version: 4
|
235
235
|
summary: Brotli compressor/decompressor
|