brotli: Sync with upstream commit ed1995b6b

ed1995b6bd
This commit is contained in:
Rémi Verschelde 2023-05-22 15:05:48 +02:00
parent 65fa775ff6
commit 7770e4447d
No known key found for this signature in database
GPG key ID: C3336907360768E1
17 changed files with 234 additions and 143 deletions

View file

@ -47,12 +47,13 @@ fix build with our own copy of zstd (patch in `patches`).
## brotli ## brotli
- Upstream: https://github.com/google/brotli - Upstream: https://github.com/google/brotli
- Version: git (f4153a09f87cbb9c826d8fc12c74642bb2d879ea, 2022) - Version: git (ed1995b6bda19244070ab5d331111f16f67c8054, 2023)
- License: MIT - License: MIT
Files extracted from upstream source: Files extracted from upstream source:
- `common/`, `dec/` and `include/` folders - `common/`, `dec/` and `include/` folders from `c/`,
minus the `dictionary.bin*` files
- `LICENSE` - `LICENSE`

View file

@ -12,10 +12,11 @@
#ifndef BROTLI_COMMON_CONSTANTS_H_ #ifndef BROTLI_COMMON_CONSTANTS_H_
#define BROTLI_COMMON_CONSTANTS_H_ #define BROTLI_COMMON_CONSTANTS_H_
#include "platform.h"
#include <brotli/port.h> #include <brotli/port.h>
#include <brotli/types.h> #include <brotli/types.h>
#include "platform.h"
/* Specification: 7.3. Encoding of the context map */ /* Specification: 7.3. Encoding of the context map */
#define BROTLI_CONTEXT_MAP_MAX_RLE 16 #define BROTLI_CONTEXT_MAP_MAX_RLE 16

View file

@ -5897,7 +5897,7 @@ static BrotliDictionary kBrotliDictionary = {
#endif #endif
}; };
const BrotliDictionary* BrotliGetDictionary() { const BrotliDictionary* BrotliGetDictionary(void) {
return &kBrotliDictionary; return &kBrotliDictionary;
} }

View file

