diff --git a/thirdparty/README.md b/thirdparty/README.md index 4d3b260d4da..6dc675794e0 100644 --- a/thirdparty/README.md +++ b/thirdparty/README.md @@ -47,12 +47,13 @@ fix build with our own copy of zstd (patch in `patches`). ## brotli - Upstream: https://github.com/google/brotli -- Version: git (f4153a09f87cbb9c826d8fc12c74642bb2d879ea, 2022) +- Version: git (ed1995b6bda19244070ab5d331111f16f67c8054, 2023) - License: MIT Files extracted from upstream source: -- `common/`, `dec/` and `include/` folders +- `common/`, `dec/` and `include/` folders from `c/`, + minus the `dictionary.bin*` files - `LICENSE` diff --git a/thirdparty/brotli/common/constants.h b/thirdparty/brotli/common/constants.h index 433c7b24d0b..31e5bd376e9 100644 --- a/thirdparty/brotli/common/constants.h +++ b/thirdparty/brotli/common/constants.h @@ -12,10 +12,11 @@ #ifndef BROTLI_COMMON_CONSTANTS_H_ #define BROTLI_COMMON_CONSTANTS_H_ -#include "platform.h" #include #include +#include "platform.h" + /* Specification: 7.3. Encoding of the context map */ #define BROTLI_CONTEXT_MAP_MAX_RLE 16 diff --git a/thirdparty/brotli/common/dictionary.c b/thirdparty/brotli/common/dictionary.c index 307525788cc..7c015ab0ba7 100644 --- a/thirdparty/brotli/common/dictionary.c +++ b/thirdparty/brotli/common/dictionary.c @@ -5897,7 +5897,7 @@ static BrotliDictionary kBrotliDictionary = { #endif }; -const BrotliDictionary* BrotliGetDictionary() { +const BrotliDictionary* BrotliGetDictionary(void) { return &kBrotliDictionary; } diff --git a/thirdparty/brotli/common/platform.c b/thirdparty/brotli/common/platform.c index acdc452f292..25d84a94672 100644 --- a/thirdparty/brotli/common/platform.c +++ b/thirdparty/brotli/common/platform.c @@ -6,9 +6,10 @@ #include -#include "platform.h" #include +#include "platform.h" + /* Default brotli_alloc_func */ void* BrotliDefaultAllocFunc(void* opaque, size_t size) { BROTLI_UNUSED(opaque); diff --git a/thirdparty/brotli/common/platform.h b/thirdparty/brotli/common/platform.h index 0e0e8aa49e0..4186a8e96d0 100644 --- a/thirdparty/brotli/common/platform.h +++ b/thirdparty/brotli/common/platform.h @@ -12,9 +12,9 @@ * BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations * BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware 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_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 or memory error * BROTLI_ENABLE_LOG enables asserts and dumps various state information @@ -208,15 +208,19 @@ OR: #define BROTLI_TARGET_RISCV64 #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) #define BROTLI_64_BITS 1 #elif defined(BROTLI_BUILD_32_BIT) #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 -#define BROTLI_64_BITS 0 +#define BROTLI_64_BITS BROTLI_TARGET_64_BITS #endif #if (BROTLI_64_BITS) @@ -260,18 +264,19 @@ OR: #undef BROTLI_X_BIG_ENDIAN #endif -#if defined(BROTLI_BUILD_PORTABLE) -#define BROTLI_ALIGNED_READ (!!1) -#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ +#if defined(BROTLI_BUILD_NO_UNALIGNED_READ_FAST) +#define BROTLI_UNALIGNED_READ_FAST (!!0) +#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \ defined(BROTLI_TARGET_RISCV64) -/* Allow unaligned read only for white-listed CPUs. */ -#define BROTLI_ALIGNED_READ (!!0) +/* These targets are known to generate efficient code for unaligned reads + * (e.g. a single instruction, not multiple 1-byte loads, shifted and or'd + * together). */ +#define BROTLI_UNALIGNED_READ_FAST (!!1) #else -#define BROTLI_ALIGNED_READ (!!1) +#define BROTLI_UNALIGNED_READ_FAST (!!0) #endif -#if BROTLI_ALIGNED_READ /* Portable unaligned memory access: read / write values via memcpy. */ static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { 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) { 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 /* 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 */ +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. */ #if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \ 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) #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. */ #if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \ !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) #endif /* armv7 / armv8 */ #endif /* gcc || clang */ +#endif /* brotli_reg_t is native */ #if !defined(BROTLI_RBIT) static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ } #endif /* BROTLI_RBIT */ -#define BROTLI_REPEAT(N, X) { \ - if ((N & 1) != 0) {X;} \ - if ((N & 2) != 0) {X; X;} \ - if ((N & 4) != 0) {X; X; X; X;} \ -} +#define BROTLI_REPEAT_4(X) {X; X; X; X;} +#define BROTLI_REPEAT_5(X) {X; X; X; X; X;} +#define BROTLI_REPEAT_6(X) {X; X; X; X; X; 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_LOAD64LE); BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE); + BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD_PTR); + BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE_PTR); BROTLI_UNUSED(&BrotliRBit); BROTLI_UNUSED(&brotli_min_double); BROTLI_UNUSED(&brotli_max_double); diff --git a/thirdparty/brotli/common/shared_dictionary_internal.h b/thirdparty/brotli/common/shared_dictionary_internal.h index 87ab13b24b8..963762e4325 100644 --- a/thirdparty/brotli/common/shared_dictionary_internal.h +++ b/thirdparty/brotli/common/shared_dictionary_internal.h @@ -9,11 +9,12 @@ #ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ #define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ -#include "dictionary.h" #include -#include "transform.h" #include +#include "dictionary.h" +#include "transform.h" + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif diff --git a/thirdparty/brotli/dec/bit_reader.c b/thirdparty/brotli/dec/bit_reader.c index 3dc848b7dcc..97e21f56f6b 100644 --- a/thirdparty/brotli/dec/bit_reader.c +++ b/thirdparty/brotli/dec/bit_reader.c @@ -8,9 +8,10 @@ #include "bit_reader.h" -#include "../common/platform.h" #include +#include "../common/platform.h" + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif @@ -36,7 +37,7 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { /* Fixing alignment after unaligned BrotliFillWindow would result accumulator overflow. If unalignment is caused by BrotliSafeReadBits, then there is enough space in accumulator to fix alignment. */ - if (!BROTLI_ALIGNED_READ) { + if (BROTLI_UNALIGNED_READ_FAST) { aligned_read_mask = 0; } if (BrotliGetAvailableBits(br) == 0) { diff --git a/thirdparty/brotli/dec/bit_reader.h b/thirdparty/brotli/dec/bit_reader.h index 39064551039..64701ecacc3 100644 --- a/thirdparty/brotli/dec/bit_reader.h +++ b/thirdparty/brotli/dec/bit_reader.h @@ -11,9 +11,10 @@ #include /* memcpy */ +#include + #include "../common/constants.h" #include "../common/platform.h" -#include #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -53,8 +54,8 @@ BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br); /* Ensures that accumulator is not empty. 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. - For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned - reading. */ + For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for + aligned reading. */ BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br); /* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden @@ -107,7 +108,8 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount( static BROTLI_INLINE void BrotliFillBitWindow( BrotliBitReader* const br, uint32_t n_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_; if (bit_pos >= 56) { br->val_ = @@ -117,8 +119,8 @@ static BROTLI_INLINE void BrotliFillBitWindow( br->avail_in -= 7; br->next_in += 7; } - } else if ( - !BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) { + } else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && + (n_bits <= 16)) { uint32_t bit_pos = br->bit_pos_; if (bit_pos >= 48) { br->val_ = @@ -140,7 +142,8 @@ static BROTLI_INLINE void BrotliFillBitWindow( } } #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_; if (bit_pos >= 24) { br->val_ = @@ -338,6 +341,11 @@ static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) { 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 |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be warmed up again after this. */ @@ -349,9 +357,10 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest, ++dest; --num; } - memcpy(dest, br->next_in, num); - br->avail_in -= num; - br->next_in += num; + if (num > 0) { + memcpy(dest, br->next_in, num); + BrotliDropBytes(br, num); + } } #if defined(__cplusplus) || defined(c_plusplus) diff --git a/thirdparty/brotli/dec/decode.c b/thirdparty/brotli/dec/decode.c index 2fe58a7b2f8..3ee1963a850 100644 --- a/thirdparty/brotli/dec/decode.c +++ b/thirdparty/brotli/dec/decode.c @@ -113,8 +113,9 @@ void BrotliDecoderDestroyInstance(BrotliDecoderState* state) { /* Saves error code and converts it to BrotliDecoderResult. */ static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( - BrotliDecoderState* s, BrotliDecoderErrorCode e) { + BrotliDecoderState* s, BrotliDecoderErrorCode e, size_t consumed_input) { s->error_code = (int)e; + s->used_input += consumed_input; switch (e) { case BROTLI_DECODER_SUCCESS: return BROTLI_DECODER_RESULT_SUCCESS; @@ -1172,7 +1173,7 @@ static BROTLI_INLINE void DetectTrivialLiteralBlockTypes( size_t sample = s->context_map[offset]; size_t j; 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) { s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31); @@ -1353,6 +1354,57 @@ static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer( 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( size_t* available_out, uint8_t** next_out, size_t* total_out, BrotliDecoderState* s) { @@ -2243,6 +2295,9 @@ BrotliDecoderResult BrotliDecoderDecompressStream( size_t* available_out, uint8_t** next_out, size_t* total_out) { BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; 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. */ if (total_out) { *total_out = s->partial_pos_out; @@ -2252,8 +2307,8 @@ BrotliDecoderResult BrotliDecoderDecompressStream( return BROTLI_DECODER_RESULT_ERROR; } if (*available_out && (!next_out || !*next_out)) { - return SaveErrorCode( - s, BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS)); + return BROTLI_SAVE_ERROR_CODE( + BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS)); } if (!*available_out) next_out = 0; if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */ @@ -2410,6 +2465,10 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } if (s->is_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; } if (s->meta_block_remaining_len == 0) { @@ -2502,17 +2561,11 @@ BrotliDecoderResult BrotliDecoderDecompressStream( } case BROTLI_STATE_METADATA: - for (; s->meta_block_remaining_len > 0; --s->meta_block_remaining_len) { - uint32_t bits; - /* Read one byte and ignore it. */ - if (!BrotliSafeReadBits(br, 8, &bits)) { - result = BROTLI_DECODER_NEEDS_MORE_INPUT; - break; - } - } - if (result == BROTLI_DECODER_SUCCESS) { - s->state = BROTLI_STATE_METABLOCK_DONE; + result = SkipMetadataBlock(s); + if (result != BROTLI_DECODER_SUCCESS) { + break; } + s->state = BROTLI_STATE_METABLOCK_DONE; break; case BROTLI_STATE_METABLOCK_HEADER_2: { @@ -2586,7 +2639,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( s, &s->distance_hgroup, distance_alphabet_size_max, distance_alphabet_size_limit, s->num_dist_htrees); if (!allocation_success) { - return SaveErrorCode(s, + return BROTLI_SAVE_ERROR_CODE( BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS)); } s->loop_counter = 0; @@ -2600,7 +2653,7 @@ BrotliDecoderResult BrotliDecoderDecompressStream( case 0: hgroup = &s->literal_hgroup; break; case 1: hgroup = &s->insert_copy_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 */ } result = HuffmanTreeGroupDecode(hgroup, s); @@ -2710,10 +2763,11 @@ BrotliDecoderResult BrotliDecoderDecompressStream( 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) { @@ -2743,7 +2797,7 @@ const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) { } else { /* ... or stream is broken. Normally this should be caught by BrotliDecoderDecompressStream, this is just a safeguard. */ - if ((int)status < 0) SaveErrorCode(s, status); + if ((int)status < 0) SaveErrorCode(s, status, 0); *size = 0; result = 0; } @@ -2776,10 +2830,19 @@ const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c) { } } -uint32_t BrotliDecoderVersion() { +uint32_t BrotliDecoderVersion(void) { 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. */ #if defined(BROTLI_TEST) BROTLI_BOOL SafeReadSymbolForTest( diff --git a/thirdparty/brotli/dec/huffman.c b/thirdparty/brotli/dec/huffman.c index 8f127d7b6f7..38064548640 100644 --- a/thirdparty/brotli/dec/huffman.c +++ b/thirdparty/brotli/dec/huffman.c @@ -10,9 +10,10 @@ #include /* memcpy, memset */ +#include + #include "../common/constants.h" #include "../common/platform.h" -#include #if defined(__cplusplus) || defined(c_plusplus) extern "C" { @@ -117,11 +118,13 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table, int bits_count; BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <= BROTLI_REVERSE_BITS_MAX); + BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5); /* Generate offsets into sorted symbol table by code length. */ symbol = -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]; offset[bits] = symbol; bits++; @@ -132,7 +135,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table, /* Sort symbols by length, by symbol order within each length. */ symbol = BROTLI_CODE_LENGTH_CODES; do { - BROTLI_REPEAT(6, { + BROTLI_REPEAT_6({ symbol--; sorted[offset[code_lengths[symbol]]--] = symbol; }); diff --git a/thirdparty/brotli/dec/huffman.h b/thirdparty/brotli/dec/huffman.h index a8fbc453479..50360962c73 100644 --- a/thirdparty/brotli/dec/huffman.h +++ b/thirdparty/brotli/dec/huffman.h @@ -9,9 +9,10 @@ #ifndef BROTLI_DEC_HUFFMAN_H_ #define BROTLI_DEC_HUFFMAN_H_ -#include "../common/platform.h" #include +#include "../common/platform.h" + #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif diff --git a/thirdparty/brotli/dec/prefix.h b/thirdparty/brotli/dec/prefix.h index 481a2c79170..e8acf077400 100644 --- a/thirdparty/brotli/dec/prefix.h +++ b/thirdparty/brotli/dec/prefix.h @@ -10,9 +10,10 @@ #ifndef BROTLI_DEC_PREFIX_H_ #define BROTLI_DEC_PREFIX_H_ -#include "../common/constants.h" #include +#include "../common/constants.h" + typedef struct CmdLutElement { uint8_t insert_len_extra_bits; uint8_t copy_len_extra_bits; diff --git a/thirdparty/brotli/dec/state.c b/thirdparty/brotli/dec/state.c index e3170c13869..a3baf37b6d0 100644 --- a/thirdparty/brotli/dec/state.c +++ b/thirdparty/brotli/dec/state.c @@ -8,8 +8,9 @@ #include /* free, malloc */ -#include "../common/dictionary.h" #include + +#include "../common/dictionary.h" #include "huffman.h" #if defined(__cplusplus) || defined(c_plusplus) @@ -43,6 +44,7 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, s->pos = 0; s->rb_roundtrips = 0; s->partial_pos_out = 0; + s->used_input = 0; s->block_type_trees = NULL; s->block_len_trees = NULL; @@ -87,6 +89,10 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque); if (!s->dictionary) return BROTLI_FALSE; + s->metadata_start_func = NULL; + s->metadata_chunk_func = NULL; + s->metadata_callback_opaque = 0; + return BROTLI_TRUE; } @@ -129,9 +135,21 @@ void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) { 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) { BrotliDecoderStateCleanupAfterMetablock(s); + BROTLI_DECODER_ON_FINISH(s); + BROTLI_DECODER_FREE(s, s->compound_dictionary); BrotliSharedDictionaryDestroyInstance(s->dictionary); s->dictionary = NULL; diff --git a/thirdparty/brotli/dec/state.h b/thirdparty/brotli/dec/state.h index 81e6bb6779c..84fddc8a72c 100644 --- a/thirdparty/brotli/dec/state.h +++ b/thirdparty/brotli/dec/state.h @@ -9,12 +9,14 @@ #ifndef BROTLI_DEC_STATE_H_ #define BROTLI_DEC_STATE_H_ +#include +#include +#include + #include "../common/constants.h" #include "../common/dictionary.h" #include "../common/platform.h" -#include #include "../common/transform.h" -#include #include "bit_reader.h" #include "huffman.h" @@ -321,6 +323,13 @@ struct BrotliDecoderStateStruct { /* 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. */ BrotliRunningMetablockHeaderState substate_metablock_header; BrotliRunningUncompressedState substate_uncompressed; diff --git a/thirdparty/brotli/include/brotli/decode.h b/thirdparty/brotli/include/brotli/decode.h index 9b580d22a08..3c473d611ea 100644 --- a/thirdparty/brotli/include/brotli/decode.h +++ b/thirdparty/brotli/include/brotli/decode.h @@ -361,6 +361,47 @@ BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c); */ 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) } /* extern "C" */ #endif diff --git a/thirdparty/brotli/include/brotli/encode.h b/thirdparty/brotli/include/brotli/encode.h index b2c6f61e0fd..7247d3d6983 100644 --- a/thirdparty/brotli/include/brotli/encode.h +++ b/thirdparty/brotli/include/brotli/encode.h @@ -453,7 +453,7 @@ BROTLI_ENC_API BROTLI_BOOL BrotliEncoderHasMoreOutput( * * This method is used to make language bindings easier and more efficient: * -# push data to ::BrotliEncoderCompressStream, - * until ::BrotliEncoderHasMoreOutput returns BROTL_TRUE + * until ::BrotliEncoderHasMoreOutput returns BROTLI_TRUE * -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific * entity * diff --git a/thirdparty/brotli/include/brotli/port.h b/thirdparty/brotli/include/brotli/port.h index a681ac48649..0d50019042d 100644 --- a/thirdparty/brotli/include/brotli/port.h +++ b/thirdparty/brotli/include/brotli/port.h @@ -224,14 +224,6 @@ #define BROTLI_HAS_FEATURE(feature) (0) #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__) #define BROTLI_PUBLIC #elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \