No issue - Update our in-tree brotli library to 1.2.0+
This includes a minor patch to encode.c to work around the "static init" check that actually doesn't do anything in its default state, but, due to compiler subtleties in handling duplicate object names, would not be able to link brotli.exe because it would refuse to expose all symbols for duplicate objects (a later one would just be ignored). Unsure how clang does this but it's not portable across compilers. (we need the brotli.exe tool for resource package compression)
This commit is contained in:
111 files changed
+21667
-16361
No files matched your search
@@ -691,6 +691,10 @@ BrotliDecoderCreateInstance
|
||||
BrotliDecoderDecompress
|
||||
BrotliDecoderDecompressStream
|
||||
BrotliDecoderDestroyInstance
|
||||
BrotliDecoderEnsureStaticInit
|
||||
BrotliDecoderIsFinished
|
||||
BrotliDecoderStateCleanup
|
||||
BrotliDecoderStateInit
|
||||
BrotliSharedDictionaryAttach
|
||||
BrotliSharedDictionaryCreateInstance
|
||||
BrotliSharedDictionaryDestroyInstance
|
||||
@@ -11,4 +11,4 @@ The in-tree copy is updated by running
|
||||
sh update.sh
|
||||
from within the modules/brotli directory.
|
||||
|
||||
Current version: 1.0.9 Re-release [commit e61745a6b7add50d380cfd7d3883dd6c62fc2c71].
|
||||
Current version: [commit 4792c8e4c4235f6b501f13dbd07a8b4b253eee21].
|
||||
@@ -4,12 +4,12 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./constants.h"
|
||||
#include "constants.h"
|
||||
|
||||
const BrotliPrefixCodeRange
|
||||
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
|
||||
{33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
|
||||
{113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
|
||||
{369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}};
|
||||
const BROTLI_MODEL("small")
|
||||
BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = {
|
||||
{1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3},
|
||||
{33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4},
|
||||
{113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6},
|
||||
{369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12},
|
||||
{8433, 13}, {16625, 24}};
|
||||
@@ -12,9 +12,7 @@
|
||||
#ifndef BROTLI_COMMON_CONSTANTS_H_
|
||||
#define BROTLI_COMMON_CONSTANTS_H_
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
/* Specification: 7.3. Encoding of the context map */
|
||||
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
|
||||
@@ -194,7 +192,7 @@ typedef struct {
|
||||
} BrotliPrefixCodeRange;
|
||||
|
||||
/* "Soft-private", it is exported, but not "advertised" as API. */
|
||||
BROTLI_COMMON_API extern const BrotliPrefixCodeRange
|
||||
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
|
||||
BROTLI_COMMON_API extern const BROTLI_MODEL("small")
|
||||
BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
|
||||
|
||||
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
|
||||
@@ -1,9 +1,9 @@
|
||||
#include "./context.h"
|
||||
#include "context.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
/* Common context lookup table for all context modes. */
|
||||
const uint8_t _kBrotliContextLookupTable[2048] = {
|
||||
const BROTLI_MODEL("small") uint8_t _kBrotliContextLookupTable[2048] = {
|
||||
/* CONTEXT_LSB6, last byte. */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
|
||||
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
|
||||
|
||||
@@ -88,8 +88,7 @@
|
||||
#ifndef BROTLI_COMMON_CONTEXT_H_
|
||||
#define BROTLI_COMMON_CONTEXT_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
typedef enum ContextType {
|
||||
CONTEXT_LSB6 = 0,
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -9,8 +9,7 @@
|
||||
#ifndef BROTLI_COMMON_DICTIONARY_H_
|
||||
#define BROTLI_COMMON_DICTIONARY_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -4,10 +4,7 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "./platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
/* Default brotli_alloc_func */
|
||||
void* BrotliDefaultAllocFunc(void* opaque, size_t size) {
|
||||
|
||||
+253
-152
@@ -12,35 +12,27 @@
|
||||
* 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
|
||||
* BROTLI_ENABLE_DUMP overrides default "dump" behaviour
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_COMMON_PLATFORM_H_
|
||||
#define BROTLI_COMMON_PLATFORM_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
#include <limits.h>
|
||||
#include <string.h> /* IWYU pragma: export memcmp, memcpy, memset */
|
||||
#include <stdlib.h> /* IWYU pragma: export exit, free, malloc */
|
||||
#include <sys/types.h> /* should include endian.h for us */
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include <brotli/port.h> /* IWYU pragma: export */
|
||||
#include <brotli/types.h> /* IWYU pragma: export */
|
||||
|
||||
#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
|
||||
#include <endian.h>
|
||||
#elif defined(OS_FREEBSD)
|
||||
#include <machine/endian.h>
|
||||
#elif defined(OS_MACOSX)
|
||||
#include <machine/endian.h>
|
||||
/* Let's try and follow the Linux convention */
|
||||
#define BROTLI_X_BYTE_ORDER BYTE_ORDER
|
||||
#define BROTLI_X_LITTLE_ENDIAN LITTLE_ENDIAN
|
||||
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
|
||||
#endif
|
||||
|
||||
#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#if BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
@@ -156,24 +148,6 @@ OR:
|
||||
#define BROTLI_NOINLINE
|
||||
#endif
|
||||
|
||||
/* BROTLI_INTERNAL could be defined to override visibility, e.g. for tests. */
|
||||
#if !defined(BROTLI_INTERNAL)
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#define BROTLI_INTERNAL
|
||||
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
|
||||
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
|
||||
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
|
||||
BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
|
||||
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
|
||||
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
|
||||
defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
|
||||
#define BROTLI_INTERNAL __attribute__ ((visibility ("hidden")))
|
||||
#else
|
||||
#define BROTLI_INTERNAL
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* <<< <<< <<< end of hedley macros. */
|
||||
|
||||
#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \
|
||||
@@ -226,15 +200,38 @@ OR:
|
||||
#define BROTLI_TARGET_RISCV64
|
||||
#endif
|
||||
|
||||
#if defined(__loongarch_lp64)
|
||||
#define BROTLI_TARGET_LOONGARCH64
|
||||
#endif
|
||||
|
||||
/* This does not seem to be an indicator of z/Architecture (64-bit); neither
|
||||
that allows to use unaligned loads. */
|
||||
#if defined(__s390x__)
|
||||
#define BROTLI_TARGET_S390X
|
||||
#endif
|
||||
|
||||
#if defined(__mips64)
|
||||
#define BROTLI_TARGET_MIPS64
|
||||
#endif
|
||||
|
||||
#if defined(__ia64__) || defined(_M_IA64)
|
||||
#define BROTLI_TARGET_IA64
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
|
||||
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) || \
|
||||
defined(BROTLI_TARGET_LOONGARCH64) || defined(BROTLI_TARGET_MIPS64)
|
||||
#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)
|
||||
@@ -256,13 +253,12 @@ OR:
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#elif defined(BROTLI_X_BYTE_ORDER)
|
||||
#if BROTLI_X_BYTE_ORDER == BROTLI_X_LITTLE_ENDIAN
|
||||
/* Likely target platform is iOS / OSX. */
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 1
|
||||
#elif BROTLI_X_BYTE_ORDER == BROTLI_X_BIG_ENDIAN
|
||||
#elif defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN)
|
||||
#define BROTLI_BIG_ENDIAN 1
|
||||
#endif
|
||||
#endif /* BROTLI_X_BYTE_ORDER */
|
||||
|
||||
#if !defined(BROTLI_LITTLE_ENDIAN)
|
||||
#define BROTLI_LITTLE_ENDIAN 0
|
||||
@@ -272,25 +268,60 @@ OR:
|
||||
#define BROTLI_BIG_ENDIAN 0
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_X_BYTE_ORDER)
|
||||
#undef BROTLI_X_BYTE_ORDER
|
||||
#undef BROTLI_X_LITTLE_ENDIAN
|
||||
#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)
|
||||
defined(BROTLI_TARGET_RISCV64) || defined(BROTLI_TARGET_LOONGARCH64)
|
||||
/* 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. */
|
||||
#if !defined(BROTLI_USE_PACKED_FOR_UNALIGNED)
|
||||
#if defined(__mips__) && (!defined(__mips_isa_rev) || __mips_isa_rev < 6)
|
||||
#define BROTLI_USE_PACKED_FOR_UNALIGNED 1
|
||||
#else
|
||||
#define BROTLI_USE_PACKED_FOR_UNALIGNED 0
|
||||
#endif
|
||||
#endif /* defined(BROTLI_USE_PACKED_FOR_UNALIGNED) */
|
||||
|
||||
#if BROTLI_USE_PACKED_FOR_UNALIGNED
|
||||
|
||||
typedef union BrotliPackedValue {
|
||||
uint16_t u16;
|
||||
uint32_t u32;
|
||||
uint64_t u64;
|
||||
size_t szt;
|
||||
} __attribute__ ((packed)) BrotliPackedValue;
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u16;
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u32;
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->u64;
|
||||
}
|
||||
static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) {
|
||||
const BrotliPackedValue* address = (const BrotliPackedValue*)p;
|
||||
return address->szt;
|
||||
}
|
||||
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
BrotliPackedValue* address = (BrotliPackedValue*)p;
|
||||
address->u64 = v;
|
||||
}
|
||||
|
||||
#else /* not BROTLI_USE_PACKED_FOR_UNALIGNED */
|
||||
|
||||
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
|
||||
uint16_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
@@ -306,78 +337,42 @@ static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) {
|
||||
size_t t;
|
||||
memcpy(&t, p, sizeof t);
|
||||
return t;
|
||||
}
|
||||
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;
|
||||
#endif /* BROTLI_USE_PACKED_FOR_UNALIGNED */
|
||||
|
||||
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;
|
||||
}
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap16, 4, 3, 0)
|
||||
#define BROTLI_BSWAP16(V) ((uint16_t)__builtin_bswap16(V))
|
||||
#else
|
||||
#define BROTLI_BSWAP16(V) ((uint16_t)( \
|
||||
(((V) & 0xFFU) << 8) | \
|
||||
(((V) >> 8) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
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_GNUC_HAS_BUILTIN(__builtin_bswap32, 4, 3, 0)
|
||||
#define BROTLI_BSWAP32(V) ((uint32_t)__builtin_bswap32(V))
|
||||
#else
|
||||
#define BROTLI_BSWAP32(V) ((uint32_t)( \
|
||||
(((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
|
||||
(((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap64, 4, 3, 0)
|
||||
#define BROTLI_BSWAP64(V) ((uint64_t)__builtin_bswap64(V))
|
||||
#else
|
||||
#define BROTLI_BSWAP64(V) ((uint64_t)( \
|
||||
(((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
|
||||
(((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
|
||||
(((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
|
||||
(((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU)))
|
||||
#endif
|
||||
|
||||
#if BROTLI_LITTLE_ENDIAN
|
||||
/* Straight endianness. Just read / write values. */
|
||||
@@ -386,32 +381,20 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
|
||||
#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64
|
||||
#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64
|
||||
#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */
|
||||
/* Explain compiler to byte-swap values. */
|
||||
#define BROTLI_BSWAP16_(V) ((uint16_t)( \
|
||||
(((V) & 0xFFU) << 8) | \
|
||||
(((V) >> 8) & 0xFFU)))
|
||||
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
|
||||
uint16_t value = BrotliUnalignedRead16(p);
|
||||
return BROTLI_BSWAP16_(value);
|
||||
return BROTLI_BSWAP16(value);
|
||||
}
|
||||
#define BROTLI_BSWAP32_(V) ( \
|
||||
(((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
|
||||
(((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU))
|
||||
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
|
||||
uint32_t value = BrotliUnalignedRead32(p);
|
||||
return BROTLI_BSWAP32_(value);
|
||||
return BROTLI_BSWAP32(value);
|
||||
}
|
||||
#define BROTLI_BSWAP64_(V) ( \
|
||||
(((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
|
||||
(((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
|
||||
(((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
|
||||
(((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU))
|
||||
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
|
||||
uint64_t value = BrotliUnalignedRead64(p);
|
||||
return BROTLI_BSWAP64_(value);
|
||||
return BROTLI_BSWAP64(value);
|
||||
}
|
||||
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
uint64_t value = BROTLI_BSWAP64_(v);
|
||||
uint64_t value = BROTLI_BSWAP64(v);
|
||||
BrotliUnalignedWrite64(p, value);
|
||||
}
|
||||
#else /* BROTLI_LITTLE_ENDIAN */
|
||||
@@ -453,6 +436,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)
|
||||
@@ -474,22 +467,34 @@ static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
#define BROTLI_ENABLE_DUMP_DEFAULT 1
|
||||
#define BROTLI_DCHECK(x) assert(x)
|
||||
#else
|
||||
#define BROTLI_ENABLE_DUMP_DEFAULT 0
|
||||
#define BROTLI_DCHECK(x)
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_ENABLE_DUMP)
|
||||
#define BROTLI_ENABLE_DUMP BROTLI_ENABLE_DUMP_DEFAULT
|
||||
#endif
|
||||
|
||||
#if BROTLI_ENABLE_DUMP
|
||||
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
|
||||
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
|
||||
fflush(stderr);
|
||||
}
|
||||
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
|
||||
#else
|
||||
#define BROTLI_DCHECK(x)
|
||||
#define BROTLI_DUMP() (void)(0)
|
||||
#endif
|
||||
|
||||
/* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */
|
||||
/* 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)
|
||||
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
|
||||
/* TODO: detect ARMv6T2 and enable this code for it. */
|
||||
/* TODO(eustas): detect ARMv6T2 and enable this code for it. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
|
||||
brotli_reg_t output;
|
||||
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
|
||||
@@ -498,15 +503,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)
|
||||
|
||||
@@ -519,6 +523,14 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
||||
#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
|
||||
#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
|
||||
|
||||
static BROTLI_INLINE int brotli_safe_add_int(int a, int b, int* result) {
|
||||
if (b > 0 && a > INT_MAX - b) return 0;
|
||||
if (b < 0 && a < INT_MIN - b) return 0;
|
||||
*result = a + b;
|
||||
return 1;
|
||||
}
|
||||
#define BROTLI_SAFE_ADD(T, A, B, R) (brotli_safe_add_ ## T((A), (B), (R)))
|
||||
|
||||
#define BROTLI_SWAP(T, A, I, J) { \
|
||||
T __brotli_swap_tmp = (A)[(I)]; \
|
||||
(A)[(I)] = (A)[(J)]; \
|
||||
@@ -529,8 +541,8 @@ BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_TZCNT64 __builtin_ctzll
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#if defined(BROTLI_TARGET_X64)
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
#if defined(BROTLI_TARGET_X64) && !defined(_M_ARM64EC)
|
||||
#define BROTLI_TZCNT64 _tzcnt_u64
|
||||
#else /* BROTLI_TARGET_X64 */
|
||||
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
|
||||
@@ -546,7 +558,7 @@ static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
|
||||
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
|
||||
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
|
||||
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
|
||||
#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0)
|
||||
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
|
||||
unsigned long msb;
|
||||
_BitScanReverse(&msb, x);
|
||||
@@ -561,16 +573,36 @@ BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
|
||||
/* Default brotli_free_func */
|
||||
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
|
||||
|
||||
/* Circular logical rotates. */
|
||||
static BROTLI_INLINE uint16_t BrotliRotateRight16(uint16_t const value,
|
||||
size_t count) {
|
||||
count &= 0x0F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint16_t)(value << ((0U - count) & 0x0F));
|
||||
}
|
||||
static BROTLI_INLINE uint32_t BrotliRotateRight32(uint32_t const value,
|
||||
size_t count) {
|
||||
count &= 0x1F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint32_t)(value << ((0U - count) & 0x1F));
|
||||
}
|
||||
static BROTLI_INLINE uint64_t BrotliRotateRight64(uint64_t const value,
|
||||
size_t count) {
|
||||
count &= 0x3F; /* for fickle pattern recognition */
|
||||
return (value >> count) | (uint64_t)(value << ((0U - count) & 0x3F));
|
||||
}
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead16);
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead32);
|
||||
BROTLI_UNUSED(&BrotliUnalignedRead64);
|
||||
BROTLI_UNUSED(&BrotliUnalignedReadSizeT);
|
||||
BROTLI_UNUSED(&BrotliUnalignedWrite64);
|
||||
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD16LE);
|
||||
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);
|
||||
@@ -584,11 +616,80 @@ BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&brotli_max_uint32_t);
|
||||
BROTLI_UNUSED(&brotli_min_uint8_t);
|
||||
BROTLI_UNUSED(&brotli_max_uint8_t);
|
||||
BROTLI_UNUSED(&brotli_safe_add_int);
|
||||
BROTLI_UNUSED(&BrotliDefaultAllocFunc);
|
||||
BROTLI_UNUSED(&BrotliDefaultFreeFunc);
|
||||
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
|
||||
BROTLI_UNUSED(&BrotliRotateRight16);
|
||||
BROTLI_UNUSED(&BrotliRotateRight32);
|
||||
BROTLI_UNUSED(&BrotliRotateRight64);
|
||||
#if BROTLI_ENABLE_DUMP
|
||||
BROTLI_UNUSED(&BrotliDump);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && \
|
||||
!defined(_M_ARM64EC)
|
||||
/* _mm_prefetch() is not defined outside of x86/x64 */
|
||||
/* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */
|
||||
#include <mmintrin.h>
|
||||
#define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0)
|
||||
#define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1)
|
||||
#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_prefetch, 3, 1, 0)
|
||||
#define PREFETCH_L1(ptr) \
|
||||
__builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */)
|
||||
#define PREFETCH_L2(ptr) \
|
||||
__builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */)
|
||||
#elif defined(__aarch64__)
|
||||
#define PREFETCH_L1(ptr) \
|
||||
do { \
|
||||
__asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); \
|
||||
} while (0)
|
||||
#define PREFETCH_L2(ptr) \
|
||||
do { \
|
||||
__asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); \
|
||||
} while (0)
|
||||
#else
|
||||
#define PREFETCH_L1(ptr) \
|
||||
do { \
|
||||
(void)(ptr); \
|
||||
} while (0) /* disabled */
|
||||
#define PREFETCH_L2(ptr) \
|
||||
do { \
|
||||
(void)(ptr); \
|
||||
} while (0) /* disabled */
|
||||
#endif
|
||||
|
||||
/* The SIMD matchers are only faster at certain quality levels. */
|
||||
#if defined(_M_X64) && defined(BROTLI_TZCNT64)
|
||||
#define BROTLI_MAX_SIMD_QUALITY 7
|
||||
#elif defined(BROTLI_TZCNT64)
|
||||
#define BROTLI_MAX_SIMD_QUALITY 6
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define BROTLI_CRASH() __debugbreak(), (void)abort()
|
||||
#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_trap, 3, 0, 0)
|
||||
#define BROTLI_CRASH() (void)__builtin_trap()
|
||||
#else
|
||||
#define BROTLI_CRASH() (void)abort()
|
||||
#endif
|
||||
|
||||
/* Make BROTLI_TEST=0 act same as undefined. */
|
||||
#if defined(BROTLI_TEST) && ((1-BROTLI_TEST-1) == 0)
|
||||
#undef BROTLI_TEST
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_MODEL) && BROTLI_GNUC_HAS_ATTRIBUTE(model, 3, 0, 3) && \
|
||||
!defined(BROTLI_TARGET_IA64) && !defined(BROTLI_TARGET_LOONGARCH64)
|
||||
#define BROTLI_MODEL(M) __attribute__((model(M)))
|
||||
#else
|
||||
#define BROTLI_MODEL(M) /* M */
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_COLD) && BROTLI_GNUC_HAS_ATTRIBUTE(cold, 4, 3, 0)
|
||||
#define BROTLI_COLD __attribute__((cold))
|
||||
#else
|
||||
#define BROTLI_COLD /* cold */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_PLATFORM_H_ */
|
||||
@@ -0,0 +1,517 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Shared Dictionary definition and utilities. */
|
||||
|
||||
#include <brotli/shared_dictionary.h>
|
||||
|
||||
#include "dictionary.h"
|
||||
#include "platform.h"
|
||||
#include "shared_dictionary_internal.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
|
||||
#define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \
|
||||
- SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1)
|
||||
|
||||
/* Max allowed by spec */
|
||||
#define BROTLI_MAX_SIZE_BITS 15u
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadBool(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
BROTLI_BOOL* result) {
|
||||
uint8_t value;
|
||||
size_t position = *pos;
|
||||
if (position >= size) return BROTLI_FALSE; /* past file end */
|
||||
value = encoded[position++];
|
||||
if (value > 1) return BROTLI_FALSE; /* invalid bool */
|
||||
*result = TO_BROTLI_BOOL(value);
|
||||
*pos = position;
|
||||
return BROTLI_TRUE; /* success */
|
||||
}
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadUint8(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
uint8_t* result) {
|
||||
size_t position = *pos;
|
||||
if (position + sizeof(uint8_t) > size) return BROTLI_FALSE;
|
||||
*result = encoded[position++];
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadUint16(const uint8_t* encoded, size_t size, size_t* pos,
|
||||
uint16_t* result) {
|
||||
size_t position = *pos;
|
||||
if (position + sizeof(uint16_t) > size) return BROTLI_FALSE;
|
||||
*result = BROTLI_UNALIGNED_LOAD16LE(&encoded[position]);
|
||||
position += 2;
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Reads a varint into a uint32_t, and returns error if it's too large */
|
||||
/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */
|
||||
static BROTLI_BOOL ReadVarint32(const uint8_t* encoded, size_t size,
|
||||
size_t* pos, uint32_t* result) {
|
||||
int num = 0;
|
||||
uint8_t byte;
|
||||
*result = 0;
|
||||
for (;;) {
|
||||
if (*pos >= size) return BROTLI_FALSE;
|
||||
byte = encoded[(*pos)++];
|
||||
if (num == 4 && byte > 15) return BROTLI_FALSE;
|
||||
*result |= (uint32_t)(byte & 127) << (num * 7);
|
||||
if (byte < 128) return BROTLI_TRUE;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Returns the total length of word list. */
|
||||
static size_t BrotliSizeBitsToOffsets(const uint8_t* size_bits_by_length,
|
||||
uint32_t* offsets_by_length) {
|
||||
uint32_t pos = 0;
|
||||
uint32_t i;
|
||||
for (i = 0; i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) {
|
||||
offsets_by_length[i] = pos;
|
||||
if (size_bits_by_length[i] != 0) {
|
||||
pos += i << size_bits_by_length[i];
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseWordList(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliDictionary* out) {
|
||||
size_t offset;
|
||||
size_t i;
|
||||
size_t position = *pos;
|
||||
if (position + BROTLI_NUM_ENCODED_LENGTHS > size) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
memset(out->size_bits_by_length, 0, SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH);
|
||||
memcpy(out->size_bits_by_length + SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH,
|
||||
&encoded[position], BROTLI_NUM_ENCODED_LENGTHS);
|
||||
for (i = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) {
|
||||
if (out->size_bits_by_length[i] > BROTLI_MAX_SIZE_BITS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
position += BROTLI_NUM_ENCODED_LENGTHS;
|
||||
offset = BrotliSizeBitsToOffsets(
|
||||
out->size_bits_by_length, out->offsets_by_length);
|
||||
|
||||
out->data = &encoded[position];
|
||||
out->data_size = offset;
|
||||
position += offset;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Computes the cutOffTransforms of a BrotliTransforms which already has the
|
||||
transforms data correctly filled in. */
|
||||
static void ComputeCutoffTransforms(BrotliTransforms* transforms) {
|
||||
uint32_t i;
|
||||
for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) {
|
||||
transforms->cutOffTransforms[i] = -1;
|
||||
}
|
||||
for (i = 0; i < transforms->num_transforms; i++) {
|
||||
const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, i);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, i);
|
||||
const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, i);
|
||||
if (type <= BROTLI_TRANSFORM_OMIT_LAST_9 && *prefix == 0 && *suffix == 0 &&
|
||||
transforms->cutOffTransforms[type] == -1) {
|
||||
transforms->cutOffTransforms[type] = (int16_t)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParsePrefixSuffixTable(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliTransforms* out, uint16_t* out_table,
|
||||
size_t* out_table_size) {
|
||||
size_t position = *pos;
|
||||
size_t offset = 0;
|
||||
size_t stringlet_count = 0; /* NUM_PREFIX_SUFFIX */
|
||||
size_t data_length = 0;
|
||||
|
||||
/* PREFIX_SUFFIX_LENGTH */
|
||||
if (!ReadUint16(encoded, size, &position, &out->prefix_suffix_size)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
data_length = out->prefix_suffix_size;
|
||||
|
||||
/* Must at least have space for null terminator. */
|
||||
if (data_length < 1) return BROTLI_FALSE;
|
||||
out->prefix_suffix = &encoded[position];
|
||||
if (position + data_length >= size) return BROTLI_FALSE;
|
||||
while (BROTLI_TRUE) {
|
||||
/* STRING_LENGTH */
|
||||
size_t stringlet_len = encoded[position + offset];
|
||||
out_table[stringlet_count] = (uint16_t)offset;
|
||||
stringlet_count++;
|
||||
offset++;
|
||||
if (stringlet_len == 0) {
|
||||
if (offset == data_length) {
|
||||
break;
|
||||
} else {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
if (stringlet_count > 255) return BROTLI_FALSE;
|
||||
offset += stringlet_len;
|
||||
if (offset >= data_length) return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
position += data_length;
|
||||
*pos = position;
|
||||
*out_table_size = (uint16_t)stringlet_count;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseTransformsList(size_t size, const uint8_t* encoded,
|
||||
size_t* pos, BrotliTransforms* out, uint16_t* prefix_suffix_table,
|
||||
size_t* prefix_suffix_count) {
|
||||
uint32_t i;
|
||||
BROTLI_BOOL has_params = BROTLI_FALSE;
|
||||
BROTLI_BOOL prefix_suffix_ok = BROTLI_FALSE;
|
||||
size_t position = *pos;
|
||||
size_t stringlet_cnt = 0;
|
||||
if (position >= size) return BROTLI_FALSE;
|
||||
|
||||
prefix_suffix_ok = ParsePrefixSuffixTable(
|
||||
size, encoded, &position, out, prefix_suffix_table, &stringlet_cnt);
|
||||
if (!prefix_suffix_ok) return BROTLI_FALSE;
|
||||
out->prefix_suffix_map = prefix_suffix_table;
|
||||
*prefix_suffix_count = stringlet_cnt;
|
||||
|
||||
out->num_transforms = encoded[position++];
|
||||
out->transforms = &encoded[position];
|
||||
position += (size_t)out->num_transforms * 3;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
/* Check for errors and read extra parameters. */
|
||||
for (i = 0; i < out->num_transforms; i++) {
|
||||
uint8_t prefix_id = BROTLI_TRANSFORM_PREFIX_ID(out, i);
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(out, i);
|
||||
uint8_t suffix_id = BROTLI_TRANSFORM_SUFFIX_ID(out, i);
|
||||
if (prefix_id >= stringlet_cnt) return BROTLI_FALSE;
|
||||
if (type >= BROTLI_NUM_TRANSFORM_TYPES) return BROTLI_FALSE;
|
||||
if (suffix_id >= stringlet_cnt) return BROTLI_FALSE;
|
||||
if (type == BROTLI_TRANSFORM_SHIFT_FIRST ||
|
||||
type == BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
has_params = BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
if (has_params) {
|
||||
out->params = &encoded[position];
|
||||
position += (size_t)out->num_transforms * 2;
|
||||
if (position > size) return BROTLI_FALSE;
|
||||
for (i = 0; i < out->num_transforms; i++) {
|
||||
uint8_t type = BROTLI_TRANSFORM_TYPE(out, i);
|
||||
if (type != BROTLI_TRANSFORM_SHIFT_FIRST &&
|
||||
type != BROTLI_TRANSFORM_SHIFT_ALL) {
|
||||
if (out->params[i * 2] != 0 || out->params[i * 2 + 1] != 0) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
out->params = NULL;
|
||||
}
|
||||
ComputeCutoffTransforms(out);
|
||||
*pos = position;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL DryParseDictionary(const uint8_t* encoded,
|
||||
size_t size, uint32_t* num_prefix, BROTLI_BOOL* is_custom_static_dict) {
|
||||
size_t pos = 0;
|
||||
uint32_t chunk_size = 0;
|
||||
uint8_t num_word_lists;
|
||||
uint8_t num_transform_lists;
|
||||
*is_custom_static_dict = BROTLI_FALSE;
|
||||
*num_prefix = 0;
|
||||
|
||||
/* Skip magic header bytes. */
|
||||
pos += 2;
|
||||
|
||||
/* LZ77_DICTIONARY_LENGTH */
|
||||
if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE;
|
||||
if (chunk_size != 0) {
|
||||
/* This limitation is not specified but the 32-bit Brotli decoder for now */
|
||||
if (chunk_size > 1073741823) return BROTLI_FALSE;
|
||||
*num_prefix = 1;
|
||||
if (pos + chunk_size > size) return BROTLI_FALSE;
|
||||
pos += chunk_size;
|
||||
}
|
||||
|
||||
if (!ReadUint8(encoded, size, &pos, &num_word_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (!ReadUint8(encoded, size, &pos, &num_transform_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (num_word_lists > 0 || num_transform_lists > 0) {
|
||||
*is_custom_static_dict = BROTLI_TRUE;
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ParseDictionary(const uint8_t* encoded, size_t size,
|
||||
BrotliSharedDictionary* dict) {
|
||||
uint32_t i;
|
||||
size_t pos = 0;
|
||||
uint32_t chunk_size = 0;
|
||||
size_t total_prefix_suffix_count = 0;
|
||||
size_t transform_list_start[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
uint16_t temporary_prefix_suffix_table[256];
|
||||
|
||||
/* Skip magic header bytes. */
|
||||
pos += 2;
|
||||
|
||||
/* LZ77_DICTIONARY_LENGTH */
|
||||
if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE;
|
||||
if (chunk_size != 0) {
|
||||
if (pos + chunk_size > size) return BROTLI_FALSE;
|
||||
dict->prefix_size[dict->num_prefix] = chunk_size;
|
||||
dict->prefix[dict->num_prefix] = &encoded[pos];
|
||||
dict->num_prefix++;
|
||||
/* LZ77_DICTIONARY_LENGTH bytes. */
|
||||
pos += chunk_size;
|
||||
}
|
||||
|
||||
/* NUM_WORD_LISTS */
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_word_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_word_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (dict->num_word_lists != 0) {
|
||||
dict->words_instances = (BrotliDictionary*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
dict->num_word_lists * sizeof(*dict->words_instances));
|
||||
if (!dict->words_instances) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
for (i = 0; i < dict->num_word_lists; i++) {
|
||||
if (!ParseWordList(size, encoded, &pos, &dict->words_instances[i])) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* NUM_TRANSFORM_LISTS */
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_transform_lists)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_transform_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (dict->num_transform_lists != 0) {
|
||||
dict->transforms_instances = (BrotliTransforms*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
dict->num_transform_lists * sizeof(*dict->transforms_instances));
|
||||
if (!dict->transforms_instances) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
for (i = 0; i < dict->num_transform_lists; i++) {
|
||||
BROTLI_BOOL ok = BROTLI_FALSE;
|
||||
size_t prefix_suffix_count = 0;
|
||||
transform_list_start[i] = pos;
|
||||
dict->transforms_instances[i].prefix_suffix_map =
|
||||
temporary_prefix_suffix_table;
|
||||
ok = ParseTransformsList(
|
||||
size, encoded, &pos, &dict->transforms_instances[i],
|
||||
temporary_prefix_suffix_table, &prefix_suffix_count);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
total_prefix_suffix_count += prefix_suffix_count;
|
||||
}
|
||||
if (total_prefix_suffix_count != 0) {
|
||||
dict->prefix_suffix_maps = (uint16_t*)dict->alloc_func(
|
||||
dict->memory_manager_opaque,
|
||||
total_prefix_suffix_count * sizeof(*dict->prefix_suffix_maps));
|
||||
if (!dict->prefix_suffix_maps) return BROTLI_FALSE; /* OOM */
|
||||
}
|
||||
total_prefix_suffix_count = 0;
|
||||
for (i = 0; i < dict->num_transform_lists; i++) {
|
||||
size_t prefix_suffix_count = 0;
|
||||
size_t position = transform_list_start[i];
|
||||
uint16_t* prefix_suffix_map =
|
||||
&dict->prefix_suffix_maps[total_prefix_suffix_count];
|
||||
BROTLI_BOOL ok = ParsePrefixSuffixTable(
|
||||
size, encoded, &position, &dict->transforms_instances[i],
|
||||
prefix_suffix_map, &prefix_suffix_count);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
dict->transforms_instances[i].prefix_suffix_map = prefix_suffix_map;
|
||||
total_prefix_suffix_count += prefix_suffix_count;
|
||||
}
|
||||
|
||||
if (dict->num_word_lists != 0 || dict->num_transform_lists != 0) {
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->num_dictionaries)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->num_dictionaries == 0 ||
|
||||
dict->num_dictionaries > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
for (i = 0; i < dict->num_dictionaries; i++) {
|
||||
uint8_t words_index;
|
||||
uint8_t transforms_index;
|
||||
if (!ReadUint8(encoded, size, &pos, &words_index)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (words_index > dict->num_word_lists) return BROTLI_FALSE;
|
||||
if (!ReadUint8(encoded, size, &pos, &transforms_index)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (transforms_index > dict->num_transform_lists) return BROTLI_FALSE;
|
||||
dict->words[i] = words_index == dict->num_word_lists ?
|
||||
BrotliGetDictionary() : &dict->words_instances[words_index];
|
||||
dict->transforms[i] = transforms_index == dict->num_transform_lists ?
|
||||
BrotliGetTransforms(): &dict->transforms_instances[transforms_index];
|
||||
}
|
||||
/* CONTEXT_ENABLED */
|
||||
if (!ReadBool(encoded, size, &pos, &dict->context_based)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
/* CONTEXT_MAP */
|
||||
if (dict->context_based) {
|
||||
for (i = 0; i < SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS; i++) {
|
||||
if (!ReadUint8(encoded, size, &pos, &dict->context_map[i])) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
if (dict->context_map[i] >= dict->num_dictionaries) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dict->context_based = BROTLI_FALSE;
|
||||
dict->num_dictionaries = 1;
|
||||
dict->words[0] = BrotliGetDictionary();
|
||||
dict->transforms[0] = BrotliGetTransforms();
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Decodes shared dictionary and verifies correctness.
|
||||
Returns BROTLI_TRUE if dictionary is valid, BROTLI_FALSE otherwise.
|
||||
The BrotliSharedDictionary must already have been initialized. If the
|
||||
BrotliSharedDictionary already contains data, compound dictionaries
|
||||
will be appended, but an error will be returned if it already has
|
||||
custom words or transforms.
|
||||
TODO(lode): link to RFC for shared brotli once published. */
|
||||
static BROTLI_BOOL DecodeSharedDictionary(
|
||||
const uint8_t* encoded, size_t size, BrotliSharedDictionary* dict) {
|
||||
uint32_t num_prefix = 0;
|
||||
BROTLI_BOOL is_custom_static_dict = BROTLI_FALSE;
|
||||
BROTLI_BOOL has_custom_static_dict =
|
||||
dict->num_word_lists > 0 || dict->num_transform_lists > 0;
|
||||
|
||||
/* Check magic header bytes. */
|
||||
if (size < 2) return BROTLI_FALSE;
|
||||
if (encoded[0] != 0x91 || encoded[1] != 0) return BROTLI_FALSE;
|
||||
|
||||
if (!DryParseDictionary(encoded, size, &num_prefix, &is_custom_static_dict)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (num_prefix + dict->num_prefix > SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
/* Cannot combine different static dictionaries, only prefix dictionaries */
|
||||
if (has_custom_static_dict && is_custom_static_dict) return BROTLI_FALSE;
|
||||
|
||||
return ParseDictionary(encoded, size, dict);
|
||||
}
|
||||
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliSharedDictionaryDestroyInstance(
|
||||
BrotliSharedDictionary* dict) {
|
||||
if (!dict) {
|
||||
return;
|
||||
} else {
|
||||
brotli_free_func free_func = dict->free_func;
|
||||
void* opaque = dict->memory_manager_opaque;
|
||||
/* Cleanup. */
|
||||
free_func(opaque, dict->words_instances);
|
||||
free_func(opaque, dict->transforms_instances);
|
||||
free_func(opaque, dict->prefix_suffix_maps);
|
||||
/* Self-destruction. */
|
||||
free_func(opaque, dict);
|
||||
}
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliSharedDictionaryAttach(
|
||||
BrotliSharedDictionary* dict, BrotliSharedDictionaryType type,
|
||||
size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) {
|
||||
if (!dict) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) {
|
||||
return DecodeSharedDictionary(data, data_size, dict);
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
if (type == BROTLI_SHARED_DICTIONARY_RAW) {
|
||||
if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
dict->prefix_size[dict->num_prefix] = data_size;
|
||||
dict->prefix[dict->num_prefix] = data;
|
||||
dict->num_prefix++;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
BrotliSharedDictionary* dict = 0;
|
||||
if (!alloc_func && !free_func) {
|
||||
dict = (BrotliSharedDictionary*)malloc(sizeof(BrotliSharedDictionary));
|
||||
} else if (alloc_func && free_func) {
|
||||
dict = (BrotliSharedDictionary*)alloc_func(
|
||||
opaque, sizeof(BrotliSharedDictionary));
|
||||
}
|
||||
if (dict == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TODO(eustas): explicitly initialize all the fields? */
|
||||
memset(dict, 0, sizeof(BrotliSharedDictionary));
|
||||
|
||||
dict->context_based = BROTLI_FALSE;
|
||||
dict->num_dictionaries = 1;
|
||||
dict->num_word_lists = 0;
|
||||
dict->num_transform_lists = 0;
|
||||
|
||||
dict->words[0] = BrotliGetDictionary();
|
||||
dict->transforms[0] = BrotliGetTransforms();
|
||||
|
||||
dict->alloc_func = alloc_func ? alloc_func : BrotliDefaultAllocFunc;
|
||||
dict->free_func = free_func ? free_func : BrotliDefaultFreeFunc;
|
||||
dict->memory_manager_opaque = opaque;
|
||||
|
||||
return dict;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* (Transparent) Shared Dictionary definition. */
|
||||
|
||||
#ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
|
||||
#define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_
|
||||
|
||||
#include <brotli/shared_dictionary.h>
|
||||
|
||||
#include "dictionary.h"
|
||||
#include "platform.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct BrotliSharedDictionaryStruct {
|
||||
/* LZ77 prefixes (compound dictionary). */
|
||||
uint32_t num_prefix; /* max SHARED_BROTLI_MAX_COMPOUND_DICTS */
|
||||
size_t prefix_size[SHARED_BROTLI_MAX_COMPOUND_DICTS];
|
||||
const uint8_t* prefix[SHARED_BROTLI_MAX_COMPOUND_DICTS];
|
||||
|
||||
/* If set, the context map is used to select word and transform list from 64
|
||||
contexts, if not set, the context map is not used and only words[0] and
|
||||
transforms[0] are to be used. */
|
||||
BROTLI_BOOL context_based;
|
||||
|
||||
uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Amount of word_list+transform_list combinations. */
|
||||
uint8_t num_dictionaries;
|
||||
|
||||
/* Must use num_dictionaries values. */
|
||||
const BrotliDictionary* words[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Must use num_dictionaries values. */
|
||||
const BrotliTransforms* transforms[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* Amount of custom word lists. May be 0 if only Brotli's built-in is used */
|
||||
uint8_t num_word_lists;
|
||||
|
||||
/* Contents of the custom words lists. Must be NULL if num_word_lists is 0. */
|
||||
BrotliDictionary* words_instances;
|
||||
|
||||
/* Amount of custom transform lists. May be 0 if only Brotli's built-in is
|
||||
used */
|
||||
uint8_t num_transform_lists;
|
||||
|
||||
/* Contents of the custom transform lists. Must be NULL if num_transform_lists
|
||||
is 0. */
|
||||
BrotliTransforms* transforms_instances;
|
||||
|
||||
/* Concatenated prefix_suffix_maps of the custom transform lists. Must be NULL
|
||||
if num_transform_lists is 0. */
|
||||
uint16_t* prefix_suffix_maps;
|
||||
|
||||
/* Memory management */
|
||||
brotli_alloc_func alloc_func;
|
||||
brotli_free_func free_func;
|
||||
void* memory_manager_opaque;
|
||||
};
|
||||
|
||||
typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionaryInternal;
|
||||
#define BrotliSharedDictionary BrotliSharedDictionaryInternal
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ */
|
||||
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/*
|
||||
Central point for static initialization.
|
||||
|
||||
In case of "lazy" mode `BrotliXxxLazyStaticInit` is not provided by the
|
||||
library. Embedder is responsible for providing it. This function should call
|
||||
`BrotliXxxLazyStaticInitInner` on the first invocation. This function should
|
||||
not return until execution of `BrotliXxxLazyStaticInitInner` is finished.
|
||||
In C or before C++11 it is possible to call `BrotliXxxLazyStaticInitInner`
|
||||
on start-up path and then `BrotliEncoderLazyStaticInit` is could be no-op;
|
||||
another option is to use available thread execution controls to meet the
|
||||
requirements. For possible C++11 implementation see static_init_lazy.cc.
|
||||
*/
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
#define THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Static data is "initialized" in compile time. */
|
||||
#define BROTLI_STATIC_INIT_NONE 0
|
||||
/* Static data is initialized before "main". */
|
||||
#define BROTLI_STATIC_INIT_EARLY 1
|
||||
/* Static data is initialized when first encoder is created. */
|
||||
#define BROTLI_STATIC_INIT_LAZY 2
|
||||
|
||||
#define BROTLI_STATIC_INIT_DEFAULT BROTLI_STATIC_INIT_NONE
|
||||
|
||||
#if !defined(BROTLI_STATIC_INIT)
|
||||
#define BROTLI_STATIC_INIT BROTLI_STATIC_INIT_DEFAULT
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) && \
|
||||
(BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_EARLY) && \
|
||||
(BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_LAZY)
|
||||
#error Invalid value for BROTLI_STATIC_INIT
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA)
|
||||
#error BROTLI_STATIC_INIT_EARLY will fail with BROTLI_EXTERNAL_DICTIONARY_DATA
|
||||
#endif
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_
|
||||
@@ -4,14 +4,15 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./transform.h"
|
||||
#include "platform.h"
|
||||
#include "transform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* RFC 7932 transforms string data */
|
||||
static const char kPrefixSuffix[217] =
|
||||
static const BROTLI_MODEL("small") char kPrefixSuffix[217] =
|
||||
"\1 \2, \10 of the \4 of \2s \1.\5 and \4 "
|
||||
/* 0x _0 _2 __5 _E _3 _6 _8 _E */
|
||||
"in \1\"\4 to \2\">\1\n\2. \1]\5 for \3 a \6 "
|
||||
@@ -27,7 +28,7 @@ static const char kPrefixSuffix[217] =
|
||||
"t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */
|
||||
/* Cx _2 _7___ ___ _A _F _5 _8 */
|
||||
|
||||
static const uint16_t kPrefixSuffixMap[50] = {
|
||||
static const BROTLI_MODEL("small") uint16_t kPrefixSuffixMap[50] = {
|
||||
0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25,
|
||||
0x2A, 0x2D, 0x2F, 0x32, 0x34, 0x3A, 0x3E, 0x45, 0x47, 0x4E,
|
||||
0x55, 0x5A, 0x5C, 0x63, 0x68, 0x6D, 0x72, 0x77, 0x7A, 0x7C,
|
||||
@@ -36,7 +37,7 @@ static const uint16_t kPrefixSuffixMap[50] = {
|
||||
};
|
||||
|
||||
/* RFC 7932 transforms */
|
||||
static const uint8_t kTransformsData[] = {
|
||||
static const BROTLI_MODEL("small") uint8_t kTransformsData[] = {
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 49,
|
||||
49, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
0, BROTLI_TRANSFORM_IDENTITY, 0,
|
||||
@@ -160,7 +161,8 @@ static const uint8_t kTransformsData[] = {
|
||||
0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34,
|
||||
};
|
||||
|
||||
static const BrotliTransforms kBrotliTransforms = {
|
||||
static const BROTLI_MODEL("small")
|
||||
BrotliTransforms kBrotliTransforms = {
|
||||
sizeof(kPrefixSuffix),
|
||||
(const uint8_t*)kPrefixSuffix,
|
||||
kPrefixSuffixMap,
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
#ifndef BROTLI_COMMON_TRANSFORM_H_
|
||||
#define BROTLI_COMMON_TRANSFORM_H_
|
||||
|
||||
#include <brotli/port.h>
|
||||
#include <brotli/types.h>
|
||||
#include "platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -9,18 +9,43 @@
|
||||
#ifndef BROTLI_COMMON_VERSION_H_
|
||||
#define BROTLI_COMMON_VERSION_H_
|
||||
|
||||
/* This macro should only be used when library is compiled together with client.
|
||||
If library is dynamically linked, use BrotliDecoderVersion and
|
||||
/* Compose 3 components into a single number. In a hexadecimal representation
|
||||
B and C components occupy exactly 3 digits. */
|
||||
#define BROTLI_MAKE_HEX_VERSION(A, B, C) ((A << 24) | (B << 12) | C)
|
||||
|
||||
/* Those macros should only be used when library is compiled together with
|
||||
the client. If library is dynamically linked, use BrotliDecoderVersion and
|
||||
BrotliEncoderVersion methods. */
|
||||
|
||||
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
|
||||
#define BROTLI_VERSION 0x1000009
|
||||
#define BROTLI_VERSION_MAJOR 1
|
||||
#define BROTLI_VERSION_MINOR 2
|
||||
#define BROTLI_VERSION_PATCH 0
|
||||
|
||||
#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \
|
||||
BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH)
|
||||
|
||||
/* This macro is used by build system to produce Libtool-friendly soname. See
|
||||
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
|
||||
Version evolution rules:
|
||||
- interfaces added (or change is compatible) -> current+1:0:age+1
|
||||
- interfaces removed (or changed is incompatible) -> current+1:0:0
|
||||
- interfaces not changed -> current:revision+1:age
|
||||
*/
|
||||
|
||||
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
|
||||
#define BROTLI_ABI_VERSION 0x1009000
|
||||
#define BROTLI_ABI_CURRENT 3
|
||||
#define BROTLI_ABI_REVISION 0
|
||||
#define BROTLI_ABI_AGE 2
|
||||
|
||||
#if BROTLI_VERSION_MAJOR != (BROTLI_ABI_CURRENT - BROTLI_ABI_AGE)
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#if BROTLI_VERSION_MINOR != BROTLI_ABI_AGE
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#if BROTLI_VERSION_PATCH != BROTLI_ABI_REVISION
|
||||
#error ABI/API version inconsistency
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_COMMON_VERSION_H_ */
|
||||
@@ -6,16 +6,16 @@
|
||||
|
||||
/* Bit reading helpers */
|
||||
|
||||
#include "./bit_reader.h"
|
||||
#include "bit_reader.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const uint32_t kBrotliBitMask[33] = { 0x00000000,
|
||||
const BROTLI_MODEL("small")
|
||||
brotli_reg_t kBrotliBitMask[33] = { 0x00000000,
|
||||
0x00000001, 0x00000003, 0x00000007, 0x0000000F,
|
||||
0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
|
||||
0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
|
||||
@@ -26,20 +26,21 @@ const uint32_t kBrotliBitMask[33] = { 0x00000000,
|
||||
0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
|
||||
};
|
||||
|
||||
void BrotliInitBitReader(BrotliBitReader* const br) {
|
||||
void BrotliInitBitReader(BrotliBitReader* br) {
|
||||
br->val_ = 0;
|
||||
br->bit_pos_ = sizeof(br->val_) << 3;
|
||||
br->bit_pos_ = 0;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* br) {
|
||||
size_t aligned_read_mask = (sizeof(br->val_) >> 1) - 1;
|
||||
/* 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) {
|
||||
br->val_ = 0;
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
@@ -54,10 +55,10 @@ BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) {
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br,
|
||||
uint32_t n_bits, uint32_t* val) {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* br,
|
||||
brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliBitReaderState memento;
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
BROTLI_DCHECK(n_bits > 24);
|
||||
|
||||
+170
-102
@@ -9,11 +9,8 @@
|
||||
#ifndef BROTLI_DEC_BIT_READER_H_
|
||||
#define BROTLI_DEC_BIT_READER_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -21,13 +18,16 @@ extern "C" {
|
||||
|
||||
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
|
||||
|
||||
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
|
||||
/* 162 bits + 7 bytes */
|
||||
#define BROTLI_FAST_INPUT_SLACK 28
|
||||
|
||||
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
BROTLI_INTERNAL extern const brotli_reg_t kBrotliBitMask[33];
|
||||
|
||||
static BROTLI_INLINE brotli_reg_t BitMask(brotli_reg_t n) {
|
||||
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
|
||||
/* Masking with this expression turns to a single
|
||||
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
|
||||
return ~((0xFFFFFFFFu) << n);
|
||||
return ~(~((brotli_reg_t)0) << n);
|
||||
} else {
|
||||
return kBrotliBitMask[n];
|
||||
}
|
||||
@@ -35,40 +35,57 @@ static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
|
||||
|
||||
typedef struct {
|
||||
brotli_reg_t val_; /* pre-fetched bits */
|
||||
uint32_t bit_pos_; /* current bit-reading position in val_ */
|
||||
brotli_reg_t bit_pos_; /* current bit-reading position in val_ */
|
||||
const uint8_t* next_in; /* the byte we're reading from */
|
||||
size_t avail_in;
|
||||
const uint8_t* guard_in; /* position from which "fast-path" is prohibited */
|
||||
const uint8_t* last_in; /* == next_in + avail_in */
|
||||
} BrotliBitReader;
|
||||
|
||||
typedef struct {
|
||||
brotli_reg_t val_;
|
||||
uint32_t bit_pos_;
|
||||
brotli_reg_t bit_pos_;
|
||||
const uint8_t* next_in;
|
||||
size_t avail_in;
|
||||
} BrotliBitReaderState;
|
||||
|
||||
/* Initializes the BrotliBitReader fields. */
|
||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
|
||||
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* 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. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
|
||||
For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for
|
||||
aligned reading. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* br);
|
||||
|
||||
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
|
||||
the main code-path. Never called for RFC brotli streams, required only for
|
||||
"large-window" mode and other extensions. */
|
||||
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
|
||||
BrotliBitReader* br, brotli_reg_t n_bits, brotli_reg_t* val);
|
||||
|
||||
static BROTLI_INLINE size_t
|
||||
BrotliBitReaderGetAvailIn(BrotliBitReader* const br) {
|
||||
return (size_t)(br->last_in - br->next_in);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderSaveState(
|
||||
BrotliBitReader* const from, BrotliBitReaderState* to) {
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
to->avail_in = BrotliBitReaderGetAvailIn(from);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderSetInput(
|
||||
BrotliBitReader* const br, const uint8_t* next_in, size_t avail_in) {
|
||||
br->next_in = next_in;
|
||||
br->last_in = (avail_in == 0) ? next_in : (next_in + avail_in);
|
||||
if (avail_in + 1 > BROTLI_FAST_INPUT_SLACK) {
|
||||
br->guard_in = next_in + (avail_in + 1 - BROTLI_FAST_INPUT_SLACK);
|
||||
} else {
|
||||
br->guard_in = next_in;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderRestoreState(
|
||||
@@ -76,12 +93,12 @@ static BROTLI_INLINE void BrotliBitReaderRestoreState(
|
||||
to->val_ = from->val_;
|
||||
to->bit_pos_ = from->bit_pos_;
|
||||
to->next_in = from->next_in;
|
||||
to->avail_in = from->avail_in;
|
||||
BrotliBitReaderSetInput(to, from->next_in, from->avail_in);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetAvailableBits(
|
||||
const BrotliBitReader* br) {
|
||||
return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
|
||||
return br->bit_pos_;
|
||||
}
|
||||
|
||||
/* Returns amount of unread bytes the bit reader still has buffered from the
|
||||
@@ -89,15 +106,27 @@ static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
|
||||
maximal ring-buffer size (larger number won't be utilized anyway). */
|
||||
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
|
||||
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
|
||||
if (br->avail_in > kCap) return kCap;
|
||||
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
size_t avail_in = BrotliBitReaderGetAvailIn(br);
|
||||
if (avail_in > kCap) return kCap;
|
||||
return avail_in + (BrotliGetAvailableBits(br) >> 3);
|
||||
}
|
||||
|
||||
/* Checks if there is at least |num| bytes left in the input ring-buffer
|
||||
(excluding the bits remaining in br->val_). */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
|
||||
BrotliBitReader* const br, size_t num) {
|
||||
return TO_BROTLI_BOOL(br->avail_in >= num);
|
||||
BrotliBitReader* const br) {
|
||||
return TO_BROTLI_BOOL(br->next_in < br->guard_in);
|
||||
}
|
||||
|
||||
/* Load more bits into accumulator. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliBitReaderLoadBits(brotli_reg_t val,
|
||||
brotli_reg_t new_bits,
|
||||
brotli_reg_t count,
|
||||
brotli_reg_t offset) {
|
||||
BROTLI_DCHECK(
|
||||
!((val >> offset) & ~new_bits & ~(~((brotli_reg_t)0) << count)));
|
||||
(void)count;
|
||||
return val | (new_bits << offset);
|
||||
}
|
||||
|
||||
/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
|
||||
@@ -105,49 +134,51 @@ static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
|
||||
|n_bits| should be in the range [1..24] for regular build. For portable
|
||||
non-64-bit little-endian build only 16 bits are safe to request. */
|
||||
static BROTLI_INLINE void BrotliFillBitWindow(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
#if (BROTLI_64_BITS)
|
||||
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 56) {
|
||||
br->val_ >>= 56;
|
||||
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8;
|
||||
br->avail_in -= 7;
|
||||
if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 8)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 8) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD64LE(br->next_in), 56, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 56;
|
||||
br->next_in += 7;
|
||||
}
|
||||
} else if (
|
||||
!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) {
|
||||
if (br->bit_pos_ >= 48) {
|
||||
br->val_ >>= 48;
|
||||
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16;
|
||||
br->avail_in -= 6;
|
||||
} else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 16)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 16) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD64LE(br->next_in), 48, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 48;
|
||||
br->next_in += 6;
|
||||
}
|
||||
} else {
|
||||
if (br->bit_pos_ >= 32) {
|
||||
br->val_ >>= 32;
|
||||
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
|
||||
br->val_ |= ((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 32) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in), 32, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 32;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
|
||||
if (br->bit_pos_ >= 24) {
|
||||
br->val_ >>= 24;
|
||||
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
|
||||
br->val_ |= BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8;
|
||||
br->avail_in -= 3;
|
||||
if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) &&
|
||||
(n_bits <= 8)) {
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 8) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
BROTLI_UNALIGNED_LOAD32LE(br->next_in), 24, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 24;
|
||||
br->next_in += 3;
|
||||
}
|
||||
} else {
|
||||
if (br->bit_pos_ >= 16) {
|
||||
br->val_ >>= 16;
|
||||
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
|
||||
br->val_ |= ((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16;
|
||||
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
brotli_reg_t bit_pos = br->bit_pos_;
|
||||
if (bit_pos <= 16) {
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in), 16, bit_pos);
|
||||
br->bit_pos_ = bit_pos + 16;
|
||||
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
|
||||
}
|
||||
}
|
||||
@@ -163,17 +194,12 @@ static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
|
||||
/* Tries to pull one byte of input to accumulator.
|
||||
Returns BROTLI_FALSE if there is no input available. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||
if (br->avail_in == 0) {
|
||||
if (br->next_in == br->last_in) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
br->val_ >>= 8;
|
||||
#if (BROTLI_64_BITS)
|
||||
br->val_ |= ((uint64_t)*br->next_in) << 56;
|
||||
#else
|
||||
br->val_ |= ((uint32_t)*br->next_in) << 24;
|
||||
#endif
|
||||
br->bit_pos_ -= 8;
|
||||
--br->avail_in;
|
||||
br->val_ = BrotliBitReaderLoadBits(br->val_,
|
||||
(brotli_reg_t)*br->next_in, 8, br->bit_pos_);
|
||||
br->bit_pos_ += 8;
|
||||
++br->next_in;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
@@ -182,81 +208,90 @@ static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
|
||||
The number of valid bits could be calculated by BrotliGetAvailableBits. */
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
return br->val_ >> br->bit_pos_;
|
||||
return br->val_;
|
||||
}
|
||||
|
||||
/* Like BrotliGetBits, but does not mask the result.
|
||||
The result contains at least 16 valid bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGet16BitsUnmasked(
|
||||
BrotliBitReader* const br) {
|
||||
BrotliFillBitWindow(br, 16);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br);
|
||||
return (brotli_reg_t)BrotliGetBitsUnmasked(br);
|
||||
}
|
||||
|
||||
/* Returns the specified number of bits from |br| without advancing bit
|
||||
position. */
|
||||
static BROTLI_INLINE uint32_t BrotliGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
static BROTLI_INLINE brotli_reg_t BrotliGetBits(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
return BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
}
|
||||
|
||||
/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there
|
||||
is not enough input. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
*val = BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Advances the bit pos by |n_bits|. */
|
||||
static BROTLI_INLINE void BrotliDropBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
br->bit_pos_ += n_bits;
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
br->bit_pos_ -= n_bits;
|
||||
br->val_ >>= n_bits;
|
||||
}
|
||||
|
||||
/* Make sure that there are no spectre bits in accumulator.
|
||||
This is important for the cases when some bytes are skipped
|
||||
(i.e. never placed into accumulator). */
|
||||
static BROTLI_INLINE void BrotliBitReaderNormalize(BrotliBitReader* br) {
|
||||
/* Actually, it is enough to normalize when br->bit_pos_ == 0 */
|
||||
if (br->bit_pos_ < (sizeof(brotli_reg_t) << 3u)) {
|
||||
br->val_ &= (((brotli_reg_t)1) << br->bit_pos_) - 1;
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
|
||||
uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
|
||||
uint32_t unused_bits = unused_bytes << 3;
|
||||
br->avail_in += unused_bytes;
|
||||
br->next_in -= unused_bytes;
|
||||
if (unused_bits == sizeof(br->val_) << 3) {
|
||||
br->val_ = 0;
|
||||
} else {
|
||||
br->val_ <<= unused_bits;
|
||||
}
|
||||
br->bit_pos_ += unused_bits;
|
||||
brotli_reg_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
|
||||
brotli_reg_t unused_bits = unused_bytes << 3;
|
||||
br->next_in =
|
||||
(unused_bytes == 0) ? br->next_in : (br->next_in - unused_bytes);
|
||||
br->bit_pos_ -= unused_bits;
|
||||
BrotliBitReaderNormalize(br);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||
Precondition: accumulator MUST contain at least |n_bits|. */
|
||||
static BROTLI_INLINE void BrotliTakeBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
static BROTLI_INLINE void BrotliTakeBits(BrotliBitReader* const br,
|
||||
brotli_reg_t n_bits,
|
||||
brotli_reg_t* val) {
|
||||
*val = BrotliGetBitsUnmasked(br) & BitMask(n_bits);
|
||||
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
|
||||
(int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
|
||||
(int)BrotliBitReaderGetAvailIn(br), (int)br->bit_pos_,
|
||||
(int)n_bits, (int)*val));
|
||||
BrotliDropBits(br, n_bits);
|
||||
}
|
||||
|
||||
/* Reads the specified number of bits from |br| and advances the bit pos.
|
||||
Assumes that there is enough input to perform BrotliFillBitWindow.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits24(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
static BROTLI_INLINE brotli_reg_t BrotliReadBits24(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
brotli_reg_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
return val;
|
||||
} else {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, 16, &low_val);
|
||||
BrotliFillBitWindow(br, 8);
|
||||
@@ -266,17 +301,17 @@ static BROTLI_INLINE uint32_t BrotliReadBits24(
|
||||
}
|
||||
|
||||
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE uint32_t BrotliReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits) {
|
||||
static BROTLI_INLINE brotli_reg_t BrotliReadBits32(
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 16)) {
|
||||
uint32_t val;
|
||||
brotli_reg_t val;
|
||||
BrotliFillBitWindow(br, n_bits);
|
||||
BrotliTakeBits(br, n_bits, &val);
|
||||
return val;
|
||||
} else {
|
||||
uint32_t low_val;
|
||||
uint32_t high_val;
|
||||
brotli_reg_t low_val;
|
||||
brotli_reg_t high_val;
|
||||
BrotliFillBitWindow(br, 16);
|
||||
BrotliTakeBits(br, 16, &low_val);
|
||||
BrotliFillBitWindow(br, 16);
|
||||
@@ -289,7 +324,7 @@ static BROTLI_INLINE uint32_t BrotliReadBits32(
|
||||
is not enough input. |n_bits| MUST be positive.
|
||||
Up to 24 bits are allowed to be requested from this method. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 24);
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
if (!BrotliPullByte(br)) {
|
||||
@@ -302,7 +337,7 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
|
||||
|
||||
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
|
||||
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
|
||||
BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) {
|
||||
BROTLI_DCHECK(n_bits <= 32);
|
||||
if (BROTLI_64_BITS || (n_bits <= 24)) {
|
||||
while (BrotliGetAvailableBits(br) < n_bits) {
|
||||
@@ -320,14 +355,22 @@ static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
|
||||
/* Advances the bit reader position to the next byte boundary and verifies
|
||||
that any skipped bits are set to zero. */
|
||||
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
|
||||
uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
|
||||
uint32_t pad_bits = 0;
|
||||
brotli_reg_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
|
||||
brotli_reg_t pad_bits = 0;
|
||||
if (pad_bits_count != 0) {
|
||||
BrotliTakeBits(br, pad_bits_count, &pad_bits);
|
||||
}
|
||||
BrotliBitReaderNormalize(br);
|
||||
return TO_BROTLI_BOOL(pad_bits == 0);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) {
|
||||
/* Check detour is legal: accumulator must to be empty. */
|
||||
BROTLI_DCHECK(br->bit_pos_ == 0);
|
||||
BROTLI_DCHECK(br->val_ == 0);
|
||||
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. */
|
||||
@@ -339,9 +382,34 @@ static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
|
||||
++dest;
|
||||
--num;
|
||||
}
|
||||
memcpy(dest, br->next_in, num);
|
||||
br->avail_in -= num;
|
||||
br->next_in += num;
|
||||
BrotliBitReaderNormalize(br);
|
||||
if (num > 0) {
|
||||
memcpy(dest, br->next_in, num);
|
||||
BrotliDropBytes(br, num);
|
||||
}
|
||||
}
|
||||
|
||||
BROTLI_UNUSED_FUNCTION void BrotliBitReaderSuppressUnusedFunctions(void) {
|
||||
BROTLI_UNUSED(&BrotliBitReaderSuppressUnusedFunctions);
|
||||
|
||||
BROTLI_UNUSED(&BrotliBitReaderGetAvailIn);
|
||||
BROTLI_UNUSED(&BrotliBitReaderLoadBits);
|
||||
BROTLI_UNUSED(&BrotliBitReaderRestoreState);
|
||||
BROTLI_UNUSED(&BrotliBitReaderSaveState);
|
||||
BROTLI_UNUSED(&BrotliBitReaderSetInput);
|
||||
BROTLI_UNUSED(&BrotliBitReaderUnload);
|
||||
BROTLI_UNUSED(&BrotliCheckInputAmount);
|
||||
BROTLI_UNUSED(&BrotliCopyBytes);
|
||||
BROTLI_UNUSED(&BrotliFillBitWindow16);
|
||||
BROTLI_UNUSED(&BrotliGet16BitsUnmasked);
|
||||
BROTLI_UNUSED(&BrotliGetBits);
|
||||
BROTLI_UNUSED(&BrotliGetRemainingBytes);
|
||||
BROTLI_UNUSED(&BrotliJumpToByteBoundary);
|
||||
BROTLI_UNUSED(&BrotliReadBits24);
|
||||
BROTLI_UNUSED(&BrotliReadBits32);
|
||||
BROTLI_UNUSED(&BrotliSafeGetBits);
|
||||
BROTLI_UNUSED(&BrotliSafeReadBits);
|
||||
BROTLI_UNUSED(&BrotliSafeReadBits32);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
+645
-255
File diff suppressed because it is too large.
Load diff
@@ -6,13 +6,10 @@
|
||||
|
||||
/* Utilities for building Huffman decoding tables. */
|
||||
|
||||
#include "./huffman.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "huffman.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -25,7 +22,8 @@ extern "C" {
|
||||
((sizeof(brotli_reg_t) << 3) - BROTLI_REVERSE_BITS_MAX)
|
||||
#else
|
||||
#define BROTLI_REVERSE_BITS_BASE 0
|
||||
static uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
static BROTLI_MODEL("small")
|
||||
uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = {
|
||||
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
||||
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
||||
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
||||
@@ -117,11 +115,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 +132,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;
|
||||
});
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define BROTLI_DEC_HUFFMAN_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "prefix.h"
|
||||
|
||||
#include "../common/platform.h" /* IWYU pragma: keep */
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/constants.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
/* Embed kCmdLut. */
|
||||
#include "prefix_inc.h"
|
||||
#else
|
||||
BROTLI_COLD BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items) {
|
||||
static const uint8_t kInsertLengthExtraBits[24] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03,
|
||||
0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18};
|
||||
static const uint8_t kCopyLengthExtraBits[24] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02,
|
||||
0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18};
|
||||
static const uint8_t kCellPos[11] = {0, 1, 0, 1, 8, 9, 2, 16, 10, 17, 18};
|
||||
|
||||
uint16_t insert_length_offsets[24];
|
||||
uint16_t copy_length_offsets[24];
|
||||
insert_length_offsets[0] = 0;
|
||||
copy_length_offsets[0] = 2;
|
||||
for (size_t i = 0; i < 23; ++i) {
|
||||
insert_length_offsets[i + 1] =
|
||||
insert_length_offsets[i] + (uint16_t)(1u << kInsertLengthExtraBits[i]);
|
||||
copy_length_offsets[i + 1] =
|
||||
copy_length_offsets[i] + (uint16_t)(1u << kCopyLengthExtraBits[i]);
|
||||
}
|
||||
|
||||
for (size_t symbol = 0; symbol < BROTLI_NUM_COMMAND_SYMBOLS; ++symbol) {
|
||||
CmdLutElement* item = items + symbol;
|
||||
const size_t cell_idx = symbol >> 6;
|
||||
const size_t cell_pos = kCellPos[cell_idx];
|
||||
const size_t copy_code = ((cell_pos << 3) & 0x18) + (symbol & 0x7);
|
||||
const uint16_t copy_len_offset = copy_length_offsets[copy_code];
|
||||
const size_t insert_code = (cell_pos & 0x18) + ((symbol >> 3) & 0x7);
|
||||
item->copy_len_extra_bits = kCopyLengthExtraBits[copy_code];
|
||||
item->context = (copy_len_offset > 4) ? 3 : ((uint8_t)copy_len_offset - 2);
|
||||
item->copy_len_offset = copy_len_offset;
|
||||
item->distance_code = (cell_idx >= 2) ? -1 : 0;
|
||||
item->insert_len_extra_bits = kInsertLengthExtraBits[insert_code];
|
||||
item->insert_len_offset = insert_length_offsets[insert_code];
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
+18
-707
@@ -11,7 +11,12 @@
|
||||
#define BROTLI_DEC_PREFIX_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h" /* IWYU pragma: keep */
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct CmdLutElement {
|
||||
uint8_t insert_len_extra_bits;
|
||||
@@ -22,711 +27,17 @@ typedef struct CmdLutElement {
|
||||
uint16_t copy_len_offset;
|
||||
} CmdLutElement;
|
||||
|
||||
static const CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
|
||||
{ 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
|
||||
{ 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
|
||||
{ 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
|
||||
{ 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
|
||||
{ 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
|
||||
{ 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
|
||||
{ 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
|
||||
{ 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
|
||||
{ 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
|
||||
{ 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
|
||||
{ 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
|
||||
{ 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
|
||||
{ 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
|
||||
{ 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
|
||||
{ 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
|
||||
{ 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
|
||||
{ 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
|
||||
{ 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
|
||||
{ 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
|
||||
{ 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
|
||||
{ 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
|
||||
{ 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
|
||||
{ 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
|
||||
{ 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
|
||||
{ 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
|
||||
{ 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
|
||||
{ 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
|
||||
{ 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
|
||||
{ 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
|
||||
{ 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
|
||||
{ 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
|
||||
{ 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
|
||||
{ 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
|
||||
{ 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
|
||||
{ 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
|
||||
{ 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
|
||||
{ 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
|
||||
{ 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
|
||||
{ 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
|
||||
{ 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
|
||||
{ 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
|
||||
{ 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
|
||||
{ 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
|
||||
{ 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
|
||||
{ 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
|
||||
{ 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
|
||||
{ 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
|
||||
{ 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
|
||||
{ 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
|
||||
{ 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
|
||||
{ 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
|
||||
{ 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
|
||||
{ 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
|
||||
{ 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
|
||||
{ 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
|
||||
{ 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
|
||||
{ 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
|
||||
{ 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
|
||||
{ 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
|
||||
{ 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
|
||||
{ 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
|
||||
{ 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
|
||||
{ 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
|
||||
{ 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
|
||||
{ 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
|
||||
{ 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
|
||||
{ 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
|
||||
{ 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
|
||||
{ 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
|
||||
{ 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
|
||||
{ 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
|
||||
{ 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
|
||||
};
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#else
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items);
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* BROTLI_DEC_PREFIX_H_ */
|
||||
@@ -0,0 +1,707 @@
|
||||
const BROTLI_MODEL("small")
|
||||
CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
|
||||
{ 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
|
||||
{ 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
|
||||
{ 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
|
||||
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
|
||||
{ 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
|
||||
{ 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
|
||||
{ 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
|
||||
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
|
||||
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
|
||||
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
|
||||
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
|
||||
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
|
||||
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
|
||||
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
|
||||
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
|
||||
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
|
||||
{ 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
|
||||
{ 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
|
||||
{ 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
|
||||
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
|
||||
{ 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
|
||||
{ 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
|
||||
{ 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
|
||||
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
|
||||
{ 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
|
||||
{ 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
|
||||
{ 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
|
||||
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
|
||||
{ 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
|
||||
{ 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
|
||||
{ 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
|
||||
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
|
||||
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
|
||||
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
|
||||
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
|
||||
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
|
||||
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
|
||||
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
|
||||
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
|
||||
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
|
||||
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
|
||||
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
|
||||
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
|
||||
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
|
||||
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
|
||||
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
|
||||
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
|
||||
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
|
||||
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
|
||||
{ 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
|
||||
{ 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
|
||||
{ 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
|
||||
{ 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
|
||||
{ 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
|
||||
{ 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
|
||||
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
|
||||
{ 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
|
||||
{ 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
|
||||
{ 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
|
||||
{ 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
|
||||
{ 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
|
||||
{ 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
|
||||
{ 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
|
||||
{ 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
|
||||
{ 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
|
||||
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
|
||||
{ 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
|
||||
{ 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
|
||||
{ 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
|
||||
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
|
||||
{ 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
|
||||
{ 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
|
||||
{ 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
|
||||
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
|
||||
{ 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
|
||||
{ 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
|
||||
{ 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
|
||||
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
|
||||
{ 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
|
||||
{ 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
|
||||
{ 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
|
||||
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
|
||||
{ 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
|
||||
{ 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
|
||||
{ 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
|
||||
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
|
||||
{ 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
|
||||
{ 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
|
||||
{ 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
|
||||
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
|
||||
{ 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
|
||||
{ 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
|
||||
{ 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
|
||||
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
|
||||
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
|
||||
{ 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
|
||||
{ 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
|
||||
{ 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
|
||||
{ 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
|
||||
{ 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
|
||||
{ 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
|
||||
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
|
||||
{ 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
|
||||
{ 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
|
||||
{ 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
|
||||
{ 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
|
||||
{ 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
|
||||
{ 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
|
||||
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
|
||||
{ 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
|
||||
{ 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
|
||||
{ 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
|
||||
{ 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
|
||||
{ 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
|
||||
{ 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
|
||||
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
|
||||
{ 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
|
||||
{ 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
|
||||
{ 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
|
||||
{ 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
|
||||
{ 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
|
||||
{ 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
|
||||
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
|
||||
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
|
||||
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
|
||||
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
|
||||
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
|
||||
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
|
||||
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
|
||||
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
|
||||
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
|
||||
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
|
||||
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
|
||||
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
|
||||
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
|
||||
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
|
||||
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
|
||||
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
|
||||
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
|
||||
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
|
||||
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
|
||||
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
|
||||
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
|
||||
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
|
||||
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
|
||||
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
|
||||
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
|
||||
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
|
||||
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
|
||||
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
|
||||
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
|
||||
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
|
||||
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
|
||||
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
|
||||
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
|
||||
{ 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
|
||||
{ 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
|
||||
{ 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
|
||||
{ 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
|
||||
{ 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
|
||||
{ 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
|
||||
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
|
||||
{ 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
|
||||
{ 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
|
||||
{ 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
|
||||
{ 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
|
||||
{ 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
|
||||
{ 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
|
||||
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
|
||||
{ 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
|
||||
{ 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
|
||||
{ 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
|
||||
{ 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
|
||||
{ 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
|
||||
{ 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
|
||||
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
|
||||
{ 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
|
||||
{ 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
|
||||
{ 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
|
||||
{ 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
|
||||
{ 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
|
||||
{ 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
|
||||
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
|
||||
{ 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
|
||||
{ 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
|
||||
{ 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
|
||||
{ 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
|
||||
{ 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
|
||||
{ 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
|
||||
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
|
||||
{ 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
|
||||
{ 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
|
||||
{ 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
|
||||
{ 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
|
||||
{ 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
|
||||
{ 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
|
||||
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
|
||||
{ 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
|
||||
{ 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
|
||||
{ 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
|
||||
{ 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
|
||||
{ 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
|
||||
{ 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
|
||||
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
|
||||
{ 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
|
||||
{ 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
|
||||
{ 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
|
||||
{ 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
|
||||
{ 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
|
||||
{ 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
|
||||
};
|
||||
+40
-13
@@ -4,19 +4,34 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./state.h"
|
||||
#include "state.h"
|
||||
|
||||
#include <stdlib.h> /* free, malloc */
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "./huffman.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include "huffman.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef BROTLI_REPORTING
|
||||
/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */
|
||||
void BrotliDecoderOnStart(const BrotliDecoderState* s);
|
||||
void BrotliDecoderOnFinish(const BrotliDecoderState* s);
|
||||
#define BROTLI_DECODER_ON_START(s) BrotliDecoderOnStart(s);
|
||||
#define BROTLI_DECODER_ON_FINISH(s) BrotliDecoderOnFinish(s);
|
||||
#else
|
||||
#if !defined(BROTLI_DECODER_ON_START)
|
||||
#define BROTLI_DECODER_ON_START(s) (void)(s);
|
||||
#endif
|
||||
#if !defined(BROTLI_DECODER_ON_FINISH)
|
||||
#define BROTLI_DECODER_ON_FINISH(s) (void)(s);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
BROTLI_DECODER_ON_START(s);
|
||||
if (!alloc_func) {
|
||||
s->alloc_func = BrotliDefaultAllocFunc;
|
||||
s->free_func = BrotliDefaultFreeFunc;
|
||||
@@ -42,6 +57,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;
|
||||
@@ -81,17 +97,23 @@ BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
|
||||
|
||||
s->mtf_upper_bound = 63;
|
||||
|
||||
s->dictionary = BrotliGetDictionary();
|
||||
s->transforms = BrotliGetTransforms();
|
||||
s->compound_dictionary = NULL;
|
||||
s->dictionary =
|
||||
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;
|
||||
}
|
||||
|
||||
void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) {
|
||||
s->meta_block_remaining_len = 0;
|
||||
s->block_length[0] = 1U << 24;
|
||||
s->block_length[1] = 1U << 24;
|
||||
s->block_length[2] = 1U << 24;
|
||||
s->block_length[0] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->block_length[1] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->block_length[2] = BROTLI_BLOCK_SIZE_CAP;
|
||||
s->num_block_types[0] = 1;
|
||||
s->num_block_types[1] = 1;
|
||||
s->num_block_types[2] = 1;
|
||||
@@ -129,13 +151,18 @@ void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) {
|
||||
void BrotliDecoderStateCleanup(BrotliDecoderState* s) {
|
||||
BrotliDecoderStateCleanupAfterMetablock(s);
|
||||
|
||||
BROTLI_DECODER_ON_FINISH(s);
|
||||
|
||||
BROTLI_DECODER_FREE(s, s->compound_dictionary);
|
||||
BrotliSharedDictionaryDestroyInstance(s->dictionary);
|
||||
s->dictionary = NULL;
|
||||
BROTLI_DECODER_FREE(s, s->ringbuffer);
|
||||
BROTLI_DECODER_FREE(s, s->block_type_trees);
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||
HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees) {
|
||||
HuffmanTreeGroup* group, brotli_reg_t alphabet_size_max,
|
||||
brotli_reg_t alphabet_size_limit, brotli_reg_t ntrees) {
|
||||
/* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables)
|
||||
This number is discovered "unlimited" "enough" calculator; it is actually
|
||||
a wee bigger than required in several cases (especially for alphabets with
|
||||
@@ -150,7 +177,7 @@ BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s,
|
||||
group->alphabet_size_limit = (uint16_t)alphabet_size_limit;
|
||||
group->num_htrees = (uint16_t)ntrees;
|
||||
group->htrees = p;
|
||||
group->codes = (HuffmanCode*)(&p[ntrees]);
|
||||
group->codes = p ? (HuffmanCode*)(&p[ntrees]) : NULL;
|
||||
return !!p;
|
||||
}
|
||||
|
||||
|
||||
+68
-37
@@ -10,12 +10,11 @@
|
||||
#define BROTLI_DEC_STATE_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/transform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_reader.h"
|
||||
#include "./huffman.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include <brotli/decode.h>
|
||||
#include "bit_reader.h"
|
||||
#include "huffman.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -189,20 +188,34 @@ typedef enum {
|
||||
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
|
||||
} BrotliRunningReadBlockLengthState;
|
||||
|
||||
/* BrotliDecoderState addon, used for Compound Dictionary functionality. */
|
||||
typedef struct BrotliDecoderCompoundDictionary {
|
||||
int num_chunks;
|
||||
int total_size;
|
||||
int br_index;
|
||||
int br_offset;
|
||||
int br_length;
|
||||
int br_copied;
|
||||
const uint8_t* chunks[16];
|
||||
int chunk_offsets[16];
|
||||
int block_bits;
|
||||
uint8_t block_map[256];
|
||||
} BrotliDecoderCompoundDictionary;
|
||||
|
||||
typedef struct BrotliMetablockHeaderArena {
|
||||
BrotliRunningTreeGroupState substate_tree_group;
|
||||
BrotliRunningContextMapState substate_context_map;
|
||||
BrotliRunningHuffmanState substate_huffman;
|
||||
|
||||
uint32_t sub_loop_counter;
|
||||
brotli_reg_t sub_loop_counter;
|
||||
|
||||
uint32_t repeat_code_len;
|
||||
uint32_t prev_code_len;
|
||||
brotli_reg_t repeat_code_len;
|
||||
brotli_reg_t prev_code_len;
|
||||
|
||||
/* For ReadHuffmanCode. */
|
||||
uint32_t symbol;
|
||||
uint32_t repeat;
|
||||
uint32_t space;
|
||||
brotli_reg_t symbol;
|
||||
brotli_reg_t repeat;
|
||||
brotli_reg_t space;
|
||||
|
||||
/* Huffman table for "histograms". */
|
||||
HuffmanCode table[32];
|
||||
@@ -216,21 +229,22 @@ typedef struct BrotliMetablockHeaderArena {
|
||||
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
|
||||
/* Population counts for the code lengths. */
|
||||
uint16_t code_length_histo[16];
|
||||
/* TODO(eustas): +2 bytes padding */
|
||||
|
||||
/* For HuffmanTreeGroupDecode. */
|
||||
int htree_index;
|
||||
HuffmanCode* next;
|
||||
|
||||
/* For DecodeContextMap. */
|
||||
uint32_t context_index;
|
||||
uint32_t max_run_length_prefix;
|
||||
uint32_t code;
|
||||
brotli_reg_t context_index;
|
||||
brotli_reg_t max_run_length_prefix;
|
||||
brotli_reg_t code;
|
||||
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
|
||||
} BrotliMetablockHeaderArena;
|
||||
|
||||
typedef struct BrotliMetablockBodyArena {
|
||||
uint8_t dist_extra_bits[544];
|
||||
uint32_t dist_offset[544];
|
||||
brotli_reg_t dist_offset[544];
|
||||
} BrotliMetablockBodyArena;
|
||||
|
||||
struct BrotliDecoderStateStruct {
|
||||
@@ -251,7 +265,7 @@ struct BrotliDecoderStateStruct {
|
||||
uint64_t u64;
|
||||
uint8_t u8[8];
|
||||
} buffer;
|
||||
uint32_t buffer_length;
|
||||
brotli_reg_t buffer_length;
|
||||
|
||||
int pos;
|
||||
int max_backward_distance;
|
||||
@@ -261,6 +275,8 @@ struct BrotliDecoderStateStruct {
|
||||
int dist_rb_idx;
|
||||
int dist_rb[4];
|
||||
int error_code;
|
||||
int meta_block_remaining_len;
|
||||
|
||||
uint8_t* ringbuffer;
|
||||
uint8_t* ringbuffer_end;
|
||||
HuffmanCode* htree_command;
|
||||
@@ -281,54 +297,64 @@ struct BrotliDecoderStateStruct {
|
||||
/* Distance context is actual after command is decoded and before distance is
|
||||
computed. After distance computation it is used as a temporary variable. */
|
||||
int distance_context;
|
||||
int meta_block_remaining_len;
|
||||
uint32_t block_length_index;
|
||||
uint32_t block_length[3];
|
||||
uint32_t num_block_types[3];
|
||||
uint32_t block_type_rb[6];
|
||||
uint32_t distance_postfix_bits;
|
||||
uint32_t num_direct_distance_codes;
|
||||
uint32_t num_dist_htrees;
|
||||
brotli_reg_t block_length[3];
|
||||
brotli_reg_t block_length_index;
|
||||
brotli_reg_t num_block_types[3];
|
||||
brotli_reg_t block_type_rb[6];
|
||||
brotli_reg_t distance_postfix_bits;
|
||||
brotli_reg_t num_direct_distance_codes;
|
||||
brotli_reg_t num_dist_htrees;
|
||||
uint8_t* dist_context_map;
|
||||
HuffmanCode* literal_htree;
|
||||
uint8_t dist_htree_index;
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
||||
/* For partial write operations. */
|
||||
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
|
||||
size_t partial_pos_out; /* how much output to the user in total */
|
||||
|
||||
/* For InverseMoveToFrontTransform. */
|
||||
uint32_t mtf_upper_bound;
|
||||
brotli_reg_t mtf_upper_bound;
|
||||
uint32_t mtf[64 + 1];
|
||||
|
||||
int copy_length;
|
||||
int distance_code;
|
||||
|
||||
uint8_t dist_htree_index;
|
||||
/* TODO(eustas): +3 bytes padding */
|
||||
|
||||
/* 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;
|
||||
BrotliRunningDecodeUint8State substate_decode_uint8;
|
||||
BrotliRunningReadBlockLengthState substate_read_block_length;
|
||||
|
||||
int new_ringbuffer_size;
|
||||
/* TODO(eustas): +4 bytes padding */
|
||||
|
||||
unsigned int is_last_metablock : 1;
|
||||
unsigned int is_uncompressed : 1;
|
||||
unsigned int is_metadata : 1;
|
||||
unsigned int should_wrap_ringbuffer : 1;
|
||||
unsigned int canny_ringbuffer_allocation : 1;
|
||||
unsigned int large_window : 1;
|
||||
unsigned int window_bits : 6;
|
||||
unsigned int size_nibbles : 8;
|
||||
uint32_t window_bits;
|
||||
/* TODO(eustas): +12 bits padding */
|
||||
|
||||
int new_ringbuffer_size;
|
||||
|
||||
uint32_t num_literal_htrees;
|
||||
brotli_reg_t num_literal_htrees;
|
||||
uint8_t* context_map;
|
||||
uint8_t* context_modes;
|
||||
|
||||
const BrotliDictionary* dictionary;
|
||||
const BrotliTransforms* transforms;
|
||||
BrotliSharedDictionary* dictionary;
|
||||
BrotliDecoderCompoundDictionary* compound_dictionary;
|
||||
|
||||
uint32_t trivial_literal_contexts[8]; /* 256 bits */
|
||||
|
||||
@@ -348,8 +374,9 @@ BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
|
||||
BrotliDecoderState* s);
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
|
||||
uint32_t alphabet_size_limit, uint32_t ntrees);
|
||||
BrotliDecoderState* s, HuffmanTreeGroup* group,
|
||||
brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit,
|
||||
brotli_reg_t ntrees);
|
||||
|
||||
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
|
||||
|
||||
@@ -358,6 +385,10 @@ BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
|
||||
X = NULL; \
|
||||
}
|
||||
|
||||
/* Literal/Command/Distance block size maximum; same as maximum metablock size;
|
||||
used as block size when there is no block switching. */
|
||||
#define BROTLI_BLOCK_SIZE_CAP (1U << 24)
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "static_init.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#include "prefix.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
static BROTLI_BOOL DoBrotliDecoderStaticInit(void) {
|
||||
BROTLI_BOOL ok = BrotliDecoderInitCmdLut(kCmdLut);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_NONE */
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
static BROTLI_BOOL kEarlyInitOk;
|
||||
static __attribute__((constructor)) void BrotliDecoderStaticInitEarly(void) {
|
||||
kEarlyInitOk = DoBrotliDecoderStaticInit();
|
||||
}
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
static BROTLI_BOOL kLazyInitOk;
|
||||
void BrotliDecoderLazyStaticInitInner(void) {
|
||||
kLazyInitOk = DoBrotliDecoderStaticInit();
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_EARLY */
|
||||
|
||||
BROTLI_BOOL BrotliDecoderEnsureStaticInit(void) {
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
return BROTLI_TRUE;
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
return kEarlyInitOk;
|
||||
#else
|
||||
return kLazyInitOk;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Central point for static initialization. */
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
#define THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
BROTLI_INTERNAL void BrotliDecoderLazyStaticInitInner(void);
|
||||
BROTLI_INTERNAL void BrotliDecoderLazyStaticInit(void);
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderEnsureStaticInit(void);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_
|
||||
@@ -6,17 +6,17 @@
|
||||
|
||||
/* Function to find backward reference copies. */
|
||||
|
||||
#include "./backward_references.h"
|
||||
#include "backward_references.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./dictionary_hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "hash.h"
|
||||
#include "params.h"
|
||||
#include "quality.h" /* IWYU pragma: keep for inc */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -52,67 +52,133 @@ static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance,
|
||||
#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER()))
|
||||
|
||||
#define PREFIX() N
|
||||
#define ENABLE_COMPOUND_DICTIONARY 0
|
||||
|
||||
#define HASHER() H2
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H3
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H4
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H5
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H6
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H40
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H41
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H42
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H54
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H35
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H55
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H65
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./backward_references_inc.h"
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H68
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#undef ENABLE_COMPOUND_DICTIONARY
|
||||
#undef PREFIX
|
||||
#define PREFIX() D
|
||||
#define ENABLE_COMPOUND_DICTIONARY 1
|
||||
|
||||
#define HASHER() H3
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H4
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H5
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H6
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H40
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H41
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H42
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H55
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H65
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#define HASHER() H68
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "backward_references_inc.h"
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#undef ENABLE_COMPOUND_DICTIONARY
|
||||
#undef PREFIX
|
||||
|
||||
#undef EXPORT_FN
|
||||
@@ -125,6 +191,35 @@ void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
ContextLut literal_context_lut, const BrotliEncoderParams* params,
|
||||
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
|
||||
Command* commands, size_t* num_commands, size_t* num_literals) {
|
||||
if (params->dictionary.compound.num_chunks != 0) {
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
CreateBackwardReferencesDH ## N(num_bytes, \
|
||||
position, ringbuffer, ringbuffer_mask, \
|
||||
literal_context_lut, params, hasher, dist_cache, \
|
||||
last_insert_len, commands, num_commands, num_literals); \
|
||||
return;
|
||||
CASE_(3)
|
||||
CASE_(4)
|
||||
CASE_(5)
|
||||
CASE_(6)
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
CASE_(58)
|
||||
CASE_(68)
|
||||
#endif
|
||||
CASE_(40)
|
||||
CASE_(41)
|
||||
CASE_(42)
|
||||
CASE_(55)
|
||||
CASE_(65)
|
||||
#undef CASE_
|
||||
default:
|
||||
BROTLI_DCHECK(BROTLI_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
switch (params->hasher.type) {
|
||||
#define CASE_(N) \
|
||||
case N: \
|
||||
@@ -136,6 +231,7 @@ void BrotliCreateBackwardReferences(size_t num_bytes,
|
||||
FOR_GENERIC_HASHERS(CASE_)
|
||||
#undef CASE_
|
||||
default:
|
||||
BROTLI_DCHECK(BROTLI_FALSE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,14 +9,11 @@
|
||||
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -6,22 +6,22 @@
|
||||
|
||||
/* Function to find backward reference copies. */
|
||||
|
||||
#include "./backward_references_hq.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "backward_references_hq.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./literal_cost.h"
|
||||
#include "./memory.h"
|
||||
#include "./params.h"
|
||||
#include "./prefix.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash.h"
|
||||
#include "literal_cost.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "prefix.h"
|
||||
#include "quality.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -32,10 +32,10 @@ extern "C" {
|
||||
|
||||
static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */
|
||||
|
||||
static const uint32_t kDistanceCacheIndex[] = {
|
||||
static const BROTLI_MODEL("small") uint32_t kDistanceCacheIndex[] = {
|
||||
0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
|
||||
};
|
||||
static const int kDistanceCacheOffset[] = {
|
||||
static const BROTLI_MODEL("small") int kDistanceCacheOffset[] = {
|
||||
0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3
|
||||
};
|
||||
|
||||
@@ -73,6 +73,14 @@ static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) {
|
||||
return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF);
|
||||
}
|
||||
|
||||
/* Temporary data for ZopfliCostModelSetFromCommands. */
|
||||
typedef struct ZopfliCostModelArena {
|
||||
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
||||
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
} ZopfliCostModelArena;
|
||||
|
||||
/* Histogram based cost model for zopflification. */
|
||||
typedef struct ZopfliCostModel {
|
||||
/* The insert and copy length symbols. */
|
||||
@@ -83,6 +91,12 @@ typedef struct ZopfliCostModel {
|
||||
float* literal_costs_;
|
||||
float min_cost_cmd_;
|
||||
size_t num_bytes_;
|
||||
|
||||
/* Temporary data. */
|
||||
union {
|
||||
size_t literal_histograms[3 * 256];
|
||||
ZopfliCostModelArena arena;
|
||||
};
|
||||
} ZopfliCostModel;
|
||||
|
||||
static void InitZopfliCostModel(
|
||||
@@ -139,18 +153,15 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
const Command* commands,
|
||||
size_t num_commands,
|
||||
size_t last_insert_len) {
|
||||
uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE];
|
||||
float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
ZopfliCostModelArena* arena = &self->arena;
|
||||
size_t pos = position - last_insert_len;
|
||||
float min_cost_cmd = kInfinity;
|
||||
size_t i;
|
||||
float* cost_cmd = self->cost_cmd_;
|
||||
|
||||
memset(histogram_literal, 0, sizeof(histogram_literal));
|
||||
memset(histogram_cmd, 0, sizeof(histogram_cmd));
|
||||
memset(histogram_dist, 0, sizeof(histogram_dist));
|
||||
memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal));
|
||||
memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd));
|
||||
memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist));
|
||||
|
||||
for (i = 0; i < num_commands; i++) {
|
||||
size_t inslength = commands[i].insert_len_;
|
||||
@@ -159,21 +170,21 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
size_t cmdcode = commands[i].cmd_prefix_;
|
||||
size_t j;
|
||||
|
||||
histogram_cmd[cmdcode]++;
|
||||
if (cmdcode >= 128) histogram_dist[distcode]++;
|
||||
arena->histogram_cmd[cmdcode]++;
|
||||
if (cmdcode >= 128) arena->histogram_dist[distcode]++;
|
||||
|
||||
for (j = 0; j < inslength; j++) {
|
||||
histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
||||
arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++;
|
||||
}
|
||||
|
||||
pos += inslength + copylength;
|
||||
}
|
||||
|
||||
SetCost(histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
||||
cost_literal);
|
||||
SetCost(histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
||||
SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE,
|
||||
arena->cost_literal);
|
||||
SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE,
|
||||
cost_cmd);
|
||||
SetCost(histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||
SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE,
|
||||
self->cost_dist_);
|
||||
|
||||
for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) {
|
||||
@@ -188,7 +199,7 @@ static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self,
|
||||
literal_costs[0] = 0.0;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
literal_carry +=
|
||||
cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||
arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]];
|
||||
literal_costs[i + 1] = literal_costs[i] + literal_carry;
|
||||
literal_carry -= literal_costs[i + 1] - literal_costs[i];
|
||||
}
|
||||
@@ -206,7 +217,8 @@ static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self,
|
||||
size_t num_bytes = self->num_bytes_;
|
||||
size_t i;
|
||||
BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask,
|
||||
ringbuffer, &literal_costs[1]);
|
||||
ringbuffer, self->literal_histograms,
|
||||
&literal_costs[1]);
|
||||
literal_costs[0] = 0.0;
|
||||
for (i = 0; i < num_bytes; ++i) {
|
||||
literal_carry += literal_costs[i + 1];
|
||||
@@ -331,22 +343,22 @@ static uint32_t ComputeDistanceShortcut(const size_t block_start,
|
||||
const size_t max_backward_limit,
|
||||
const size_t gap,
|
||||
const ZopfliNode* nodes) {
|
||||
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
|
||||
const size_t ilen = nodes[pos].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t c_len = ZopfliNodeCopyLength(&nodes[pos]);
|
||||
const size_t i_len = nodes[pos].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]);
|
||||
/* Since |block_start + pos| is the end position of the command, the copy part
|
||||
starts from |block_start + pos - clen|. Distances that are greater than
|
||||
starts from |block_start + pos - c_len|. Distances that are greater than
|
||||
this or greater than |max_backward_limit| + |gap| are static dictionary
|
||||
references, and do not update the last distances.
|
||||
Also distance code 0 (last distance) does not update the last distances. */
|
||||
if (pos == 0) {
|
||||
return 0;
|
||||
} else if (dist + clen <= block_start + pos + gap &&
|
||||
} else if (dist + c_len <= block_start + pos + gap &&
|
||||
dist <= max_backward_limit + gap &&
|
||||
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
|
||||
return (uint32_t)pos;
|
||||
} else {
|
||||
return nodes[pos - clen - ilen].u.shortcut;
|
||||
return nodes[pos - c_len - i_len].u.shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,12 +376,12 @@ static void ComputeDistanceCache(const size_t pos,
|
||||
int idx = 0;
|
||||
size_t p = nodes[pos].u.shortcut;
|
||||
while (idx < 4 && p > 0) {
|
||||
const size_t ilen = nodes[p].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t clen = ZopfliNodeCopyLength(&nodes[p]);
|
||||
const size_t i_len = nodes[p].dcode_insert_length & 0x7FFFFFF;
|
||||
const size_t c_len = ZopfliNodeCopyLength(&nodes[p]);
|
||||
const size_t dist = ZopfliNodeCopyDistance(&nodes[p]);
|
||||
dist_cache[idx++] = (int)dist;
|
||||
/* Because of prerequisite, p >= clen + ilen >= 2. */
|
||||
p = nodes[p - clen - ilen].u.shortcut;
|
||||
/* Because of prerequisite, p >= c_len + i_len >= 2. */
|
||||
p = nodes[p - c_len - i_len].u.shortcut;
|
||||
}
|
||||
for (; idx < 4; ++idx) {
|
||||
dist_cache[idx] = *starting_dist_cache++;
|
||||
@@ -418,7 +430,10 @@ static size_t UpdateNodes(
|
||||
size_t min_len;
|
||||
size_t result = 0;
|
||||
size_t k;
|
||||
size_t gap = 0;
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_len <= ringbuffer_mask + 1);
|
||||
|
||||
EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap,
|
||||
starting_dist_cache, model, queue, nodes);
|
||||
@@ -472,6 +487,24 @@ static size_t UpdateNodes(
|
||||
len = FindMatchLengthWithLimit(&ringbuffer[prev_ix],
|
||||
&ringbuffer[cur_ix_masked],
|
||||
max_len);
|
||||
} else if (backward > dictionary_start) {
|
||||
size_t d = 0;
|
||||
size_t offset;
|
||||
size_t limit;
|
||||
const uint8_t* source;
|
||||
offset = dictionary_start + 1 + addon->total_size - 1;
|
||||
while (offset >= backward + addon->chunk_offsets[d + 1]) d++;
|
||||
source = addon->chunk_source[d];
|
||||
offset = offset - addon->chunk_offsets[d] - backward;
|
||||
limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset;
|
||||
limit = limit > max_len ? max_len : limit;
|
||||
if (best_len >= limit ||
|
||||
continuation != source[offset + best_len]) {
|
||||
continue;
|
||||
}
|
||||
len = FindMatchLengthWithLimit(&source[offset],
|
||||
&ringbuffer[cur_ix_masked],
|
||||
limit);
|
||||
} else {
|
||||
/* "Gray" area. It is addressable by decoder, but this encoder
|
||||
instance does not have that data -> should not touch it. */
|
||||
@@ -577,7 +610,7 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
|
||||
size_t pos = 0;
|
||||
uint32_t offset = nodes[0].u.next;
|
||||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t gap = params->dictionary.compound.total_size;
|
||||
for (i = 0; offset != BROTLI_UINT32_MAX; i++) {
|
||||
const ZopfliNode* next = &nodes[pos + offset];
|
||||
size_t copy_length = ZopfliNodeCopyLength(next);
|
||||
@@ -653,6 +686,23 @@ static size_t ZopfliIterate(size_t num_bytes, size_t position,
|
||||
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
||||
}
|
||||
|
||||
static void MergeMatches(BackwardMatch* dst,
|
||||
BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) {
|
||||
while (len1 > 0 && len2 > 0) {
|
||||
size_t l1 = BackwardMatchLength(src1);
|
||||
size_t l2 = BackwardMatchLength(src2);
|
||||
if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) {
|
||||
*dst++ = *src1++;
|
||||
len1--;
|
||||
} else {
|
||||
*dst++ = *src2++;
|
||||
len2--;
|
||||
}
|
||||
}
|
||||
while (len1-- > 0) *dst++ = *src1++;
|
||||
while (len2-- > 0) *dst++ = *src2++;
|
||||
}
|
||||
|
||||
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
|
||||
size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
|
||||
@@ -661,21 +711,26 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
const size_t stream_offset = params->stream_offset;
|
||||
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
|
||||
const size_t max_zopfli_len = MaxZopfliLen(params);
|
||||
ZopfliCostModel model;
|
||||
StartPosQueue queue;
|
||||
BackwardMatch matches[2 * (MAX_NUM_MATCHES_H10 + 64)];
|
||||
BackwardMatch* BROTLI_RESTRICT matches =
|
||||
BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64));
|
||||
const size_t store_end = num_bytes >= StoreLookaheadH10() ?
|
||||
position + num_bytes - StoreLookaheadH10() + 1 : position;
|
||||
size_t i;
|
||||
size_t gap = 0;
|
||||
size_t lz_matches_offset = 0;
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
size_t lz_matches_offset =
|
||||
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
||||
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) {
|
||||
return 0;
|
||||
}
|
||||
nodes[0].length = 0;
|
||||
nodes[0].u.cost = 0;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
ZopfliCostModelSetFromLiteralCosts(
|
||||
&model, position, ringbuffer, ringbuffer_mask);
|
||||
model, position, ringbuffer, ringbuffer_mask);
|
||||
InitStartPosQueue(&queue);
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) {
|
||||
const size_t pos = position + i;
|
||||
@@ -684,17 +739,35 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
pos + stream_offset, max_backward_limit);
|
||||
size_t skip;
|
||||
size_t num_matches;
|
||||
int dict_id = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
uint8_t p1 = pos >= 1 ?
|
||||
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
||||
uint8_t p2 = pos >= 2 ?
|
||||
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
num_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
|
||||
dictionary_start + gap, params, &matches[lz_matches_offset]);
|
||||
if (addon->num_chunks != 0) {
|
||||
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
||||
ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i,
|
||||
dictionary_start, params->dist.max_distance,
|
||||
&matches[lz_matches_offset - 64], 64);
|
||||
MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches,
|
||||
&matches[lz_matches_offset], num_matches);
|
||||
num_matches += cd_matches;
|
||||
}
|
||||
if (num_matches > 0 &&
|
||||
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
|
||||
matches[0] = matches[num_matches - 1];
|
||||
num_matches = 1;
|
||||
}
|
||||
skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask,
|
||||
params, max_backward_limit, dist_cache, num_matches, matches, &model,
|
||||
params, max_backward_limit, dist_cache, num_matches, matches, model,
|
||||
&queue, nodes);
|
||||
if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0;
|
||||
if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) {
|
||||
@@ -710,12 +783,14 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
|
||||
i++;
|
||||
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
|
||||
EvaluateNode(position + stream_offset, i, max_backward_limit, gap,
|
||||
dist_cache, &model, &queue, nodes);
|
||||
dist_cache, model, &queue, nodes);
|
||||
skip--;
|
||||
}
|
||||
}
|
||||
}
|
||||
CleanupZopfliCostModel(m, &model);
|
||||
CleanupZopfliCostModel(m, model);
|
||||
BROTLI_FREE(m, model);
|
||||
BROTLI_FREE(m, matches);
|
||||
return ComputeShortestPathFromNodes(num_bytes, nodes);
|
||||
}
|
||||
|
||||
@@ -753,14 +828,15 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t orig_last_insert_len;
|
||||
int orig_dist_cache[4];
|
||||
size_t orig_num_commands;
|
||||
ZopfliCostModel model;
|
||||
ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1);
|
||||
ZopfliNode* nodes;
|
||||
BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size);
|
||||
size_t gap = 0;
|
||||
size_t shadow_matches = 0;
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(num_matches) ||
|
||||
BROTLI_IS_NULL(matches)) {
|
||||
const CompoundDictionary* addon = ¶ms->dictionary.compound;
|
||||
size_t gap = addon->total_size;
|
||||
size_t shadow_matches =
|
||||
(addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) ||
|
||||
BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) {
|
||||
return;
|
||||
}
|
||||
for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) {
|
||||
@@ -772,15 +848,34 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
size_t num_found_matches;
|
||||
size_t cur_match_end;
|
||||
size_t j;
|
||||
int dict_id = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
uint8_t p1 = pos >= 1 ?
|
||||
ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0;
|
||||
uint8_t p2 = pos >= 2 ?
|
||||
ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
/* Ensure that we have enough free slots. */
|
||||
BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size,
|
||||
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
num_found_matches = FindAllMatchesH10(&hasher->privat._H10,
|
||||
¶ms->dictionary,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, pos, max_length,
|
||||
max_distance, dictionary_start + gap, params,
|
||||
&matches[cur_match_pos + shadow_matches]);
|
||||
if (addon->num_chunks != 0) {
|
||||
size_t cd_matches = LookupAllCompoundDictionaryMatches(addon,
|
||||
ringbuffer, ringbuffer_mask, pos, 3, max_length,
|
||||
dictionary_start, params->dist.max_distance,
|
||||
&matches[cur_match_pos + shadow_matches - 64], 64);
|
||||
MergeMatches(&matches[cur_match_pos],
|
||||
&matches[cur_match_pos + shadow_matches - 64], cd_matches,
|
||||
&matches[cur_match_pos + shadow_matches], num_found_matches);
|
||||
num_found_matches += cd_matches;
|
||||
}
|
||||
cur_match_end = cur_match_pos + num_found_matches;
|
||||
for (j = cur_match_pos; j + 1 < cur_match_end; ++j) {
|
||||
BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <=
|
||||
@@ -810,15 +905,15 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
orig_num_commands = *num_commands;
|
||||
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return;
|
||||
InitZopfliCostModel(m, &model, ¶ms->dist, num_bytes);
|
||||
InitZopfliCostModel(m, model, ¶ms->dist, num_bytes);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
for (i = 0; i < 2; i++) {
|
||||
BrotliInitZopfliNodes(nodes, num_bytes + 1);
|
||||
if (i == 0) {
|
||||
ZopfliCostModelSetFromLiteralCosts(
|
||||
&model, position, ringbuffer, ringbuffer_mask);
|
||||
model, position, ringbuffer, ringbuffer_mask);
|
||||
} else {
|
||||
ZopfliCostModelSetFromCommands(&model, position, ringbuffer,
|
||||
ZopfliCostModelSetFromCommands(model, position, ringbuffer,
|
||||
ringbuffer_mask, commands, *num_commands - orig_num_commands,
|
||||
orig_last_insert_len);
|
||||
}
|
||||
@@ -827,12 +922,13 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
|
||||
*last_insert_len = orig_last_insert_len;
|
||||
memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0]));
|
||||
*num_commands += ZopfliIterate(num_bytes, position, ringbuffer,
|
||||
ringbuffer_mask, params, gap, dist_cache, &model, num_matches, matches,
|
||||
ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches,
|
||||
nodes);
|
||||
BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
|
||||
last_insert_len, params, commands, num_literals);
|
||||
}
|
||||
CleanupZopfliCostModel(m, &model);
|
||||
CleanupZopfliCostModel(m, model);
|
||||
BROTLI_FREE(m, model);
|
||||
BROTLI_FREE(m, nodes);
|
||||
BROTLI_FREE(m, matches);
|
||||
BROTLI_FREE(m, num_matches);
|
||||
|
||||
@@ -9,15 +9,12 @@
|
||||
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./hash.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -28,13 +28,11 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
const size_t random_heuristics_window_size =
|
||||
LiteralSpreeLengthForSparseSearch(params);
|
||||
size_t apply_random_heuristics = position + random_heuristics_window_size;
|
||||
const size_t gap = 0;
|
||||
const size_t gap = params->dictionary.compound.total_size;
|
||||
|
||||
/* Minimum score to accept a backward reference. */
|
||||
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
|
||||
|
||||
BROTLI_UNUSED(literal_context_lut);
|
||||
|
||||
FN(PrepareDistanceCache)(privat, dist_cache);
|
||||
|
||||
while (position + FN(HashTypeLength)() < pos_end) {
|
||||
@@ -43,13 +41,29 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
size_t dictionary_start = BROTLI_MIN(size_t,
|
||||
position + position_offset, max_backward_limit);
|
||||
HasherSearchResult sr;
|
||||
int dict_id = 0;
|
||||
uint8_t p1 = 0;
|
||||
uint8_t p2 = 0;
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
p1 = position >= 1 ?
|
||||
ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0;
|
||||
p2 = position >= 2 ?
|
||||
ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0;
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
sr.len = 0;
|
||||
sr.len_code_delta = 0;
|
||||
sr.distance = 0;
|
||||
sr.score = kMinScore;
|
||||
FN(FindLongestMatch)(privat, ¶ms->dictionary,
|
||||
FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance, &sr);
|
||||
if (ENABLE_COMPOUND_DICTIONARY) {
|
||||
LookupCompoundDictionaryMatch(¶ms->dictionary.compound, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position, max_length,
|
||||
dictionary_start, params->dist.max_distance, &sr);
|
||||
}
|
||||
if (sr.score > kMinScore) {
|
||||
/* Found a match. Let's look for something even better ahead. */
|
||||
int delayed_backward_references_in_row = 0;
|
||||
@@ -65,11 +79,23 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
|
||||
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
|
||||
dictionary_start = BROTLI_MIN(size_t,
|
||||
position + 1 + position_offset, max_backward_limit);
|
||||
if (params->dictionary.contextual.context_based) {
|
||||
p2 = p1;
|
||||
p1 = ringbuffer[position & ringbuffer_mask];
|
||||
dict_id = params->dictionary.contextual.context_map[
|
||||
BROTLI_CONTEXT(p1, p2, literal_context_lut)];
|
||||
}
|
||||
FN(FindLongestMatch)(privat,
|
||||
¶ms->dictionary,
|
||||
params->dictionary.contextual.dict[dict_id],
|
||||
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
max_distance, dictionary_start + gap, params->dist.max_distance,
|
||||
&sr2);
|
||||
if (ENABLE_COMPOUND_DICTIONARY) {
|
||||
LookupCompoundDictionaryMatch(
|
||||
¶ms->dictionary.compound, ringbuffer,
|
||||
ringbuffer_mask, dist_cache, position + 1, max_length,
|
||||
dictionary_start, params->dist.max_distance, &sr2);
|
||||
}
|
||||
if (sr2.score >= sr.score + cost_diff_lazy) {
|
||||
/* Ok, let's just write one byte for now and start a match from the
|
||||
next byte. */
|
||||
|
||||
@@ -6,28 +6,53 @@
|
||||
|
||||
/* Functions to estimate the bit cost of Huffman trees. */
|
||||
|
||||
#include "./bit_cost.h"
|
||||
#include "bit_cost.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
double BrotliBitsEntropy(const uint32_t* population, size_t size) {
|
||||
size_t sum = 0;
|
||||
double retval = 0;
|
||||
const uint32_t* population_end = population + size;
|
||||
size_t p;
|
||||
if (size & 1) {
|
||||
goto odd_number_of_elements_left;
|
||||
}
|
||||
while (population < population_end) {
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
odd_number_of_elements_left:
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
}
|
||||
if (sum) retval += (double)sum * FastLog2(sum);
|
||||
|
||||
if (retval < (double)sum) {
|
||||
/* TODO(eustas): consider doing that per-symbol? */
|
||||
/* At least one bit per literal is needed. */
|
||||
retval = (double)sum;
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#include "bit_cost_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
||||
@@ -10,51 +10,20 @@
|
||||
#define BROTLI_ENC_BIT_COST_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "histogram.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE double ShannonEntropy(
|
||||
const uint32_t* population, size_t size, size_t* total) {
|
||||
size_t sum = 0;
|
||||
double retval = 0;
|
||||
const uint32_t* population_end = population + size;
|
||||
size_t p;
|
||||
if (size & 1) {
|
||||
goto odd_number_of_elements_left;
|
||||
}
|
||||
while (population < population_end) {
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
odd_number_of_elements_left:
|
||||
p = *population++;
|
||||
sum += p;
|
||||
retval -= (double)p * FastLog2(p);
|
||||
}
|
||||
if (sum) retval += (double)sum * FastLog2(sum);
|
||||
*total = sum;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE double BitsEntropy(
|
||||
const uint32_t* population, size_t size) {
|
||||
size_t sum;
|
||||
double retval = ShannonEntropy(population, size, &sum);
|
||||
if (retval < sum) {
|
||||
/* At least one bit per literal is needed. */
|
||||
retval = (double)sum;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
BROTLI_INTERNAL double BrotliPopulationCostLiteral(const HistogramLiteral*);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostCommand(const HistogramCommand*);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostDistance(const HistogramDistance*);
|
||||
BROTLI_INTERNAL double BrotliBitsEntropy(
|
||||
const uint32_t* population, size_t size);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostLiteral(
|
||||
const HistogramLiteral* histogram);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostCommand(
|
||||
const HistogramCommand* histogram);
|
||||
BROTLI_INTERNAL double BrotliPopulationCostDistance(
|
||||
const HistogramDistance* histogram);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -119,7 +119,7 @@ double FN(BrotliPopulationCost)(const HistogramType* histogram) {
|
||||
/* Add the estimated encoding cost of the code length code histogram. */
|
||||
bits += (double)(18 + 2 * max_depth);
|
||||
/* Add the entropy of the code length code histogram. */
|
||||
bits += BitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
|
||||
bits += BrotliBitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
|
||||
}
|
||||
return bits;
|
||||
}
|
||||
|
||||
@@ -6,18 +6,16 @@
|
||||
|
||||
/* Block split point selection utilities. */
|
||||
|
||||
#include "./block_splitter.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "block_splitter.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "./bit_cost.h"
|
||||
#include "./cluster.h"
|
||||
#include "./command.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "bit_cost.h"
|
||||
#include "cluster.h"
|
||||
#include "command.h"
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "quality.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -30,6 +28,7 @@ static const double kCommandBlockSwitchCost = 13.5;
|
||||
static const double kDistanceBlockSwitchCost = 14.6;
|
||||
static const size_t kLiteralStrideLength = 70;
|
||||
static const size_t kCommandStrideLength = 40;
|
||||
static const size_t kDistanceStrideLength = 40;
|
||||
static const size_t kSymbolsPerLiteralHistogram = 544;
|
||||
static const size_t kSymbolsPerCommandHistogram = 530;
|
||||
static const size_t kSymbolsPerDistanceHistogram = 544;
|
||||
@@ -89,19 +88,19 @@ static BROTLI_INLINE double BitCost(size_t count) {
|
||||
#define FN(X) X ## Literal
|
||||
#define DataType uint8_t
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef DataType
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#define DataType uint16_t
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_splitter_inc.h"
|
||||
#include "block_splitter_inc.h"
|
||||
#undef DataType
|
||||
#undef FN
|
||||
|
||||
@@ -119,6 +118,8 @@ void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) {
|
||||
BROTLI_FREE(m, self->lengths);
|
||||
}
|
||||
|
||||
/* Extracts literals, command distance and prefix codes, then applies
|
||||
* SplitByteVector to create partitioning. */
|
||||
void BrotliSplitBlock(MemoryManager* m,
|
||||
const Command* cmds,
|
||||
const size_t num_commands,
|
||||
@@ -136,7 +137,9 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
/* Create a continuous array of literals. */
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals);
|
||||
/* Create the block split on the array of literals.
|
||||
Literal histograms have alphabet size 256. */
|
||||
* Literal histograms can have alphabet size up to 256.
|
||||
* Though, to accommodate context modeling, less than half of maximum size
|
||||
* is allowed. */
|
||||
SplitByteVectorLiteral(
|
||||
m, literals, literals_count,
|
||||
kSymbolsPerLiteralHistogram, kMaxLiteralHistograms,
|
||||
@@ -144,6 +147,10 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
literal_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_FREE(m, literals);
|
||||
/* NB: this might be a good place for injecting extra splitting without
|
||||
* increasing encoder complexity; however, output partition would be less
|
||||
* optimal than one produced with forced splitting inside
|
||||
* SplitByteVector (FindBlocks / ClusterBlocks). */
|
||||
}
|
||||
|
||||
{
|
||||
@@ -161,7 +168,7 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
kCommandStrideLength, kCommandBlockSwitchCost, params,
|
||||
insert_and_copy_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
/* TODO: reuse for distances? */
|
||||
/* TODO(eustas): reuse for distances? */
|
||||
BROTLI_FREE(m, insert_and_copy_codes);
|
||||
}
|
||||
|
||||
@@ -181,13 +188,26 @@ void BrotliSplitBlock(MemoryManager* m,
|
||||
SplitByteVectorDistance(
|
||||
m, distance_prefixes, j,
|
||||
kSymbolsPerDistanceHistogram, kMaxCommandHistograms,
|
||||
kCommandStrideLength, kDistanceBlockSwitchCost, params,
|
||||
kDistanceStrideLength, kDistanceBlockSwitchCost, params,
|
||||
dist_split);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BROTLI_FREE(m, distance_prefixes);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BROTLI_TEST)
|
||||
size_t BrotliCountLiteralsForTest(const Command*, size_t);
|
||||
size_t BrotliCountLiteralsForTest(const Command* cmds, size_t num_commands) {
|
||||
return CountLiterals(cmds, num_commands);
|
||||
}
|
||||
void BrotliCopyLiteralsToByteArrayForTest(
|
||||
const Command*, size_t, const uint8_t*, size_t, size_t, uint8_t*);
|
||||
void BrotliCopyLiteralsToByteArrayForTest(const Command* cmds,
|
||||
size_t num_commands, const uint8_t* data, size_t offset, size_t mask,
|
||||
uint8_t* literals) {
|
||||
CopyLiteralsToByteArray(cmds, num_commands, data, offset, mask, literals);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -10,10 +10,8 @@
|
||||
#define BROTLI_ENC_BLOCK_SPLITTER_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "command.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -46,17 +46,17 @@ static void FN(RandomSample)(uint32_t* seed,
|
||||
static void FN(RefineEntropyCodes)(const DataType* data, size_t length,
|
||||
size_t stride,
|
||||
size_t num_histograms,
|
||||
HistogramType* histograms) {
|
||||
HistogramType* histograms,
|
||||
HistogramType* tmp) {
|
||||
size_t iters =
|
||||
kIterMulForRefining * length / stride + kMinItersForRefining;
|
||||
uint32_t seed = 7;
|
||||
size_t iter;
|
||||
iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms;
|
||||
for (iter = 0; iter < iters; ++iter) {
|
||||
HistogramType sample;
|
||||
FN(HistogramClear)(&sample);
|
||||
FN(RandomSample)(&seed, data, length, stride, &sample);
|
||||
FN(HistogramAddHistogram)(&histograms[iter % num_histograms], &sample);
|
||||
FN(HistogramClear)(tmp);
|
||||
FN(RandomSample)(&seed, data, length, stride, tmp);
|
||||
FN(HistogramAddHistogram)(&histograms[iter % num_histograms], tmp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,46 +71,58 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||
double* cost,
|
||||
uint8_t* switch_signal,
|
||||
uint8_t* block_id) {
|
||||
const size_t data_size = FN(HistogramDataSize)();
|
||||
const size_t bitmaplen = (num_histograms + 7) >> 3;
|
||||
const size_t alphabet_size = FN(HistogramDataSize)();
|
||||
const size_t bitmap_len = (num_histograms + 7) >> 3;
|
||||
size_t num_blocks = 1;
|
||||
size_t byte_ix;
|
||||
size_t i;
|
||||
size_t j;
|
||||
BROTLI_DCHECK(num_histograms <= 256);
|
||||
|
||||
/* Trivial case: single histogram -> single block type. */
|
||||
if (num_histograms <= 1) {
|
||||
for (i = 0; i < length; ++i) {
|
||||
block_id[i] = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
memset(insert_cost, 0, sizeof(insert_cost[0]) * data_size * num_histograms);
|
||||
|
||||
/* Fill bitcost for each symbol of all histograms.
|
||||
* Non-existing symbol cost: 2 + log2(total_count).
|
||||
* Regular symbol cost: -log2(symbol_count / total_count). */
|
||||
memset(insert_cost, 0,
|
||||
sizeof(insert_cost[0]) * alphabet_size * num_histograms);
|
||||
for (i = 0; i < num_histograms; ++i) {
|
||||
insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_);
|
||||
}
|
||||
for (i = data_size; i != 0;) {
|
||||
for (i = alphabet_size; i != 0;) {
|
||||
/* Reverse order to use the 0-th row as a temporary storage. */
|
||||
--i;
|
||||
for (j = 0; j < num_histograms; ++j) {
|
||||
insert_cost[i * num_histograms + j] =
|
||||
insert_cost[j] - BitCost(histograms[j].data_[i]);
|
||||
}
|
||||
}
|
||||
memset(cost, 0, sizeof(cost[0]) * num_histograms);
|
||||
memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmaplen);
|
||||
|
||||
/* After each iteration of this loop, cost[k] will contain the difference
|
||||
between the minimum cost of arriving at the current byte position using
|
||||
entropy code k, and the minimum cost of arriving at the current byte
|
||||
position. This difference is capped at the block switch cost, and if it
|
||||
reaches block switch cost, it means that when we trace back from the last
|
||||
position, we need to switch here. */
|
||||
for (i = 0; i < length; ++i) {
|
||||
const size_t byte_ix = i;
|
||||
size_t ix = byte_ix * bitmaplen;
|
||||
size_t insert_cost_ix = data[byte_ix] * num_histograms;
|
||||
memset(cost, 0, sizeof(cost[0]) * num_histograms);
|
||||
memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmap_len);
|
||||
for (byte_ix = 0; byte_ix < length; ++byte_ix) {
|
||||
size_t ix = byte_ix * bitmap_len;
|
||||
size_t symbol = data[byte_ix];
|
||||
size_t insert_cost_ix = symbol * num_histograms;
|
||||
double min_cost = 1e99;
|
||||
double block_switch_cost = block_switch_bitcost;
|
||||
static const size_t prologue_length = 2000;
|
||||
static const double multiplier = 0.07 / 2000;
|
||||
size_t k;
|
||||
for (k = 0; k < num_histograms; ++k) {
|
||||
/* We are coding the symbol in data[byte_ix] with entropy code k. */
|
||||
/* We are coding the symbol with entropy code k. */
|
||||
cost[k] += insert_cost[insert_cost_ix + k];
|
||||
if (cost[k] < min_cost) {
|
||||
min_cost = cost[k];
|
||||
@@ -118,28 +130,29 @@ static size_t FN(FindBlocks)(const DataType* data, const size_t length,
|
||||
}
|
||||
}
|
||||
/* More blocks for the beginning. */
|
||||
if (byte_ix < 2000) {
|
||||
block_switch_cost *= 0.77 + 0.07 * (double)byte_ix / 2000;
|
||||
if (byte_ix < prologue_length) {
|
||||
block_switch_cost *= 0.77 + multiplier * (double)byte_ix;
|
||||
}
|
||||
for (k = 0; k < num_histograms; ++k) {
|
||||
cost[k] -= min_cost;
|
||||
if (cost[k] >= block_switch_cost) {
|
||||
const uint8_t mask = (uint8_t)(1u << (k & 7));
|
||||
cost[k] = block_switch_cost;
|
||||
BROTLI_DCHECK((k >> 3) < bitmaplen);
|
||||
BROTLI_DCHECK((k >> 3) < bitmap_len);
|
||||
switch_signal[ix + (k >> 3)] |= mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte_ix = length - 1;
|
||||
{ /* Trace back from the last position and switch at the marked places. */
|
||||
size_t byte_ix = length - 1;
|
||||
size_t ix = byte_ix * bitmaplen;
|
||||
size_t ix = byte_ix * bitmap_len;
|
||||
uint8_t cur_id = block_id[byte_ix];
|
||||
while (byte_ix > 0) {
|
||||
const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
|
||||
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmaplen);
|
||||
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmap_len);
|
||||
--byte_ix;
|
||||
ix -= bitmaplen;
|
||||
ix -= bitmap_len;
|
||||
if (switch_signal[ix + (cur_id >> 3)] & mask) {
|
||||
if (cur_id != block_id[byte_ix]) {
|
||||
cur_id = block_id[byte_ix];
|
||||
@@ -185,13 +198,16 @@ static void FN(BuildBlockHistograms)(const DataType* data, const size_t length,
|
||||
}
|
||||
}
|
||||
|
||||
/* Given the initial partitioning build partitioning with limited number
|
||||
* of histograms (and block types). */
|
||||
static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
const DataType* data, const size_t length,
|
||||
const size_t num_blocks,
|
||||
uint8_t* block_ids,
|
||||
BlockSplit* split) {
|
||||
uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks);
|
||||
uint32_t* block_lengths = BROTLI_ALLOC(m, uint32_t, num_blocks);
|
||||
uint32_t* u32 =
|
||||
BROTLI_ALLOC(m, uint32_t, num_blocks + 4 * HISTOGRAMS_PER_BATCH);
|
||||
const size_t expected_num_clusters = CLUSTERS_PER_BATCH *
|
||||
(num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH;
|
||||
size_t all_histograms_size = 0;
|
||||
@@ -214,20 +230,29 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
|
||||
uint32_t* new_index;
|
||||
size_t i;
|
||||
uint32_t sizes[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t new_clusters[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const sizes =
|
||||
u32 ? (u32 + 0 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const new_clusters =
|
||||
u32 ? (u32 + 1 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const symbols =
|
||||
u32 ? (u32 + 2 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const remap =
|
||||
u32 ? (u32 + 3 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
uint32_t* BROTLI_RESTRICT const block_lengths =
|
||||
u32 ? (u32 + 4 * HISTOGRAMS_PER_BATCH) : NULL;
|
||||
/* TODO(eustas): move to arena? */
|
||||
HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 2);
|
||||
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
|
||||
BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
|
||||
BROTLI_IS_NULL(u32) || BROTLI_IS_NULL(all_histograms) ||
|
||||
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
|
||||
BROTLI_IS_NULL(pairs)) {
|
||||
BROTLI_IS_NULL(pairs) || BROTLI_IS_NULL(tmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
|
||||
memset(u32, 0, (num_blocks + 4 * HISTOGRAMS_PER_BATCH) * sizeof(uint32_t));
|
||||
|
||||
/* Calculate block lengths (convert repeating values -> series length). */
|
||||
{
|
||||
size_t block_idx = 0;
|
||||
for (i = 0; i < length; ++i) {
|
||||
@@ -240,6 +265,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
BROTLI_DCHECK(block_idx == num_blocks);
|
||||
}
|
||||
|
||||
/* Pre-cluster blocks (cluster batches). */
|
||||
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
|
||||
const size_t num_to_combine =
|
||||
BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
|
||||
@@ -247,8 +273,9 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
size_t j;
|
||||
for (j = 0; j < num_to_combine; ++j) {
|
||||
size_t k;
|
||||
size_t block_length = block_lengths[i + j];
|
||||
FN(HistogramClear)(&histograms[j]);
|
||||
for (k = 0; k < block_lengths[i + j]; ++k) {
|
||||
for (k = 0; k < block_length; ++k) {
|
||||
FN(HistogramAdd)(&histograms[j], data[pos++]);
|
||||
}
|
||||
histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
|
||||
@@ -257,7 +284,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
sizes[j] = 1;
|
||||
}
|
||||
num_new_clusters = FN(BrotliHistogramCombine)(
|
||||
histograms, sizes, symbols, new_clusters, pairs, num_to_combine,
|
||||
histograms, tmp, sizes, symbols, new_clusters, pairs, num_to_combine,
|
||||
num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs);
|
||||
BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms,
|
||||
all_histograms_capacity, all_histograms_size + num_new_clusters);
|
||||
@@ -278,6 +305,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
}
|
||||
BROTLI_FREE(m, histograms);
|
||||
|
||||
/* Final clustering. */
|
||||
max_num_pairs =
|
||||
BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters);
|
||||
if (pairs_capacity < max_num_pairs + 1) {
|
||||
@@ -285,19 +313,19 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
|
||||
}
|
||||
|
||||
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
clusters[i] = (uint32_t)i;
|
||||
}
|
||||
num_final_clusters = FN(BrotliHistogramCombine)(
|
||||
all_histograms, cluster_size, histogram_symbols, clusters, pairs,
|
||||
all_histograms, tmp, cluster_size, histogram_symbols, clusters, pairs,
|
||||
num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES,
|
||||
max_num_pairs);
|
||||
BROTLI_FREE(m, pairs);
|
||||
BROTLI_FREE(m, cluster_size);
|
||||
|
||||
/* Assign blocks to final histograms. */
|
||||
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
|
||||
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
|
||||
@@ -305,20 +333,21 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
{
|
||||
uint32_t next_index = 0;
|
||||
for (i = 0; i < num_blocks; ++i) {
|
||||
HistogramType histo;
|
||||
size_t j;
|
||||
uint32_t best_out;
|
||||
double best_bits;
|
||||
FN(HistogramClear)(&histo);
|
||||
FN(HistogramClear)(tmp);
|
||||
for (j = 0; j < block_lengths[i]; ++j) {
|
||||
FN(HistogramAdd)(&histo, data[pos++]);
|
||||
FN(HistogramAdd)(tmp, data[pos++]);
|
||||
}
|
||||
/* Among equally good histograms prefer last used. */
|
||||
/* TODO(eustas): should we give a block-switch discount here? */
|
||||
best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1];
|
||||
best_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&histo, &all_histograms[best_out]);
|
||||
best_bits = FN(BrotliHistogramBitCostDistance)(
|
||||
tmp, &all_histograms[best_out], tmp + 1);
|
||||
for (j = 0; j < num_final_clusters; ++j) {
|
||||
const double cur_bits = FN(BrotliHistogramBitCostDistance)(
|
||||
&histo, &all_histograms[clusters[j]]);
|
||||
tmp, &all_histograms[clusters[j]], tmp + 1);
|
||||
if (cur_bits < best_bits) {
|
||||
best_bits = cur_bits;
|
||||
best_out = clusters[j];
|
||||
@@ -330,6 +359,7 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_FREE(m, tmp);
|
||||
BROTLI_FREE(m, clusters);
|
||||
BROTLI_FREE(m, all_histograms);
|
||||
BROTLI_ENSURE_CAPACITY(
|
||||
@@ -337,6 +367,9 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
BROTLI_ENSURE_CAPACITY(
|
||||
m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
|
||||
/* Rewrite final assignment to block-split. There might be less blocks
|
||||
* than |num_blocks| due to clustering. */
|
||||
{
|
||||
uint32_t cur_length = 0;
|
||||
size_t block_idx = 0;
|
||||
@@ -357,28 +390,41 @@ static void FN(ClusterBlocks)(MemoryManager* m,
|
||||
split->num_types = (size_t)max_type + 1;
|
||||
}
|
||||
BROTLI_FREE(m, new_index);
|
||||
BROTLI_FREE(m, block_lengths);
|
||||
BROTLI_FREE(m, u32);
|
||||
BROTLI_FREE(m, histogram_symbols);
|
||||
}
|
||||
|
||||
/* Create BlockSplit (partitioning) given the limits, estimates and "effort"
|
||||
* parameters.
|
||||
*
|
||||
* NB: max_histograms is often less than number of histograms allowed by format;
|
||||
* this is done intentionally, to save some "space" for context-aware
|
||||
* clustering (here entropy is estimated for context-free symbols). */
|
||||
static void FN(SplitByteVector)(MemoryManager* m,
|
||||
const DataType* data, const size_t length,
|
||||
const size_t literals_per_histogram,
|
||||
const size_t symbols_per_histogram,
|
||||
const size_t max_histograms,
|
||||
const size_t sampling_stride_length,
|
||||
const double block_switch_cost,
|
||||
const BrotliEncoderParams* params,
|
||||
BlockSplit* split) {
|
||||
const size_t data_size = FN(HistogramDataSize)();
|
||||
size_t num_histograms = length / literals_per_histogram + 1;
|
||||
HistogramType* histograms;
|
||||
HistogramType* tmp;
|
||||
/* Calculate number of histograms; initial estimate is one histogram per
|
||||
* specified amount of symbols; however, this value is capped. */
|
||||
size_t num_histograms = length / symbols_per_histogram + 1;
|
||||
if (num_histograms > max_histograms) {
|
||||
num_histograms = max_histograms;
|
||||
}
|
||||
|
||||
/* Corner case: no input. */
|
||||
if (length == 0) {
|
||||
split->num_types = 1;
|
||||
return;
|
||||
} else if (length < kMinLengthForBlockSplitting) {
|
||||
}
|
||||
|
||||
if (length < kMinLengthForBlockSplitting) {
|
||||
BROTLI_ENSURE_CAPACITY(m, uint8_t,
|
||||
split->types, split->types_alloc_size, split->num_blocks + 1);
|
||||
BROTLI_ENSURE_CAPACITY(m, uint32_t,
|
||||
@@ -390,7 +436,8 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
split->num_blocks++;
|
||||
return;
|
||||
}
|
||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
|
||||
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms + 1);
|
||||
tmp = histograms + num_histograms;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
|
||||
/* Find good entropy codes. */
|
||||
FN(InitialEntropyCodes)(data, length,
|
||||
@@ -398,7 +445,7 @@ static void FN(SplitByteVector)(MemoryManager* m,
|
||||
num_histograms, histograms);
|
||||
FN(RefineEntropyCodes)(data, length,
|
||||
sampling_stride_length,
|
||||
num_histograms, histograms);
|
||||
num_histograms, histograms, tmp);
|
||||
{
|
||||
/* Find a good path through literals with the good entropy codes. */
|
||||
uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length);
|
||||
|
||||
@@ -8,20 +8,17 @@
|
||||
compression algorithms here, just the right ordering of bits to match the
|
||||
specs. */
|
||||
|
||||
#include "./brotli_bit_stream.h"
|
||||
|
||||
#include <string.h> /* memcpy, memset */
|
||||
#include "brotli_bit_stream.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./entropy_encode.h"
|
||||
#include "./entropy_encode_static.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "entropy_encode_static.h"
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -168,7 +165,8 @@ static void BrotliStoreUncompressedMetaBlockHeader(size_t length,
|
||||
static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
|
||||
const int num_codes, const uint8_t* code_length_bitdepth,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static const uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = {
|
||||
1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15
|
||||
};
|
||||
/* The bit lengths of the Huffman code over the code length alphabet
|
||||
@@ -181,10 +179,12 @@ static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(
|
||||
3 01
|
||||
4 10
|
||||
5 1111 */
|
||||
static const uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = {
|
||||
0, 7, 3, 2, 1, 15
|
||||
};
|
||||
static const uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = {
|
||||
2, 4, 3, 2, 2, 4
|
||||
};
|
||||
|
||||
@@ -286,6 +286,7 @@ void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
/* Write the Huffman tree into the brotli-representation.
|
||||
The command alphabet is the largest, so this allocation will fit all
|
||||
alphabets. */
|
||||
/* TODO(eustas): fix me */
|
||||
uint8_t huffman_tree[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t huffman_tree_extra_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
size_t huffman_tree_size = 0;
|
||||
@@ -400,7 +401,7 @@ static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree(
|
||||
return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_);
|
||||
}
|
||||
|
||||
void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
void BrotliBuildAndStoreHuffmanTreeFast(HuffmanTree* tree,
|
||||
const uint32_t* histogram,
|
||||
const size_t histogram_total,
|
||||
const size_t max_bits,
|
||||
@@ -432,10 +433,7 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
|
||||
memset(depth, 0, length * sizeof(depth[0]));
|
||||
{
|
||||
const size_t max_tree_size = 2 * length + 1;
|
||||
HuffmanTree* tree = BROTLI_ALLOC(m, HuffmanTree, max_tree_size);
|
||||
uint32_t count_limit;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
for (count_limit = 1; ; count_limit *= 2) {
|
||||
HuffmanTree* node = tree;
|
||||
size_t l;
|
||||
@@ -500,7 +498,6 @@ void BrotliBuildAndStoreHuffmanTreeFast(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
BROTLI_FREE(m, tree);
|
||||
}
|
||||
BrotliConvertBitDepthsToSymbols(depth, length, bits);
|
||||
if (count <= 4) {
|
||||
@@ -677,7 +674,14 @@ static void RunLengthCodeZeros(const size_t in_size,
|
||||
|
||||
#define SYMBOL_BITS 9
|
||||
|
||||
typedef struct EncodeContextMapArena {
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
} EncodeContextMapArena;
|
||||
|
||||
static void EncodeContextMap(MemoryManager* m,
|
||||
EncodeContextMapArena* arena,
|
||||
const uint32_t* context_map,
|
||||
size_t context_map_size,
|
||||
size_t num_clusters,
|
||||
@@ -687,10 +691,10 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
uint32_t* rle_symbols;
|
||||
uint32_t max_run_length_prefix = 6;
|
||||
size_t num_rle_symbols = 0;
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint32_t* BROTLI_RESTRICT const histogram = arena->histogram;
|
||||
static const uint32_t kSymbolMask = (1u << SYMBOL_BITS) - 1u;
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t* BROTLI_RESTRICT const depths = arena->depths;
|
||||
uint16_t* BROTLI_RESTRICT const bits = arena->bits;
|
||||
|
||||
StoreVarLenUint8(num_clusters - 1, storage_ix, storage);
|
||||
|
||||
@@ -703,7 +707,7 @@ static void EncodeContextMap(MemoryManager* m,
|
||||
MoveToFrontTransform(context_map, context_map_size, rle_symbols);
|
||||
RunLengthCodeZeros(context_map_size, rle_symbols,
|
||||
&num_rle_symbols, &max_run_length_prefix);
|
||||
memset(histogram, 0, sizeof(histogram));
|
||||
memset(histogram, 0, sizeof(arena->histogram));
|
||||
for (i = 0; i < num_rle_symbols; ++i) {
|
||||
++histogram[rle_symbols[i] & kSymbolMask];
|
||||
}
|
||||
@@ -774,7 +778,7 @@ static void BuildAndStoreBlockSplitCode(const uint8_t* types,
|
||||
++length_histo[BlockLengthPrefixCode(lengths[i])];
|
||||
}
|
||||
StoreVarLenUint8(num_types - 1, storage_ix, storage);
|
||||
if (num_types > 1) { /* TODO: else? could StoreBlockSwitch occur? */
|
||||
if (num_types > 1) { /* TODO(eustas): else? could StoreBlockSwitch occur? */
|
||||
BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, num_types + 2, tree,
|
||||
&code->type_depths[0], &code->type_bits[0],
|
||||
storage_ix, storage);
|
||||
@@ -787,7 +791,8 @@ static void BuildAndStoreBlockSplitCode(const uint8_t* types,
|
||||
}
|
||||
|
||||
/* Stores a context map where the histogram type is always the block type. */
|
||||
static void StoreTrivialContextMap(size_t num_types,
|
||||
static void StoreTrivialContextMap(EncodeContextMapArena* arena,
|
||||
size_t num_types,
|
||||
size_t context_bits,
|
||||
HuffmanTree* tree,
|
||||
size_t* storage_ix,
|
||||
@@ -797,9 +802,9 @@ static void StoreTrivialContextMap(size_t num_types,
|
||||
size_t repeat_code = context_bits - 1u;
|
||||
size_t repeat_bits = (1u << repeat_code) - 1u;
|
||||
size_t alphabet_size = num_types + repeat_code;
|
||||
uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS];
|
||||
uint32_t* BROTLI_RESTRICT const histogram = arena->histogram;
|
||||
uint8_t* BROTLI_RESTRICT const depths = arena->depths;
|
||||
uint16_t* BROTLI_RESTRICT const bits = arena->bits;
|
||||
size_t i;
|
||||
memset(histogram, 0, alphabet_size * sizeof(histogram[0]));
|
||||
/* Write RLEMAX. */
|
||||
@@ -914,17 +919,17 @@ static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol,
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
/* NOLINTNEXTLINE(build/include) */
|
||||
#include "./block_encoder_inc.h"
|
||||
#include "block_encoder_inc.h"
|
||||
#undef FN
|
||||
|
||||
static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||
@@ -932,6 +937,13 @@ static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) {
|
||||
storage[*storage_ix >> 3] = 0;
|
||||
}
|
||||
|
||||
typedef struct StoreMetablockArena {
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
EncodeContextMapArena context_map_arena;
|
||||
} StoreMetablockArena;
|
||||
|
||||
void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
|
||||
@@ -945,9 +957,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit;
|
||||
HuffmanTree* tree;
|
||||
ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
|
||||
BlockEncoder literal_enc;
|
||||
BlockEncoder command_enc;
|
||||
BlockEncoder distance_enc;
|
||||
StoreMetablockArena* arena = NULL;
|
||||
BlockEncoder* literal_enc = NULL;
|
||||
BlockEncoder* command_enc = NULL;
|
||||
BlockEncoder* distance_enc = NULL;
|
||||
const BrotliDistanceParams* dist = ¶ms->dist;
|
||||
BROTLI_DCHECK(
|
||||
num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS);
|
||||
@@ -955,21 +968,24 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
InitBlockEncoder(&literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
arena = BROTLI_ALLOC(m, StoreMetablockArena, 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree) || BROTLI_IS_NULL(arena)) return;
|
||||
literal_enc = &arena->literal_enc;
|
||||
command_enc = &arena->command_enc;
|
||||
distance_enc = &arena->distance_enc;
|
||||
InitBlockEncoder(literal_enc, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
mb->literal_split.num_types, mb->literal_split.types,
|
||||
mb->literal_split.lengths, mb->literal_split.num_blocks);
|
||||
InitBlockEncoder(&command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
InitBlockEncoder(command_enc, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
mb->command_split.num_types, mb->command_split.types,
|
||||
mb->command_split.lengths, mb->command_split.num_blocks);
|
||||
InitBlockEncoder(&distance_enc, num_effective_distance_symbols,
|
||||
InitBlockEncoder(distance_enc, num_effective_distance_symbols,
|
||||
mb->distance_split.num_types, mb->distance_split.types,
|
||||
mb->distance_split.lengths, mb->distance_split.num_blocks);
|
||||
|
||||
BuildAndStoreBlockSwitchEntropyCodes(&literal_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(&command_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(
|
||||
&distance_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage);
|
||||
BuildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage);
|
||||
|
||||
BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage);
|
||||
BrotliWriteBits(
|
||||
@@ -980,34 +996,36 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
}
|
||||
|
||||
if (mb->literal_context_map_size == 0) {
|
||||
StoreTrivialContextMap(mb->literal_histograms_size,
|
||||
StoreTrivialContextMap(
|
||||
&arena->context_map_arena, mb->literal_histograms_size,
|
||||
BROTLI_LITERAL_CONTEXT_BITS, tree, storage_ix, storage);
|
||||
} else {
|
||||
EncodeContextMap(m,
|
||||
EncodeContextMap(m, &arena->context_map_arena,
|
||||
mb->literal_context_map, mb->literal_context_map_size,
|
||||
mb->literal_histograms_size, tree, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
if (mb->distance_context_map_size == 0) {
|
||||
StoreTrivialContextMap(mb->distance_histograms_size,
|
||||
StoreTrivialContextMap(
|
||||
&arena->context_map_arena, mb->distance_histograms_size,
|
||||
BROTLI_DISTANCE_CONTEXT_BITS, tree, storage_ix, storage);
|
||||
} else {
|
||||
EncodeContextMap(m,
|
||||
EncodeContextMap(m, &arena->context_map_arena,
|
||||
mb->distance_context_map, mb->distance_context_map_size,
|
||||
mb->distance_histograms_size, tree, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
|
||||
BuildAndStoreEntropyCodesLiteral(m, &literal_enc, mb->literal_histograms,
|
||||
BuildAndStoreEntropyCodesLiteral(m, literal_enc, mb->literal_histograms,
|
||||
mb->literal_histograms_size, BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreEntropyCodesCommand(m, &command_enc, mb->command_histograms,
|
||||
BuildAndStoreEntropyCodesCommand(m, command_enc, mb->command_histograms,
|
||||
mb->command_histograms_size, BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreEntropyCodesDistance(m, &distance_enc, mb->distance_histograms,
|
||||
BuildAndStoreEntropyCodesDistance(m, distance_enc, mb->distance_histograms,
|
||||
mb->distance_histograms_size, num_distance_symbols, tree,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
@@ -1016,12 +1034,12 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
const Command cmd = commands[i];
|
||||
size_t cmd_code = cmd.cmd_prefix_;
|
||||
StoreSymbol(&command_enc, cmd_code, storage_ix, storage);
|
||||
StoreSymbol(command_enc, cmd_code, storage_ix, storage);
|
||||
StoreCommandExtra(&cmd, storage_ix, storage);
|
||||
if (mb->literal_context_map_size == 0) {
|
||||
size_t j;
|
||||
for (j = cmd.insert_len_; j != 0; --j) {
|
||||
StoreSymbol(&literal_enc, input[pos & mask], storage_ix, storage);
|
||||
StoreSymbol(literal_enc, input[pos & mask], storage_ix, storage);
|
||||
++pos;
|
||||
}
|
||||
} else {
|
||||
@@ -1030,7 +1048,7 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
size_t context =
|
||||
BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
|
||||
uint8_t literal = input[pos & mask];
|
||||
StoreSymbolWithContext(&literal_enc, literal, context,
|
||||
StoreSymbolWithContext(literal_enc, literal, context,
|
||||
mb->literal_context_map, storage_ix, storage,
|
||||
BROTLI_LITERAL_CONTEXT_BITS);
|
||||
prev_byte2 = prev_byte;
|
||||
@@ -1047,10 +1065,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
uint32_t distnumextra = cmd.dist_prefix_ >> 10;
|
||||
uint64_t distextra = cmd.dist_extra_;
|
||||
if (mb->distance_context_map_size == 0) {
|
||||
StoreSymbol(&distance_enc, dist_code, storage_ix, storage);
|
||||
StoreSymbol(distance_enc, dist_code, storage_ix, storage);
|
||||
} else {
|
||||
size_t context = CommandDistanceContext(&cmd);
|
||||
StoreSymbolWithContext(&distance_enc, dist_code, context,
|
||||
StoreSymbolWithContext(distance_enc, dist_code, context,
|
||||
mb->distance_context_map, storage_ix, storage,
|
||||
BROTLI_DISTANCE_CONTEXT_BITS);
|
||||
}
|
||||
@@ -1058,9 +1076,10 @@ void BrotliStoreMetaBlock(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
}
|
||||
CleanupBlockEncoder(m, &distance_enc);
|
||||
CleanupBlockEncoder(m, &command_enc);
|
||||
CleanupBlockEncoder(m, &literal_enc);
|
||||
CleanupBlockEncoder(m, distance_enc);
|
||||
CleanupBlockEncoder(m, command_enc);
|
||||
CleanupBlockEncoder(m, literal_enc);
|
||||
BROTLI_FREE(m, arena);
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1131,54 +1150,60 @@ static void StoreDataWithHuffmanCodes(const uint8_t* input,
|
||||
}
|
||||
}
|
||||
|
||||
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
/* TODO(eustas): pull alloc/dealloc to caller? */
|
||||
typedef struct MetablockArena {
|
||||
HistogramLiteral lit_histo;
|
||||
HistogramCommand cmd_histo;
|
||||
HistogramDistance dist_histo;
|
||||
/* TODO(eustas): merge bits and depth? */
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HuffmanTree* tree;
|
||||
HuffmanTree tree[MAX_HUFFMAN_TREE_SIZE];
|
||||
} MetablockArena;
|
||||
|
||||
void BrotliStoreMetaBlockTrivial(MemoryManager* m,
|
||||
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1);
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
HistogramClearLiteral(&lit_histo);
|
||||
HistogramClearCommand(&cmd_histo);
|
||||
HistogramClearDistance(&dist_histo);
|
||||
HistogramClearLiteral(&arena->lit_histo);
|
||||
HistogramClearCommand(&arena->cmd_histo);
|
||||
HistogramClearDistance(&arena->dist_histo);
|
||||
|
||||
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
||||
&lit_histo, &cmd_histo, &dist_histo);
|
||||
&arena->lit_histo, &arena->cmd_histo, &arena->dist_histo);
|
||||
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree)) return;
|
||||
BuildAndStoreHuffmanTree(lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, tree,
|
||||
lit_depth, lit_bits,
|
||||
BuildAndStoreHuffmanTree(arena->lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS,
|
||||
BROTLI_NUM_LITERAL_SYMBOLS, arena->tree,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
BuildAndStoreHuffmanTree(cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, tree,
|
||||
cmd_depth, cmd_bits,
|
||||
BuildAndStoreHuffmanTree(arena->cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
BROTLI_NUM_COMMAND_SYMBOLS, arena->tree,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
storage_ix, storage);
|
||||
BuildAndStoreHuffmanTree(dist_histo.data_, MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||
num_distance_symbols, tree,
|
||||
dist_depth, dist_bits,
|
||||
BuildAndStoreHuffmanTree(arena->dist_histo.data_,
|
||||
MAX_SIMPLE_DISTANCE_ALPHABET_SIZE,
|
||||
num_distance_symbols, arena->tree,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
BROTLI_FREE(m, tree);
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
cmd_depth, cmd_bits,
|
||||
dist_depth, dist_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
BROTLI_FREE(m, arena);
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1189,9 +1214,11 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
|
||||
const Command* commands, size_t n_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1);
|
||||
uint32_t num_distance_symbols = params->dist.alphabet_size_max;
|
||||
uint32_t distance_alphabet_bits =
|
||||
Log2FloorNonZero(num_distance_symbols - 1) + 1;
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
|
||||
|
||||
StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage);
|
||||
|
||||
@@ -1202,8 +1229,6 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
size_t pos = start_pos;
|
||||
size_t num_literals = 0;
|
||||
size_t i;
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
const Command cmd = commands[i];
|
||||
size_t j;
|
||||
@@ -1214,61 +1239,50 @@ void BrotliStoreMetaBlockFast(MemoryManager* m,
|
||||
num_literals += cmd.insert_len_;
|
||||
pos += CommandCopyLen(&cmd);
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, histogram, num_literals,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, histogram, num_literals,
|
||||
/* max_bits = */ 8,
|
||||
lit_depth, lit_bits,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
StoreStaticCommandHuffmanTree(storage_ix, storage);
|
||||
StoreStaticDistanceHuffmanTree(storage_ix, storage);
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
kStaticCommandCodeDepth,
|
||||
kStaticCommandCodeBits,
|
||||
kStaticDistanceCodeDepth,
|
||||
kStaticDistanceCodeBits,
|
||||
storage_ix, storage);
|
||||
} else {
|
||||
HistogramLiteral lit_histo;
|
||||
HistogramCommand cmd_histo;
|
||||
HistogramDistance dist_histo;
|
||||
uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE];
|
||||
HistogramClearLiteral(&lit_histo);
|
||||
HistogramClearCommand(&cmd_histo);
|
||||
HistogramClearDistance(&dist_histo);
|
||||
HistogramClearLiteral(&arena->lit_histo);
|
||||
HistogramClearCommand(&arena->cmd_histo);
|
||||
HistogramClearDistance(&arena->dist_histo);
|
||||
BuildHistograms(input, start_pos, mask, commands, n_commands,
|
||||
&lit_histo, &cmd_histo, &dist_histo);
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo.data_,
|
||||
lit_histo.total_count_,
|
||||
&arena->lit_histo, &arena->cmd_histo, &arena->dist_histo);
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->lit_histo.data_,
|
||||
arena->lit_histo.total_count_,
|
||||
/* max_bits = */ 8,
|
||||
lit_depth, lit_bits,
|
||||
arena->lit_depth, arena->lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, cmd_histo.data_,
|
||||
cmd_histo.total_count_,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->cmd_histo.data_,
|
||||
arena->cmd_histo.total_count_,
|
||||
/* max_bits = */ 10,
|
||||
cmd_depth, cmd_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, dist_histo.data_,
|
||||
dist_histo.total_count_,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->dist_histo.data_,
|
||||
arena->dist_histo.total_count_,
|
||||
/* max_bits = */
|
||||
distance_alphabet_bits,
|
||||
dist_depth, dist_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
StoreDataWithHuffmanCodes(input, start_pos, mask, commands,
|
||||
n_commands, lit_depth, lit_bits,
|
||||
cmd_depth, cmd_bits,
|
||||
dist_depth, dist_bits,
|
||||
n_commands, arena->lit_depth, arena->lit_bits,
|
||||
arena->cmd_depth, arena->cmd_bits,
|
||||
arena->dist_depth, arena->dist_bits,
|
||||
storage_ix, storage);
|
||||
}
|
||||
|
||||
BROTLI_FREE(m, arena);
|
||||
|
||||
if (is_last) {
|
||||
JumpToByteBoundary(storage_ix, storage);
|
||||
}
|
||||
@@ -1309,6 +1323,15 @@ void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block,
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BROTLI_TEST)
|
||||
void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra);
|
||||
void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code,
|
||||
uint32_t* n_extra, uint32_t* extra) {
|
||||
GetBlockLengthPrefixCode(len, code, n_extra, extra);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -18,11 +18,10 @@
|
||||
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./command.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./memory.h"
|
||||
#include "./metablock.h"
|
||||
#include "command.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "memory.h"
|
||||
#include "metablock.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -35,7 +34,7 @@ BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
|
||||
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage);
|
||||
|
||||
BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
|
||||
MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
|
||||
HuffmanTree* tree, const uint32_t* histogram, const size_t histogram_total,
|
||||
const size_t max_bits, uint8_t* depth, uint16_t* bits, size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
|
||||
|
||||
@@ -6,14 +6,13 @@
|
||||
|
||||
/* Functions for clustering similar histograms together. */
|
||||
|
||||
#include "./cluster.h"
|
||||
#include "cluster.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h" /* BrotliPopulationCost */
|
||||
#include "./fast_log.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "bit_cost.h" /* BrotliPopulationCost */
|
||||
#include "fast_log.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -38,15 +37,15 @@ static BROTLI_INLINE double ClusterCostDiff(size_t size_a, size_t size_b) {
|
||||
#define CODE(X) X
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#undef CODE
|
||||
|
||||
@@ -10,9 +10,8 @@
|
||||
#define BROTLI_ENC_CLUSTER_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -28,15 +27,15 @@ typedef struct HistogramPair {
|
||||
#define CODE(X) /* Declaration */;
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./cluster_inc.h" /* NOLINT(build/include) */
|
||||
#include "cluster_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#undef CODE
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
|
||||
it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
|
||||
BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
|
||||
uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
||||
const HistogramType* out, HistogramType* tmp, const uint32_t* cluster_size,
|
||||
uint32_t idx1, uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
|
||||
size_t* num_pairs) CODE({
|
||||
BROTLI_BOOL is_good_pair = BROTLI_FALSE;
|
||||
HistogramPair p;
|
||||
@@ -42,10 +42,10 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
} else {
|
||||
double threshold = *num_pairs == 0 ? 1e99 :
|
||||
BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
|
||||
HistogramType combo = out[idx1];
|
||||
double cost_combo;
|
||||
FN(HistogramAddHistogram)(&combo, &out[idx2]);
|
||||
cost_combo = FN(BrotliPopulationCost)(&combo);
|
||||
*tmp = out[idx1];
|
||||
FN(HistogramAddHistogram)(tmp, &out[idx2]);
|
||||
cost_combo = FN(BrotliPopulationCost)(tmp);
|
||||
if (cost_combo < threshold - p.cost_diff) {
|
||||
p.cost_combo = cost_combo;
|
||||
is_good_pair = BROTLI_TRUE;
|
||||
@@ -68,6 +68,7 @@ BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
|
||||
})
|
||||
|
||||
BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
HistogramType* tmp,
|
||||
uint32_t* cluster_size,
|
||||
uint32_t* symbols,
|
||||
uint32_t* clusters,
|
||||
@@ -87,7 +88,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
for (idx1 = 0; idx1 < num_clusters; ++idx1) {
|
||||
size_t idx2;
|
||||
for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
|
||||
FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
|
||||
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, clusters[idx1],
|
||||
clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
|
||||
}
|
||||
}
|
||||
@@ -146,8 +147,8 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
|
||||
/* Push new pairs formed with the combined histogram to the heap. */
|
||||
for (i = 0; i < num_clusters; ++i) {
|
||||
FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
|
||||
max_num_pairs, &pairs[0], &num_pairs);
|
||||
FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, best_idx1,
|
||||
clusters[i], max_num_pairs, &pairs[0], &num_pairs);
|
||||
}
|
||||
}
|
||||
return num_clusters;
|
||||
@@ -155,13 +156,14 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
|
||||
|
||||
/* What is the bit cost of moving histogram from cur_symbol to candidate. */
|
||||
BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
||||
const HistogramType* histogram, const HistogramType* candidate) CODE({
|
||||
const HistogramType* histogram, const HistogramType* candidate,
|
||||
HistogramType* tmp) CODE({
|
||||
if (histogram->total_count_ == 0) {
|
||||
return 0.0;
|
||||
} else {
|
||||
HistogramType tmp = *histogram;
|
||||
FN(HistogramAddHistogram)(&tmp, candidate);
|
||||
return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
|
||||
*tmp = *histogram;
|
||||
FN(HistogramAddHistogram)(tmp, candidate);
|
||||
return FN(BrotliPopulationCost)(tmp) - candidate->bit_cost_;
|
||||
}
|
||||
})
|
||||
|
||||
@@ -171,16 +173,16 @@ BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
|
||||
Note: we assume that out[]->bit_cost_ is already up-to-date. */
|
||||
BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
|
||||
size_t in_size, const uint32_t* clusters, size_t num_clusters,
|
||||
HistogramType* out, uint32_t* symbols) CODE({
|
||||
HistogramType* out, HistogramType* tmp, uint32_t* symbols) CODE({
|
||||
size_t i;
|
||||
for (i = 0; i < in_size; ++i) {
|
||||
uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
|
||||
double best_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out], tmp);
|
||||
size_t j;
|
||||
for (j = 0; j < num_clusters; ++j) {
|
||||
const double cur_bits =
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
|
||||
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]], tmp);
|
||||
if (cur_bits < best_bits) {
|
||||
best_bits = cur_bits;
|
||||
best_out = clusters[j];
|
||||
@@ -226,7 +228,7 @@ BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
|
||||
++next_index;
|
||||
}
|
||||
}
|
||||
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
|
||||
/* TODO(eustas): by using idea of "cycle-sort" we can avoid allocation of
|
||||
tmp and reduce the number of copying by the factor of 2. */
|
||||
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
|
||||
@@ -257,10 +259,12 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
|
||||
/* For the first pass of clustering, we allow all pairs. */
|
||||
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
|
||||
/* TODO(eustas): move to "persistent" arena? */
|
||||
HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 1);
|
||||
size_t i;
|
||||
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
|
||||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
|
||||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)|| BROTLI_IS_NULL(tmp)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -283,7 +287,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
clusters[num_clusters + j] = (uint32_t)(i + j);
|
||||
}
|
||||
num_new_clusters =
|
||||
FN(BrotliHistogramCombine)(out, cluster_size,
|
||||
FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
||||
&histogram_symbols[i],
|
||||
&clusters[num_clusters], pairs,
|
||||
num_to_combine, num_to_combine,
|
||||
@@ -301,7 +305,7 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
|
||||
/* Collapse similar histograms. */
|
||||
num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
|
||||
num_clusters = FN(BrotliHistogramCombine)(out, tmp, cluster_size,
|
||||
histogram_symbols, clusters,
|
||||
pairs, num_clusters, in_size,
|
||||
max_histograms, max_num_pairs);
|
||||
@@ -310,7 +314,8 @@ BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
|
||||
BROTLI_FREE(m, cluster_size);
|
||||
/* Find the optimal map from original histograms to the final ones. */
|
||||
FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
|
||||
out, histogram_symbols);
|
||||
out, tmp, histogram_symbols);
|
||||
BROTLI_FREE(m, tmp);
|
||||
BROTLI_FREE(m, clusters);
|
||||
/* Convert the context map to a canonical form. */
|
||||
*out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./command.h"
|
||||
#include "command.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -11,23 +11,22 @@
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./params.h"
|
||||
#include "./prefix.h"
|
||||
#include "fast_log.h"
|
||||
#include "params.h"
|
||||
#include "prefix.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const uint32_t
|
||||
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
|
||||
|
||||
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
|
||||
if (insertlen < 6) {
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "compound_dictionary.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "memory.h"
|
||||
|
||||
static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size, uint32_t bucket_bits,
|
||||
uint32_t slot_bits, uint32_t hash_bits, uint16_t bucket_limit) {
|
||||
/* Step 1: create "bloated" hasher. */
|
||||
uint32_t num_slots = 1u << slot_bits;
|
||||
uint32_t num_buckets = 1u << bucket_bits;
|
||||
uint32_t hash_shift = 64u - bucket_bits;
|
||||
uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
uint32_t slot_mask = num_slots - 1;
|
||||
size_t alloc_size = (sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint16_t) << bucket_bits) +
|
||||
(sizeof(uint32_t) << bucket_bits) +
|
||||
(sizeof(uint32_t) * source_size);
|
||||
uint8_t* flat = NULL;
|
||||
PreparedDictionary* result = NULL;
|
||||
uint16_t* num = NULL;
|
||||
uint32_t* bucket_heads = NULL;
|
||||
uint32_t* next_bucket = NULL;
|
||||
uint32_t* slot_offsets = NULL;
|
||||
uint16_t* heads = NULL;
|
||||
uint32_t* items = NULL;
|
||||
uint8_t** source_ref = NULL;
|
||||
uint32_t i;
|
||||
uint32_t* slot_size = NULL;
|
||||
uint32_t* slot_limit = NULL;
|
||||
uint32_t total_items = 0;
|
||||
if (slot_bits > 16) return NULL;
|
||||
if (slot_bits > bucket_bits) return NULL;
|
||||
if (bucket_bits - slot_bits >= 16) return NULL;
|
||||
|
||||
flat = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(flat)) return NULL;
|
||||
|
||||
slot_size = (uint32_t*)flat;
|
||||
slot_limit = (uint32_t*)(&slot_size[num_slots]);
|
||||
num = (uint16_t*)(&slot_limit[num_slots]);
|
||||
bucket_heads = (uint32_t*)(&num[num_buckets]);
|
||||
next_bucket = (uint32_t*)(&bucket_heads[num_buckets]);
|
||||
memset(num, 0, num_buckets * sizeof(num[0]));
|
||||
|
||||
/* TODO(eustas): apply custom "store" order. */
|
||||
for (i = 0; i + 7 < source_size; ++i) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(&source[i]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
uint16_t count = num[key];
|
||||
next_bucket[i] = (count == 0) ? ((uint32_t)(-1)) : bucket_heads[key];
|
||||
bucket_heads[key] = i;
|
||||
count++;
|
||||
if (count > bucket_limit) count = bucket_limit;
|
||||
num[key] = count;
|
||||
}
|
||||
|
||||
/* Step 2: find slot limits. */
|
||||
for (i = 0; i < num_slots; ++i) {
|
||||
BROTLI_BOOL overflow = BROTLI_FALSE;
|
||||
slot_limit[i] = bucket_limit;
|
||||
while (BROTLI_TRUE) {
|
||||
uint32_t limit = slot_limit[i];
|
||||
size_t j;
|
||||
uint32_t count = 0;
|
||||
overflow = BROTLI_FALSE;
|
||||
for (j = i; j < num_buckets; j += num_slots) {
|
||||
uint32_t size = num[j];
|
||||
/* Last chain may span behind 64K limit; overflow happens only if
|
||||
we are about to use 0xFFFF+ as item offset. */
|
||||
if (count >= 0xFFFF) {
|
||||
overflow = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
if (size > limit) size = limit;
|
||||
count += size;
|
||||
}
|
||||
if (!overflow) {
|
||||
slot_size[i] = count;
|
||||
total_items += count;
|
||||
break;
|
||||
}
|
||||
slot_limit[i]--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Step 3: transfer data to "slim" hasher. */
|
||||
alloc_size = sizeof(PreparedDictionary) + (sizeof(uint32_t) << slot_bits) +
|
||||
(sizeof(uint16_t) << bucket_bits) + (sizeof(uint32_t) * total_items) +
|
||||
sizeof(uint8_t*);
|
||||
|
||||
result = (PreparedDictionary*)BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(result)) {
|
||||
BROTLI_FREE(m, flat);
|
||||
return NULL;
|
||||
}
|
||||
slot_offsets = (uint32_t*)(&result[1]);
|
||||
heads = (uint16_t*)(&slot_offsets[num_slots]);
|
||||
items = (uint32_t*)(&heads[num_buckets]);
|
||||
source_ref = (uint8_t**)(&items[total_items]);
|
||||
|
||||
result->magic = kLeanPreparedDictionaryMagic;
|
||||
result->num_items = total_items;
|
||||
result->source_size = (uint32_t)source_size;
|
||||
result->hash_bits = hash_bits;
|
||||
result->bucket_bits = bucket_bits;
|
||||
result->slot_bits = slot_bits;
|
||||
BROTLI_UNALIGNED_STORE_PTR(source_ref, source);
|
||||
|
||||
total_items = 0;
|
||||
for (i = 0; i < num_slots; ++i) {
|
||||
slot_offsets[i] = total_items;
|
||||
total_items += slot_size[i];
|
||||
slot_size[i] = 0;
|
||||
}
|
||||
for (i = 0; i < num_buckets; ++i) {
|
||||
uint32_t slot = i & slot_mask;
|
||||
uint32_t count = num[i];
|
||||
uint32_t pos;
|
||||
size_t j;
|
||||
size_t cursor = slot_size[slot];
|
||||
if (count > slot_limit[slot]) count = slot_limit[slot];
|
||||
if (count == 0) {
|
||||
heads[i] = 0xFFFF;
|
||||
continue;
|
||||
}
|
||||
heads[i] = (uint16_t)cursor;
|
||||
cursor += slot_offsets[slot];
|
||||
slot_size[slot] += count;
|
||||
pos = bucket_heads[i];
|
||||
for (j = 0; j < count; j++) {
|
||||
items[cursor++] = pos;
|
||||
pos = next_bucket[pos];
|
||||
}
|
||||
items[cursor - 1] |= 0x80000000;
|
||||
}
|
||||
|
||||
BROTLI_FREE(m, flat);
|
||||
return result;
|
||||
}
|
||||
|
||||
PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size) {
|
||||
uint32_t bucket_bits = 17;
|
||||
uint32_t slot_bits = 7;
|
||||
uint32_t hash_bits = 40;
|
||||
uint16_t bucket_limit = 32;
|
||||
size_t volume = 16u << bucket_bits;
|
||||
/* Tune parameters to fit dictionary size. */
|
||||
while (volume < source_size && bucket_bits < 22) {
|
||||
bucket_bits++;
|
||||
slot_bits++;
|
||||
volume <<= 1;
|
||||
}
|
||||
return CreatePreparedDictionaryWithParams(m,
|
||||
source, source_size, bucket_bits, slot_bits, hash_bits, bucket_limit);
|
||||
}
|
||||
|
||||
void DestroyPreparedDictionary(MemoryManager* m,
|
||||
PreparedDictionary* dictionary) {
|
||||
if (!dictionary) return;
|
||||
BROTLI_FREE(m, dictionary);
|
||||
}
|
||||
|
||||
BROTLI_BOOL AttachPreparedDictionary(
|
||||
CompoundDictionary* compound, const PreparedDictionary* dictionary) {
|
||||
size_t length = 0;
|
||||
size_t index = 0;
|
||||
|
||||
if (compound->num_chunks == SHARED_BROTLI_MAX_COMPOUND_DICTS) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
if (!dictionary) return BROTLI_FALSE;
|
||||
|
||||
length = dictionary->source_size;
|
||||
index = compound->num_chunks;
|
||||
compound->total_size += length;
|
||||
compound->chunks[index] = dictionary;
|
||||
compound->chunk_offsets[index + 1] = compound->total_size;
|
||||
{
|
||||
uint32_t* slot_offsets = (uint32_t*)(&dictionary[1]);
|
||||
uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << dictionary->slot_bits]);
|
||||
uint32_t* items = (uint32_t*)(&heads[(size_t)1u << dictionary->bucket_bits]);
|
||||
const void* tail = (void*)&items[dictionary->num_items];
|
||||
if (dictionary->magic == kPreparedDictionaryMagic) {
|
||||
compound->chunk_source[index] = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* dictionary->magic == kLeanPreparedDictionaryMagic */
|
||||
compound->chunk_source[index] =
|
||||
(const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
}
|
||||
compound->num_chunks++;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2017 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#ifndef BROTLI_ENC_PREPARED_DICTIONARY_H_
|
||||
#define BROTLI_ENC_PREPARED_DICTIONARY_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "memory.h"
|
||||
|
||||
/* "Fat" prepared dictionary, could be cooked outside of C implementation,
|
||||
* e.g. on Java side. LZ77 data is copied inside PreparedDictionary struct. */
|
||||
static const uint32_t kPreparedDictionaryMagic = 0xDEBCEDE0;
|
||||
|
||||
static const uint32_t kSharedDictionaryMagic = 0xDEBCEDE1;
|
||||
|
||||
static const uint32_t kManagedDictionaryMagic = 0xDEBCEDE2;
|
||||
|
||||
/* "Lean" prepared dictionary. LZ77 data is referenced. It is the responsibility
|
||||
* of caller of "prepare dictionary" to keep the LZ77 data while prepared
|
||||
* dictionary is in use. */
|
||||
static const uint32_t kLeanPreparedDictionaryMagic = 0xDEBCEDE3;
|
||||
|
||||
static const uint64_t kPreparedDictionaryHashMul64Long =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
typedef struct PreparedDictionary {
|
||||
uint32_t magic;
|
||||
uint32_t num_items;
|
||||
uint32_t source_size;
|
||||
uint32_t hash_bits;
|
||||
uint32_t bucket_bits;
|
||||
uint32_t slot_bits;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* uint32_t slot_offsets[1 << slot_bits]; */
|
||||
/* uint16_t heads[1 << bucket_bits]; */
|
||||
/* uint32_t items[variable]; */
|
||||
|
||||
/* [maybe] uint8_t* source_ref, depending on magic. */
|
||||
/* [maybe] uint8_t source[source_size], depending on magic. */
|
||||
} PreparedDictionary;
|
||||
|
||||
BROTLI_INTERNAL PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
|
||||
const uint8_t* source, size_t source_size);
|
||||
|
||||
BROTLI_INTERNAL void DestroyPreparedDictionary(MemoryManager* m,
|
||||
PreparedDictionary* dictionary);
|
||||
|
||||
typedef struct CompoundDictionary {
|
||||
/* LZ77 prefix, compound dictionary */
|
||||
size_t num_chunks;
|
||||
size_t total_size;
|
||||
/* Client instances. */
|
||||
const PreparedDictionary* chunks[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
const uint8_t* chunk_source[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
size_t chunk_offsets[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
|
||||
size_t num_prepared_instances_;
|
||||
/* Owned instances. */
|
||||
PreparedDictionary* prepared_instances_[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1];
|
||||
} CompoundDictionary;
|
||||
|
||||
BROTLI_INTERNAL BROTLI_BOOL AttachPreparedDictionary(
|
||||
CompoundDictionary* compound, const PreparedDictionary* dictionary);
|
||||
|
||||
#endif /* BROTLI_ENC_PREPARED_DICTIONARY */
|
||||
@@ -12,19 +12,16 @@
|
||||
Adapted from the CompressFragment() function in
|
||||
https://github.com/google/snappy/blob/master/snappy.cc */
|
||||
|
||||
#include "./compress_fragment.h"
|
||||
|
||||
#include <string.h> /* memcmp, memcpy, memset */
|
||||
#include "compress_fragment.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./brotli_bit_stream.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "brotli_bit_stream.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -32,14 +29,6 @@ extern "C" {
|
||||
|
||||
#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32;
|
||||
return (uint32_t)(h >> shift);
|
||||
@@ -69,16 +58,18 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) {
|
||||
and thus have to assign a non-zero depth for each literal.
|
||||
Returns estimated compression ratio millibytes/char for encoding given input
|
||||
with generated code. */
|
||||
static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
static size_t BuildAndStoreLiteralPrefixCode(BrotliOnePassArena* s,
|
||||
const uint8_t* input,
|
||||
const size_t input_size,
|
||||
uint8_t depths[256],
|
||||
uint16_t bits[256],
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
uint32_t histogram[256] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const histogram = s->histogram;
|
||||
size_t histogram_total;
|
||||
size_t i;
|
||||
memset(histogram, 0, sizeof(s->histogram));
|
||||
|
||||
if (input_size < (1 << 15)) {
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
++histogram[input[i]];
|
||||
@@ -108,10 +99,9 @@ static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
histogram_total += adjust;
|
||||
}
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, histogram, histogram_total,
|
||||
BrotliBuildAndStoreHuffmanTreeFast(s->tree, histogram, histogram_total,
|
||||
/* max_bits = */ 8,
|
||||
depths, bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
{
|
||||
size_t literal_ratio = 0;
|
||||
for (i = 0; i < 256; ++i) {
|
||||
@@ -124,53 +114,56 @@ static size_t BuildAndStoreLiteralPrefixCode(MemoryManager* m,
|
||||
|
||||
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
||||
"bits" based on "histogram" and stores it into the bit stream. */
|
||||
static void BuildAndStoreCommandPrefixCode(const uint32_t histogram[128],
|
||||
uint8_t depth[128], uint16_t bits[128], size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
|
||||
HuffmanTree tree[129];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
|
||||
uint16_t cmd_bits[64];
|
||||
static void BuildAndStoreCommandPrefixCode(BrotliOnePassArena* s,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
const uint32_t* const histogram = s->cmd_histo;
|
||||
uint8_t* const depth = s->cmd_depth;
|
||||
uint16_t* const bits = s->cmd_bits;
|
||||
uint8_t* BROTLI_RESTRICT const tmp_depth = s->tmp_depth;
|
||||
uint16_t* BROTLI_RESTRICT const tmp_bits = s->tmp_bits;
|
||||
/* TODO(eustas): do only once on initialization. */
|
||||
memset(tmp_depth, 0, BROTLI_NUM_COMMAND_SYMBOLS);
|
||||
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, s->tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, s->tree, &depth[64]);
|
||||
/* We have to jump through a few hoops here in order to compute
|
||||
the command bits because the symbols are in a different order than in
|
||||
the full alphabet. This looks complicated, but having the symbols
|
||||
in this order in the command bits saves a few branches in the Emit*
|
||||
functions. */
|
||||
memcpy(cmd_depth, depth, 24);
|
||||
memcpy(cmd_depth + 24, depth + 40, 8);
|
||||
memcpy(cmd_depth + 32, depth + 24, 8);
|
||||
memcpy(cmd_depth + 40, depth + 48, 8);
|
||||
memcpy(cmd_depth + 48, depth + 32, 8);
|
||||
memcpy(cmd_depth + 56, depth + 56, 8);
|
||||
BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
|
||||
memcpy(bits, cmd_bits, 48);
|
||||
memcpy(bits + 24, cmd_bits + 32, 16);
|
||||
memcpy(bits + 32, cmd_bits + 48, 16);
|
||||
memcpy(bits + 40, cmd_bits + 24, 16);
|
||||
memcpy(bits + 48, cmd_bits + 40, 16);
|
||||
memcpy(bits + 56, cmd_bits + 56, 16);
|
||||
memcpy(tmp_depth, depth, 24);
|
||||
memcpy(tmp_depth + 24, depth + 40, 8);
|
||||
memcpy(tmp_depth + 32, depth + 24, 8);
|
||||
memcpy(tmp_depth + 40, depth + 48, 8);
|
||||
memcpy(tmp_depth + 48, depth + 32, 8);
|
||||
memcpy(tmp_depth + 56, depth + 56, 8);
|
||||
BrotliConvertBitDepthsToSymbols(tmp_depth, 64, tmp_bits);
|
||||
memcpy(bits, tmp_bits, 48);
|
||||
memcpy(bits + 24, tmp_bits + 32, 16);
|
||||
memcpy(bits + 32, tmp_bits + 48, 16);
|
||||
memcpy(bits + 40, tmp_bits + 24, 16);
|
||||
memcpy(bits + 48, tmp_bits + 40, 16);
|
||||
memcpy(bits + 56, tmp_bits + 56, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
|
||||
{
|
||||
/* Create the bit length array for the full command alphabet. */
|
||||
size_t i;
|
||||
memset(cmd_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(cmd_depth, depth, 8);
|
||||
memcpy(cmd_depth + 64, depth + 8, 8);
|
||||
memcpy(cmd_depth + 128, depth + 16, 8);
|
||||
memcpy(cmd_depth + 192, depth + 24, 8);
|
||||
memcpy(cmd_depth + 384, depth + 32, 8);
|
||||
memset(tmp_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(tmp_depth, depth, 8);
|
||||
memcpy(tmp_depth + 64, depth + 8, 8);
|
||||
memcpy(tmp_depth + 128, depth + 16, 8);
|
||||
memcpy(tmp_depth + 192, depth + 24, 8);
|
||||
memcpy(tmp_depth + 384, depth + 32, 8);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
cmd_depth[128 + 8 * i] = depth[40 + i];
|
||||
cmd_depth[256 + 8 * i] = depth[48 + i];
|
||||
cmd_depth[448 + 8 * i] = depth[56 + i];
|
||||
tmp_depth[128 + 8 * i] = depth[40 + i];
|
||||
tmp_depth[256 + 8 * i] = depth[48 + i];
|
||||
tmp_depth[448 + 8 * i] = depth[56 + i];
|
||||
}
|
||||
/* TODO(eustas): could/should full-length machinery be avoided? */
|
||||
BrotliStoreHuffmanTree(
|
||||
cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
|
||||
tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS, s->tree, storage_ix, storage);
|
||||
}
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, s->tree, storage_ix, storage);
|
||||
}
|
||||
|
||||
/* REQUIRES: insertlen < 6210 */
|
||||
@@ -369,11 +362,12 @@ static void RewindBitPosition(const size_t new_storage_ix,
|
||||
*storage_ix = new_storage_ix;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ShouldMergeBlock(
|
||||
static BROTLI_BOOL ShouldMergeBlock(BrotliOnePassArena* s,
|
||||
const uint8_t* data, size_t len, const uint8_t* depths) {
|
||||
size_t histo[256] = { 0 };
|
||||
uint32_t* BROTLI_RESTRICT const histo = s->histogram;
|
||||
static const size_t kSampleRate = 43;
|
||||
size_t i;
|
||||
memset(histo, 0, sizeof(s->histogram));
|
||||
for (i = 0; i < len; i += kSampleRate) {
|
||||
++histo[data[i]];
|
||||
}
|
||||
@@ -413,7 +407,7 @@ static void EmitUncompressedMetaBlock(const uint8_t* begin, const uint8_t* end,
|
||||
storage[*storage_ix >> 3] = 0;
|
||||
}
|
||||
|
||||
static uint32_t kCmdHistoSeed[128] = {
|
||||
static BROTLI_MODEL("small") uint32_t kCmdHistoSeed[128] = {
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
@@ -423,11 +417,14 @@ static uint32_t kCmdHistoSeed[128] = {
|
||||
};
|
||||
|
||||
static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_bits, uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_bits,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
uint32_t cmd_histo[128];
|
||||
uint8_t* BROTLI_RESTRICT const cmd_depth = s->cmd_depth;
|
||||
uint16_t* BROTLI_RESTRICT const cmd_bits = s->cmd_bits;
|
||||
uint32_t* BROTLI_RESTRICT const cmd_histo = s->cmd_histo;
|
||||
uint8_t* BROTLI_RESTRICT const lit_depth = s->lit_depth;
|
||||
uint16_t* BROTLI_RESTRICT const lit_bits = s->lit_bits;
|
||||
const uint8_t* ip_end;
|
||||
|
||||
/* "next_emit" is a pointer to the first byte that is not covered by a
|
||||
@@ -451,9 +448,6 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
we can update it later if we decide to extend this meta-block. */
|
||||
size_t mlen_storage_ix = *storage_ix + 3;
|
||||
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
size_t literal_ratio;
|
||||
|
||||
const uint8_t* ip;
|
||||
@@ -466,25 +460,24 @@ static BROTLI_INLINE void BrotliCompressFragmentFastImpl(
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
|
||||
literal_ratio = BuildAndStoreLiteralPrefixCode(
|
||||
m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
s, input, block_size, s->lit_depth, s->lit_bits, storage_ix, storage);
|
||||
|
||||
{
|
||||
/* Store the pre-compressed command and distance prefix codes. */
|
||||
size_t i;
|
||||
for (i = 0; i + 7 < *cmd_code_numbits; i += 8) {
|
||||
BrotliWriteBits(8, cmd_code[i >> 3], storage_ix, storage);
|
||||
for (i = 0; i + 7 < s->cmd_code_numbits; i += 8) {
|
||||
BrotliWriteBits(8, s->cmd_code[i >> 3], storage_ix, storage);
|
||||
}
|
||||
}
|
||||
BrotliWriteBits(*cmd_code_numbits & 7, cmd_code[*cmd_code_numbits >> 3],
|
||||
storage_ix, storage);
|
||||
BrotliWriteBits(s->cmd_code_numbits & 7,
|
||||
s->cmd_code[s->cmd_code_numbits >> 3], storage_ix, storage);
|
||||
|
||||
emit_commands:
|
||||
/* Initialize the command and distance histograms. We will gather
|
||||
statistics of command and distance codes during the processing
|
||||
of this block and use it to update the command and distance
|
||||
prefix codes for the next block. */
|
||||
memcpy(cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
|
||||
memcpy(s->cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed));
|
||||
|
||||
/* "ip" is the input pointer. */
|
||||
ip = input;
|
||||
@@ -565,6 +558,8 @@ trawl:
|
||||
int distance = (int)(base - candidate); /* > 0 */
|
||||
size_t insert = (size_t)(base - next_emit);
|
||||
ip += matched;
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n",
|
||||
(int)(next_emit - base_ip), (unsigned long)insert, 2));
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
||||
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
||||
@@ -593,6 +588,12 @@ trawl:
|
||||
}
|
||||
EmitCopyLenLastDistance(matched, cmd_depth, cmd_bits, cmd_histo,
|
||||
storage_ix, storage);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n"
|
||||
"[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), (int)distance,
|
||||
(int)(base - base_ip) + 2, 0, (int)matched - 2,
|
||||
(int)(base - base_ip) + 2, (int)distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -630,6 +631,10 @@ trawl:
|
||||
storage_ix, storage);
|
||||
EmitDistance((size_t)last_distance, cmd_depth, cmd_bits,
|
||||
cmd_histo, storage_ix, storage);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), 0, (int)matched,
|
||||
(int)(base - base_ip), (int)last_distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -667,7 +672,7 @@ trawl:
|
||||
last insert-only command. */
|
||||
if (input_size > 0 &&
|
||||
total_block_size + block_size <= (1 << 20) &&
|
||||
ShouldMergeBlock(input, block_size, lit_depth)) {
|
||||
ShouldMergeBlock(s, input, block_size, lit_depth)) {
|
||||
BROTLI_DCHECK(total_block_size > (1 << 16));
|
||||
/* Update the size of the current meta-block and continue emitting commands.
|
||||
We can do this because the current size and the new size both have 5
|
||||
@@ -680,6 +685,8 @@ trawl:
|
||||
/* Emit the remaining bytes as literals. */
|
||||
if (next_emit < ip_end) {
|
||||
const size_t insert = (size_t)(ip_end - next_emit);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n",
|
||||
(int)(next_emit - base_ip), (unsigned long)insert, 2));
|
||||
if (BROTLI_PREDICT_TRUE(insert < 6210)) {
|
||||
EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo,
|
||||
storage_ix, storage);
|
||||
@@ -711,20 +718,17 @@ next_block:
|
||||
/* No block splits, no contexts. */
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
literal_ratio = BuildAndStoreLiteralPrefixCode(
|
||||
m, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
|
||||
storage_ix, storage);
|
||||
s, input, block_size, lit_depth, lit_bits, storage_ix, storage);
|
||||
BuildAndStoreCommandPrefixCode(s, storage_ix, storage);
|
||||
goto emit_commands;
|
||||
}
|
||||
|
||||
if (!is_last) {
|
||||
/* If this is not the last block, update the command and distance prefix
|
||||
codes for the next block and store the compressed forms. */
|
||||
cmd_code[0] = 0;
|
||||
*cmd_code_numbits = 0;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depth, cmd_bits,
|
||||
cmd_code_numbits, cmd_code);
|
||||
s->cmd_code[0] = 0;
|
||||
s->cmd_code_numbits = 0;
|
||||
BuildAndStoreCommandPrefixCode(s, &s->cmd_code_numbits, s->cmd_code);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -732,20 +736,17 @@ next_block:
|
||||
|
||||
#define BAKE_METHOD_PARAM_(B) \
|
||||
static BROTLI_NOINLINE void BrotliCompressFragmentFastImpl ## B( \
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, int* table, uint8_t cmd_depth[128], \
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code, \
|
||||
size_t* storage_ix, uint8_t* storage) { \
|
||||
BrotliCompressFragmentFastImpl(m, input, input_size, is_last, table, B, \
|
||||
cmd_depth, cmd_bits, cmd_code_numbits, cmd_code, storage_ix, storage); \
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, int* table, size_t* storage_ix, uint8_t* storage) { \
|
||||
BrotliCompressFragmentFastImpl(s, input, input_size, is_last, table, B, \
|
||||
storage_ix, storage); \
|
||||
}
|
||||
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
||||
#undef BAKE_METHOD_PARAM_
|
||||
|
||||
void BrotliCompressFragmentFast(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_size, uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128], size_t* cmd_code_numbits, uint8_t* cmd_code,
|
||||
BrotliOnePassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, int* table, size_t table_size,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t initial_storage_ix = *storage_ix;
|
||||
const size_t table_bits = Log2FloorNonZero(table_size);
|
||||
@@ -762,8 +763,7 @@ void BrotliCompressFragmentFast(
|
||||
#define CASE_(B) \
|
||||
case B: \
|
||||
BrotliCompressFragmentFastImpl ## B( \
|
||||
m, input, input_size, is_last, table, cmd_depth, cmd_bits, \
|
||||
cmd_code_numbits, cmd_code, storage_ix, storage); \
|
||||
s, input, input_size, is_last, table, storage_ix, storage);\
|
||||
break;
|
||||
FOR_TABLE_BITS_(CASE_)
|
||||
#undef CASE_
|
||||
|
||||
@@ -12,14 +12,41 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct BrotliOnePassArena {
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
/* Command and distance prefix codes (each 64 symbols, stored back-to-back)
|
||||
used for the next block. The command prefix code is over a smaller alphabet
|
||||
with the following 64 symbols:
|
||||
0 - 15: insert length code 0, copy length code 0 - 15, same distance
|
||||
16 - 39: insert length code 0, copy length code 0 - 23
|
||||
40 - 63: insert length code 0 - 23, copy length code 0
|
||||
Note that symbols 16 and 40 represent the same code in the full alphabet,
|
||||
but we do not use either of them. */
|
||||
uint8_t cmd_depth[128];
|
||||
uint16_t cmd_bits[128];
|
||||
uint32_t cmd_histo[128];
|
||||
|
||||
/* The compressed form of the command and distance prefix codes for the next
|
||||
block. */
|
||||
uint8_t cmd_code[512];
|
||||
size_t cmd_code_numbits;
|
||||
|
||||
HuffmanTree tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1];
|
||||
uint32_t histogram[256];
|
||||
uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t tmp_bits[64];
|
||||
} BrotliOnePassArena;
|
||||
|
||||
/* Compresses "input" string to the "*storage" buffer as one or more complete
|
||||
meta-blocks, and updates the "*storage_ix" bit position.
|
||||
|
||||
@@ -42,15 +69,11 @@ extern "C" {
|
||||
REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
|
||||
OUTPUT: maximal copy distance <= |input_size|
|
||||
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentFast(MemoryManager* m,
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentFast(BrotliOnePassArena* s,
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
BROTLI_BOOL is_last,
|
||||
int* table, size_t table_size,
|
||||
uint8_t cmd_depth[128],
|
||||
uint16_t cmd_bits[128],
|
||||
size_t* cmd_code_numbits,
|
||||
uint8_t* cmd_code,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage);
|
||||
|
||||
|
||||
@@ -10,20 +10,17 @@
|
||||
second pass we emit them into the bit stream using prefix codes built based
|
||||
on the actual command and literal byte histograms. */
|
||||
|
||||
#include "./compress_fragment_two_pass.h"
|
||||
|
||||
#include <string.h> /* memcmp, memcpy, memset */
|
||||
#include "compress_fragment_two_pass.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h"
|
||||
#include "./brotli_bit_stream.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./write_bits.h"
|
||||
#include "bit_cost.h"
|
||||
#include "brotli_bit_stream.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -31,14 +28,6 @@ extern "C" {
|
||||
|
||||
#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18)
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* p,
|
||||
size_t shift, size_t length) {
|
||||
const uint64_t h =
|
||||
@@ -66,53 +55,53 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2,
|
||||
|
||||
/* Builds a command and distance prefix code (each 64 symbols) into "depth" and
|
||||
"bits" based on "histogram" and stores it into the bit stream. */
|
||||
static void BuildAndStoreCommandPrefixCode(
|
||||
const uint32_t histogram[128],
|
||||
uint8_t depth[128], uint16_t bits[128],
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static void BuildAndStoreCommandPrefixCode(BrotliTwoPassArena* s,
|
||||
size_t* storage_ix,
|
||||
uint8_t* storage) {
|
||||
/* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */
|
||||
HuffmanTree tree[129];
|
||||
uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS] = { 0 };
|
||||
uint16_t cmd_bits[64];
|
||||
BrotliCreateHuffmanTree(histogram, 64, 15, tree, depth);
|
||||
BrotliCreateHuffmanTree(&histogram[64], 64, 14, tree, &depth[64]);
|
||||
/* TODO(eustas): initialize once. */
|
||||
memset(s->tmp_depth, 0, sizeof(s->tmp_depth));
|
||||
BrotliCreateHuffmanTree(s->cmd_histo, 64, 15, s->tmp_tree, s->cmd_depth);
|
||||
BrotliCreateHuffmanTree(&s->cmd_histo[64], 64, 14, s->tmp_tree,
|
||||
&s->cmd_depth[64]);
|
||||
/* We have to jump through a few hoops here in order to compute
|
||||
the command bits because the symbols are in a different order than in
|
||||
the full alphabet. This looks complicated, but having the symbols
|
||||
in this order in the command bits saves a few branches in the Emit*
|
||||
functions. */
|
||||
memcpy(cmd_depth, depth + 24, 24);
|
||||
memcpy(cmd_depth + 24, depth, 8);
|
||||
memcpy(cmd_depth + 32, depth + 48, 8);
|
||||
memcpy(cmd_depth + 40, depth + 8, 8);
|
||||
memcpy(cmd_depth + 48, depth + 56, 8);
|
||||
memcpy(cmd_depth + 56, depth + 16, 8);
|
||||
BrotliConvertBitDepthsToSymbols(cmd_depth, 64, cmd_bits);
|
||||
memcpy(bits, cmd_bits + 24, 16);
|
||||
memcpy(bits + 8, cmd_bits + 40, 16);
|
||||
memcpy(bits + 16, cmd_bits + 56, 16);
|
||||
memcpy(bits + 24, cmd_bits, 48);
|
||||
memcpy(bits + 48, cmd_bits + 32, 16);
|
||||
memcpy(bits + 56, cmd_bits + 48, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]);
|
||||
memcpy(s->tmp_depth, s->cmd_depth + 24, 24);
|
||||
memcpy(s->tmp_depth + 24, s->cmd_depth, 8);
|
||||
memcpy(s->tmp_depth + 32, s->cmd_depth + 48, 8);
|
||||
memcpy(s->tmp_depth + 40, s->cmd_depth + 8, 8);
|
||||
memcpy(s->tmp_depth + 48, s->cmd_depth + 56, 8);
|
||||
memcpy(s->tmp_depth + 56, s->cmd_depth + 16, 8);
|
||||
BrotliConvertBitDepthsToSymbols(s->tmp_depth, 64, s->tmp_bits);
|
||||
memcpy(s->cmd_bits, s->tmp_bits + 24, 16);
|
||||
memcpy(s->cmd_bits + 8, s->tmp_bits + 40, 16);
|
||||
memcpy(s->cmd_bits + 16, s->tmp_bits + 56, 16);
|
||||
memcpy(s->cmd_bits + 24, s->tmp_bits, 48);
|
||||
memcpy(s->cmd_bits + 48, s->tmp_bits + 32, 16);
|
||||
memcpy(s->cmd_bits + 56, s->tmp_bits + 48, 16);
|
||||
BrotliConvertBitDepthsToSymbols(&s->cmd_depth[64], 64, &s->cmd_bits[64]);
|
||||
{
|
||||
/* Create the bit length array for the full command alphabet. */
|
||||
size_t i;
|
||||
memset(cmd_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(cmd_depth, depth + 24, 8);
|
||||
memcpy(cmd_depth + 64, depth + 32, 8);
|
||||
memcpy(cmd_depth + 128, depth + 40, 8);
|
||||
memcpy(cmd_depth + 192, depth + 48, 8);
|
||||
memcpy(cmd_depth + 384, depth + 56, 8);
|
||||
memset(s->tmp_depth, 0, 64); /* only 64 first values were used */
|
||||
memcpy(s->tmp_depth, s->cmd_depth + 24, 8);
|
||||
memcpy(s->tmp_depth + 64, s->cmd_depth + 32, 8);
|
||||
memcpy(s->tmp_depth + 128, s->cmd_depth + 40, 8);
|
||||
memcpy(s->tmp_depth + 192, s->cmd_depth + 48, 8);
|
||||
memcpy(s->tmp_depth + 384, s->cmd_depth + 56, 8);
|
||||
for (i = 0; i < 8; ++i) {
|
||||
cmd_depth[128 + 8 * i] = depth[i];
|
||||
cmd_depth[256 + 8 * i] = depth[8 + i];
|
||||
cmd_depth[448 + 8 * i] = depth[16 + i];
|
||||
s->tmp_depth[128 + 8 * i] = s->cmd_depth[i];
|
||||
s->tmp_depth[256 + 8 * i] = s->cmd_depth[8 + i];
|
||||
s->tmp_depth[448 + 8 * i] = s->cmd_depth[16 + i];
|
||||
}
|
||||
BrotliStoreHuffmanTree(
|
||||
cmd_depth, BROTLI_NUM_COMMAND_SYMBOLS, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(s->tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
s->tmp_tree, storage_ix, storage);
|
||||
}
|
||||
BrotliStoreHuffmanTree(&depth[64], 64, tree, storage_ix, storage);
|
||||
BrotliStoreHuffmanTree(&s->cmd_depth[64], 64, s->tmp_tree, storage_ix,
|
||||
storage);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void EmitInsertLen(
|
||||
@@ -330,6 +319,8 @@ trawl:
|
||||
ip += matched;
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
EmitInsertLen((uint32_t)insert, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n",
|
||||
(int)(next_emit - base_ip), insert, 2));
|
||||
memcpy(*literals, next_emit, (size_t)insert);
|
||||
*literals += insert;
|
||||
if (distance == last_distance) {
|
||||
@@ -340,6 +331,12 @@ trawl:
|
||||
last_distance = distance;
|
||||
}
|
||||
EmitCopyLenLastDistance(matched, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n"
|
||||
"[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), (int)distance,
|
||||
(int)(base - base_ip) + 2, 0, (int)matched - 2,
|
||||
(int)(base - base_ip) + 2, (int)distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -395,6 +392,10 @@ trawl:
|
||||
BROTLI_DCHECK(0 == memcmp(base, candidate, matched));
|
||||
EmitCopyLen(matched, commands);
|
||||
EmitDistance((uint32_t)last_distance, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n"
|
||||
"[CompressFragment] pos = %d distance = %d\n",
|
||||
(int)(base - base_ip), 0, (int)matched,
|
||||
(int)(base - base_ip), (int)last_distance));
|
||||
|
||||
next_emit = ip;
|
||||
if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) {
|
||||
@@ -447,70 +448,71 @@ emit_remainder:
|
||||
if (next_emit < ip_end) {
|
||||
const uint32_t insert = (uint32_t)(ip_end - next_emit);
|
||||
EmitInsertLen(insert, commands);
|
||||
BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n",
|
||||
(int)(next_emit - base_ip), insert, 2));
|
||||
memcpy(*literals, next_emit, insert);
|
||||
*literals += insert;
|
||||
}
|
||||
}
|
||||
|
||||
static void StoreCommands(MemoryManager* m,
|
||||
static void StoreCommands(BrotliTwoPassArena* s,
|
||||
const uint8_t* literals, const size_t num_literals,
|
||||
const uint32_t* commands, const size_t num_commands,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
static const uint32_t kNumExtraBits[128] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
static const BROTLI_MODEL("small") uint32_t kNumExtraBits[128] = {
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5,
|
||||
6, 7, 8, 9, 10, 12, 14, 24, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8,
|
||||
9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24,
|
||||
};
|
||||
static const uint32_t kInsertOffset[24] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, 34, 50, 66, 98, 130, 194, 322, 578,
|
||||
1090, 2114, 6210, 22594,
|
||||
static const BROTLI_MODEL("small") uint32_t kInsertOffset[24] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26,
|
||||
34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594,
|
||||
};
|
||||
|
||||
uint8_t lit_depths[256];
|
||||
uint16_t lit_bits[256];
|
||||
uint32_t lit_histo[256] = { 0 };
|
||||
uint8_t cmd_depths[128] = { 0 };
|
||||
uint16_t cmd_bits[128] = { 0 };
|
||||
uint32_t cmd_histo[128] = { 0 };
|
||||
size_t i;
|
||||
memset(s->lit_histo, 0, sizeof(s->lit_histo));
|
||||
/* TODO(eustas): is that necessary? */
|
||||
memset(s->cmd_depth, 0, sizeof(s->cmd_depth));
|
||||
/* TODO(eustas): is that necessary? */
|
||||
memset(s->cmd_bits, 0, sizeof(s->cmd_bits));
|
||||
memset(s->cmd_histo, 0, sizeof(s->cmd_histo));
|
||||
for (i = 0; i < num_literals; ++i) {
|
||||
++lit_histo[literals[i]];
|
||||
++s->lit_histo[literals[i]];
|
||||
}
|
||||
BrotliBuildAndStoreHuffmanTreeFast(m, lit_histo, num_literals,
|
||||
/* max_bits = */ 8,
|
||||
lit_depths, lit_bits,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
BrotliBuildAndStoreHuffmanTreeFast(s->tmp_tree, s->lit_histo, num_literals,
|
||||
/* max_bits = */ 8, s->lit_depth,
|
||||
s->lit_bits, storage_ix, storage);
|
||||
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const uint32_t code = commands[i] & 0xFF;
|
||||
BROTLI_DCHECK(code < 128);
|
||||
++cmd_histo[code];
|
||||
++s->cmd_histo[code];
|
||||
}
|
||||
cmd_histo[1] += 1;
|
||||
cmd_histo[2] += 1;
|
||||
cmd_histo[64] += 1;
|
||||
cmd_histo[84] += 1;
|
||||
BuildAndStoreCommandPrefixCode(cmd_histo, cmd_depths, cmd_bits,
|
||||
storage_ix, storage);
|
||||
s->cmd_histo[1] += 1;
|
||||
s->cmd_histo[2] += 1;
|
||||
s->cmd_histo[64] += 1;
|
||||
s->cmd_histo[84] += 1;
|
||||
BuildAndStoreCommandPrefixCode(s, storage_ix, storage);
|
||||
|
||||
for (i = 0; i < num_commands; ++i) {
|
||||
const uint32_t cmd = commands[i];
|
||||
const uint32_t code = cmd & 0xFF;
|
||||
const uint32_t extra = cmd >> 8;
|
||||
BROTLI_DCHECK(code < 128);
|
||||
BrotliWriteBits(cmd_depths[code], cmd_bits[code], storage_ix, storage);
|
||||
BrotliWriteBits(s->cmd_depth[code], s->cmd_bits[code], storage_ix, storage);
|
||||
BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage);
|
||||
if (code < 24) {
|
||||
const uint32_t insert = kInsertOffset[code] + extra;
|
||||
uint32_t j;
|
||||
for (j = 0; j < insert; ++j) {
|
||||
const uint8_t lit = *literals;
|
||||
BrotliWriteBits(lit_depths[lit], lit_bits[lit], storage_ix, storage);
|
||||
BrotliWriteBits(s->lit_depth[lit], s->lit_bits[lit], storage_ix,
|
||||
storage);
|
||||
++literals;
|
||||
}
|
||||
}
|
||||
@@ -521,19 +523,20 @@ static void StoreCommands(MemoryManager* m,
|
||||
#define MIN_RATIO 0.98
|
||||
#define SAMPLE_RATE 43
|
||||
|
||||
static BROTLI_BOOL ShouldCompress(
|
||||
static BROTLI_BOOL ShouldCompress(BrotliTwoPassArena* s,
|
||||
const uint8_t* input, size_t input_size, size_t num_literals) {
|
||||
double corpus_size = (double)input_size;
|
||||
if ((double)num_literals < MIN_RATIO * corpus_size) {
|
||||
return BROTLI_TRUE;
|
||||
} else {
|
||||
uint32_t literal_histo[256] = { 0 };
|
||||
const double max_total_bit_cost = corpus_size * 8 * MIN_RATIO / SAMPLE_RATE;
|
||||
size_t i;
|
||||
memset(s->lit_histo, 0, sizeof(s->lit_histo));
|
||||
for (i = 0; i < input_size; i += SAMPLE_RATE) {
|
||||
++literal_histo[input[i]];
|
||||
++s->lit_histo[input[i]];
|
||||
}
|
||||
return TO_BROTLI_BOOL(BitsEntropy(literal_histo, 256) < max_total_bit_cost);
|
||||
return TO_BROTLI_BOOL(
|
||||
BrotliBitsEntropy(s->lit_histo, 256) < max_total_bit_cost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -555,7 +558,7 @@ static void EmitUncompressedMetaBlock(const uint8_t* input, size_t input_size,
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
||||
int* table, size_t table_bits, size_t min_match,
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
@@ -573,14 +576,13 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
CreateCommands(input, block_size, input_size, base_ip, table,
|
||||
table_bits, min_match, &literals, &commands);
|
||||
num_literals = (size_t)(literals - literal_buf);
|
||||
if (ShouldCompress(input, block_size, num_literals)) {
|
||||
if (ShouldCompress(s, input, block_size, num_literals)) {
|
||||
const size_t num_commands = (size_t)(commands - command_buf);
|
||||
BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage);
|
||||
/* No block splits, no contexts. */
|
||||
BrotliWriteBits(13, 0, storage_ix, storage);
|
||||
StoreCommands(m, literal_buf, num_literals, command_buf, num_commands,
|
||||
StoreCommands(s, literal_buf, num_literals, command_buf, num_commands,
|
||||
storage_ix, storage);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
} else {
|
||||
/* Since we did not find many backward references and the entropy of
|
||||
the data is close to 8 bits, we can simply emit an uncompressed block.
|
||||
@@ -597,18 +599,18 @@ static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl(
|
||||
|
||||
#define BAKE_METHOD_PARAM_(B) \
|
||||
static BROTLI_NOINLINE void BrotliCompressFragmentTwoPassImpl ## B( \
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size, \
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size, \
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \
|
||||
int* table, size_t* storage_ix, uint8_t* storage) { \
|
||||
size_t min_match = (B <= 15) ? 4 : 6; \
|
||||
BrotliCompressFragmentTwoPassImpl(m, input, input_size, is_last, command_buf,\
|
||||
BrotliCompressFragmentTwoPassImpl(s, input, input_size, is_last, command_buf,\
|
||||
literal_buf, table, B, min_match, storage_ix, storage); \
|
||||
}
|
||||
FOR_TABLE_BITS_(BAKE_METHOD_PARAM_)
|
||||
#undef BAKE_METHOD_PARAM_
|
||||
|
||||
void BrotliCompressFragmentTwoPass(
|
||||
MemoryManager* m, const uint8_t* input, size_t input_size,
|
||||
BrotliTwoPassArena* s, const uint8_t* input, size_t input_size,
|
||||
BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf,
|
||||
int* table, size_t table_size, size_t* storage_ix, uint8_t* storage) {
|
||||
const size_t initial_storage_ix = *storage_ix;
|
||||
@@ -617,7 +619,7 @@ void BrotliCompressFragmentTwoPass(
|
||||
#define CASE_(B) \
|
||||
case B: \
|
||||
BrotliCompressFragmentTwoPassImpl ## B( \
|
||||
m, input, input_size, is_last, command_buf, \
|
||||
s, input, input_size, is_last, command_buf, \
|
||||
literal_buf, table, storage_ix, storage); \
|
||||
break;
|
||||
FOR_TABLE_BITS_(CASE_)
|
||||
|
||||
@@ -13,16 +13,32 @@
|
||||
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* TODO(eustas): turn to macro. */
|
||||
static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
|
||||
|
||||
typedef struct BrotliTwoPassArena {
|
||||
uint32_t lit_histo[256];
|
||||
uint8_t lit_depth[256];
|
||||
uint16_t lit_bits[256];
|
||||
|
||||
uint32_t cmd_histo[128];
|
||||
uint8_t cmd_depth[128];
|
||||
uint16_t cmd_bits[128];
|
||||
|
||||
/* BuildAndStoreCommandPrefixCode */
|
||||
HuffmanTree tmp_tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1];
|
||||
uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS];
|
||||
uint16_t tmp_bits[64];
|
||||
} BrotliTwoPassArena;
|
||||
|
||||
/* Compresses "input" string to the "*storage" buffer as one or more complete
|
||||
meta-blocks, and updates the "*storage_ix" bit position.
|
||||
|
||||
@@ -36,7 +52,7 @@ static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
|
||||
REQUIRES: "table_size" is a power of two
|
||||
OUTPUT: maximal copy distance <= |input_size|
|
||||
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(MemoryManager* m,
|
||||
BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(BrotliTwoPassArena* s,
|
||||
const uint8_t* input,
|
||||
size_t input_size,
|
||||
BROTLI_BOOL is_last,
|
||||
|
||||
+128
-1829
File diff suppressed because it is too large.
Load diff
@@ -9,14 +9,34 @@
|
||||
#ifndef BROTLI_ENC_DICTIONARY_HASH_H_
|
||||
#define BROTLI_ENC_DICTIONARY_HASH_H_
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern const uint16_t kStaticDictionaryHashWords[32768];
|
||||
extern const uint8_t kStaticDictionaryHashLengths[32768];
|
||||
/* Bucket is (Hash14 * 2 + length_lt_8); in other words we reserve 2 buckets
|
||||
for each hash - one for shorter words and one for longer words. */
|
||||
#define BROTLI_ENC_NUM_HASH_BUCKETS 32768
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
BROTLI_BOOL BROTLI_INTERNAL BrotliEncoderInitDictionaryHash(
|
||||
const BrotliDictionary* dictionary, uint16_t* words, uint8_t* lengths);
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") uint16_t
|
||||
kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") uint8_t
|
||||
kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
#else
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint16_t
|
||||
kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint8_t
|
||||
kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS];
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
+523
-427
File diff suppressed because it is too large.
Load diff
@@ -4,18 +4,47 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./encoder_dict.h"
|
||||
#include "encoder_dict.h"
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "../common/shared_dictionary_internal.h"
|
||||
#include "../common/transform.h"
|
||||
#include "./dictionary_hash.h"
|
||||
#include "./hash.h"
|
||||
#include <brotli/encode.h>
|
||||
#include "compound_dictionary.h"
|
||||
#include "dictionary_hash.h"
|
||||
#include "hash_base.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "quality.h"
|
||||
#include "static_dict_lut.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
#define NUM_HASH_BITS 15u
|
||||
#define NUM_HASH_BUCKETS (1u << NUM_HASH_BITS)
|
||||
|
||||
static void BrotliTrieInit(BrotliTrie* trie) {
|
||||
trie->pool_capacity = 0;
|
||||
trie->pool_size = 0;
|
||||
trie->pool = 0;
|
||||
|
||||
/* Set up the root node */
|
||||
trie->root.single = 0;
|
||||
trie->root.len_ = 0;
|
||||
trie->root.idx_ = 0;
|
||||
trie->root.sub = 0;
|
||||
}
|
||||
|
||||
static void BrotliTrieFree(MemoryManager* m, BrotliTrie* trie) {
|
||||
BrotliFree(m, trie->pool);
|
||||
}
|
||||
|
||||
/* Initializes to RFC 7932 static dictionary / transforms. */
|
||||
static void InitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
dict->words = BrotliGetDictionary();
|
||||
dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms;
|
||||
|
||||
@@ -26,8 +55,588 @@ void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict) {
|
||||
|
||||
dict->cutoffTransformsCount = kCutoffTransformsCount;
|
||||
dict->cutoffTransforms = kCutoffTransforms;
|
||||
|
||||
dict->parent = 0;
|
||||
|
||||
dict->hash_table_data_words_ = 0;
|
||||
dict->hash_table_data_lengths_ = 0;
|
||||
dict->buckets_alloc_size_ = 0;
|
||||
dict->buckets_data_ = 0;
|
||||
dict->dict_words_alloc_size_ = 0;
|
||||
dict->dict_words_data_ = 0;
|
||||
dict->words_instance_ = 0;
|
||||
dict->has_words_heavy = BROTLI_FALSE;
|
||||
BrotliTrieInit(&dict->trie);
|
||||
}
|
||||
|
||||
static void BrotliDestroyEncoderDictionary(MemoryManager* m,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
BrotliFree(m, dict->hash_table_data_words_);
|
||||
BrotliFree(m, dict->hash_table_data_lengths_);
|
||||
BrotliFree(m, dict->buckets_data_);
|
||||
BrotliFree(m, dict->dict_words_data_);
|
||||
BrotliFree(m, dict->words_instance_);
|
||||
BrotliTrieFree(m, &dict->trie);
|
||||
}
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* Word length must be at least 4 bytes */
|
||||
static uint32_t Hash(const uint8_t* data, int bits) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - bits);
|
||||
}
|
||||
|
||||
/* Theoretical max possible word size after transform */
|
||||
#define kTransformedBufferSize \
|
||||
(256 + 256 + SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH)
|
||||
|
||||
/* To be safe buffer must have at least kTransformedBufferSize */
|
||||
static void TransformedDictionaryWord(uint32_t word_idx, int len, int transform,
|
||||
const BrotliTransforms* transforms,
|
||||
const BrotliEncoderDictionary* dict,
|
||||
uint8_t* buffer, size_t* size) {
|
||||
const uint8_t* dict_word = &dict->words->data[
|
||||
dict->words->offsets_by_length[len] + (uint32_t)len * word_idx];
|
||||
*size = (size_t)BrotliTransformDictionaryWord(buffer, dict_word, len,
|
||||
transforms, transform);
|
||||
}
|
||||
|
||||
static DictWord MakeDictWord(uint8_t len, uint8_t transform, uint16_t idx) {
|
||||
DictWord result;
|
||||
result.len = len;
|
||||
result.transform = transform;
|
||||
result.idx = idx;
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint32_t BrotliTrieAlloc(MemoryManager* m, size_t num, BrotliTrie* trie,
|
||||
BrotliTrieNode** keep) {
|
||||
uint32_t result;
|
||||
uint32_t keep_index = 0;
|
||||
if (keep && *keep != &trie->root) {
|
||||
/* Optional node to keep, since address may change after re-allocating */
|
||||
keep_index = (uint32_t)(*keep - trie->pool);
|
||||
}
|
||||
if (trie->pool_size == 0) {
|
||||
/* Have a placeholder node in the front. We do not want the result to be 0,
|
||||
it must be at least 1, 0 represents "null pointer" */
|
||||
trie->pool_size = 1;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY(m, BrotliTrieNode, trie->pool, trie->pool_capacity,
|
||||
trie->pool_size + num);
|
||||
if (BROTLI_IS_OOM(m)) return 0;
|
||||
/* Init the new nodes to empty */
|
||||
memset(trie->pool + trie->pool_size, 0, sizeof(*trie->pool) * num);
|
||||
result = (uint32_t)trie->pool_size;
|
||||
trie->pool_size += num;
|
||||
if (keep && *keep != &trie->root) {
|
||||
*keep = trie->pool + keep_index;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* len and idx: payload for last node
|
||||
* word, size: the string
|
||||
* index: position in the string
|
||||
*/
|
||||
static BROTLI_BOOL BrotliTrieNodeAdd(MemoryManager* m, uint8_t len,
|
||||
uint32_t idx, const uint8_t* word, size_t size, int index,
|
||||
BrotliTrieNode* node, BrotliTrie* trie) {
|
||||
BrotliTrieNode* child = 0;
|
||||
uint8_t c;
|
||||
if ((size_t)index == size) {
|
||||
if (!node->len_ || idx < node->idx_) {
|
||||
node->len_ = len;
|
||||
node->idx_ = idx;
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
c = word[index];
|
||||
if (node->single && c != node->c) {
|
||||
BrotliTrieNode old = trie->pool[node->sub];
|
||||
uint32_t new_nodes = BrotliTrieAlloc(m, 32, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
node->single = 0;
|
||||
node->sub = new_nodes;
|
||||
trie->pool[node->sub + (node->c >> 4)].sub = new_nodes + 16;
|
||||
trie->pool[trie->pool[node->sub + (node->c >> 4)].sub + (node->c & 15)] =
|
||||
old;
|
||||
}
|
||||
if (!node->sub) {
|
||||
uint32_t new_node = BrotliTrieAlloc(m, 1, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
node->single = 1;
|
||||
node->c = c;
|
||||
node->sub = new_node;
|
||||
}
|
||||
if (node->single) {
|
||||
child = &trie->pool[node->sub];
|
||||
} else {
|
||||
if (!trie->pool[node->sub + (c >> 4)].sub) {
|
||||
uint32_t new_nodes = BrotliTrieAlloc(m, 16, trie, &node);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
trie->pool[node->sub + (c >> 4)].sub = new_nodes;
|
||||
}
|
||||
child = &trie->pool[trie->pool[node->sub + (c >> 4)].sub + (c & 15)];
|
||||
}
|
||||
return BrotliTrieNodeAdd(m, len, idx, word, size, index + 1, child, trie);
|
||||
}
|
||||
|
||||
static BROTLI_BOOL BrotliTrieAdd(MemoryManager* m, uint8_t len, uint32_t idx,
|
||||
const uint8_t* word, size_t size, BrotliTrie* trie) {
|
||||
return BrotliTrieNodeAdd(m, len, idx, word, size, 0, &trie->root, trie);
|
||||
}
|
||||
|
||||
const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie,
|
||||
const BrotliTrieNode* node, uint8_t c) {
|
||||
BrotliTrieNode* temp_node;
|
||||
if (node->single) {
|
||||
if (node->c == c) return &trie->pool[node->sub];
|
||||
return 0;
|
||||
}
|
||||
if (!node->sub) return 0;
|
||||
temp_node = &trie->pool[node->sub + (c >> 4)];
|
||||
if (!temp_node->sub) return 0;
|
||||
return &trie->pool[temp_node->sub + (c & 15)];
|
||||
}
|
||||
|
||||
static const BrotliTrieNode* BrotliTrieFind(const BrotliTrie* trie,
|
||||
const uint8_t* word, size_t size) {
|
||||
const BrotliTrieNode* node = &trie->root;
|
||||
size_t i;
|
||||
for (i = 0; i < size; i++) {
|
||||
node = BrotliTrieSub(trie, node, word[i]);
|
||||
if (!node) return 0;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
static BROTLI_BOOL BuildDictionaryLut(MemoryManager* m,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
uint32_t i;
|
||||
DictWord* dict_words;
|
||||
uint16_t* buckets;
|
||||
DictWord** words_by_hash;
|
||||
size_t* words_by_hash_size;
|
||||
size_t* words_by_hash_capacity;
|
||||
BrotliTrie dedup;
|
||||
uint8_t word[kTransformedBufferSize];
|
||||
size_t word_size;
|
||||
size_t total = 0;
|
||||
uint8_t l;
|
||||
uint16_t idx;
|
||||
|
||||
BrotliTrieInit(&dedup);
|
||||
|
||||
words_by_hash = (DictWord**)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash) * NUM_HASH_BUCKETS);
|
||||
words_by_hash_size = (size_t*)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS);
|
||||
words_by_hash_capacity = (size_t*)BrotliAllocate(m,
|
||||
sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
memset(words_by_hash, 0, sizeof(*words_by_hash) * NUM_HASH_BUCKETS);
|
||||
memset(words_by_hash_size, 0, sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS);
|
||||
memset(words_by_hash_capacity, 0,
|
||||
sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS);
|
||||
|
||||
if (transforms->num_transforms > 0) {
|
||||
for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) {
|
||||
uint16_t n = dict->words->size_bits_by_length[l] ?
|
||||
(uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u;
|
||||
for (idx = 0; idx < n; ++idx) {
|
||||
uint32_t key;
|
||||
/* First transform (usually identity) */
|
||||
TransformedDictionaryWord(idx, l, 0, transforms, dict, word,
|
||||
&word_size);
|
||||
/* Cannot hash words smaller than 4 bytes */
|
||||
if (word_size < 4) {
|
||||
/* Break instead of continue, all next words of this length will have
|
||||
same length after transform */
|
||||
break;
|
||||
}
|
||||
if (!BrotliTrieAdd(m, 0, idx, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
key = Hash(word, NUM_HASH_BITS);
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, 0, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* These LUT transforms only supported if no custom transforms. This is
|
||||
ok, we will use the heavy trie instead. */
|
||||
if (transforms == BrotliGetTransforms()) {
|
||||
for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH;
|
||||
l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) {
|
||||
uint16_t n = dict->words->size_bits_by_length[l] ?
|
||||
(uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u;
|
||||
for (idx = 0; idx < n; ++idx) {
|
||||
int k;
|
||||
BROTLI_BOOL is_ascii = BROTLI_TRUE;
|
||||
size_t offset = dict->words->offsets_by_length[l] + (size_t)l * idx;
|
||||
const uint8_t* data = &dict->words->data[offset];
|
||||
for (k = 0; k < l; ++k) {
|
||||
if (data[k] >= 128) is_ascii = BROTLI_FALSE;
|
||||
}
|
||||
if (data[0] < 128) {
|
||||
int transform = 9; /* {empty, uppercase first, empty} */
|
||||
uint32_t ix = idx + (uint32_t)transform * n;
|
||||
const BrotliTrieNode* it;
|
||||
TransformedDictionaryWord(idx, l, transform, transforms,
|
||||
dict, word, &word_size);
|
||||
it = BrotliTrieFind(&dedup, word, word_size);
|
||||
if (!it || it->idx_ > ix) {
|
||||
uint32_t key = Hash(word, NUM_HASH_BITS);
|
||||
if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_FIRST, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
if (is_ascii) {
|
||||
int transform = 44; /* {empty, uppercase all, empty} */
|
||||
uint32_t ix = idx + (uint32_t)transform * n;
|
||||
const BrotliTrieNode* it;
|
||||
TransformedDictionaryWord(idx, l, transform, transforms,
|
||||
dict, word, &word_size);
|
||||
it = BrotliTrieFind(&dedup, word, word_size);
|
||||
if (!it || it->idx_ > ix) {
|
||||
uint32_t key = Hash(word, NUM_HASH_BITS);
|
||||
if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key],
|
||||
words_by_hash_capacity[key], words_by_hash_size[key],
|
||||
MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_ALL, idx));
|
||||
++total;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dict_words = (DictWord*)BrotliAllocate(m,
|
||||
sizeof(*dict->dict_words) * (total + 1));
|
||||
buckets = (uint16_t*)BrotliAllocate(m,
|
||||
sizeof(*dict->buckets) * NUM_HASH_BUCKETS);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
dict->dict_words_alloc_size_ = total + 1;
|
||||
dict->dict_words = dict->dict_words_data_ = dict_words;
|
||||
dict->buckets_alloc_size_ = NUM_HASH_BUCKETS;
|
||||
dict->buckets = dict->buckets_data_ = buckets;
|
||||
|
||||
/* Unused; makes offsets start from 1. */
|
||||
dict_words[0] = MakeDictWord(0, 0, 0);
|
||||
total = 1;
|
||||
for (i = 0; i < NUM_HASH_BUCKETS; ++i) {
|
||||
size_t num_words = words_by_hash_size[i];
|
||||
if (num_words > 0) {
|
||||
buckets[i] = (uint16_t)(total);
|
||||
memcpy(&dict_words[total], &words_by_hash[i][0],
|
||||
sizeof(dict_words[0]) * num_words);
|
||||
total += num_words;
|
||||
dict_words[total - 1].len |= 0x80;
|
||||
} else {
|
||||
buckets[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_HASH_BUCKETS; ++i) {
|
||||
BrotliFree(m, words_by_hash[i]);
|
||||
}
|
||||
BrotliFree(m, words_by_hash);
|
||||
BrotliFree(m, words_by_hash_size);
|
||||
BrotliFree(m, words_by_hash_capacity);
|
||||
BrotliTrieFree(m, &dedup);
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
static void BuildDictionaryHashTable(uint16_t* hash_table_words,
|
||||
uint8_t* hash_table_lengths, const BrotliDictionary* dict) {
|
||||
int j, len;
|
||||
/* The order of the loops is such that in case of collision, words with
|
||||
shorter length are preferred, and in case of same length, words with
|
||||
smaller index. There is only a single word per bucket. */
|
||||
/* TODO(lode): consider adding optional user-supplied frequency_map to use
|
||||
for preferred words instead, this can make the encoder better for
|
||||
quality 9 and below without affecting the decoder */
|
||||
memset(hash_table_words, 0, sizeof(kStaticDictionaryHashWords));
|
||||
memset(hash_table_lengths, 0, sizeof(kStaticDictionaryHashLengths));
|
||||
for (len = SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH;
|
||||
len >= SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; --len) {
|
||||
const size_t num_words = dict->size_bits_by_length[len] ?
|
||||
(1u << dict->size_bits_by_length[len]) : 0;
|
||||
for (j = (int)num_words - 1; j >= 0; --j) {
|
||||
size_t offset = dict->offsets_by_length[len] +
|
||||
(size_t)len * (size_t)j;
|
||||
const uint8_t* word = &dict->data[offset];
|
||||
const uint32_t key = Hash(word, 14);
|
||||
int idx = (int)(key << 1) + (len < 8 ? 1 : 0);
|
||||
BROTLI_DCHECK(idx < (int)NUM_HASH_BUCKETS);
|
||||
hash_table_words[idx] = (uint16_t)j;
|
||||
hash_table_lengths[idx] = (uint8_t)len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL GenerateWordsHeavy(MemoryManager* m,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* dict) {
|
||||
int i, j, l;
|
||||
for (j = (int)transforms->num_transforms - 1; j >= 0 ; --j) {
|
||||
for (l = 0; l < 32; l++) {
|
||||
int num = (int)((1u << dict->words->size_bits_by_length[l]) & ~1u);
|
||||
for (i = 0; i < num; i++) {
|
||||
uint8_t transformed[kTransformedBufferSize];
|
||||
size_t size;
|
||||
TransformedDictionaryWord(
|
||||
(uint32_t)i, l, j, transforms, dict, transformed, &size);
|
||||
if (size < 4) continue;
|
||||
if (!BrotliTrieAdd(m, (uint8_t)l, (uint32_t)(i + num * j),
|
||||
transformed, size, &dict->trie)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
/* Computes cutoffTransformsCount (in count) and cutoffTransforms (in data) for
|
||||
the custom transforms, where possible within the limits of the
|
||||
cutoffTransforms encoding. The fast encoder uses this to do fast lookup for
|
||||
transforms that remove the N last characters (OmitLast). */
|
||||
static void ComputeCutoffTransforms(
|
||||
const BrotliTransforms* transforms,
|
||||
uint32_t* count, uint64_t* data) {
|
||||
int i;
|
||||
/* The encoding in a 64-bit integer of transform N in the data is: (N << 2) +
|
||||
((cutoffTransforms >> (N * 6)) & 0x3F), so for example the identity
|
||||
transform code must be 0-63, for N=1 the transform code must be 4-67, ...,
|
||||
for N=9 it must be 36-99.
|
||||
TODO(lode): consider a simple flexible uint8_t[10] instead of the uint64_t
|
||||
for the cutoff transforms, so that shared dictionaries can have the
|
||||
OmitLast transforms anywhere without loss. */
|
||||
*count = 0;
|
||||
*data = 0;
|
||||
for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) {
|
||||
int idx = transforms->cutOffTransforms[i];
|
||||
if (idx == -1) break; /* Not found */
|
||||
if (idx < (i << 2)) break; /* Too small for the encoding */
|
||||
if (idx >= (i << 2) + 64) break; /* Too large for the encoding */
|
||||
(*count)++;
|
||||
*data |= (uint64_t)(((uint64_t)idx -
|
||||
((uint64_t)i << 2u)) << ((uint64_t)i * 6u));
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_BOOL ComputeDictionary(MemoryManager* m, int quality,
|
||||
const BrotliTransforms* transforms,
|
||||
BrotliEncoderDictionary* current) {
|
||||
int default_words = current->words == BrotliGetDictionary();
|
||||
int default_transforms = transforms == BrotliGetTransforms();
|
||||
|
||||
if (default_words && default_transforms) {
|
||||
/* hashes are already set to Brotli defaults */
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
current->hash_table_data_words_ = (uint16_t*)BrotliAllocate(
|
||||
m, sizeof(kStaticDictionaryHashWords));
|
||||
current->hash_table_data_lengths_ = (uint8_t*)BrotliAllocate(
|
||||
m, sizeof(kStaticDictionaryHashLengths));
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
current->hash_table_words = current->hash_table_data_words_;
|
||||
current->hash_table_lengths = current->hash_table_data_lengths_;
|
||||
|
||||
BuildDictionaryHashTable(current->hash_table_data_words_,
|
||||
current->hash_table_data_lengths_, current->words);
|
||||
|
||||
ComputeCutoffTransforms(transforms,
|
||||
¤t->cutoffTransformsCount, ¤t->cutoffTransforms);
|
||||
|
||||
/* Only compute the data for slow encoder if the requested quality is high
|
||||
enough to need it */
|
||||
if (quality >= ZOPFLIFICATION_QUALITY) {
|
||||
if (!BuildDictionaryLut(m, transforms, current)) return BROTLI_FALSE;
|
||||
|
||||
/* For the built-in Brotli transforms, there is a hard-coded function to
|
||||
handle all transforms, but for custom transforms, we use the following
|
||||
large hammer instead */
|
||||
current->has_words_heavy = !default_transforms;
|
||||
if (current->has_words_heavy) {
|
||||
if (!GenerateWordsHeavy(m, transforms, current)) return BROTLI_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliInitSharedEncoderDictionary(SharedEncoderDictionary* dict) {
|
||||
dict->magic = kSharedDictionaryMagic;
|
||||
|
||||
dict->compound.num_chunks = 0;
|
||||
dict->compound.total_size = 0;
|
||||
dict->compound.chunk_offsets[0] = 0;
|
||||
dict->compound.num_prepared_instances_ = 0;
|
||||
|
||||
dict->contextual.context_based = 0;
|
||||
dict->contextual.num_dictionaries = 1;
|
||||
dict->contextual.instances_ = 0;
|
||||
dict->contextual.num_instances_ = 1; /* The instance_ field */
|
||||
dict->contextual.dict[0] = &dict->contextual.instance_;
|
||||
InitEncoderDictionary(&dict->contextual.instance_);
|
||||
dict->contextual.instance_.parent = &dict->contextual;
|
||||
|
||||
dict->max_quality = BROTLI_MAX_QUALITY;
|
||||
}
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* TODO(eustas): make sure that tooling will warn user if not all the cutoff
|
||||
transforms are available (for low-quality encoder). */
|
||||
static BROTLI_BOOL InitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const BrotliSharedDictionary* decoded_dict,
|
||||
int quality, SharedEncoderDictionary* dict) {
|
||||
ContextualEncoderDictionary* contextual;
|
||||
CompoundDictionary* compound;
|
||||
BrotliEncoderDictionary* instances;
|
||||
int i;
|
||||
BrotliInitSharedEncoderDictionary(dict);
|
||||
|
||||
contextual = &dict->contextual;
|
||||
compound = &dict->compound;
|
||||
|
||||
for (i = 0; i < (int)decoded_dict->num_prefix; i++) {
|
||||
PreparedDictionary* prepared = CreatePreparedDictionary(m,
|
||||
decoded_dict->prefix[i], decoded_dict->prefix_size[i]);
|
||||
AttachPreparedDictionary(compound, prepared);
|
||||
/* remember for cleanup */
|
||||
compound->prepared_instances_[
|
||||
compound->num_prepared_instances_++] = prepared;
|
||||
}
|
||||
|
||||
dict->max_quality = quality;
|
||||
contextual->context_based = decoded_dict->context_based;
|
||||
if (decoded_dict->context_based) {
|
||||
memcpy(contextual->context_map, decoded_dict->context_map,
|
||||
SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS);
|
||||
}
|
||||
|
||||
contextual->num_dictionaries = decoded_dict->num_dictionaries;
|
||||
contextual->num_instances_ = decoded_dict->num_dictionaries;
|
||||
if (contextual->num_instances_ == 1) {
|
||||
instances = &contextual->instance_;
|
||||
} else {
|
||||
contextual->instances_ = (BrotliEncoderDictionary*)
|
||||
BrotliAllocate(m, sizeof(*contextual->instances_) *
|
||||
contextual->num_instances_);
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
instances = contextual->instances_;
|
||||
}
|
||||
for (i = 0; i < (int)contextual->num_instances_; i++) {
|
||||
BrotliEncoderDictionary* current = &instances[i];
|
||||
InitEncoderDictionary(current);
|
||||
current->parent = &dict->contextual;
|
||||
if (decoded_dict->words[i] == BrotliGetDictionary()) {
|
||||
current->words = BrotliGetDictionary();
|
||||
} else {
|
||||
current->words_instance_ = (BrotliDictionary*)BrotliAllocate(
|
||||
m, sizeof(BrotliDictionary));
|
||||
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
|
||||
*current->words_instance_ = *decoded_dict->words[i];
|
||||
current->words = current->words_instance_;
|
||||
}
|
||||
current->num_transforms =
|
||||
(uint32_t)decoded_dict->transforms[i]->num_transforms;
|
||||
if (!ComputeDictionary(
|
||||
m, quality, decoded_dict->transforms[i], current)) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
|
||||
contextual->dict[i] = current;
|
||||
}
|
||||
|
||||
return BROTLI_TRUE; /* success */
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const uint8_t* encoded_dict, size_t size,
|
||||
int quality, SharedEncoderDictionary* dict) {
|
||||
BROTLI_BOOL success = BROTLI_FALSE;
|
||||
BrotliSharedDictionary* decoded_dict = BrotliSharedDictionaryCreateInstance(
|
||||
m->alloc_func, m->free_func, m->opaque);
|
||||
if (!decoded_dict) { /* OOM */
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
success = BrotliSharedDictionaryAttach(
|
||||
decoded_dict, BROTLI_SHARED_DICTIONARY_SERIALIZED, size, encoded_dict);
|
||||
if (success) {
|
||||
success = InitCustomSharedEncoderDictionary(m,
|
||||
decoded_dict, quality, dict);
|
||||
}
|
||||
BrotliSharedDictionaryDestroyInstance(decoded_dict);
|
||||
return success;
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
void BrotliCleanupSharedEncoderDictionary(MemoryManager* m,
|
||||
SharedEncoderDictionary* dict) {
|
||||
size_t i;
|
||||
for (i = 0; i < dict->compound.num_prepared_instances_; i++) {
|
||||
DestroyPreparedDictionary(m,
|
||||
(PreparedDictionary*)dict->compound.prepared_instances_[i]);
|
||||
}
|
||||
if (dict->contextual.num_instances_ == 1) {
|
||||
BrotliDestroyEncoderDictionary(m, &dict->contextual.instance_);
|
||||
} else if (dict->contextual.num_instances_ > 1) {
|
||||
for (i = 0; i < dict->contextual.num_instances_; i++) {
|
||||
BrotliDestroyEncoderDictionary(m, &dict->contextual.instances_[i]);
|
||||
}
|
||||
BrotliFree(m, dict->contextual.instances_);
|
||||
}
|
||||
}
|
||||
|
||||
ManagedDictionary* BrotliCreateManagedDictionary(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
ManagedDictionary* result = (ManagedDictionary*)BrotliBootstrapAlloc(
|
||||
sizeof(ManagedDictionary), alloc_func, free_func, opaque);
|
||||
if (result == NULL) return NULL;
|
||||
|
||||
result->magic = kManagedDictionaryMagic;
|
||||
BrotliInitMemoryManager(
|
||||
&result->memory_manager_, alloc_func, free_func, opaque);
|
||||
result->dictionary = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void BrotliDestroyManagedDictionary(ManagedDictionary* dictionary) {
|
||||
if (!dictionary) return;
|
||||
BrotliBootstrapFree(dictionary, &dictionary->memory_manager_);
|
||||
}
|
||||
|
||||
/* Escalate internal functions visibility; for testing purposes only. */
|
||||
#if defined(BROTLI_TEST)
|
||||
void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary*);
|
||||
void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary* d) {
|
||||
InitEncoderDictionary(d);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -8,14 +8,53 @@
|
||||
#define BROTLI_ENC_ENCODER_DICT_H_
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include <brotli/shared_dictionary.h>
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./static_dict_lut.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "memory.h"
|
||||
#include "static_dict_lut.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*
|
||||
Dictionary hierarchy for Encoder:
|
||||
-SharedEncoderDictionary
|
||||
--CompoundDictionary
|
||||
---PreparedDictionary [up to 15x]
|
||||
= prefix dictionary with precomputed hashes
|
||||
--ContextualEncoderDictionary
|
||||
---BrotliEncoderDictionary [up to 64x]
|
||||
= for each context, precomputed static dictionary with words + transforms
|
||||
|
||||
Dictionary hierarchy from common: similar, but without precomputed hashes
|
||||
-BrotliSharedDictionary
|
||||
--BrotliDictionary [up to 64x]
|
||||
--BrotliTransforms [up to 64x]
|
||||
--const uint8_t* prefix [up to 15x]: compound dictionaries
|
||||
*/
|
||||
|
||||
typedef struct BrotliTrieNode {
|
||||
uint8_t single; /* if 1, sub is a single node for c instead of 256 */
|
||||
uint8_t c;
|
||||
uint8_t len_; /* untransformed length */
|
||||
uint32_t idx_; /* word index + num words * transform index */
|
||||
uint32_t sub; /* index of sub node(s) in the pool */
|
||||
} BrotliTrieNode;
|
||||
|
||||
typedef struct BrotliTrie {
|
||||
BrotliTrieNode* pool;
|
||||
size_t pool_capacity;
|
||||
size_t pool_size;
|
||||
BrotliTrieNode root;
|
||||
} BrotliTrie;
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
BROTLI_INTERNAL const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie,
|
||||
const BrotliTrieNode* node, uint8_t c);
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
/* Dictionary data (words and transforms) for 1 possible context */
|
||||
typedef struct BrotliEncoderDictionary {
|
||||
const BrotliDictionary* words;
|
||||
@@ -32,9 +71,82 @@ typedef struct BrotliEncoderDictionary {
|
||||
/* from static_dict_lut.h, for slow encoder */
|
||||
const uint16_t* buckets;
|
||||
const DictWord* dict_words;
|
||||
/* Heavy version, for use by slow encoder when there are custom transforms.
|
||||
Contains every possible transformed dictionary word in a trie. It encodes
|
||||
about as fast as the non-heavy encoder but consumes a lot of memory and
|
||||
takes time to build. */
|
||||
BrotliTrie trie;
|
||||
BROTLI_BOOL has_words_heavy;
|
||||
|
||||
/* Reference to other dictionaries. */
|
||||
const struct ContextualEncoderDictionary* parent;
|
||||
|
||||
/* Allocated memory, used only when not using the Brotli defaults */
|
||||
uint16_t* hash_table_data_words_;
|
||||
uint8_t* hash_table_data_lengths_;
|
||||
size_t buckets_alloc_size_;
|
||||
uint16_t* buckets_data_;
|
||||
size_t dict_words_alloc_size_;
|
||||
DictWord* dict_words_data_;
|
||||
BrotliDictionary* words_instance_;
|
||||
} BrotliEncoderDictionary;
|
||||
|
||||
BROTLI_INTERNAL void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict);
|
||||
/* Dictionary data for all 64 contexts */
|
||||
typedef struct ContextualEncoderDictionary {
|
||||
BROTLI_BOOL context_based;
|
||||
uint8_t num_dictionaries;
|
||||
uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
const BrotliEncoderDictionary* dict[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS];
|
||||
|
||||
/* If num_instances_ is 1, instance_ is used, else dynamic allocation with
|
||||
instances_ is used. */
|
||||
size_t num_instances_;
|
||||
BrotliEncoderDictionary instance_;
|
||||
BrotliEncoderDictionary* instances_;
|
||||
} ContextualEncoderDictionary;
|
||||
|
||||
typedef struct SharedEncoderDictionary {
|
||||
/* Magic value to distinguish this struct from PreparedDictionary for
|
||||
certain external usages. */
|
||||
uint32_t magic;
|
||||
|
||||
/* LZ77 prefix, compound dictionary */
|
||||
CompoundDictionary compound;
|
||||
|
||||
/* Custom static dictionary (optionally context-based) */
|
||||
ContextualEncoderDictionary contextual;
|
||||
|
||||
/* The maximum quality the dictionary was computed for */
|
||||
int max_quality;
|
||||
} SharedEncoderDictionary;
|
||||
|
||||
typedef struct ManagedDictionary {
|
||||
uint32_t magic;
|
||||
MemoryManager memory_manager_;
|
||||
uint32_t* dictionary;
|
||||
} ManagedDictionary;
|
||||
|
||||
/* Initializes to the brotli built-in dictionary */
|
||||
BROTLI_INTERNAL void BrotliInitSharedEncoderDictionary(
|
||||
SharedEncoderDictionary* dict);
|
||||
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
/* Initializes to shared dictionary that will be parsed from
|
||||
encoded_dict. Requires that you keep the encoded_dict buffer
|
||||
around, parts of data will point to it. */
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary(
|
||||
MemoryManager* m, const uint8_t* encoded_dict, size_t size,
|
||||
int quality, SharedEncoderDictionary* dict);
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
|
||||
BROTLI_INTERNAL void BrotliCleanupSharedEncoderDictionary(
|
||||
MemoryManager* m, SharedEncoderDictionary* dict);
|
||||
|
||||
BROTLI_INTERNAL ManagedDictionary* BrotliCreateManagedDictionary(
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
|
||||
BROTLI_INTERNAL void BrotliDestroyManagedDictionary(
|
||||
ManagedDictionary* dictionary);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -6,19 +6,16 @@
|
||||
|
||||
/* Entropy encoding (Huffman) utilities. */
|
||||
|
||||
#include "./entropy_encode.h"
|
||||
|
||||
#include <string.h> /* memset */
|
||||
#include "entropy_encode.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
const size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
|
||||
const BROTLI_MODEL("small") size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1};
|
||||
|
||||
BROTLI_BOOL BrotliSetDepth(
|
||||
int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) {
|
||||
@@ -455,7 +452,8 @@ void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||
}
|
||||
|
||||
static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) {
|
||||
static const size_t kLut[16] = { /* Pre-reversed 4-bit values. */
|
||||
static const size_t BROTLI_MODEL("small") kLut[16] =
|
||||
{ /* Pre-reversed 4-bit values. */
|
||||
0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E,
|
||||
0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F
|
||||
};
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define BROTLI_ENC_ENTROPY_ENCODE_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -66,7 +65,7 @@ BROTLI_INTERNAL void BrotliOptimizeHuffmanCountsForRle(
|
||||
of a Huffman tree. The generated Huffman tree is to be compressed once
|
||||
more using a Huffman tree */
|
||||
BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth,
|
||||
size_t num,
|
||||
size_t length,
|
||||
size_t* tree_size,
|
||||
uint8_t* tree,
|
||||
uint8_t* extra_bits_data);
|
||||
@@ -76,7 +75,7 @@ BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
|
||||
size_t len,
|
||||
uint16_t* bits);
|
||||
|
||||
BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
|
||||
BROTLI_INTERNAL extern BROTLI_MODEL("small") const size_t kBrotliShellGaps[6];
|
||||
/* Input size optimized Shell sort. */
|
||||
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
|
||||
const HuffmanTree*, const HuffmanTree*);
|
||||
|
||||
@@ -11,18 +11,18 @@
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./write_bits.h"
|
||||
#include "write_bits.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static const uint8_t kCodeLengthDepth[18] = {
|
||||
static const BROTLI_MODEL("small") uint8_t kCodeLengthDepth[18] = {
|
||||
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4,
|
||||
};
|
||||
|
||||
static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
|
||||
@@ -69,14 +69,17 @@ static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
|
||||
};
|
||||
|
||||
static const uint8_t kStaticDistanceCodeDepth[64] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint8_t kStaticDistanceCodeDepth[64] = {
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
};
|
||||
|
||||
static const uint32_t kCodeLengthBits[18] = {
|
||||
/* GENERATED CODE START */
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kCodeLengthBits[18] = {
|
||||
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7,
|
||||
};
|
||||
|
||||
@@ -86,7 +89,8 @@ static BROTLI_INLINE void StoreStaticCodeLengthCode(
|
||||
40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage);
|
||||
}
|
||||
|
||||
static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x00000017, 0x00000027,
|
||||
0x00000037, 0x00000047, 0x00000057, 0x00000067, 0x00000077, 0x00000770,
|
||||
0x00000b87, 0x00001387, 0x00001b87, 0x00002387, 0x00002b87, 0x00003387,
|
||||
@@ -207,7 +211,8 @@ static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x06f9cb87, 0x08f9cb87,
|
||||
};
|
||||
|
||||
static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0, 4, 8, 7, 7, 7, 7, 7, 7, 7, 7, 11, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
@@ -254,7 +259,8 @@ static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||
};
|
||||
|
||||
static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x0000000b, 0x0000001b, 0x0000002b, 0x0000003b, 0x000002cb, 0x000006cb,
|
||||
0x00000acb, 0x00000ecb, 0x000002db, 0x000006db, 0x00000adb, 0x00000edb,
|
||||
0x000002eb, 0x000006eb, 0x00000aeb, 0x00000eeb, 0x000002fb, 0x000006fb,
|
||||
@@ -375,7 +381,8 @@ static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0x2baeb6db, 0x3baeb6db,
|
||||
};
|
||||
|
||||
static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
@@ -422,7 +429,8 @@ static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
|
||||
};
|
||||
|
||||
static const uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
static const BROTLI_MODEL("small")
|
||||
uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
|
||||
0, 256, 128, 384, 64, 320, 192, 448,
|
||||
32, 288, 160, 416, 96, 352, 224, 480,
|
||||
16, 272, 144, 400, 80, 336, 208, 464,
|
||||
@@ -520,7 +528,7 @@ static BROTLI_INLINE void StoreStaticCommandHuffmanTree(
|
||||
BrotliWriteBits(3, 0x00000000U, storage_ix, storage);
|
||||
}
|
||||
|
||||
static const uint16_t kStaticDistanceCodeBits[64] = {
|
||||
static const BROTLI_MODEL("small") uint16_t kStaticDistanceCodeBits[64] = {
|
||||
0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
|
||||
2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
|
||||
1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
|
||||
@@ -531,6 +539,7 @@ static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
|
||||
size_t* storage_ix, uint8_t* storage) {
|
||||
BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage);
|
||||
}
|
||||
/* GENERATED CODE END */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./fast_log.h"
|
||||
#include "fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */
|
||||
const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
|
||||
const BROTLI_MODEL("small") double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = {
|
||||
0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f,
|
||||
1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f,
|
||||
2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f,
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <math.h>
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -32,7 +31,8 @@ static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
|
||||
|
||||
/* A lookup table for small values of log2(int) to be used in entropy
|
||||
computation. */
|
||||
BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
|
||||
BROTLI_INTERNAL extern const BROTLI_MODEL("small")
|
||||
double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
|
||||
|
||||
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
|
||||
* function defined, so we use log() and a multiplication instead. */
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -21,31 +20,23 @@ extern "C" {
|
||||
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||
const uint8_t* s2,
|
||||
size_t limit) {
|
||||
size_t matched = 0;
|
||||
size_t limit2 = (limit >> 3) + 1; /* + 1 is for pre-decrement in while */
|
||||
while (BROTLI_PREDICT_TRUE(--limit2)) {
|
||||
if (BROTLI_PREDICT_FALSE(BROTLI_UNALIGNED_LOAD64LE(s2) ==
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1 + matched))) {
|
||||
s2 += 8;
|
||||
matched += 8;
|
||||
} else {
|
||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
|
||||
const uint8_t *s1_orig = s1;
|
||||
for (; limit >= 8; limit -= 8) {
|
||||
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
|
||||
BROTLI_UNALIGNED_LOAD64LE(s1);
|
||||
s2 += 8;
|
||||
if (x != 0) {
|
||||
size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
|
||||
matched += matching_bits >> 3;
|
||||
return matched;
|
||||
return (size_t)(s1 - s1_orig) + (matching_bits >> 3);
|
||||
}
|
||||
s1 += 8;
|
||||
}
|
||||
limit = (limit & 7) + 1; /* + 1 is for pre-decrement in while */
|
||||
while (--limit) {
|
||||
if (BROTLI_PREDICT_TRUE(s1[matched] == *s2)) {
|
||||
++s2;
|
||||
++matched;
|
||||
} else {
|
||||
return matched;
|
||||
}
|
||||
while (limit && *s1 == *s2) {
|
||||
limit--;
|
||||
++s2;
|
||||
++s1;
|
||||
}
|
||||
return matched;
|
||||
return (size_t)(s1 - s1_orig);
|
||||
}
|
||||
#else
|
||||
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
|
||||
|
||||
+311
-64
@@ -10,33 +10,47 @@
|
||||
#ifndef BROTLI_ENC_HASH_H_
|
||||
#define BROTLI_ENC_HASH_H_
|
||||
|
||||
#include <string.h> /* memcmp, memset */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./encoder_dict.h"
|
||||
#include "./fast_log.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "./static_dict.h"
|
||||
#include "compound_dictionary.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "fast_log.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
#include "matching_tag_mask.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "quality.h"
|
||||
#include "static_dict.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
/* Dynamically allocated area; first member for quickest access. */
|
||||
void* extra;
|
||||
/**
|
||||
* Dynamically allocated areas; regular hasher uses one or two allocations;
|
||||
* "composite" hasher uses up to 4 allocations.
|
||||
*/
|
||||
void* extra[4];
|
||||
|
||||
/**
|
||||
* False before the first invocation of HasherSetup (where "extra" memory)
|
||||
* is allocated.
|
||||
*/
|
||||
BROTLI_BOOL is_setup_;
|
||||
|
||||
size_t dict_num_lookups;
|
||||
size_t dict_num_matches;
|
||||
|
||||
BrotliHasherParams params;
|
||||
|
||||
/* False if hasher needs to be "prepared" before use. */
|
||||
/**
|
||||
* False if hasher needs to be "prepared" before use (before the first
|
||||
* invocation of HasherSetup or after HasherReset). "preparation" is hasher
|
||||
* data initialization (using input ringbuffer).
|
||||
*/
|
||||
BROTLI_BOOL is_prepared_;
|
||||
} HasherCommon;
|
||||
|
||||
@@ -55,24 +69,6 @@ typedef struct HasherSearchResult {
|
||||
int len_code_delta; /* == len_code - len */
|
||||
} HasherSearchResult;
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
|
||||
static const uint64_t kHashMul64Long =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 14);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void PrepareDistanceCache(
|
||||
int* BROTLI_RESTRICT distance_cache, const int num_distances) {
|
||||
if (num_distances > 4) {
|
||||
@@ -232,7 +228,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define BUCKET_BITS 17
|
||||
#define MAX_TREE_SEARCH_DEPTH 64
|
||||
#define MAX_TREE_COMP_LENGTH 128
|
||||
#include "./hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
|
||||
#undef MAX_TREE_SEARCH_DEPTH
|
||||
#undef MAX_TREE_COMP_LENGTH
|
||||
#undef BUCKET_BITS
|
||||
@@ -249,7 +245,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define BUCKET_SWEEP_BITS 0
|
||||
#define HASH_LEN 5
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASHER
|
||||
@@ -257,7 +253,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H3
|
||||
#define BUCKET_SWEEP_BITS 1
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
#undef BUCKET_BITS
|
||||
@@ -267,7 +263,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define BUCKET_BITS 17
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define USE_DICTIONARY 1
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
@@ -275,26 +271,36 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H5
|
||||
#include "./hash_longest_match_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H6
|
||||
#include "./hash_longest_match64_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match64_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define HASHER() H58
|
||||
#include "hash_longest_match_simd_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
|
||||
#define HASHER() H68
|
||||
#include "hash_longest_match64_simd_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#endif
|
||||
|
||||
#define BUCKET_BITS 15
|
||||
|
||||
#define NUM_LAST_DISTANCES_TO_CHECK 4
|
||||
#define NUM_BANKS 1
|
||||
#define BANK_BITS 16
|
||||
#define HASHER() H40
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
|
||||
#define NUM_LAST_DISTANCES_TO_CHECK 10
|
||||
#define HASHER() H41
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
#undef NUM_BANKS
|
||||
@@ -304,7 +310,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define NUM_BANKS 512
|
||||
#define BANK_BITS 9
|
||||
#define HASHER() H42
|
||||
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER
|
||||
#undef NUM_LAST_DISTANCES_TO_CHECK
|
||||
#undef NUM_BANKS
|
||||
@@ -317,7 +323,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define BUCKET_SWEEP_BITS 2
|
||||
#define HASH_LEN 7
|
||||
#define USE_DICTIONARY 0
|
||||
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
|
||||
#undef USE_DICTIONARY
|
||||
#undef HASH_LEN
|
||||
#undef BUCKET_SWEEP_BITS
|
||||
@@ -331,14 +337,14 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define JUMP 4
|
||||
#define NUMBUCKETS 16777216
|
||||
#define MASK ((NUMBUCKETS * 64) - 1)
|
||||
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#undef JUMP
|
||||
#undef HASHER
|
||||
|
||||
|
||||
#define HASHER() HROLLING
|
||||
#define JUMP 1
|
||||
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_rolling_inc.h" /* NOLINT(build/include) */
|
||||
#undef MASK
|
||||
#undef NUMBUCKETS
|
||||
#undef JUMP
|
||||
@@ -348,7 +354,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H35
|
||||
#define HASHER_A H3
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -356,7 +362,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H55
|
||||
#define HASHER_A H54
|
||||
#define HASHER_B HROLLING_FAST
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -364,7 +370,7 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#define HASHER() H65
|
||||
#define HASHER_A H6
|
||||
#define HASHER_B HROLLING
|
||||
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#include "hash_composite_inc.h" /* NOLINT(build/include) */
|
||||
#undef HASHER_A
|
||||
#undef HASHER_B
|
||||
#undef HASHER
|
||||
@@ -373,7 +379,13 @@ static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
|
||||
#undef CAT
|
||||
#undef EXPAND_CAT
|
||||
|
||||
#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
#define FOR_SIMPLE_HASHERS(H) \
|
||||
H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54) H(58) H(68)
|
||||
#else
|
||||
#define FOR_SIMPLE_HASHERS(H) \
|
||||
H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
|
||||
#endif
|
||||
#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
|
||||
#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
|
||||
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
|
||||
@@ -391,43 +403,55 @@ typedef struct {
|
||||
|
||||
/* MUST be invoked before any other method. */
|
||||
static BROTLI_INLINE void HasherInit(Hasher* hasher) {
|
||||
hasher->common.extra = NULL;
|
||||
hasher->common.is_setup_ = BROTLI_FALSE;
|
||||
hasher->common.extra[0] = NULL;
|
||||
hasher->common.extra[1] = NULL;
|
||||
hasher->common.extra[2] = NULL;
|
||||
hasher->common.extra[3] = NULL;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
|
||||
if (hasher->common.extra == NULL) return;
|
||||
BROTLI_FREE(m, hasher->common.extra);
|
||||
if (hasher->common.extra[0] != NULL) BROTLI_FREE(m, hasher->common.extra[0]);
|
||||
if (hasher->common.extra[1] != NULL) BROTLI_FREE(m, hasher->common.extra[1]);
|
||||
if (hasher->common.extra[2] != NULL) BROTLI_FREE(m, hasher->common.extra[2]);
|
||||
if (hasher->common.extra[3] != NULL) BROTLI_FREE(m, hasher->common.extra[3]);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void HasherReset(Hasher* hasher) {
|
||||
hasher->common.is_prepared_ = BROTLI_FALSE;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
|
||||
BROTLI_BOOL one_shot, const size_t input_size) {
|
||||
static BROTLI_INLINE void HasherSize(const BrotliEncoderParams* params,
|
||||
BROTLI_BOOL one_shot, const size_t input_size, size_t* alloc_size) {
|
||||
switch (params->hasher.type) {
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
return HashMemAllocInBytesH ## N(params, one_shot, input_size);
|
||||
#define SIZE_(N) \
|
||||
case N: \
|
||||
HashMemAllocInBytesH ## N(params, one_shot, input_size, alloc_size); \
|
||||
break;
|
||||
FOR_ALL_HASHERS(SIZE_)
|
||||
#undef SIZE_
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 0; /* Default case. */
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
|
||||
BrotliEncoderParams* params, const uint8_t* data, size_t position,
|
||||
size_t input_size, BROTLI_BOOL is_last) {
|
||||
BROTLI_BOOL one_shot = (position == 0 && is_last);
|
||||
if (hasher->common.extra == NULL) {
|
||||
size_t alloc_size;
|
||||
if (!hasher->common.is_setup_) {
|
||||
size_t alloc_size[4] = {0};
|
||||
size_t i;
|
||||
ChooseHasher(params, ¶ms->hasher);
|
||||
alloc_size = HasherSize(params, one_shot, input_size);
|
||||
hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
|
||||
hasher->common.params = params->hasher;
|
||||
hasher->common.dict_num_lookups = 0;
|
||||
hasher->common.dict_num_matches = 0;
|
||||
HasherSize(params, one_shot, input_size, alloc_size);
|
||||
for (i = 0; i < 4; ++i) {
|
||||
if (alloc_size[i] == 0) continue;
|
||||
hasher->common.extra[i] = BROTLI_ALLOC(m, uint8_t, alloc_size[i]);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra[i])) return;
|
||||
}
|
||||
switch (hasher->common.params.type) {
|
||||
#define INITIALIZE_(N) \
|
||||
case N: \
|
||||
@@ -440,6 +464,7 @@ static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
|
||||
break;
|
||||
}
|
||||
HasherReset(hasher);
|
||||
hasher->common.is_setup_ = BROTLI_TRUE;
|
||||
}
|
||||
|
||||
if (!hasher->common.is_prepared_) {
|
||||
@@ -454,10 +479,6 @@ static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
|
||||
#undef PREPARE_
|
||||
default: break;
|
||||
}
|
||||
if (position == 0) {
|
||||
hasher->common.dict_num_lookups = 0;
|
||||
hasher->common.dict_num_matches = 0;
|
||||
}
|
||||
hasher->common.is_prepared_ = BROTLI_TRUE;
|
||||
}
|
||||
}
|
||||
@@ -481,6 +502,232 @@ static BROTLI_INLINE void InitOrStitchToPreviousBlock(
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
|
||||
to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
|
||||
static BROTLI_INLINE void FindCompoundDictionaryMatch(
|
||||
const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length, const size_t distance_offset,
|
||||
const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
const uint32_t source_size = self->source_size;
|
||||
const size_t boundary = distance_offset - source_size;
|
||||
const uint32_t hash_bits = self->hash_bits;
|
||||
const uint32_t bucket_bits = self->bucket_bits;
|
||||
const uint32_t slot_bits = self->slot_bits;
|
||||
|
||||
const uint32_t hash_shift = 64u - bucket_bits;
|
||||
const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
|
||||
const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
|
||||
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
|
||||
const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]);
|
||||
const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]);
|
||||
const uint8_t* source = NULL;
|
||||
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
const uint64_t h =
|
||||
(BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
const uint32_t slot = key & slot_mask;
|
||||
const uint32_t head = heads[key];
|
||||
const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
|
||||
uint32_t item = (head == 0xFFFF) ? 1 : 0;
|
||||
|
||||
const void* tail = (void*)&items[self->num_items];
|
||||
if (self->magic == kPreparedDictionaryMagic) {
|
||||
source = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* kLeanPreparedDictionaryMagic */
|
||||
source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
for (i = 0; i < 4; ++i) {
|
||||
const size_t distance = (size_t)distance_cache[i];
|
||||
size_t offset;
|
||||
size_t limit;
|
||||
size_t len;
|
||||
if (distance <= boundary || distance > distance_offset) continue;
|
||||
offset = distance_offset - distance;
|
||||
limit = source_size - offset;
|
||||
limit = limit > max_length ? max_length : limit;
|
||||
len = FindMatchLengthWithLimit(&source[offset], &data[cur_ix_masked],
|
||||
limit);
|
||||
if (len >= 2) {
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
if (len > best_len) best_len = len;
|
||||
out->len = len;
|
||||
out->len_code_delta = 0;
|
||||
out->distance = distance;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
while (item == 0) {
|
||||
size_t offset;
|
||||
size_t distance;
|
||||
size_t limit;
|
||||
item = *chain;
|
||||
chain++;
|
||||
offset = item & 0x7FFFFFFF;
|
||||
item &= 0x80000000;
|
||||
distance = distance_offset - offset;
|
||||
limit = source_size - offset;
|
||||
limit = (limit > max_length) ? max_length : limit;
|
||||
if (distance > max_distance) continue;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask || best_len >= limit ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&source[offset + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&source[offset],
|
||||
&data[cur_ix_masked],
|
||||
limit);
|
||||
if (len >= 4) {
|
||||
score_t score = BackwardReferenceScore(len, distance);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->len_code_delta = 0;
|
||||
out->distance = distance;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget
|
||||
to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */
|
||||
static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
|
||||
const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const size_t cur_ix, const size_t min_length,
|
||||
const size_t max_length, const size_t distance_offset,
|
||||
const size_t max_distance, BackwardMatch* matches, size_t match_limit) {
|
||||
const uint32_t source_size = self->source_size;
|
||||
const uint32_t hash_bits = self->hash_bits;
|
||||
const uint32_t bucket_bits = self->bucket_bits;
|
||||
const uint32_t slot_bits = self->slot_bits;
|
||||
|
||||
const uint32_t hash_shift = 64u - bucket_bits;
|
||||
const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits);
|
||||
const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits);
|
||||
|
||||
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
|
||||
const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]);
|
||||
const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]);
|
||||
const uint8_t* source = NULL;
|
||||
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
size_t best_len = min_length;
|
||||
const uint64_t h =
|
||||
(BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) *
|
||||
kPreparedDictionaryHashMul64Long;
|
||||
const uint32_t key = (uint32_t)(h >> hash_shift);
|
||||
const uint32_t slot = key & slot_mask;
|
||||
const uint32_t head = heads[key];
|
||||
const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head];
|
||||
uint32_t item = (head == 0xFFFF) ? 1 : 0;
|
||||
size_t found = 0;
|
||||
|
||||
const void* tail = (void*)&items[self->num_items];
|
||||
if (self->magic == kPreparedDictionaryMagic) {
|
||||
source = (const uint8_t*)tail;
|
||||
} else {
|
||||
/* kLeanPreparedDictionaryMagic */
|
||||
source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail);
|
||||
}
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
while (item == 0) {
|
||||
size_t offset;
|
||||
size_t distance;
|
||||
size_t limit;
|
||||
size_t len;
|
||||
item = *chain;
|
||||
chain++;
|
||||
offset = item & 0x7FFFFFFF;
|
||||
item &= 0x80000000;
|
||||
distance = distance_offset - offset;
|
||||
limit = source_size - offset;
|
||||
limit = (limit > max_length) ? max_length : limit;
|
||||
if (distance > max_distance) continue;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
best_len >= limit ||
|
||||
data[cur_ix_masked + best_len] != source[offset + best_len]) {
|
||||
continue;
|
||||
}
|
||||
len = FindMatchLengthWithLimit(
|
||||
&source[offset], &data[cur_ix_masked], limit);
|
||||
if (len > best_len) {
|
||||
best_len = len;
|
||||
InitBackwardMatch(matches++, distance, len);
|
||||
found++;
|
||||
if (found == match_limit) break;
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void LookupCompoundDictionaryMatch(
|
||||
const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
|
||||
const size_t cur_ix, const size_t max_length,
|
||||
const size_t max_ring_buffer_distance, const size_t max_distance,
|
||||
HasherSearchResult* sr) {
|
||||
size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
|
||||
size_t d;
|
||||
for (d = 0; d < addon->num_chunks; ++d) {
|
||||
/* Only one prepared dictionary type is currently supported. */
|
||||
FindCompoundDictionaryMatch(
|
||||
(const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
|
||||
distance_cache, cur_ix, max_length,
|
||||
base_offset - addon->chunk_offsets[d], max_distance, sr);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t LookupAllCompoundDictionaryMatches(
|
||||
const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t ring_buffer_mask, const size_t cur_ix, size_t min_length,
|
||||
const size_t max_length, const size_t max_ring_buffer_distance,
|
||||
const size_t max_distance, BackwardMatch* matches,
|
||||
size_t match_limit) {
|
||||
size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1;
|
||||
size_t d;
|
||||
size_t total_found = 0;
|
||||
for (d = 0; d < addon->num_chunks; ++d) {
|
||||
/* Only one prepared dictionary type is currently supported. */
|
||||
total_found += FindAllCompoundDictionaryMatches(
|
||||
(const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask,
|
||||
cur_ix, min_length, max_length, base_offset - addon->chunk_offsets[d],
|
||||
max_distance, matches + total_found, match_limit - total_found);
|
||||
if (total_found == match_limit) break;
|
||||
if (total_found > 0) {
|
||||
min_length = BackwardMatchLength(&matches[total_found - 1]);
|
||||
}
|
||||
}
|
||||
return total_found;
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Basic common hash functions / constants. */
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
#define THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
|
||||
/* kHashMul32 multiplier has these properties:
|
||||
* The multiplier must be odd. Otherwise we may lose the highest bit.
|
||||
* No long streaks of ones or zeros.
|
||||
* There is no effort to ensure that it is a prime, the oddity is enough
|
||||
for this use.
|
||||
* The number has been tuned heuristically against compression benchmarks. */
|
||||
static const uint32_t kHashMul32 = 0x1E35A7BD;
|
||||
static const uint64_t kHashMul64 =
|
||||
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 14);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash15(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - 15);
|
||||
}
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_
|
||||
@@ -30,10 +30,10 @@ static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
|
||||
typedef struct HashComposite {
|
||||
HASHER_A ha;
|
||||
HASHER_B hb;
|
||||
HasherCommon ha_common;
|
||||
HasherCommon hb_common;
|
||||
|
||||
/* Shortcuts. */
|
||||
void* extra;
|
||||
HasherCommon* common;
|
||||
|
||||
BROTLI_BOOL fresh;
|
||||
@@ -43,12 +43,12 @@ typedef struct HashComposite {
|
||||
static void FN(Initialize)(HasherCommon* common,
|
||||
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
self->extra = common->extra;
|
||||
|
||||
self->ha_common = *self->common;
|
||||
self->hb_common = *self->common;
|
||||
self->fresh = BROTLI_TRUE;
|
||||
self->params = params;
|
||||
/* TODO: Initialize of the hashers is defered to Prepare (and params
|
||||
/* TODO(lode): Initialize of the hashers is deferred to Prepare (and params
|
||||
remembered here) because we don't get the one_shot and input_size params
|
||||
here that are needed to know the memory size of them. Instead provide
|
||||
those params to all hashers FN(Initialize) */
|
||||
@@ -59,21 +59,36 @@ static void FN(Prepare)(
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
if (self->fresh) {
|
||||
self->fresh = BROTLI_FALSE;
|
||||
self->hb_common.extra = (uint8_t*)self->extra +
|
||||
FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
|
||||
self->ha_common.extra[0] = self->common->extra[0];
|
||||
self->ha_common.extra[1] = self->common->extra[1];
|
||||
self->ha_common.extra[2] = NULL;
|
||||
self->ha_common.extra[3] = NULL;
|
||||
self->hb_common.extra[0] = self->common->extra[2];
|
||||
self->hb_common.extra[1] = self->common->extra[3];
|
||||
self->hb_common.extra[2] = NULL;
|
||||
self->hb_common.extra[3] = NULL;
|
||||
|
||||
FN_A(Initialize)(self->common, &self->ha, self->params);
|
||||
FN_A(Initialize)(&self->ha_common, &self->ha, self->params);
|
||||
FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
|
||||
}
|
||||
FN_A(Prepare)(&self->ha, one_shot, input_size, data);
|
||||
FN_B(Prepare)(&self->hb, one_shot, input_size, data);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
|
||||
FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t alloc_size_a[4] = {0};
|
||||
size_t alloc_size_b[4] = {0};
|
||||
FN_A(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_a);
|
||||
FN_B(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_b);
|
||||
/* Should never happen. */
|
||||
if (alloc_size_a[2] != 0 || alloc_size_a[3] != 0) exit(EXIT_FAILURE);
|
||||
if (alloc_size_b[2] != 0 || alloc_size_b[3] != 0) exit(EXIT_FAILURE);
|
||||
alloc_size[0] = alloc_size_a[0];
|
||||
alloc_size[1] = alloc_size_a[1];
|
||||
alloc_size[2] = alloc_size_b[0];
|
||||
alloc_size[3] = alloc_size_b[1];
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
|
||||
|
||||
@@ -49,7 +49,7 @@ typedef struct HashForgetfulChain {
|
||||
size_t max_hops;
|
||||
|
||||
/* Shortcuts. */
|
||||
void* extra;
|
||||
void* extra[2];
|
||||
HasherCommon* common;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
@@ -77,14 +77,15 @@ static uint8_t* FN(TinyHash)(void* extra) {
|
||||
}
|
||||
|
||||
static FN(Bank)* FN(Banks)(void* extra) {
|
||||
return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
|
||||
return (FN(Bank)*)(extra);
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common = common;
|
||||
self->extra = common->extra;
|
||||
self->extra[0] = common->extra[0];
|
||||
self->extra[1] = common->extra[1];
|
||||
|
||||
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
|
||||
}
|
||||
@@ -92,9 +93,9 @@ static void FN(Initialize)(
|
||||
static void FN(Prepare)(
|
||||
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]);
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
@@ -116,24 +117,25 @@ static void FN(Prepare)(
|
||||
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
|
||||
sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
|
||||
alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE +
|
||||
sizeof(uint16_t) * BUCKET_SIZE + sizeof(uint8_t) * 65536;
|
||||
alloc_size[1] = sizeof(FN(Bank)) * NUM_BANKS;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
|
||||
node to corresponding chain; also update tiny_hash for current position. */
|
||||
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]);
|
||||
const size_t key = FN(HashBytes)(&data[ix & mask]);
|
||||
const size_t bank = key & (NUM_BANKS - 1);
|
||||
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
|
||||
@@ -196,10 +198,10 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
const size_t cur_ix, const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
|
||||
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]);
|
||||
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]);
|
||||
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra[0]);
|
||||
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]);
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
@@ -210,6 +212,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
const uint8_t tiny_hash = (uint8_t)(key);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < NUM_LAST_DISTANCES_TO_CHECK; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
@@ -239,6 +244,11 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const size_t bank = key & (NUM_BANKS - 1);
|
||||
size_t backward = 0;
|
||||
@@ -255,7 +265,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
delta = banks[bank].slots[last].delta;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
|
||||
@@ -20,13 +20,12 @@ static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||
const uint64_t mask,
|
||||
const int shift) {
|
||||
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||
uint64_t hash_mul) {
|
||||
const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (uint32_t)(h >> shift);
|
||||
return (size_t)(h >> (64 - 15));
|
||||
}
|
||||
|
||||
typedef struct HashLongestMatch {
|
||||
@@ -35,10 +34,8 @@ typedef struct HashLongestMatch {
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Left-shift for computing hash bucket index from hash value. */
|
||||
int hash_shift_;
|
||||
/* Mask for selecting the next 4-8 bytes of input */
|
||||
uint64_t hash_mask_;
|
||||
/* Hash multiplier tuned to match length. */
|
||||
uint64_t hash_mul_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
@@ -63,16 +60,16 @@ static void FN(Initialize)(
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 64 - common->params.bucket_bits;
|
||||
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
|
||||
self->hash_mul_ = kHashMul64 << (64 - 5 * 8);
|
||||
BROTLI_DCHECK(common->params.bucket_bits == 15);
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
self->num_ = (uint16_t*)common->extra;
|
||||
self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->buckets_ = (uint32_t*)common->extra[1];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(
|
||||
@@ -84,8 +81,7 @@ static void FN(Prepare)(
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_,
|
||||
self->hash_shift_);
|
||||
const size_t key = FN(HashBytes)(&data[i], self->hash_mul_);
|
||||
num[key] = 0;
|
||||
}
|
||||
} else {
|
||||
@@ -93,15 +89,15 @@ static void FN(Prepare)(
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(uint16_t) * bucket_size +
|
||||
sizeof(uint32_t) * bucket_size * block_size;
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
@@ -111,8 +107,7 @@ static BROTLI_INLINE void FN(Store)(
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
|
||||
self->hash_shift_);
|
||||
const size_t key = FN(HashBytes)(&data[ix & mask], self->hash_mul_);
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
++num[key];
|
||||
@@ -175,8 +170,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const size_t key = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
@@ -189,8 +192,10 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
@@ -216,41 +221,48 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint32_t key = FN(HashBytes)(
|
||||
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ?
|
||||
(num[key] - self->block_size_) : 0u;
|
||||
for (i = num[key]; i > down;) {
|
||||
const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked);
|
||||
const size_t max_length_m4 = max_length - 4;
|
||||
i = num[key];
|
||||
for (; i > down;) {
|
||||
size_t prev_ix = bucket[--i & self->block_mask_];
|
||||
uint32_t current4;
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
current4 = BrotliUnalignedRead32(data + prev_ix);
|
||||
if (first4 != current4) continue;
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 4) {
|
||||
/* Comparing for >= 3 does not change the semantics, but just saves
|
||||
for a few unnecessary binary logarithms in backward reference
|
||||
score, since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
|
||||
&data[cur_ix_masked + 4],
|
||||
max_length_m4) + 4;
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,304 @@
|
||||
/* NOLINT(build/header_guard) */
|
||||
/* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* template parameters: FN */
|
||||
|
||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||
help create backward references to previous data.
|
||||
|
||||
This is a hash map of fixed size (bucket_size_) to a ring buffer of
|
||||
fixed size (block_size_). The ring buffer contains the last block_size_
|
||||
index positions of the given hash key in the compressed data. */
|
||||
|
||||
#define HashLongestMatch HASHER()
|
||||
|
||||
#define TAG_HASH_BITS 8
|
||||
#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1)
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
|
||||
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
|
||||
uint64_t hash_mul) {
|
||||
const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (size_t)(h >> (64 - 15 - TAG_HASH_BITS));
|
||||
}
|
||||
|
||||
typedef struct HashLongestMatch {
|
||||
/* Number of hash buckets. */
|
||||
size_t bucket_size_;
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Hash multiplier tuned to match length. */
|
||||
uint64_t hash_mul_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
|
||||
/* --- Dynamic size members --- */
|
||||
|
||||
/* Number of entries in a particular bucket. */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
|
||||
uint8_t* tags_;
|
||||
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_mul_ = kHashMul64 << (64 - 5 * 8);
|
||||
BROTLI_DCHECK(common->params.bucket_bits == 15);
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->tags_ = (uint8_t*)common->extra[1];
|
||||
self->buckets_ = (uint32_t*)common->extra[2];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const size_t hash = FN(HashBytes)(&data[i], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
num[key] = 65535;
|
||||
}
|
||||
} else {
|
||||
/* Set all the bytes of num to 255, which makes each uint16_t 65535. */
|
||||
memset(num, 255, self->bucket_size_ * sizeof(num[0]));
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size;
|
||||
alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
--num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
tags[offset] = tag;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
max_length and stores the position cur_ix in the hash table.
|
||||
|
||||
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
|
||||
values; if this method is invoked repeatedly with the same distance
|
||||
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
|
||||
|
||||
Does not look for matches longer than max_length.
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const size_t hash = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
PREFETCH_L1(tag_bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
continue;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 3 || (len == 2 && i < 2)) {
|
||||
/* Comparing for >= 2 does not change the semantics, but just saves for
|
||||
a few unnecessary binary logarithms in backward reference score,
|
||||
since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked);
|
||||
const size_t max_length_m4 = max_length - 4;
|
||||
const size_t head = (num[key] + 1) & self->block_mask_;
|
||||
uint64_t matches =
|
||||
GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head);
|
||||
/* Mask off any matches from uninitialized tags. */
|
||||
uint16_t n = 65535 - num[key];
|
||||
uint64_t block_has_unused_slots = self->block_size_ > n;
|
||||
uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1;
|
||||
matches &= mask;
|
||||
for (; matches > 0; matches &= (matches - 1)) {
|
||||
const size_t rb_index =
|
||||
(head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_;
|
||||
size_t prev_ix = bucket[rb_index];
|
||||
uint32_t current4;
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
current4 = BrotliUnalignedRead32(data + prev_ix);
|
||||
if (first4 != current4) continue;
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4],
|
||||
&data[cur_ix_masked + 4],
|
||||
max_length_m4) + 4;
|
||||
const score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
|
||||
tag_bucket[num[key] & self->block_mask_] = tag;
|
||||
--num[key];
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
#undef HashLongestMatch
|
||||
@@ -54,10 +54,6 @@ typedef struct HashLongestMatch {
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
|
||||
static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
|
||||
return (uint16_t*)extra;
|
||||
}
|
||||
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
@@ -68,8 +64,8 @@ static void FN(Initialize)(
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_ = (uint16_t*)common->extra;
|
||||
self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->buckets_ = (uint32_t*)common->extra[1];
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
@@ -92,15 +88,15 @@ static void FN(Prepare)(
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(uint16_t) * bucket_size +
|
||||
sizeof(uint32_t) * bucket_size * block_size;
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
@@ -108,11 +104,13 @@ static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
||||
const size_t minor_ix = self->num_[key] & self->block_mask_;
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
self->buckets_[offset] = (uint32_t)ix;
|
||||
++self->num_[key];
|
||||
++num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
@@ -171,8 +169,17 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const uint32_t key =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
@@ -185,8 +192,10 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
@@ -212,10 +221,12 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint32_t key =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
const size_t down =
|
||||
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
|
||||
for (i = num[key]; i > down;) {
|
||||
@@ -225,9 +236,13 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask ||
|
||||
prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
|
||||
@@ -49,7 +49,7 @@ static void FN(Initialize)(
|
||||
self->common = common;
|
||||
|
||||
BROTLI_UNUSED(params);
|
||||
self->buckets_ = (uint32_t*)common->extra;
|
||||
self->buckets_ = (uint32_t*)common->extra[0];
|
||||
}
|
||||
|
||||
static void FN(Prepare)(
|
||||
@@ -80,13 +80,13 @@ static void FN(Prepare)(
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
return sizeof(uint32_t) * BUCKET_SIZE;
|
||||
alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE;
|
||||
}
|
||||
|
||||
/* Look at 5 bytes at &data[ix & mask].
|
||||
@@ -155,6 +155,7 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t best_len_in = out->len;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* TODO: compare 4 bytes at once (and set the minimum best len to 4) */
|
||||
int compare_char = data[cur_ix_masked + best_len_in];
|
||||
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
|
||||
size_t key_out;
|
||||
@@ -163,8 +164,11 @@ static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
size_t best_len = best_len_in;
|
||||
size_t cached_backward = (size_t)distance_cache[0];
|
||||
size_t prev_ix = cur_ix - cached_backward;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
out->len_code_delta = 0;
|
||||
if (prev_ix < cur_ix) {
|
||||
if (prev_ix < cur_ix && cached_backward <= max_backward) {
|
||||
prev_ix &= (uint32_t)ring_buffer_mask;
|
||||
if (compare_char == data[prev_ix + best_len]) {
|
||||
const size_t len = FindMatchLengthWithLimit(
|
||||
|
||||
@@ -0,0 +1,278 @@
|
||||
/* NOLINT(build/header_guard) */
|
||||
/* Copyright 2010 Google Inc. All Rights Reserved.
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
/* template parameters: FN */
|
||||
/* A (forgetful) hash table to the data seen by the compressor, to
|
||||
help create backward references to previous data.
|
||||
This is a hash map of fixed size (bucket_size_) to a ring buffer of
|
||||
fixed size (block_size_). The ring buffer contains the last block_size_
|
||||
index positions of the given hash key in the compressed data. */
|
||||
#define HashLongestMatch HASHER()
|
||||
#define TAG_HASH_BITS 8
|
||||
#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1)
|
||||
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
|
||||
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
|
||||
/* HashBytes is the function that chooses the bucket to place the address in. */
|
||||
static uint32_t FN(HashBytes)(
|
||||
const uint8_t* BROTLI_RESTRICT data, const int shift) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return (uint32_t)(h >> shift);
|
||||
}
|
||||
typedef struct HashLongestMatch {
|
||||
/* Number of hash buckets. */
|
||||
size_t bucket_size_;
|
||||
/* Only block_size_ newest backward references are kept,
|
||||
and the older are forgotten. */
|
||||
size_t block_size_;
|
||||
/* Left-shift for computing hash bucket index from hash value. */
|
||||
int hash_shift_;
|
||||
/* Mask for accessing entries in a block (in a ring-buffer manner). */
|
||||
uint32_t block_mask_;
|
||||
int block_bits_;
|
||||
int num_last_distances_to_check_;
|
||||
/* Shortcuts. */
|
||||
HasherCommon* common_;
|
||||
/* --- Dynamic size members --- */
|
||||
/* Number of entries in a particular bucket. */
|
||||
uint16_t* num_; /* uint16_t[bucket_size]; */
|
||||
uint8_t* tags_;
|
||||
/* Buckets containing block_size_ of backward references. */
|
||||
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
|
||||
} HashLongestMatch;
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->common_ = common;
|
||||
BROTLI_UNUSED(params);
|
||||
self->hash_shift_ = 32 - common->params.bucket_bits - TAG_HASH_BITS;
|
||||
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
|
||||
self->block_size_ = (size_t)1 << common->params.block_bits;
|
||||
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
|
||||
self->num_ = (uint16_t*)common->extra[0];
|
||||
self->tags_ = (uint8_t*)common->extra[1];
|
||||
self->buckets_ = (uint32_t*)common->extra[2];
|
||||
self->block_bits_ = common->params.block_bits;
|
||||
self->num_last_distances_to_check_ =
|
||||
common->params.num_last_distances_to_check;
|
||||
}
|
||||
static void FN(Prepare)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
/* Partial preparation is 100 times slower (per socket). */
|
||||
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
|
||||
if (one_shot && input_size <= partial_prepare_threshold) {
|
||||
size_t i;
|
||||
for (i = 0; i < input_size; ++i) {
|
||||
const uint32_t hash = FN(HashBytes)(&data[i], self->hash_shift_);
|
||||
const uint32_t key = hash >> TAG_HASH_BITS;
|
||||
num[key] = 65535;
|
||||
}
|
||||
} else {
|
||||
/* Set all the bytes of num to 255, which makes each uint16_t 65535. */
|
||||
memset(num, 255, self->bucket_size_ * sizeof(num[0]));
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
|
||||
size_t block_size = (size_t)1 << params->hasher.block_bits;
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = sizeof(uint16_t) * bucket_size;
|
||||
alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size;
|
||||
alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size;
|
||||
}
|
||||
/* Look at 4 bytes at &data[ix & mask].
|
||||
Compute a hash from these, and store the value of ix at that position. */
|
||||
static BROTLI_INLINE void FN(Store)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
|
||||
const size_t mask, const size_t ix) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
|
||||
const size_t key = hash >> TAG_HASH_BITS;
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t minor_ix = num[key] & self->block_mask_;
|
||||
const size_t offset = minor_ix + (key << self->block_bits_);
|
||||
--num[key];
|
||||
buckets[offset] = (uint32_t)ix;
|
||||
tags[offset] = tag;
|
||||
}
|
||||
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
|
||||
const size_t ix_start, const size_t ix_end) {
|
||||
size_t i;
|
||||
for (i = ix_start; i < ix_end; ++i) {
|
||||
FN(Store)(self, data, mask, i);
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
|
||||
size_t ringbuffer_mask) {
|
||||
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
|
||||
/* Prepare the hashes for three last bytes of the last write.
|
||||
These could not be calculated before, since they require knowledge
|
||||
of both the previous and the current block. */
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
|
||||
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
|
||||
}
|
||||
}
|
||||
static BROTLI_INLINE void FN(PrepareDistanceCache)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
int* BROTLI_RESTRICT distance_cache) {
|
||||
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
|
||||
}
|
||||
|
||||
/* Find a longest backward match of &data[cur_ix] up to the length of
|
||||
max_length and stores the position cur_ix in the hash table.
|
||||
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
|
||||
values; if this method is invoked repeatedly with the same distance
|
||||
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
|
||||
Does not look for matches longer than max_length.
|
||||
Does not look for matches further away than max_backward.
|
||||
Writes the best match into |out|.
|
||||
|out|->score is updated only if a better match is found. */
|
||||
static BROTLI_INLINE void FN(FindLongestMatch)(
|
||||
HashLongestMatch* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderDictionary* dictionary,
|
||||
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
|
||||
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
|
||||
const size_t max_length, const size_t max_backward,
|
||||
const size_t dictionary_distance, const size_t max_distance,
|
||||
HasherSearchResult* BROTLI_RESTRICT out) {
|
||||
uint16_t* BROTLI_RESTRICT num = self->num_;
|
||||
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
|
||||
uint8_t* BROTLI_RESTRICT tags = self->tags_;
|
||||
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
|
||||
/* Don't accept a short copy from far away. */
|
||||
score_t min_score = out->score;
|
||||
score_t best_score = out->score;
|
||||
size_t best_len = out->len;
|
||||
size_t i;
|
||||
/* Precalculate the hash key and prefetch the bucket. */
|
||||
const uint32_t hash =
|
||||
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
|
||||
const uint32_t key = hash >> TAG_HASH_BITS;
|
||||
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
|
||||
uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_];
|
||||
PREFETCH_L1(bucket);
|
||||
PREFETCH_L1(tag_bucket);
|
||||
if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16);
|
||||
out->len = 0;
|
||||
out->len_code_delta = 0;
|
||||
|
||||
BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask + 1);
|
||||
|
||||
/* Try last distance first. */
|
||||
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
|
||||
const size_t backward = (size_t)distance_cache[i];
|
||||
size_t prev_ix = (size_t)(cur_ix - backward);
|
||||
if (prev_ix >= cur_ix) {
|
||||
continue;
|
||||
}
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
continue;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 3 || (len == 2 && i < 2)) {
|
||||
/* Comparing for >= 2 does not change the semantics, but just saves for
|
||||
a few unnecessary binary logarithms in backward reference score,
|
||||
since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScoreUsingLastDistance(len);
|
||||
if (best_score < score) {
|
||||
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* we require matches of len >4, so increase best_len to 3, so we can compare
|
||||
* 4 bytes all the time. */
|
||||
if (best_len < 3) {
|
||||
best_len = 3;
|
||||
}
|
||||
{
|
||||
const uint8_t tag = hash & TAG_HASH_MASK;
|
||||
const size_t head = (num[key] + 1) & self->block_mask_;
|
||||
uint64_t matches =
|
||||
GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head);
|
||||
/* Mask off any matches from uninitialized tags. */
|
||||
uint16_t n = 65535 - num[key];
|
||||
uint64_t block_has_unused_slots = self->block_size_ > n;
|
||||
uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1;
|
||||
matches &= mask;
|
||||
for (; matches > 0; matches &= (matches - 1)) {
|
||||
const size_t rb_index =
|
||||
(head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_;
|
||||
size_t prev_ix = bucket[rb_index];
|
||||
const size_t backward = cur_ix - prev_ix;
|
||||
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
|
||||
break;
|
||||
}
|
||||
prev_ix &= ring_buffer_mask;
|
||||
if (cur_ix_masked + best_len > ring_buffer_mask) {
|
||||
break;
|
||||
}
|
||||
if (prev_ix + best_len > ring_buffer_mask ||
|
||||
/* compare 4 bytes ending at best_len + 1 */
|
||||
BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) !=
|
||||
BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) {
|
||||
continue;
|
||||
}
|
||||
{
|
||||
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
|
||||
&data[cur_ix_masked],
|
||||
max_length);
|
||||
if (len >= 4) {
|
||||
/* Comparing for >= 3 does not change the semantics, but just saves
|
||||
for a few unnecessary binary logarithms in backward reference
|
||||
score, since we are not interested in such short matches. */
|
||||
score_t score = BackwardReferenceScore(len, backward);
|
||||
if (best_score < score) {
|
||||
best_score = score;
|
||||
best_len = len;
|
||||
out->len = best_len;
|
||||
out->distance = backward;
|
||||
out->score = best_score;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
|
||||
tag_bucket[num[key] & self->block_mask_] = tag;
|
||||
--num[key];
|
||||
}
|
||||
if (min_score == out->score) {
|
||||
SearchInStaticDictionary(dictionary,
|
||||
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
|
||||
max_distance, out, BROTLI_FALSE);
|
||||
}
|
||||
}
|
||||
#undef HashLongestMatch
|
||||
@@ -67,7 +67,7 @@ static void FN(Initialize)(
|
||||
self->factor_remove *= self->factor;
|
||||
}
|
||||
|
||||
self->table = (uint32_t*)common->extra;
|
||||
self->table = (uint32_t*)common->extra[0];
|
||||
for (i = 0; i < NUMBUCKETS; i++) {
|
||||
self->table[i] = FN(kInvalidPos);
|
||||
}
|
||||
@@ -88,13 +88,13 @@ static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
|
||||
BROTLI_UNUSED(one_shot);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
return NUMBUCKETS * sizeof(uint32_t);
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
BROTLI_UNUSED(params);
|
||||
BROTLI_UNUSED(one_shot);
|
||||
BROTLI_UNUSED(input_size);
|
||||
alloc_size[0] = NUMBUCKETS * sizeof(uint32_t);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
|
||||
|
||||
@@ -57,8 +57,8 @@ typedef struct HashToBinaryTree {
|
||||
static void FN(Initialize)(
|
||||
HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
|
||||
const BrotliEncoderParams* params) {
|
||||
self->buckets_ = (uint32_t*)common->extra;
|
||||
self->forest_ = &self->buckets_[BUCKET_SIZE];
|
||||
self->buckets_ = (uint32_t*)common->extra[0];
|
||||
self->forest_ = (uint32_t*)common->extra[1];
|
||||
|
||||
self->window_mask_ = (1u << params->lgwin) - 1u;
|
||||
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
|
||||
@@ -78,14 +78,15 @@ static void FN(Prepare)
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
|
||||
static BROTLI_INLINE void FN(HashMemAllocInBytes)(
|
||||
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
|
||||
size_t input_size) {
|
||||
size_t input_size, size_t* alloc_size) {
|
||||
size_t num_nodes = (size_t)1 << params->lgwin;
|
||||
if (one_shot && input_size < num_nodes) {
|
||||
num_nodes = input_size;
|
||||
}
|
||||
return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
|
||||
alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE;
|
||||
alloc_size[1] = 2 * sizeof(uint32_t) * num_nodes;
|
||||
}
|
||||
|
||||
static BROTLI_INLINE size_t FN(LeftChildIndex)(
|
||||
|
||||
@@ -6,11 +6,12 @@
|
||||
|
||||
/* Build per-context histograms of literals, commands and distance codes. */
|
||||
|
||||
#include "./histogram.h"
|
||||
#include "histogram.h"
|
||||
|
||||
#include "../common/context.h"
|
||||
#include "./block_splitter.h"
|
||||
#include "./command.h"
|
||||
#include "../common/platform.h"
|
||||
#include "block_splitter.h"
|
||||
#include "command.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -63,7 +64,7 @@ void BrotliBuildHistogramsWithContext(
|
||||
BlockSplitIteratorNext(&insert_and_copy_it);
|
||||
HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_],
|
||||
cmd->cmd_prefix_);
|
||||
/* TODO: unwrap iterator blocks. */
|
||||
/* TODO(eustas): unwrap iterator blocks. */
|
||||
for (j = cmd->insert_len_; j != 0; --j) {
|
||||
size_t context;
|
||||
BlockSplitIteratorNext(&literal_it);
|
||||
|
||||
@@ -9,14 +9,11 @@
|
||||
#ifndef BROTLI_ENC_HISTOGRAM_H_
|
||||
#define BROTLI_ENC_HISTOGRAM_H_
|
||||
|
||||
#include <string.h> /* memset */
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./block_splitter.h"
|
||||
#include "./command.h"
|
||||
#include "block_splitter.h"
|
||||
#include "command.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -28,7 +25,7 @@ extern "C" {
|
||||
#define FN(X) X ## Literal
|
||||
#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
|
||||
#define DataType uint8_t
|
||||
#include "./histogram_inc.h" /* NOLINT(build/include) */
|
||||
#include "histogram_inc.h" /* NOLINT(build/include) */
|
||||
#undef DataType
|
||||
#undef DATA_SIZE
|
||||
#undef FN
|
||||
@@ -36,13 +33,13 @@ extern "C" {
|
||||
#define FN(X) X ## Command
|
||||
#define DataType uint16_t
|
||||
#define DATA_SIZE BROTLI_NUM_COMMAND_SYMBOLS
|
||||
#include "./histogram_inc.h" /* NOLINT(build/include) */
|
||||
#include "histogram_inc.h" /* NOLINT(build/include) */
|
||||
#undef DATA_SIZE
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
|
||||
#include "./histogram_inc.h" /* NOLINT(build/include) */
|
||||
#include "histogram_inc.h" /* NOLINT(build/include) */
|
||||
#undef DataType
|
||||
#undef DATA_SIZE
|
||||
#undef FN
|
||||
|
||||
@@ -7,12 +7,11 @@
|
||||
/* Literal cost model to allow backward reference replacement to be efficient.
|
||||
*/
|
||||
|
||||
#include "./literal_cost.h"
|
||||
#include "literal_cost.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "./utf8_util.h"
|
||||
#include "fast_log.h"
|
||||
#include "utf8_util.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -54,22 +53,23 @@ static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask,
|
||||
}
|
||||
|
||||
static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
const uint8_t* data, float* cost) {
|
||||
const uint8_t* data,
|
||||
size_t* histogram, float* cost) {
|
||||
/* max_utf8 is 0 (normal ASCII single byte modeling),
|
||||
1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */
|
||||
const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data);
|
||||
size_t histogram[3][256] = { { 0 } };
|
||||
size_t window_half = 495;
|
||||
size_t in_window = BROTLI_MIN(size_t, window_half, len);
|
||||
size_t in_window_utf8[3] = { 0 };
|
||||
|
||||
size_t i;
|
||||
memset(histogram, 0, 3 * 256 * sizeof(histogram[0]));
|
||||
|
||||
{ /* Bootstrap histograms. */
|
||||
size_t last_c = 0;
|
||||
size_t utf8_pos = 0;
|
||||
for (i = 0; i < in_window; ++i) {
|
||||
size_t c = data[(pos + i) & mask];
|
||||
++histogram[utf8_pos][c];
|
||||
++histogram[256 * utf8_pos + c];
|
||||
++in_window_utf8[utf8_pos];
|
||||
utf8_pos = UTF8Position(last_c, c, max_utf8);
|
||||
last_c = c;
|
||||
@@ -85,7 +85,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
size_t last_c =
|
||||
i < window_half + 2 ? 0 : data[(pos + i - window_half - 2) & mask];
|
||||
size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
|
||||
--histogram[utf8_pos2][data[(pos + i - window_half) & mask]];
|
||||
--histogram[256 * utf8_pos2 + data[(pos + i - window_half) & mask]];
|
||||
--in_window_utf8[utf8_pos2];
|
||||
}
|
||||
if (i + window_half < len) {
|
||||
@@ -93,7 +93,7 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
size_t c = data[(pos + i + window_half - 1) & mask];
|
||||
size_t last_c = data[(pos + i + window_half - 2) & mask];
|
||||
size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8);
|
||||
++histogram[utf8_pos2][data[(pos + i + window_half) & mask]];
|
||||
++histogram[256 * utf8_pos2 + data[(pos + i + window_half) & mask]];
|
||||
++in_window_utf8[utf8_pos2];
|
||||
}
|
||||
{
|
||||
@@ -101,7 +101,9 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
size_t last_c = i < 2 ? 0 : data[(pos + i - 2) & mask];
|
||||
size_t utf8_pos = UTF8Position(last_c, c, max_utf8);
|
||||
size_t masked_pos = (pos + i) & mask;
|
||||
size_t histo = histogram[utf8_pos][data[masked_pos]];
|
||||
size_t histo = histogram[256 * utf8_pos + data[masked_pos]];
|
||||
static const size_t prologue_length = 2000;
|
||||
static const double multiplier = 0.35 / 2000;
|
||||
double lit_cost;
|
||||
if (histo == 0) {
|
||||
histo = 1;
|
||||
@@ -116,8 +118,8 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
Perhaps because the entropy source is changing its properties
|
||||
rapidly in the beginning of the file, perhaps because the beginning
|
||||
of the data is a statistical "anomaly". */
|
||||
if (i < 2000) {
|
||||
lit_cost += 0.7 - ((double)(2000 - i) / 2000.0 * 0.35);
|
||||
if (i < prologue_length) {
|
||||
lit_cost += 0.35 + multiplier * (double)i;
|
||||
}
|
||||
cost[i] = (float)lit_cost;
|
||||
}
|
||||
@@ -125,17 +127,18 @@ static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask,
|
||||
}
|
||||
|
||||
void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask,
|
||||
const uint8_t* data, float* cost) {
|
||||
const uint8_t* data,
|
||||
size_t* histogram, float* cost) {
|
||||
if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) {
|
||||
EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, cost);
|
||||
EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, histogram, cost);
|
||||
return;
|
||||
} else {
|
||||
size_t histogram[256] = { 0 };
|
||||
size_t window_half = 2000;
|
||||
size_t in_window = BROTLI_MIN(size_t, window_half, len);
|
||||
size_t i;
|
||||
memset(histogram, 0, 256 * sizeof(histogram[0]));
|
||||
|
||||
/* Bootstrap histogram. */
|
||||
size_t i;
|
||||
for (i = 0; i < in_window; ++i) {
|
||||
++histogram[data[(pos + i) & mask]];
|
||||
}
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#define BROTLI_ENC_LITERAL_COST_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -21,7 +20,8 @@ extern "C" {
|
||||
ring-buffer (data, mask) will take entropy coded and writes these estimates
|
||||
to the cost[0..len) array. */
|
||||
BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
|
||||
size_t pos, size_t len, size_t mask, const uint8_t* data, float* cost);
|
||||
size_t pos, size_t len, size_t mask, const uint8_t* data, size_t* histogram,
|
||||
float* cost);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
#ifndef THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_
|
||||
#define THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__SSE2__) || defined(_M_AMD64) || \
|
||||
(defined(_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2))
|
||||
#define SUPPORTS_SSE_2
|
||||
#endif
|
||||
|
||||
#if defined(SUPPORTS_SSE_2)
|
||||
#include <immintrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
static BROTLI_INLINE uint64_t GetMatchingTagMask(
|
||||
size_t chunk_count, const uint8_t tag,
|
||||
const uint8_t* BROTLI_RESTRICT tag_bucket, const size_t head) {
|
||||
uint64_t matches = 0;
|
||||
#if defined(SUPPORTS_SSE_2)
|
||||
const __m128i comparison_mask = _mm_set1_epi8((char)tag);
|
||||
size_t i;
|
||||
for (i = 0; i < chunk_count && i < 4; i++) {
|
||||
const __m128i chunk =
|
||||
_mm_loadu_si128((const __m128i*)(const void*)(tag_bucket + 16 * i));
|
||||
const __m128i equal_mask = _mm_cmpeq_epi8(chunk, comparison_mask);
|
||||
matches |= (uint64_t)_mm_movemask_epi8(equal_mask) << 16 * i;
|
||||
}
|
||||
#else
|
||||
const int chunk_size = sizeof(size_t);
|
||||
const size_t shift_amount = ((chunk_size * 8) - chunk_size);
|
||||
const size_t xFF = ~((size_t)0);
|
||||
const size_t x01 = xFF / 0xFF;
|
||||
const size_t x80 = x01 << 7;
|
||||
const size_t splat_char = tag * x01;
|
||||
int i = ((int)chunk_count * 16) - chunk_size;
|
||||
BROTLI_DCHECK((sizeof(size_t) == 4) || (sizeof(size_t) == 8));
|
||||
#if BROTLI_LITTLE_ENDIAN
|
||||
const size_t extractMagic = (xFF / 0x7F) >> chunk_size;
|
||||
do {
|
||||
size_t chunk = BrotliUnalignedReadSizeT(&tag_bucket[i]);
|
||||
chunk ^= splat_char;
|
||||
chunk = (((chunk | x80) - x01) | chunk) & x80;
|
||||
matches <<= chunk_size;
|
||||
matches |= (chunk * extractMagic) >> shift_amount;
|
||||
i -= chunk_size;
|
||||
} while (i >= 0);
|
||||
#else
|
||||
const size_t msb = xFF ^ (xFF >> 1);
|
||||
const size_t extractMagic = (msb / 0x1FF) | msb;
|
||||
do {
|
||||
size_t chunk = BrotliUnalignedReadSizeT(&tag_bucket[i]);
|
||||
chunk ^= splat_char;
|
||||
chunk = (((chunk | x80) - x01) | chunk) & x80;
|
||||
matches <<= chunk_size;
|
||||
matches |= ((chunk >> 7) * extractMagic) >> shift_amount;
|
||||
i -= chunk_size;
|
||||
} while (i >= 0);
|
||||
#endif
|
||||
matches = ~matches;
|
||||
#endif
|
||||
if (chunk_count == 1) return BrotliRotateRight16((uint16_t)matches, head);
|
||||
if (chunk_count == 2) return BrotliRotateRight32((uint32_t)matches, head);
|
||||
return BrotliRotateRight64(matches, head);
|
||||
}
|
||||
|
||||
#undef SUPPORTS_SSE_2
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_
|
||||
@@ -7,21 +7,17 @@
|
||||
/* Algorithms for distributing the literals and commands of a metablock between
|
||||
block types and contexts. */
|
||||
|
||||
#include "./memory.h"
|
||||
|
||||
#include <stdlib.h> /* exit, free, malloc */
|
||||
#include <string.h> /* memcpy */
|
||||
#include "memory.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_PERM_ALLOCATED 128
|
||||
#define MAX_NEW_ALLOCATED 64
|
||||
#define MAX_NEW_FREED 64
|
||||
#define MAX_NEW_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2)
|
||||
#define MAX_NEW_FREED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2)
|
||||
#define MAX_PERM_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 1)
|
||||
|
||||
#define PERM_ALLOCATED_OFFSET 0
|
||||
#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED
|
||||
@@ -67,6 +63,7 @@ void BrotliWipeOutMemoryManager(MemoryManager* m) {
|
||||
|
||||
static void SortPointers(void** items, const size_t n) {
|
||||
/* Shell sort. */
|
||||
/* TODO(eustas): fine-tune for "many slots" case */
|
||||
static const size_t gaps[] = {23, 10, 4, 1};
|
||||
int g = 0;
|
||||
for (; g < 4; ++g) {
|
||||
@@ -165,6 +162,28 @@ void BrotliWipeOutMemoryManager(MemoryManager* m) {
|
||||
|
||||
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
|
||||
|
||||
void* BrotliBootstrapAlloc(size_t size,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) {
|
||||
if (!alloc_func && !free_func) {
|
||||
return malloc(size);
|
||||
} else if (alloc_func && free_func) {
|
||||
return alloc_func(opaque, size);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void BrotliBootstrapFree(void* address, MemoryManager* m) {
|
||||
if (!address) {
|
||||
/* Should not happen! */
|
||||
return;
|
||||
} else {
|
||||
/* Copy values, as those would be freed. */
|
||||
brotli_free_func free_func = m->free_func;
|
||||
void* opaque = m->opaque;
|
||||
free_func(opaque, address);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -9,10 +9,7 @@
|
||||
#ifndef BROTLI_ENC_MEMORY_H_
|
||||
#define BROTLI_ENC_MEMORY_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
@@ -23,6 +20,16 @@ extern "C" {
|
||||
#define BROTLI_ENCODER_EXIT_ON_OOM
|
||||
#endif
|
||||
|
||||
#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS (48*1024)
|
||||
#else /* BROTLI_EXPERIMENTAL */
|
||||
#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 256
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
#else /* BROTLI_ENCODER_EXIT_ON_OOM */
|
||||
#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 0
|
||||
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
|
||||
|
||||
typedef struct MemoryManager {
|
||||
brotli_alloc_func alloc_func;
|
||||
brotli_free_func free_func;
|
||||
@@ -32,7 +39,7 @@ typedef struct MemoryManager {
|
||||
size_t perm_allocated;
|
||||
size_t new_allocated;
|
||||
size_t new_freed;
|
||||
void* pointers[256];
|
||||
void* pointers[BROTLI_ENCODER_MEMORY_MANAGER_SLOTS];
|
||||
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
|
||||
} MemoryManager;
|
||||
|
||||
@@ -107,6 +114,12 @@ V: value to append
|
||||
A[(S) - 1] = (V); \
|
||||
}
|
||||
|
||||
/* "Bootstrap" allocations are not tracked by memory manager; should be used
|
||||
only to allocate MemoryManager itself (or structure containing it). */
|
||||
BROTLI_INTERNAL void* BrotliBootstrapAlloc(size_t size,
|
||||
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
|
||||
BROTLI_INTERNAL void BrotliBootstrapFree(void* address, MemoryManager* m);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
@@ -7,27 +7,27 @@
|
||||
/* Algorithms for distributing the literals and commands of a metablock between
|
||||
block types and contexts. */
|
||||
|
||||
#include "./metablock.h"
|
||||
#include "metablock.h"
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./bit_cost.h"
|
||||
#include "./block_splitter.h"
|
||||
#include "./cluster.h"
|
||||
#include "./entropy_encode.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "bit_cost.h"
|
||||
#include "block_splitter.h"
|
||||
#include "cluster.h"
|
||||
#include "command.h"
|
||||
#include "entropy_encode.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "prefix.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||
uint32_t npostfix, uint32_t ndirect) {
|
||||
BrotliDistanceParams* dist_params = ¶ms->dist;
|
||||
void BrotliInitDistanceParams(BrotliDistanceParams* dist_params,
|
||||
uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window) {
|
||||
uint32_t alphabet_size_max;
|
||||
uint32_t alphabet_size_limit;
|
||||
uint32_t max_distance;
|
||||
@@ -41,7 +41,7 @@ void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||
max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
|
||||
(1U << (npostfix + 2));
|
||||
|
||||
if (params->large_window) {
|
||||
if (large_window) {
|
||||
BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
|
||||
BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
|
||||
alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
|
||||
@@ -83,14 +83,14 @@ static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
|
||||
size_t num_commands,
|
||||
const BrotliDistanceParams* orig_params,
|
||||
const BrotliDistanceParams* new_params,
|
||||
double* cost) {
|
||||
double* cost,
|
||||
HistogramDistance* tmp) {
|
||||
size_t i;
|
||||
BROTLI_BOOL equal_params = BROTLI_FALSE;
|
||||
uint16_t dist_prefix;
|
||||
uint32_t dist_extra;
|
||||
double extra_bits = 0.0;
|
||||
HistogramDistance histo;
|
||||
HistogramClearDistance(&histo);
|
||||
HistogramClearDistance(tmp);
|
||||
|
||||
if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
|
||||
orig_params->num_direct_distance_codes ==
|
||||
@@ -114,12 +114,12 @@ static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
|
||||
&dist_prefix,
|
||||
&dist_extra);
|
||||
}
|
||||
HistogramAddDistance(&histo, dist_prefix & 0x3FF);
|
||||
HistogramAddDistance(tmp, dist_prefix & 0x3FF);
|
||||
extra_bits += dist_prefix >> 10;
|
||||
}
|
||||
}
|
||||
|
||||
*cost = BrotliPopulationCostDistance(&histo) + extra_bits;
|
||||
*cost = BrotliPopulationCostDistance(tmp) + extra_bits;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
@@ -147,43 +147,46 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||
uint32_t ndirect_msb = 0;
|
||||
BROTLI_BOOL check_orig = BROTLI_TRUE;
|
||||
double best_dist_cost = 1e99;
|
||||
BrotliEncoderParams orig_params = *params;
|
||||
BrotliEncoderParams new_params = *params;
|
||||
BrotliDistanceParams orig_params = params->dist;
|
||||
BrotliDistanceParams new_params = params->dist;
|
||||
HistogramDistance* tmp = BROTLI_ALLOC(m, HistogramDistance, 1);
|
||||
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return;
|
||||
|
||||
for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
|
||||
for (; ndirect_msb < 16; ndirect_msb++) {
|
||||
uint32_t ndirect = ndirect_msb << npostfix;
|
||||
BROTLI_BOOL skip;
|
||||
double dist_cost;
|
||||
BrotliInitDistanceParams(&new_params, npostfix, ndirect);
|
||||
if (npostfix == orig_params.dist.distance_postfix_bits &&
|
||||
ndirect == orig_params.dist.num_direct_distance_codes) {
|
||||
BrotliInitDistanceParams(&new_params, npostfix, ndirect,
|
||||
params->large_window);
|
||||
if (npostfix == orig_params.distance_postfix_bits &&
|
||||
ndirect == orig_params.num_direct_distance_codes) {
|
||||
check_orig = BROTLI_FALSE;
|
||||
}
|
||||
skip = !ComputeDistanceCost(
|
||||
cmds, num_commands,
|
||||
&orig_params.dist, &new_params.dist, &dist_cost);
|
||||
cmds, num_commands, &orig_params, &new_params, &dist_cost, tmp);
|
||||
if (skip || (dist_cost > best_dist_cost)) {
|
||||
break;
|
||||
}
|
||||
best_dist_cost = dist_cost;
|
||||
params->dist = new_params.dist;
|
||||
params->dist = new_params;
|
||||
}
|
||||
if (ndirect_msb > 0) ndirect_msb--;
|
||||
ndirect_msb /= 2;
|
||||
}
|
||||
if (check_orig) {
|
||||
double dist_cost;
|
||||
ComputeDistanceCost(cmds, num_commands,
|
||||
&orig_params.dist, &orig_params.dist, &dist_cost);
|
||||
ComputeDistanceCost(cmds, num_commands, &orig_params, &orig_params,
|
||||
&dist_cost, tmp);
|
||||
if (dist_cost < best_dist_cost) {
|
||||
/* NB: currently unused; uncomment when more param tuning is added. */
|
||||
/* best_dist_cost = dist_cost; */
|
||||
params->dist = orig_params.dist;
|
||||
params->dist = orig_params;
|
||||
}
|
||||
}
|
||||
RecomputeDistancePrefixes(cmds, num_commands,
|
||||
&orig_params.dist, ¶ms->dist);
|
||||
BROTLI_FREE(m, tmp);
|
||||
RecomputeDistancePrefixes(cmds, num_commands, &orig_params, ¶ms->dist);
|
||||
|
||||
BrotliSplitBlock(m, cmds, num_commands,
|
||||
ringbuffer, pos, mask, params,
|
||||
@@ -284,19 +287,17 @@ void BrotliBuildMetaBlock(MemoryManager* m,
|
||||
}
|
||||
|
||||
#define FN(X) X ## Literal
|
||||
#include "./metablock_inc.h" /* NOLINT(build/include) */
|
||||
#include "metablock_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Command
|
||||
#include "./metablock_inc.h" /* NOLINT(build/include) */
|
||||
#include "metablock_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define FN(X) X ## Distance
|
||||
#include "./metablock_inc.h" /* NOLINT(build/include) */
|
||||
#include "metablock_inc.h" /* NOLINT(build/include) */
|
||||
#undef FN
|
||||
|
||||
#define BROTLI_MAX_STATIC_CONTEXTS 13
|
||||
|
||||
/* Greedy block splitter for one block category (literal, command or distance).
|
||||
Gathers histograms for all context buckets. */
|
||||
typedef struct ContextBlockSplitter {
|
||||
@@ -397,7 +398,7 @@ static void ContextBlockSplitterFinishBlock(
|
||||
|
||||
for (i = 0; i < num_contexts; ++i) {
|
||||
last_entropy[i] =
|
||||
BitsEntropy(histograms[i].data_, self->alphabet_size_);
|
||||
BrotliBitsEntropy(histograms[i].data_, self->alphabet_size_);
|
||||
last_entropy[num_contexts + i] = last_entropy[i];
|
||||
}
|
||||
++self->num_blocks_;
|
||||
@@ -423,15 +424,15 @@ static void ContextBlockSplitterFinishBlock(
|
||||
for (i = 0; i < num_contexts; ++i) {
|
||||
size_t curr_histo_ix = self->curr_histogram_ix_ + i;
|
||||
size_t j;
|
||||
entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
|
||||
self->alphabet_size_);
|
||||
entropy[i] = BrotliBitsEntropy(histograms[curr_histo_ix].data_,
|
||||
self->alphabet_size_);
|
||||
for (j = 0; j < 2; ++j) {
|
||||
size_t jx = j * num_contexts + i;
|
||||
size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
|
||||
combined_histo[jx] = histograms[curr_histo_ix];
|
||||
HistogramAddHistogramLiteral(&combined_histo[jx],
|
||||
&histograms[last_histogram_ix]);
|
||||
combined_entropy[jx] = BitsEntropy(
|
||||
combined_entropy[jx] = BrotliBitsEntropy(
|
||||
&combined_histo[jx].data_[0], self->alphabet_size_);
|
||||
diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
|
||||
}
|
||||
@@ -535,17 +536,21 @@ static void MapStaticContexts(MemoryManager* m,
|
||||
}
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
|
||||
uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
|
||||
const size_t num_contexts, const uint32_t* static_context_map,
|
||||
const Command* commands, size_t n_commands, MetaBlockSplit* mb) {
|
||||
typedef struct GreedyMetablockArena {
|
||||
union {
|
||||
BlockSplitterLiteral plain;
|
||||
ContextBlockSplitter ctx;
|
||||
} lit_blocks;
|
||||
BlockSplitterCommand cmd_blocks;
|
||||
BlockSplitterDistance dist_blocks;
|
||||
} GreedyMetablockArena;
|
||||
|
||||
static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||
MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer,
|
||||
size_t pos, size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
|
||||
ContextLut literal_context_lut, const size_t num_contexts,
|
||||
const uint32_t* static_context_map, const Command* commands,
|
||||
size_t n_commands, MetaBlockSplit* mb) {
|
||||
size_t num_literals = 0;
|
||||
size_t i;
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
@@ -553,20 +558,20 @@ static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||
}
|
||||
|
||||
if (num_contexts == 1) {
|
||||
InitBlockSplitterLiteral(m, &lit_blocks.plain, 256, 512, 400.0,
|
||||
InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0,
|
||||
num_literals, &mb->literal_split, &mb->literal_histograms,
|
||||
&mb->literal_histograms_size);
|
||||
} else {
|
||||
InitContextBlockSplitter(m, &lit_blocks.ctx, 256, num_contexts, 512, 400.0,
|
||||
num_literals, &mb->literal_split, &mb->literal_histograms,
|
||||
InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512,
|
||||
400.0, num_literals, &mb->literal_split, &mb->literal_histograms,
|
||||
&mb->literal_histograms_size);
|
||||
}
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
InitBlockSplitterCommand(m, &cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, 1024,
|
||||
500.0, n_commands, &mb->command_split, &mb->command_histograms,
|
||||
InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS,
|
||||
1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms,
|
||||
&mb->command_histograms_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
InitBlockSplitterDistance(m, &dist_blocks, 64, 512, 100.0, n_commands,
|
||||
InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands,
|
||||
&mb->distance_split, &mb->distance_histograms,
|
||||
&mb->distance_histograms_size);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
@@ -574,15 +579,15 @@ static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||
for (i = 0; i < n_commands; ++i) {
|
||||
const Command cmd = commands[i];
|
||||
size_t j;
|
||||
BlockSplitterAddSymbolCommand(&cmd_blocks, cmd.cmd_prefix_);
|
||||
BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_);
|
||||
for (j = cmd.insert_len_; j != 0; --j) {
|
||||
uint8_t literal = ringbuffer[pos & mask];
|
||||
if (num_contexts == 1) {
|
||||
BlockSplitterAddSymbolLiteral(&lit_blocks.plain, literal);
|
||||
BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal);
|
||||
} else {
|
||||
size_t context =
|
||||
BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
|
||||
ContextBlockSplitterAddSymbol(&lit_blocks.ctx, m, literal,
|
||||
ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal,
|
||||
static_context_map[context]);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
@@ -595,21 +600,24 @@ static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
|
||||
prev_byte2 = ringbuffer[(pos - 2) & mask];
|
||||
prev_byte = ringbuffer[(pos - 1) & mask];
|
||||
if (cmd.cmd_prefix_ >= 128) {
|
||||
BlockSplitterAddSymbolDistance(&dist_blocks, cmd.dist_prefix_ & 0x3FF);
|
||||
BlockSplitterAddSymbolDistance(
|
||||
&arena->dist_blocks, cmd.dist_prefix_ & 0x3FF);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (num_contexts == 1) {
|
||||
BlockSplitterFinishBlockLiteral(
|
||||
&lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
|
||||
&arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
|
||||
} else {
|
||||
ContextBlockSplitterFinishBlock(
|
||||
&lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
|
||||
&arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
|
||||
if (BROTLI_IS_OOM(m)) return;
|
||||
}
|
||||
BlockSplitterFinishBlockCommand(&cmd_blocks, /* is_final = */ BROTLI_TRUE);
|
||||
BlockSplitterFinishBlockDistance(&dist_blocks, /* is_final = */ BROTLI_TRUE);
|
||||
BlockSplitterFinishBlockCommand(
|
||||
&arena->cmd_blocks, /* is_final = */ BROTLI_TRUE);
|
||||
BlockSplitterFinishBlockDistance(
|
||||
&arena->dist_blocks, /* is_final = */ BROTLI_TRUE);
|
||||
|
||||
if (num_contexts > 1) {
|
||||
MapStaticContexts(m, num_contexts, static_context_map, mb);
|
||||
@@ -628,14 +636,18 @@ void BrotliBuildMetaBlockGreedy(MemoryManager* m,
|
||||
const Command* commands,
|
||||
size_t n_commands,
|
||||
MetaBlockSplit* mb) {
|
||||
GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1);
|
||||
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
|
||||
if (num_contexts == 1) {
|
||||
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
||||
prev_byte2, literal_context_lut, 1, NULL, commands, n_commands, mb);
|
||||
BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
|
||||
prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands,
|
||||
n_commands, mb);
|
||||
} else {
|
||||
BrotliBuildMetaBlockGreedyInternal(m, ringbuffer, pos, mask, prev_byte,
|
||||
prev_byte2, literal_context_lut, num_contexts, static_context_map,
|
||||
commands, n_commands, mb);
|
||||
BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
|
||||
prev_byte, prev_byte2, literal_context_lut, num_contexts,
|
||||
static_context_map, commands, n_commands, mb);
|
||||
}
|
||||
BROTLI_FREE(m, arena);
|
||||
}
|
||||
|
||||
void BrotliOptimizeHistograms(uint32_t num_distance_codes,
|
||||
|
||||
@@ -12,17 +12,18 @@
|
||||
|
||||
#include "../common/context.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./block_splitter.h"
|
||||
#include "./command.h"
|
||||
#include "./histogram.h"
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "block_splitter.h"
|
||||
#include "command.h"
|
||||
#include "histogram.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BROTLI_MAX_STATIC_CONTEXTS 13
|
||||
|
||||
typedef struct MetaBlockSplit {
|
||||
BlockSplit literal_split;
|
||||
BlockSplit command_split;
|
||||
@@ -95,8 +96,8 @@ BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy(
|
||||
BROTLI_INTERNAL void BrotliOptimizeHistograms(uint32_t num_distance_codes,
|
||||
MetaBlockSplit* mb);
|
||||
|
||||
BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliEncoderParams* params,
|
||||
uint32_t npostfix, uint32_t ndirect);
|
||||
BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliDistanceParams* params,
|
||||
uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
|
||||
@@ -27,6 +27,9 @@ typedef struct FN(BlockSplitter) {
|
||||
HistogramType* histograms_; /* not owned */
|
||||
size_t* histograms_size_; /* not owned */
|
||||
|
||||
/* Temporary storage for BlockSplitterFinishBlock. */
|
||||
HistogramType combined_histo[2];
|
||||
|
||||
/* The number of symbols that we want to collect before deciding on whether
|
||||
or not to merge the block with a previous one or emit a new block. */
|
||||
size_t target_block_size_;
|
||||
@@ -93,7 +96,7 @@ static void FN(BlockSplitterFinishBlock)(
|
||||
split->lengths[0] = (uint32_t)self->block_size_;
|
||||
split->types[0] = 0;
|
||||
last_entropy[0] =
|
||||
BitsEntropy(histograms[0].data_, self->alphabet_size_);
|
||||
BrotliBitsEntropy(histograms[0].data_, self->alphabet_size_);
|
||||
last_entropy[1] = last_entropy[0];
|
||||
++self->num_blocks_;
|
||||
++split->num_types;
|
||||
@@ -102,19 +105,18 @@ static void FN(BlockSplitterFinishBlock)(
|
||||
FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
|
||||
self->block_size_ = 0;
|
||||
} else if (self->block_size_ > 0) {
|
||||
double entropy = BitsEntropy(histograms[self->curr_histogram_ix_].data_,
|
||||
self->alphabet_size_);
|
||||
HistogramType combined_histo[2];
|
||||
double entropy = BrotliBitsEntropy(
|
||||
histograms[self->curr_histogram_ix_].data_, self->alphabet_size_);
|
||||
double combined_entropy[2];
|
||||
double diff[2];
|
||||
size_t j;
|
||||
for (j = 0; j < 2; ++j) {
|
||||
size_t last_histogram_ix = self->last_histogram_ix_[j];
|
||||
combined_histo[j] = histograms[self->curr_histogram_ix_];
|
||||
FN(HistogramAddHistogram)(&combined_histo[j],
|
||||
self->combined_histo[j] = histograms[self->curr_histogram_ix_];
|
||||
FN(HistogramAddHistogram)(&self->combined_histo[j],
|
||||
&histograms[last_histogram_ix]);
|
||||
combined_entropy[j] = BitsEntropy(
|
||||
&combined_histo[j].data_[0], self->alphabet_size_);
|
||||
combined_entropy[j] = BrotliBitsEntropy(
|
||||
&self->combined_histo[j].data_[0], self->alphabet_size_);
|
||||
diff[j] = combined_entropy[j] - entropy - last_entropy[j];
|
||||
}
|
||||
|
||||
@@ -141,7 +143,7 @@ static void FN(BlockSplitterFinishBlock)(
|
||||
split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
|
||||
split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
|
||||
BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
|
||||
histograms[self->last_histogram_ix_[0]] = combined_histo[1];
|
||||
histograms[self->last_histogram_ix_[0]] = self->combined_histo[1];
|
||||
last_entropy[1] = last_entropy[0];
|
||||
last_entropy[0] = combined_entropy[1];
|
||||
++self->num_blocks_;
|
||||
@@ -152,7 +154,7 @@ static void FN(BlockSplitterFinishBlock)(
|
||||
} else {
|
||||
/* Combine this block with last block. */
|
||||
split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
|
||||
histograms[self->last_histogram_ix_[0]] = combined_histo[0];
|
||||
histograms[self->last_histogram_ix_[0]] = self->combined_histo[0];
|
||||
last_entropy[0] = combined_entropy[0];
|
||||
if (split->num_types == 1) {
|
||||
last_entropy[1] = last_entropy[0];
|
||||
|
||||
@@ -10,13 +10,12 @@
|
||||
#define BROTLI_ENC_PARAMS_H_
|
||||
|
||||
#include <brotli/encode.h>
|
||||
#include "./encoder_dict.h"
|
||||
#include "encoder_dict.h"
|
||||
|
||||
typedef struct BrotliHasherParams {
|
||||
int type;
|
||||
int bucket_bits;
|
||||
int block_bits;
|
||||
int hash_len;
|
||||
int num_last_distances_to_check;
|
||||
} BrotliHasherParams;
|
||||
|
||||
@@ -40,7 +39,8 @@ typedef struct BrotliEncoderParams {
|
||||
BROTLI_BOOL large_window;
|
||||
BrotliHasherParams hasher;
|
||||
BrotliDistanceParams dist;
|
||||
BrotliEncoderDictionary dictionary;
|
||||
/* TODO(eustas): rename to BrotliShared... */
|
||||
SharedEncoderDictionary dictionary;
|
||||
} BrotliEncoderParams;
|
||||
|
||||
#endif /* BROTLI_ENC_PARAMS_H_ */
|
||||
@@ -12,8 +12,7 @@
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./fast_log.h"
|
||||
#include "fast_log.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/encode.h>
|
||||
#include "./params.h"
|
||||
#include "params.h"
|
||||
|
||||
#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
|
||||
#define FAST_TWO_PASS_COMPRESSION_QUALITY 1
|
||||
@@ -118,6 +118,41 @@ static BROTLI_INLINE size_t LiteralSpreeLengthForSparseSearch(
|
||||
return params->quality < 9 ? 64 : 512;
|
||||
}
|
||||
|
||||
/* Quality to hasher mapping:
|
||||
|
||||
- q02: h02 (longest_match_quickly), b16, l5
|
||||
|
||||
- q03: h03 (longest_match_quickly), b17, l5
|
||||
|
||||
- q04: h04 (longest_match_quickly), b17, l5
|
||||
- q04: h54 (longest_match_quickly), b20, l7 | for large files
|
||||
|
||||
- q05: h58 (longest_match_simd ), b14, l4
|
||||
- q05: h68 (longest_match64_simd ), b15, l5 | for large files
|
||||
- q05: h40 (forgetful_chain ), b15, l4 | for small window
|
||||
|
||||
- q06: h58 (longest_match_simd ), b14, l4
|
||||
- q06: h68 (longest_match64_simd ), b15, l5 | for large files
|
||||
- q06: h40 (forgetful_chain ), b15, l4 | for small window
|
||||
|
||||
- q07: h58 (longest_match_simd ), b15, l4
|
||||
- q07: h68 (longest_match64_simd ), b15, l5 | for large files
|
||||
- q07: h41 (forgetful_chain ), b15, l4 | for small window
|
||||
|
||||
- q08: h05 (longest_match ), b15, l4
|
||||
- q08: h06 (longest_match64 ), b15, l5 | for large files
|
||||
- q08: h41 (forgetful_chain ), b15, l4 | for small window
|
||||
|
||||
- q09: h05 (longest_match ), b15, l4
|
||||
- q09: h06 (longest_match64 ), b15, l5 | for large files
|
||||
- q09: h42 (forgetful_chain ), b15, l4 | for small window
|
||||
|
||||
- q10: t10 (to_binary_tree ), b17, l128
|
||||
|
||||
- q11: t10 (to_binary_tree ), b17, l128
|
||||
|
||||
Where "q" is quality, "h" is hasher type, "b" is bucket bits,
|
||||
"l" is source len. */
|
||||
static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
|
||||
BrotliHasherParams* hparams) {
|
||||
if (params->quality > 9) {
|
||||
@@ -129,14 +164,23 @@ static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
|
||||
} else if (params->lgwin <= 16) {
|
||||
hparams->type = params->quality < 7 ? 40 : params->quality < 9 ? 41 : 42;
|
||||
} else if (params->size_hint >= (1 << 20) && params->lgwin >= 19) {
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
hparams->type = params->quality <= BROTLI_MAX_SIMD_QUALITY ? 68 : 6;
|
||||
#else
|
||||
hparams->type = 6;
|
||||
#endif
|
||||
hparams->block_bits = params->quality - 1;
|
||||
hparams->bucket_bits = 15;
|
||||
hparams->hash_len = 5;
|
||||
hparams->num_last_distances_to_check =
|
||||
params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
|
||||
} else {
|
||||
/* TODO(eustas): often previous setting (H6) is faster and denser; consider
|
||||
adding an option to use it. */
|
||||
#if defined(BROTLI_MAX_SIMD_QUALITY)
|
||||
hparams->type = params->quality <= BROTLI_MAX_SIMD_QUALITY ? 58 : 5;
|
||||
#else
|
||||
hparams->type = 5;
|
||||
#endif
|
||||
hparams->block_bits = params->quality - 1;
|
||||
hparams->bucket_bits = params->quality < 7 ? 14 : 15;
|
||||
hparams->num_last_distances_to_check =
|
||||
@@ -149,14 +193,14 @@ static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
|
||||
hasher already works well with large window. So the changes are:
|
||||
H3 --> H35: for quality 3.
|
||||
H54 --> H55: for quality 4 with size hint > 1MB
|
||||
H6 --> H65: for qualities 5, 6, 7, 8, 9. */
|
||||
H6/H68 --> H65: for qualities 5, 6, 7, 8, 9. */
|
||||
if (hparams->type == 3) {
|
||||
hparams->type = 35;
|
||||
}
|
||||
if (hparams->type == 54) {
|
||||
hparams->type = 55;
|
||||
}
|
||||
if (hparams->type == 6) {
|
||||
if (hparams->type == 6 || hparams->type == 68) {
|
||||
hparams->type = 65;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@
|
||||
#ifndef BROTLI_ENC_RINGBUFFER_H_
|
||||
#define BROTLI_ENC_RINGBUFFER_H_
|
||||
|
||||
#include <string.h> /* memcpy */
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./memory.h"
|
||||
#include "./quality.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "quality.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/* Copyright 2022 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Encoder state. */
|
||||
|
||||
#ifndef BROTLI_ENC_STATE_H_
|
||||
#define BROTLI_ENC_STATE_H_
|
||||
|
||||
#include "../common/constants.h"
|
||||
#include "../common/platform.h"
|
||||
#include "command.h"
|
||||
#include "compress_fragment.h"
|
||||
#include "compress_fragment_two_pass.h"
|
||||
#include "hash.h"
|
||||
#include "memory.h"
|
||||
#include "params.h"
|
||||
#include "ringbuffer.h"
|
||||
|
||||
typedef enum BrotliEncoderStreamState {
|
||||
/* Default state. */
|
||||
BROTLI_STREAM_PROCESSING = 0,
|
||||
/* Intermediate state; after next block is emitted, byte-padding should be
|
||||
performed before getting back to default state. */
|
||||
BROTLI_STREAM_FLUSH_REQUESTED = 1,
|
||||
/* Last metablock was produced; no more input is acceptable. */
|
||||
BROTLI_STREAM_FINISHED = 2,
|
||||
/* Flushing compressed block and writing meta-data block header. */
|
||||
BROTLI_STREAM_METADATA_HEAD = 3,
|
||||
/* Writing metadata block body. */
|
||||
BROTLI_STREAM_METADATA_BODY = 4
|
||||
} BrotliEncoderStreamState;
|
||||
|
||||
typedef enum BrotliEncoderFlintState {
|
||||
BROTLI_FLINT_NEEDS_2_BYTES = 2,
|
||||
BROTLI_FLINT_NEEDS_1_BYTE = 1,
|
||||
BROTLI_FLINT_WAITING_FOR_PROCESSING = 0,
|
||||
BROTLI_FLINT_WAITING_FOR_FLUSHING = -1,
|
||||
BROTLI_FLINT_DONE = -2
|
||||
} BrotliEncoderFlintState;
|
||||
|
||||
typedef struct BrotliEncoderStateStruct {
|
||||
BrotliEncoderParams params;
|
||||
|
||||
MemoryManager memory_manager_;
|
||||
|
||||
uint64_t input_pos_;
|
||||
RingBuffer ringbuffer_;
|
||||
size_t cmd_alloc_size_;
|
||||
Command* commands_;
|
||||
size_t num_commands_;
|
||||
size_t num_literals_;
|
||||
size_t last_insert_len_;
|
||||
uint64_t last_flush_pos_;
|
||||
uint64_t last_processed_pos_;
|
||||
int dist_cache_[BROTLI_NUM_DISTANCE_SHORT_CODES];
|
||||
int saved_dist_cache_[4];
|
||||
uint16_t last_bytes_;
|
||||
uint8_t last_bytes_bits_;
|
||||
/* "Flint" is a tiny uncompressed block emitted before the continuation
|
||||
block to unwire literal context from previous data. Despite being int8_t,
|
||||
field is actually BrotliEncoderFlintState enum. */
|
||||
int8_t flint_;
|
||||
uint8_t prev_byte_;
|
||||
uint8_t prev_byte2_;
|
||||
size_t storage_size_;
|
||||
uint8_t* storage_;
|
||||
|
||||
Hasher hasher_;
|
||||
|
||||
/* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */
|
||||
int small_table_[1 << 10]; /* 4KiB */
|
||||
int* large_table_; /* Allocated only when needed */
|
||||
size_t large_table_size_;
|
||||
|
||||
BrotliOnePassArena* one_pass_arena_;
|
||||
BrotliTwoPassArena* two_pass_arena_;
|
||||
|
||||
/* Command and literal buffers for FAST_TWO_PASS_COMPRESSION_QUALITY. */
|
||||
uint32_t* command_buf_;
|
||||
uint8_t* literal_buf_;
|
||||
|
||||
uint64_t total_in_;
|
||||
uint8_t* next_out_;
|
||||
size_t available_out_;
|
||||
uint64_t total_out_;
|
||||
/* Temporary buffer for padding flush bits or metadata block header / body. */
|
||||
union {
|
||||
uint64_t u64[2];
|
||||
uint8_t u8[16];
|
||||
} tiny_buf_;
|
||||
uint32_t remaining_metadata_bytes_;
|
||||
BrotliEncoderStreamState stream_state_;
|
||||
|
||||
BROTLI_BOOL is_last_block_emitted_;
|
||||
BROTLI_BOOL is_initialized_;
|
||||
} BrotliEncoderStateStruct;
|
||||
|
||||
typedef struct BrotliEncoderStateStruct BrotliEncoderStateInternal;
|
||||
#define BrotliEncoderState BrotliEncoderStateInternal
|
||||
|
||||
#endif // BROTLI_ENC_STATE_H_
|
||||
@@ -4,25 +4,19 @@
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "./static_dict.h"
|
||||
#include "static_dict.h"
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include "../common/transform.h"
|
||||
#include "./encoder_dict.h"
|
||||
#include "./find_match_length.h"
|
||||
#include "encoder_dict.h"
|
||||
#include "find_match_length.h"
|
||||
#include "hash_base.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static BROTLI_INLINE uint32_t Hash(const uint8_t* data) {
|
||||
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kDictHashMul32;
|
||||
/* The higher bits contain more mixture from the multiplication,
|
||||
so we take our results from there. */
|
||||
return h >> (32 - kDictNumBits);
|
||||
}
|
||||
|
||||
static BROTLI_INLINE void AddMatch(size_t distance, size_t len, size_t len_code,
|
||||
uint32_t* matches) {
|
||||
uint32_t match = (uint32_t)((distance << 5) + len_code);
|
||||
@@ -74,12 +68,29 @@ static BROTLI_INLINE BROTLI_BOOL IsMatch(const BrotliDictionary* dictionary,
|
||||
}
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
/* Finds matches for a single static dictionary */
|
||||
static BROTLI_BOOL BrotliFindAllStaticDictionaryMatchesFor(
|
||||
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
|
||||
size_t min_length, size_t max_length, uint32_t* matches) {
|
||||
BROTLI_BOOL has_found_match = BROTLI_FALSE;
|
||||
#if defined(BROTLI_EXPERIMENTAL)
|
||||
if (dictionary->has_words_heavy) {
|
||||
const BrotliTrieNode* node = &dictionary->trie.root;
|
||||
size_t l = 0;
|
||||
while (node && l < max_length) {
|
||||
uint8_t c;
|
||||
if (l >= min_length && node->len_) {
|
||||
AddMatch(node->idx_, l, node->len_, matches);
|
||||
has_found_match = BROTLI_TRUE;
|
||||
}
|
||||
c = data[l++];
|
||||
node = BrotliTrieSub(&dictionary->trie, node, c);
|
||||
}
|
||||
return has_found_match;
|
||||
}
|
||||
#endif /* BROTLI_EXPERIMENTAL */
|
||||
{
|
||||
size_t offset = dictionary->buckets[Hash(data)];
|
||||
size_t offset = dictionary->buckets[Hash15(data)];
|
||||
BROTLI_BOOL end = !offset;
|
||||
while (!end) {
|
||||
DictWord w = dictionary->dict_words[offset++];
|
||||
@@ -324,7 +335,7 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
/* Transforms with prefixes " " and "." */
|
||||
if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) {
|
||||
BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' ');
|
||||
size_t offset = dictionary->buckets[Hash(&data[1])];
|
||||
size_t offset = dictionary->buckets[Hash15(&data[1])];
|
||||
BROTLI_BOOL end = !offset;
|
||||
while (!end) {
|
||||
DictWord w = dictionary->dict_words[offset++];
|
||||
@@ -419,7 +430,7 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
if ((data[1] == ' ' &&
|
||||
(data[0] == 'e' || data[0] == 's' || data[0] == ',')) ||
|
||||
(data[0] == 0xC2 && data[1] == 0xA0)) {
|
||||
size_t offset = dictionary->buckets[Hash(&data[2])];
|
||||
size_t offset = dictionary->buckets[Hash15(&data[2])];
|
||||
BROTLI_BOOL end = !offset;
|
||||
while (!end) {
|
||||
DictWord w = dictionary->dict_words[offset++];
|
||||
@@ -448,7 +459,7 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
data[3] == 'e' && data[4] == ' ') ||
|
||||
(data[0] == '.' && data[1] == 'c' && data[2] == 'o' &&
|
||||
data[3] == 'm' && data[4] == '/')) {
|
||||
size_t offset = dictionary->buckets[Hash(&data[5])];
|
||||
size_t offset = dictionary->buckets[Hash15(&data[5])];
|
||||
BROTLI_BOOL end = !offset;
|
||||
while (!end) {
|
||||
DictWord w = dictionary->dict_words[offset++];
|
||||
@@ -481,6 +492,45 @@ BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
return has_found_match;
|
||||
}
|
||||
|
||||
/* Finds matches for one or more dictionaries, if multiple are present
|
||||
in the contextual dictionary */
|
||||
BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
|
||||
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
|
||||
size_t min_length, size_t max_length, uint32_t* matches) {
|
||||
BROTLI_BOOL has_found_match =
|
||||
BrotliFindAllStaticDictionaryMatchesFor(
|
||||
dictionary, data, min_length, max_length, matches);
|
||||
|
||||
if (!!dictionary->parent && dictionary->parent->num_dictionaries > 1) {
|
||||
uint32_t matches2[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];
|
||||
int l;
|
||||
const BrotliEncoderDictionary* dictionary2 = dictionary->parent->dict[0];
|
||||
if (dictionary2 == dictionary) {
|
||||
dictionary2 = dictionary->parent->dict[1];
|
||||
}
|
||||
|
||||
for (l = 0; l < BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1; l++) {
|
||||
matches2[l] = kInvalidMatch;
|
||||
}
|
||||
|
||||
has_found_match |= BrotliFindAllStaticDictionaryMatchesFor(
|
||||
dictionary2, data, min_length, max_length, matches2);
|
||||
|
||||
for (l = 0; l < BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1; l++) {
|
||||
if (matches2[l] != kInvalidMatch) {
|
||||
uint32_t dist = (uint32_t)(matches2[l] >> 5);
|
||||
uint32_t len_code = matches2[l] & 31;
|
||||
uint32_t skipdist = (uint32_t)((uint32_t)(1 << dictionary->words->
|
||||
size_bits_by_length[len_code]) & ~1u) *
|
||||
(uint32_t)dictionary->num_transforms;
|
||||
/* TODO(lode): check for dist overflow */
|
||||
dist += skipdist;
|
||||
AddMatch(dist, (size_t)l, len_code, matches);
|
||||
}
|
||||
}
|
||||
}
|
||||
return has_found_match;
|
||||
}
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -9,10 +9,9 @@
|
||||
#ifndef BROTLI_ENC_STATIC_DICT_H_
|
||||
#define BROTLI_ENC_STATIC_DICT_H_
|
||||
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/platform.h"
|
||||
#include <brotli/types.h>
|
||||
#include "./encoder_dict.h"
|
||||
|
||||
#include "encoder_dict.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Lookup table for static dictionary and transforms. */
|
||||
|
||||
#include "static_dict_lut.h"
|
||||
|
||||
#include "../common/platform.h" /* IWYU pragma: keep */
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#include "../common/transform.h"
|
||||
#include "hash_base.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
|
||||
/* TODO(eustas): deal with largest bucket(s). Not it contains 163 items. */
|
||||
static BROTLI_BOOL BROTLI_COLD DoBrotliEncoderInitStaticDictionaryLut(
|
||||
const BrotliDictionary* dict, uint16_t* buckets, DictWord* words,
|
||||
void* arena) {
|
||||
DictWord* slots = (DictWord*)arena;
|
||||
uint16_t* heads = (uint16_t*)(slots + BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS);
|
||||
uint16_t* counts = heads + BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS;
|
||||
uint16_t* prev = counts + BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS;
|
||||
size_t next_slot = 0;
|
||||
uint8_t transformed_word[24];
|
||||
uint8_t transformed_other_word[24];
|
||||
size_t l;
|
||||
size_t pos;
|
||||
size_t i;
|
||||
|
||||
memset(counts, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * sizeof(uint16_t));
|
||||
memset(heads, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * sizeof(uint16_t));
|
||||
memset(prev, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS * sizeof(uint16_t));
|
||||
|
||||
for (l = 4; l <= 24; ++l) {
|
||||
size_t n = 1u << dict->size_bits_by_length[l];
|
||||
const uint8_t* dict_words = dict->data + dict->offsets_by_length[l];
|
||||
for (i = 0; i < n; ++i) {
|
||||
const uint8_t* dict_word = dict_words + l * i;
|
||||
uint32_t key = Hash15(dict_word);
|
||||
slots[next_slot].len = (uint8_t)l;
|
||||
slots[next_slot].transform = BROTLI_TRANSFORM_IDENTITY;
|
||||
slots[next_slot].idx = (uint16_t)i;
|
||||
prev[next_slot] = heads[key];
|
||||
heads[key] = (uint16_t)next_slot;
|
||||
counts[key]++;
|
||||
++next_slot;
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
uint32_t key;
|
||||
uint32_t prefix;
|
||||
BROTLI_BOOL found;
|
||||
size_t curr;
|
||||
const uint8_t* dict_word = dict_words + l * i;
|
||||
if (dict_word[0] < 'a' || dict_word[0] > 'z') continue;
|
||||
memcpy(transformed_word, dict_word, l);
|
||||
transformed_word[0] = transformed_word[0] - 32;
|
||||
key = Hash15(transformed_word);
|
||||
prefix = BROTLI_UNALIGNED_LOAD32LE(transformed_word) & ~0x20202020u;
|
||||
found = BROTLI_FALSE;
|
||||
curr = heads[key];
|
||||
while (curr != 0) {
|
||||
const uint8_t* other_word;
|
||||
uint32_t other_prefix;
|
||||
if (slots[curr].len != l) break;
|
||||
other_word = dict_words + l * slots[curr].idx;
|
||||
other_prefix = BROTLI_UNALIGNED_LOAD32LE(other_word) & ~0x20202020u;
|
||||
if (prefix == other_prefix) {
|
||||
if (memcmp(transformed_word, other_word, l) == 0) {
|
||||
found = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
curr = prev[curr];
|
||||
}
|
||||
if (found) continue;
|
||||
slots[next_slot].len = (uint8_t)l;
|
||||
slots[next_slot].transform = BROTLI_TRANSFORM_UPPERCASE_FIRST;
|
||||
slots[next_slot].idx = (uint16_t)i;
|
||||
prev[next_slot] = heads[key];
|
||||
heads[key] = (uint16_t)next_slot;
|
||||
counts[key]++;
|
||||
++next_slot;
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
const uint8_t* dict_word = dict_words + l * i;
|
||||
BROTLI_BOOL is_ascii = BROTLI_TRUE;
|
||||
BROTLI_BOOL has_lower = BROTLI_FALSE;
|
||||
size_t k;
|
||||
uint32_t prefix;
|
||||
uint32_t key;
|
||||
size_t curr;
|
||||
BROTLI_BOOL found;
|
||||
for (k = 0; k < l; ++k) {
|
||||
if (dict_word[k] >= 128) is_ascii = BROTLI_FALSE;
|
||||
if (k > 0 && dict_word[k] >= 'a' && dict_word[k] <= 'z')
|
||||
has_lower = BROTLI_TRUE;
|
||||
}
|
||||
if (!is_ascii || !has_lower) continue;
|
||||
memcpy(transformed_word, dict_word, l);
|
||||
prefix = BROTLI_UNALIGNED_LOAD32LE(transformed_word) & ~0x20202020u;
|
||||
for (k = 0; k < l; ++k) {
|
||||
if (transformed_word[k] >= 'a' && transformed_word[k] <= 'z') {
|
||||
transformed_word[k] = transformed_word[k] - 32;
|
||||
}
|
||||
}
|
||||
key = Hash15(transformed_word);
|
||||
found = BROTLI_FALSE;
|
||||
curr = heads[key];
|
||||
while (curr != 0) {
|
||||
const uint8_t* other_word;
|
||||
uint32_t other_prefix;
|
||||
if (slots[curr].len != l) break;
|
||||
other_word = dict_words + l * slots[curr].idx;
|
||||
other_prefix = BROTLI_UNALIGNED_LOAD32LE(other_word) & ~0x20202020u;
|
||||
if (prefix == other_prefix) {
|
||||
if (slots[curr].transform == BROTLI_TRANSFORM_IDENTITY) {
|
||||
if (memcmp(transformed_word, other_word, l) == 0) {
|
||||
found = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
} else if (slots[curr].transform ==
|
||||
BROTLI_TRANSFORM_UPPERCASE_FIRST) {
|
||||
if ((transformed_word[0] == (other_word[0] - 32)) &&
|
||||
memcmp(transformed_word + 1, other_word + 1, l - 1) == 0) {
|
||||
found = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (k = 0; k < l; ++k) {
|
||||
if (other_word[k] >= 'a' && other_word[k] <= 'z') {
|
||||
transformed_other_word[k] = other_word[k] - 32;
|
||||
} else {
|
||||
transformed_other_word[k] = other_word[k];
|
||||
}
|
||||
}
|
||||
if (memcmp(transformed_word, transformed_other_word, l) == 0) {
|
||||
found = BROTLI_TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
curr = prev[curr];
|
||||
}
|
||||
if (found) {
|
||||
continue;
|
||||
}
|
||||
slots[next_slot].len = (uint8_t)l;
|
||||
slots[next_slot].transform = BROTLI_TRANSFORM_UPPERCASE_ALL;
|
||||
slots[next_slot].idx = (uint16_t)i;
|
||||
prev[next_slot] = heads[key];
|
||||
heads[key] = (uint16_t)next_slot;
|
||||
counts[key]++;
|
||||
++next_slot;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_slot != 31704) return BROTLI_FALSE;
|
||||
pos = 0;
|
||||
/* Unused; makes offsets start from 1. */
|
||||
words[pos].len = 0;
|
||||
words[pos].transform = 0;
|
||||
words[pos].idx = 0;
|
||||
pos++;
|
||||
for (i = 0; i < BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS; ++i) {
|
||||
size_t num_words = counts[i];
|
||||
size_t curr;
|
||||
if (num_words == 0) {
|
||||
buckets[i] = 0;
|
||||
continue;
|
||||
}
|
||||
buckets[i] = (uint16_t)pos;
|
||||
curr = heads[i];
|
||||
pos += num_words;
|
||||
for (size_t k = 0; k < num_words; ++k) {
|
||||
words[pos - 1 - k] = slots[curr];
|
||||
curr = prev[curr];
|
||||
}
|
||||
words[pos - 1].len |= 0x80;
|
||||
}
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
|
||||
BROTLI_BOOL BrotliEncoderInitStaticDictionaryLut(
|
||||
const BrotliDictionary* dict, uint16_t* buckets, DictWord* words) {
|
||||
size_t arena_size =
|
||||
BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS *
|
||||
(sizeof(uint16_t) + sizeof(DictWord)) +
|
||||
BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * 2 * sizeof(uint16_t);
|
||||
void* arena = malloc(arena_size);
|
||||
BROTLI_BOOL ok;
|
||||
if (arena == NULL) {
|
||||
return BROTLI_FALSE;
|
||||
}
|
||||
ok = DoBrotliEncoderInitStaticDictionaryLut(dict, buckets, words, arena);
|
||||
free(arena);
|
||||
return ok;
|
||||
}
|
||||
|
||||
BROTLI_MODEL("small")
|
||||
uint16_t kStaticDictionaryBuckets[BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS];
|
||||
BROTLI_MODEL("small")
|
||||
DictWord kStaticDictionaryWords[BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS];
|
||||
|
||||
#else /* BROTLI_STATIC_INIT */
|
||||
|
||||
/* Embed kStaticDictionaryBuckets and kStaticDictionaryWords. */
|
||||
#include "static_dict_lut_inc.h"
|
||||
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,59 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "static_init.h"
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
#include "../common/dictionary.h"
|
||||
#include "dictionary_hash.h"
|
||||
#include "static_dict_lut.h"
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE)
|
||||
static BROTLI_BOOL DoBrotliEncoderStaticInit(void) {
|
||||
const BrotliDictionary* dict = BrotliGetDictionary();
|
||||
BROTLI_BOOL ok = BrotliEncoderInitStaticDictionaryLut(
|
||||
dict, kStaticDictionaryBuckets, kStaticDictionaryWords);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
ok = BrotliEncoderInitDictionaryHash(dict, kStaticDictionaryHashWords,
|
||||
kStaticDictionaryHashLengths);
|
||||
if (!ok) return BROTLI_FALSE;
|
||||
return BROTLI_TRUE;
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_NONE */
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
static BROTLI_BOOL kEarlyInitOk;
|
||||
static __attribute__((constructor)) void BrotliEncoderStaticInitEarly(void) {
|
||||
kEarlyInitOk = DoBrotliEncoderStaticInit();
|
||||
}
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
static BROTLI_BOOL kLazyInitOk;
|
||||
void BrotliEncoderLazyStaticInitInner(void) {
|
||||
kLazyInitOk = DoBrotliEncoderStaticInit();
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_EARLY */
|
||||
|
||||
BROTLI_BOOL BrotliEncoderEnsureStaticInit(void) {
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE)
|
||||
return BROTLI_TRUE;
|
||||
#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY)
|
||||
return kEarlyInitOk;
|
||||
#else
|
||||
return kLazyInitOk;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
/* Copyright 2025 Google Inc. All Rights Reserved.
|
||||
|
||||
Distributed under MIT license.
|
||||
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
/* Central point for static initialization. */
|
||||
|
||||
#ifndef THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_
|
||||
#define THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_
|
||||
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY)
|
||||
BROTLI_INTERNAL void BrotliEncoderLazyStaticInitInner(void);
|
||||
BROTLI_INTERNAL void BrotliEncoderLazyStaticInit(void);
|
||||
#endif /* BROTLI_STATIC_INIT */
|
||||
|
||||
BROTLI_INTERNAL BROTLI_BOOL BrotliEncoderEnsureStaticInit(void);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif // THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_
|
||||
@@ -0,0 +1,26 @@
|
||||
#include "../common/platform.h"
|
||||
#include "../common/static_init.h"
|
||||
#include "static_init.h"
|
||||
|
||||
#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_LAZY)
|
||||
#error "BROTLI_STATIC_INIT should be BROTLI_STATIC_INIT_LAZY"
|
||||
#else
|
||||
void BrotliEncoderLazyStaticInit(void) {
|
||||
/* From https://en.cppreference.com/w/cpp/language/storage_duration.html:
|
||||
### Static block variables ###
|
||||
Block variables with static or thread (since C++11) storage duration are
|
||||
initialized the first time control passes through their declaration...
|
||||
On all further calls, the declaration is skipped...
|
||||
If multiple threads attempt to initialize the same static local variable
|
||||
concurrently, the initialization occurs exactly once...
|
||||
Usual implementations of this feature use variants of the double-checked
|
||||
locking pattern, which reduces runtime overhead for already-initialized
|
||||
local statics to a single non-atomic boolean comparison.
|
||||
*/
|
||||
static bool ok = [](){
|
||||
BrotliEncoderLazyStaticInitInner();
|
||||
return true;
|
||||
}();
|
||||
if (!ok) BROTLI_CRASH();
|
||||
}
|
||||
#endif /* BROTLI_STATIC_INIT_LAZY */
|
||||
@@ -6,9 +6,9 @@
|
||||
|
||||
/* Heuristics for deciding about the UTF8-ness of strings. */
|
||||
|
||||
#include "./utf8_util.h"
|
||||
#include "utf8_util.h"
|
||||
|
||||
#include <brotli/types.h>
|
||||
#include "../common/platform.h"
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
extern "C" {
|
||||
|
||||
Loaded 100 of 111 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user