@ -6,9 +6,10 @@
#include <stdlib.h> #include <stdlib.h>
#include "platform.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "platform.h"
/* Default brotli_alloc_func */ /* Default brotli_alloc_func */
void* BrotliDefaultAllocFunc(void* opaque, size_t size) { void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
BROTLI_UNUSED(opaque); BROTLI_UNUSED(opaque);

View file

@ -12,9 +12,9 @@
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations * BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations * BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
* BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
read and overlapping memcpy; this reduces decompression speed by 5%
* BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs * BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
* BROTLI_BUILD_NO_UNALIGNED_READ_FAST forces off the fast-unaligned-read
optimizations (mainly for testing purposes).
* BROTLI_DEBUG dumps file name and line number when decoder detects stream * BROTLI_DEBUG dumps file name and line number when decoder detects stream
or memory error or memory error
* BROTLI_ENABLE_LOG enables asserts and dumps various state information * BROTLI_ENABLE_LOG enables asserts and dumps various state information
@ -208,15 +208,19 @@ OR:
#define BROTLI_TARGET_RISCV64 #define BROTLI_TARGET_RISCV64
#endif #endif
#if defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
#define BROTLI_TARGET_64_BITS 1
#else
#define BROTLI_TARGET_64_BITS 0
#endif
#if defined(BROTLI_BUILD_64_BIT) #if defined(BROTLI_BUILD_64_BIT)
#define BROTLI_64_BITS 1 #define BROTLI_64_BITS 1
#elif defined(BROTLI_BUILD_32_BIT) #elif defined(BROTLI_BUILD_32_BIT)
#define BROTLI_64_BITS 0 #define BROTLI_64_BITS 0
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
#define BROTLI_64_BITS 1
#else #else
#define BROTLI_64_BITS 0 #define BROTLI_64_BITS BROTLI_TARGET_64_BITS
#endif #endif
#if (BROTLI_64_BITS) #if (BROTLI_64_BITS)
@ -260,18 +264,19 @@ OR:
#undef BROTLI_X_BIG_ENDIAN #undef BROTLI_X_BIG_ENDIAN
#endif #endif
#if defined(BROTLI_BUILD_PORTABLE) #if defined(BROTLI_BUILD_NO_UNALIGNED_READ_FAST)
#define BROTLI_ALIGNED_READ (!!1) #define BROTLI_UNALIGNED_READ_FAST (!!0)
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ #elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \ defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
defined(BROTLI_TARGET_RISCV64) defined(BROTLI_TARGET_RISCV64)
/* Allow unaligned read only for white-listed CPUs. */ /* These targets are known to generate efficient code for unaligned reads
#define BROTLI_ALIGNED_READ (!!0) * (e.g. a single instruction, not multiple 1-byte loads, shifted and or'd
* together). */
#define BROTLI_UNALIGNED_READ_FAST (!!1)
#else #else
#define BROTLI_ALIGNED_READ (!!1) #define BROTLI_UNALIGNED_READ_FAST (!!0)
#endif #endif
#if BROTLI_ALIGNED_READ
/* Portable unaligned memory access: read / write values via memcpy. */ /* Portable unaligned memory access: read / write values via memcpy. */
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
uint16_t t; uint16_t t;
@ -291,75 +296,6 @@ static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
memcpy(p, &v, sizeof v); memcpy(p, &v, sizeof v);
} }
#else /* BROTLI_ALIGNED_READ */
/* Unaligned memory access is allowed: just cast pointer to requested type. */
#if BROTLI_SANITIZED
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
will miss a bug if 08 is the first unaddressable byte.
ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
miss a race between this access and some other accesses to 08.
MemorySanitizer will correctly propagate the shadow on unaligned stores
and correctly report bugs on unaligned loads, but it may not properly
update and report the origin of the uninitialized memory.
For all three tools, replacing an unaligned access with a tool-specific
callback solves the problem. */
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
uint16_t __sanitizer_unaligned_load16(const void* p);
uint32_t __sanitizer_unaligned_load32(const void* p);
uint64_t __sanitizer_unaligned_load64(const void* p);
void __sanitizer_unaligned_store64(void* p, uint64_t v);
#if defined(__cplusplus)
} /* extern "C" */
#endif /* __cplusplus */
#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
#else /* BROTLI_SANITIZED */
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
return *(const uint16_t*)p;
}
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
return *(const uint32_t*)p;
}
#if (BROTLI_64_BITS)
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return *(const uint64_t*)p;
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
*(uint64_t*)p = v;
}
#else /* BROTLI_64_BITS */
/* Avoid emitting LDRD / STRD, which require properly aligned address. */
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
dwords[0] = (brotli_unaligned_uint64_t) v;
}
#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
uint64_t v;
memcpy(&v, p, sizeof(uint64_t));
return v;
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
memcpy(p, &v, sizeof(uint64_t));
}
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
#endif /* BROTLI_64_BITS */
#endif /* BROTLI_SANITIZED */
#endif /* BROTLI_ALIGNED_READ */
#if BROTLI_LITTLE_ENDIAN #if BROTLI_LITTLE_ENDIAN
/* Straight endianness. Just read / write values. */ /* Straight endianness. Just read / write values. */
@ -435,6 +371,16 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
} }
#endif /* BROTLI_LITTLE_ENDIAN */ #endif /* BROTLI_LITTLE_ENDIAN */
static BROTLI_INLINE void* BROTLI_UNALIGNED_LOAD_PTR(const void* p) {
void* v;
memcpy(&v, p, sizeof(void*));
return v;
}
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE_PTR(void* p, const void* v) {
memcpy(p, &v, sizeof(void*));
}
/* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */ /* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \ #if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
@ -467,6 +413,8 @@ static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
#define BROTLI_DUMP() (void)(0) #define BROTLI_DUMP() (void)(0)
#endif #endif
/* BrotliRBit assumes brotli_reg_t fits native CPU register type. */
#if (BROTLI_64_BITS == BROTLI_TARGET_64_BITS)
/* TODO(eustas): add appropriate icc/sunpro/arm/ibm/ti checks. */ /* TODO(eustas): add appropriate icc/sunpro/arm/ibm/ti checks. */
#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \ #if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \
!defined(BROTLI_BUILD_NO_RBIT) !defined(BROTLI_BUILD_NO_RBIT)
@ -480,15 +428,14 @@ static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
#define BROTLI_RBIT(x) BrotliRBit(x) #define BROTLI_RBIT(x) BrotliRBit(x)
#endif /* armv7 / armv8 */ #endif /* armv7 / armv8 */
#endif /* gcc || clang */ #endif /* gcc || clang */
#endif /* brotli_reg_t is native */
#if !defined(BROTLI_RBIT) #if !defined(BROTLI_RBIT)
static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ } static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ }
#endif /* BROTLI_RBIT */ #endif /* BROTLI_RBIT */
#define BROTLI_REPEAT(N, X) { \ #define BROTLI_REPEAT_4(X) {X; X; X; X;}
if ((N & 1) != 0) {X;} \ #define BROTLI_REPEAT_5(X) {X; X; X; X; X;}
if ((N & 2) != 0) {X; X;} \ #define BROTLI_REPEAT_6(X) {X; X; X; X; X; X;}
if ((N & 4) != 0) {X; X; X; X;} \
}
#define BROTLI_UNUSED(X) (void)(X) #define BROTLI_UNUSED(X) (void)(X)
@ -553,6 +500,8 @@ BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE); BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE); BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE); BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD_PTR);
BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE_PTR);
BROTLI_UNUSED(&BrotliRBit); BROTLI_UNUSED(&BrotliRBit);
BROTLI_UNUSED(&brotli_min_double); BROTLI_UNUSED(&brotli_min_double);
BROTLI_UNUSED(&brotli_max_double); BROTLI_UNUSED(&brotli_max_double);

View file

@ -9,11 +9,12 @@
#ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ #ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
#define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ #define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
#include "dictionary.h"
#include <brotli/shared_dictionary.h> #include <brotli/shared_dictionary.h>
#include "transform.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "dictionary.h"
#include "transform.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif

View file

@ -8,9 +8,10 @@
#include "bit_reader.h" #include "bit_reader.h"
#include "../common/platform.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "../common/platform.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif
@ -36,7 +37,7 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
/* Fixing alignment after unaligned BrotliFillWindow would result accumulator /* Fixing alignment after unaligned BrotliFillWindow would result accumulator
overflow. If unalignment is caused by BrotliSafeReadBits, then there is overflow. If unalignment is caused by BrotliSafeReadBits, then there is
enough space in accumulator to fix alignment. */ enough space in accumulator to fix alignment. */
if (!BROTLI_ALIGNED_READ) { if (BROTLI_UNALIGNED_READ_FAST) {
aligned_read_mask = 0; aligned_read_mask = 0;
} }
if (BrotliGetAvailableBits(br) == 0) { if (BrotliGetAvailableBits(br) == 0) {

View file

@ -11,9 +11,10 @@
#include <string.h> /* memcpy */ #include <string.h> /* memcpy */
#include <brotli/types.h>
#include "../common/constants.h" #include "../common/constants.h"
#include "../common/platform.h" #include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
@ -53,8 +54,8 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
/* Ensures that accumulator is not empty. /* Ensures that accumulator is not empty.
May consume up to sizeof(brotli_reg_t) - 1 bytes of input. May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
Returns BROTLI_FALSE if data is required but there is no input available. Returns BROTLI_FALSE if data is required but there is no input available.
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for
reading. */ aligned reading. */
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br); BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden /* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
@ -107,7 +108,8 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
static BROTLI_INLINE void BrotliFillBitWindow( static BROTLI_INLINE void BrotliFillBitWindow(
BrotliBitReader* const br, uint32_t n_bits) { BrotliBitReader* const br, uint32_t n_bits) {
#if (BROTLI_64_BITS) #if (BROTLI_64_BITS)
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) { if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
(n_bits <= 8)) {
uint32_t bit_pos = br->bit_pos_; uint32_t bit_pos = br->bit_pos_;
if (bit_pos >= 56) { if (bit_pos >= 56) {
br->val_ = br->val_ =
@ -117,8 +119,8 @@ static BROTLI_INLINE void BrotliFillBitWindow(
br->avail_in -= 7; br->avail_in -= 7;
br->next_in += 7; br->next_in += 7;
} }
} else if ( } else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) { (n_bits <= 16)) {
uint32_t bit_pos = br->bit_pos_; uint32_t bit_pos = br->bit_pos_;
if (bit_pos >= 48) { if (bit_pos >= 48) {
br->val_ = br->val_ =
@ -140,7 +142,8 @@ static BROTLI_INLINE void BrotliFillBitWindow(
} }
} }
#else #else
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) { if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
(n_bits <= 8)) {
uint32_t bit_pos = br->bit_pos_; uint32_t bit_pos = br->bit_pos_;
if (bit_pos >= 24) { if (bit_pos >= 24) {
br->val_ = br->val_ =
@ -338,6 +341,11 @@ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
return TO_BROTLI_BOOL(pad_bits == 0); return TO_BROTLI_BOOL(pad_bits == 0);
} }
static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) {
br->avail_in -= num;
br->next_in += num;
}
/* Copies remaining input bytes stored in the bit reader to the output. Value /* Copies remaining input bytes stored in the bit reader to the output. Value
|num| may not be larger than BrotliGetRemainingBytes. The bit reader must be |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
warmed up again after this. */ warmed up again after this. */
@ -349,9 +357,10 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
++dest; ++dest;
--num; --num;
} }
if (num > 0) {
memcpy(dest, br->next_in, num); memcpy(dest, br->next_in, num);
br->avail_in -= num; BrotliDropBytes(br, num);
br->next_in += num; }
} }
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)

View file

@ -113,8 +113,9 @@ void BrotliDecoderDestroyInstance(BrotliDecoderState* state) {
/* Saves error code and converts it to BrotliDecoderResult. */ /* Saves error code and converts it to BrotliDecoderResult. */
static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode(
BrotliDecoderState* s, BrotliDecoderErrorCode e) { BrotliDecoderState* s, BrotliDecoderErrorCode e, size_t consumed_input) {
s->error_code = (int)e; s->error_code = (int)e;
s->used_input += consumed_input;
switch (e) { switch (e) {
case BROTLI_DECODER_SUCCESS: case BROTLI_DECODER_SUCCESS:
return BROTLI_DECODER_RESULT_SUCCESS; return BROTLI_DECODER_RESULT_SUCCESS;
@ -1172,7 +1173,7 @@ static BROTLI_INLINE void DetectTrivialLiteralBlockTypes(
size_t sample = s->context_map[offset]; size_t sample = s->context_map[offset];
size_t j; size_t j;
for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS);) { for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS);) {
BROTLI_REPEAT(4, error |= s->context_map[offset + j++] ^ sample;) BROTLI_REPEAT_4({ error |= s->context_map[offset + j++] ^ sample; })
} }
if (error == 0) { if (error == 0) {
s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31); s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31);
@ -1353,6 +1354,57 @@ static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer(
return BROTLI_TRUE; return BROTLI_TRUE;
} }
static BrotliDecoderErrorCode BROTLI_NOINLINE
SkipMetadataBlock(BrotliDecoderState* s) {
BrotliBitReader* br = &s->br;
if (s->meta_block_remaining_len == 0) {
return BROTLI_DECODER_SUCCESS;
}
BROTLI_DCHECK((BrotliGetAvailableBits(br) & 7) == 0);
/* Drain accumulator. */
if (BrotliGetAvailableBits(br) >= 8) {
uint8_t buffer[8];
int nbytes = (int)(BrotliGetAvailableBits(br)) >> 3;
BROTLI_DCHECK(nbytes <= 8);
if (nbytes > s->meta_block_remaining_len) {
nbytes = s->meta_block_remaining_len;
}
BrotliCopyBytes(buffer, br, (size_t)nbytes);
if (s->metadata_chunk_func) {
s->metadata_chunk_func(s->metadata_callback_opaque, buffer,
(size_t)nbytes);
}
s->meta_block_remaining_len -= nbytes;
if (s->meta_block_remaining_len == 0) {
return BROTLI_DECODER_SUCCESS;
}
}
/* Direct access to metadata is possible. */
int nbytes = (int)BrotliGetRemainingBytes(br);
if (nbytes > s->meta_block_remaining_len) {
nbytes = s->meta_block_remaining_len;
}
if (nbytes > 0) {
if (s->metadata_chunk_func) {
s->metadata_chunk_func(s->metadata_callback_opaque, br->next_in,
(size_t)nbytes);
}
BrotliDropBytes(br, (size_t)nbytes);
s->meta_block_remaining_len -= nbytes;
if (s->meta_block_remaining_len == 0) {
return BROTLI_DECODER_SUCCESS;
}
}
BROTLI_DCHECK(BrotliGetRemainingBytes(br) == 0);
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput( static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput(
size_t* available_out, uint8_t** next_out, size_t* total_out, size_t* available_out, uint8_t** next_out, size_t* total_out,
BrotliDecoderState* s) { BrotliDecoderState* s) {
@ -2243,6 +2295,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
size_t* available_out, uint8_t** next_out, size_t* total_out) { size_t* available_out, uint8_t** next_out, size_t* total_out) {
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS;
BrotliBitReader* br = &s->br; BrotliBitReader* br = &s->br;
size_t input_size = *available_in;
#define BROTLI_SAVE_ERROR_CODE(code) \
SaveErrorCode(s, (code), input_size - *available_in)
/* Ensure that |total_out| is set, even if no data will ever be pushed out. */ /* Ensure that |total_out| is set, even if no data will ever be pushed out. */
if (total_out) { if (total_out) {
*total_out = s->partial_pos_out; *total_out = s->partial_pos_out;
@ -2252,8 +2307,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
return BROTLI_DECODER_RESULT_ERROR; return BROTLI_DECODER_RESULT_ERROR;
} }
if (*available_out && (!next_out || !*next_out)) { if (*available_out && (!next_out || !*next_out)) {
return SaveErrorCode( return BROTLI_SAVE_ERROR_CODE(
s, BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS)); BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS));
} }
if (!*available_out) next_out = 0; if (!*available_out) next_out = 0;
if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */ if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */
@ -2410,6 +2465,10 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
} }
if (s->is_metadata) { if (s->is_metadata) {
s->state = BROTLI_STATE_METADATA; s->state = BROTLI_STATE_METADATA;
if (s->metadata_start_func) {
s->metadata_start_func(s->metadata_callback_opaque,
(size_t)s->meta_block_remaining_len);
}
break; break;
} }
if (s->meta_block_remaining_len == 0) { if (s->meta_block_remaining_len == 0) {
@ -2502,17 +2561,11 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
} }
case BROTLI_STATE_METADATA: case BROTLI_STATE_METADATA:
for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { result = SkipMetadataBlock(s);
uint32_t bits; if (result != BROTLI_DECODER_SUCCESS) {
/* Read one byte and ignore it. */
if (!BrotliSafeReadBits(br, 8, &bits)) {
result = BROTLI_DECODER_NEEDS_MORE_INPUT;
break; break;
} }
}
if (result == BROTLI_DECODER_SUCCESS) {
s->state = BROTLI_STATE_METABLOCK_DONE; s->state = BROTLI_STATE_METABLOCK_DONE;
}
break; break;
case BROTLI_STATE_METABLOCK_HEADER_2: { case BROTLI_STATE_METABLOCK_HEADER_2: {
@ -2586,7 +2639,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
s, &s->distance_hgroup, distance_alphabet_size_max, s, &s->distance_hgroup, distance_alphabet_size_max,
distance_alphabet_size_limit, s->num_dist_htrees); distance_alphabet_size_limit, s->num_dist_htrees);
if (!allocation_success) { if (!allocation_success) {
return SaveErrorCode(s, return BROTLI_SAVE_ERROR_CODE(
BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS)); BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS));
} }
s->loop_counter = 0; s->loop_counter = 0;
@ -2600,7 +2653,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
case 0: hgroup = &s->literal_hgroup; break; case 0: hgroup = &s->literal_hgroup; break;
case 1: hgroup = &s->insert_copy_hgroup; break; case 1: hgroup = &s->insert_copy_hgroup; break;
case 2: hgroup = &s->distance_hgroup; break; case 2: hgroup = &s->distance_hgroup; break;
default: return SaveErrorCode(s, BROTLI_FAILURE( default: return BROTLI_SAVE_ERROR_CODE(BROTLI_FAILURE(
BROTLI_DECODER_ERROR_UNREACHABLE)); /* COV_NF_LINE */ BROTLI_DECODER_ERROR_UNREACHABLE)); /* COV_NF_LINE */
} }
result = HuffmanTreeGroupDecode(hgroup, s); result = HuffmanTreeGroupDecode(hgroup, s);
@ -2710,10 +2763,11 @@ BrotliDecoderResult BrotliDecoderDecompressStream(
break; break;
} }
} }
return SaveErrorCode(s, result); return BROTLI_SAVE_ERROR_CODE(result);
} }
} }
return SaveErrorCode(s, result); return BROTLI_SAVE_ERROR_CODE(result);
#undef BROTLI_SAVE_ERROR_CODE
} }
BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s) { BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s) {
@ -2743,7 +2797,7 @@ const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) {
} else { } else {
/* ... or stream is broken. Normally this should be caught by /* ... or stream is broken. Normally this should be caught by
BrotliDecoderDecompressStream, this is just a safeguard. */ BrotliDecoderDecompressStream, this is just a safeguard. */
if ((int)status < 0) SaveErrorCode(s, status); if ((int)status < 0) SaveErrorCode(s, status, 0);
*size = 0; *size = 0;
result = 0; result = 0;
} }
@ -2776,10 +2830,19 @@ const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c) {
} }
} }
uint32_t BrotliDecoderVersion() { uint32_t BrotliDecoderVersion(void) {
return BROTLI_VERSION; return BROTLI_VERSION;
} }
void BrotliDecoderSetMetadataCallbacks(
BrotliDecoderState* state,
brotli_decoder_metadata_start_func start_func,
brotli_decoder_metadata_chunk_func chunk_func, void* opaque) {
state->metadata_start_func = start_func;
state->metadata_chunk_func = chunk_func;
state->metadata_callback_opaque = opaque;
}
/* Escalate internal functions visibility; for testing purposes only. */ /* Escalate internal functions visibility; for testing purposes only. */
#if defined(BROTLI_TEST) #if defined(BROTLI_TEST)
BROTLI_BOOL SafeReadSymbolForTest( BROTLI_BOOL SafeReadSymbolForTest(

View file

@ -10,9 +10,10 @@
#include <string.h> /* memcpy, memset */ #include <string.h> /* memcpy, memset */
#include <brotli/types.h>
#include "../common/constants.h" #include "../common/constants.h"
#include "../common/platform.h" #include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
@ -117,11 +118,13 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
int bits_count; int bits_count;
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <= BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <=
BROTLI_REVERSE_BITS_MAX); BROTLI_REVERSE_BITS_MAX);
BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5);
/* Generate offsets into sorted symbol table by code length. */ /* Generate offsets into sorted symbol table by code length. */
symbol = -1; symbol = -1;
bits = 1; bits = 1;
BROTLI_REPEAT(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH, { /* BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5 */
BROTLI_REPEAT_5({
symbol += count[bits]; symbol += count[bits];
offset[bits] = symbol; offset[bits] = symbol;
bits++; bits++;
@ -132,7 +135,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
/* Sort symbols by length, by symbol order within each length. */ /* Sort symbols by length, by symbol order within each length. */
symbol = BROTLI_CODE_LENGTH_CODES; symbol = BROTLI_CODE_LENGTH_CODES;
do { do {
BROTLI_REPEAT(6, { BROTLI_REPEAT_6({
symbol--; symbol--;
sorted[offset[code_lengths[symbol]]--] = symbol; sorted[offset[code_lengths[symbol]]--] = symbol;
}); });

View file

@ -9,9 +9,10 @@
#ifndef BROTLI_DEC_HUFFMAN_H_ #ifndef BROTLI_DEC_HUFFMAN_H_
#define BROTLI_DEC_HUFFMAN_H_ #define BROTLI_DEC_HUFFMAN_H_
#include "../common/platform.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "../common/platform.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
extern "C" { extern "C" {
#endif #endif

View file

@ -10,9 +10,10 @@
#ifndef BROTLI_DEC_PREFIX_H_ #ifndef BROTLI_DEC_PREFIX_H_
#define BROTLI_DEC_PREFIX_H_ #define BROTLI_DEC_PREFIX_H_
#include "../common/constants.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "../common/constants.h"
typedef struct CmdLutElement { typedef struct CmdLutElement {
uint8_t insert_len_extra_bits; uint8_t insert_len_extra_bits;
uint8_t copy_len_extra_bits; uint8_t copy_len_extra_bits;

View file

@ -8,8 +8,9 @@
#include <stdlib.h> /* free, malloc */ #include <stdlib.h> /* free, malloc */
#include "../common/dictionary.h"
#include <brotli/types.h> #include <brotli/types.h>
#include "../common/dictionary.h"
#include "huffman.h" #include "huffman.h"
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
@ -43,6 +44,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
s->pos = 0; s->pos = 0;
s->rb_roundtrips = 0; s->rb_roundtrips = 0;
s->partial_pos_out = 0; s->partial_pos_out = 0;
s->used_input = 0;
s->block_type_trees = NULL; s->block_type_trees = NULL;
s->block_len_trees = NULL; s->block_len_trees = NULL;
@ -87,6 +89,10 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque); BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque);
if (!s->dictionary) return BROTLI_FALSE; if (!s->dictionary) return BROTLI_FALSE;
s->metadata_start_func = NULL;
s->metadata_chunk_func = NULL;
s->metadata_callback_opaque = 0;
return BROTLI_TRUE; return BROTLI_TRUE;
} }
@ -129,9 +135,21 @@ void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees); BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees);
} }
#ifdef BROTLI_REPORTING
/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */
void BrotliDecoderOnFinish(const BrotliDecoderState* s);
#define BROTLI_DECODER_ON_FINISH(s) BrotliDecoderOnFinish(s);
#else
#if !defined(BROTLI_DECODER_ON_FINISH)
#define BROTLI_DECODER_ON_FINISH(s) (void)(s);
#endif
#endif
void BrotliDecoderStateCleanup(BrotliDecoderState* s) { void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
BrotliDecoderStateCleanupAfterMetablock(s); BrotliDecoderStateCleanupAfterMetablock(s);
BROTLI_DECODER_ON_FINISH(s);
BROTLI_DECODER_FREE(s, s->compound_dictionary); BROTLI_DECODER_FREE(s, s->compound_dictionary);
BrotliSharedDictionaryDestroyInstance(s->dictionary); BrotliSharedDictionaryDestroyInstance(s->dictionary);
s->dictionary = NULL; s->dictionary = NULL;

View file

@ -9,12 +9,14 @@
#ifndef BROTLI_DEC_STATE_H_ #ifndef BROTLI_DEC_STATE_H_
#define BROTLI_DEC_STATE_H_ #define BROTLI_DEC_STATE_H_
#include <brotli/decode.h>
#include <brotli/shared_dictionary.h>
#include <brotli/types.h>
#include "../common/constants.h" #include "../common/constants.h"
#include "../common/dictionary.h" #include "../common/dictionary.h"
#include "../common/platform.h" #include "../common/platform.h"
#include <brotli/shared_dictionary.h>
#include "../common/transform.h" #include "../common/transform.h"
#include <brotli/types.h>
#include "bit_reader.h" #include "bit_reader.h"
#include "huffman.h" #include "huffman.h"
@ -321,6 +323,13 @@ struct BrotliDecoderStateStruct {
/* Less used attributes are at the end of this struct. */ /* Less used attributes are at the end of this struct. */
brotli_decoder_metadata_start_func metadata_start_func;
brotli_decoder_metadata_chunk_func metadata_chunk_func;
void* metadata_callback_opaque;
/* For reporting. */
uint64_t used_input; /* how many bytes of input are consumed */
/* States inside function calls. */ /* States inside function calls. */
BrotliRunningMetablockHeaderState substate_metablock_header; BrotliRunningMetablockHeaderState substate_metablock_header;
BrotliRunningUncompressedState substate_uncompressed; BrotliRunningUncompressedState substate_uncompressed;

View file

@ -361,6 +361,47 @@ BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
*/ */
BROTLI_DEC_API uint32_t BrotliDecoderVersion(void); BROTLI_DEC_API uint32_t BrotliDecoderVersion(void);
/**
* Callback to fire on metadata block start.
*
* After this callback is fired, if @p size is not @c 0, it is followed by
* ::brotli_decoder_metadata_chunk_func as more metadata block contents become
* accessible.
*
* @param opaque callback handle
* @param size size of metadata block
*/
typedef void (*brotli_decoder_metadata_start_func)(void* opaque, size_t size);
/**
* Callback to fire on metadata block chunk becomes available.
*
* This function can be invoked multiple times per metadata block; block should
* be considered finished when sum of @p size matches the announced metadata
* block size. Chunks contents pointed by @p data are transient and shouln not
* be accessed after leaving the callback.
*
* @param opaque callback handle
* @param data pointer to metadata contents
* @param size size of metadata block chunk, at least @c 1
*/
typedef void (*brotli_decoder_metadata_chunk_func)(void* opaque,
const uint8_t* data,
size_t size);
/**
* Sets callback for receiving metadata blocks.
*
* @param state decoder instance
* @param start_func callback on metadata block start
* @param chunk_func callback on metadata block chunk
* @param opaque callback handle
*/
BROTLI_DEC_API void BrotliDecoderSetMetadataCallbacks(
BrotliDecoderState* state,
brotli_decoder_metadata_start_func start_func,
brotli_decoder_metadata_chunk_func chunk_func, void* opaque);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */ } /* extern "C" */
#endif #endif

View file

@ -453,7 +453,7 @@ BROTLI_ENC_API BROTLI_BOOL BrotliEncoderHasMoreOutput(
* *
* This method is used to make language bindings easier and more efficient: * This method is used to make language bindings easier and more efficient:
* -# push data to ::BrotliEncoderCompressStream, * -# push data to ::BrotliEncoderCompressStream,
* until ::BrotliEncoderHasMoreOutput returns BROTL_TRUE * until ::BrotliEncoderHasMoreOutput returns BROTLI_TRUE
* -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific * -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific
* entity * entity
* *

View file

@ -224,14 +224,6 @@
#define BROTLI_HAS_FEATURE(feature) (0) #define BROTLI_HAS_FEATURE(feature) (0)
#endif #endif
#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \
defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) || \
defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer)
#define BROTLI_SANITIZED 1
#else
#define BROTLI_SANITIZED 0
#endif
#if defined(_WIN32) || defined(__CYGWIN__) #if defined(_WIN32) || defined(__CYGWIN__)
#define BROTLI_PUBLIC #define BROTLI_PUBLIC
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \ #elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \