aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorElliott Hughes <enh@google.com>2018-10-29 13:17:56 -0700
committerElliott Hughes <enh@google.com>2018-10-29 13:22:06 -0700
commitd7e435979afd38dc8b27dae217a8524835b5659c (patch)
treea8c2225bd1b3946f63401165dbd550d4b27ecae3
parent5912ddfcfec36ed32da49d7bcc50a4678dc7bf0d (diff)
parentd6d98957ca8ccb1ef45922e978bb10efca0ea541 (diff)
downloadbrotli-d7e435979afd38dc8b27dae217a8524835b5659c.tar.gz
Merge tag 'v1.0.7' into HEAD
Change-Id: I4944ea888d852cdb0369dd23e8420916ca804a2b
-rw-r--r--.travis.yml14
-rw-r--r--CMakeLists.txt32
-rw-r--r--METADATA6
-rw-r--r--Makefile16
-rwxr-xr-xc/common/platform.h14
-rwxr-xr-xc/common/transform.c8
-rw-r--r--c/common/version.h4
-rw-r--r--c/dec/decode.c91
-rw-r--r--c/dec/huffman.c77
-rw-r--r--c/dec/huffman.h55
-rw-r--r--c/enc/backward_references_hq.c105
-rw-r--r--c/enc/backward_references_hq.h13
-rw-r--r--c/enc/backward_references_inc.h18
-rw-r--r--c/enc/encode.c34
-rw-r--r--c/enc/hash.h9
-rwxr-xr-xc/enc/hash_composite_inc.h11
-rw-r--r--c/enc/hash_longest_match64_inc.h5
-rw-r--r--c/enc/hash_longest_match_inc.h5
-rwxr-xr-xc/enc/hash_rolling_inc.h5
-rw-r--r--c/enc/hash_to_binary_tree_inc.h5
-rw-r--r--c/tools/brotli.c5
-rw-r--r--java/BUILD34
-rw-r--r--java/WORKSPACE74
-rwxr-xr-xscripts/.travis.sh6
-rw-r--r--scripts/appveyor.yml2
-rwxr-xr-xtests/compatibility_test.sh5
-rwxr-xr-xtests/roundtrip_test.sh5
-rw-r--r--tests/run-compatibility-test.cmake2
-rw-r--r--tests/run-roundtrip-test.cmake2
29 files changed, 375 insertions, 287 deletions
diff --git a/.travis.yml b/.travis.yml
index fba9c55..5cfeafc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -76,6 +76,20 @@ matrix:
- clang-3.5
###
+ ## testing arm via qemu on Linux
+ ###
+ - os: linux
+ env: BUILD_SYSTEM=cmake C_COMPILER=arm-linux-gnueabihf-gcc CXX_COMPILER=arm-linux-gnueabihf-g++ CFLAGS="-march=armv7-a -mfloat-abi=hard -mfpu=neon"
+ addons:
+ apt:
+ sources:
+ - ubuntu-toolchain-r-test
+ packages:
+ - qemu
+ - gcc-arm-linux-gnueabihf
+ - libc6-dev-armhf-cross
+
+ ###
## PGI Community Edition on Linux
###
- os: linux
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6f1c5a2..fc45f80 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -218,15 +218,37 @@ endif()
# to run the tests...
if(NOT BROTLI_DISABLE_TESTS)
if(WIN32 AND NOT CMAKE_HOST_WIN32)
- find_program(BROTLI_WINE NAMES wine)
+ find_program(BROTLI_WRAPPER NAMES wine)
- if(NOT BROTLI_WINE)
+ if(NOT BROTLI_WRAPPER)
message(STATUS "wine not found, disabling tests")
set(BROTLI_DISABLE_TESTS TRUE)
endif()
endif()
endif()
+# If our compiler is a cross-compiler that we know about (arm/aarch64),
+# then we need to use qemu to execute the tests.
+if(NOT BROTLI_DISABLE_TESTS)
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabihf-.*$")
+ message(STATUS "Detected arm-linux-gnueabihf cross-compilation")
+ set(BROTLI_WRAPPER "qemu-arm")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabihf")
+ endif()
+
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabi-.*$")
+ message(STATUS "Detected arm-linux-gnueabi cross-compilation")
+ set(BROTLI_WRAPPER "qemu-arm")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabi")
+ endif()
+
+ if ("${CMAKE_C_COMPILER}" MATCHES "^.*/aarch64-linux-gnu-.*$")
+ message(STATUS "Detected aarch64-linux-gnu cross-compilation")
+ set(BROTLI_WRAPPER "qemu-aarch64")
+ set(BROTLI_WRAPPER_LD_PREFIX "/usr/aarch64-linux-gnu")
+ endif()
+endif()
+
if(NOT BROTLI_DISABLE_TESTS)
include(CTest)
enable_testing()
@@ -249,7 +271,8 @@ if(NOT BROTLI_DISABLE_TESTS)
foreach(quality 1 6 9 11)
add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
COMMAND "${CMAKE_COMMAND}"
- -DBROTLI_WRAPPER=${BROTLI_WINE}
+ -DBROTLI_WRAPPER=${BROTLI_WRAPPER}
+ -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
-DBROTLI_CLI=$<TARGET_FILE:brotli>
-DQUALITY=${quality}
-DINPUT=${INPUT_FILE}
@@ -266,7 +289,8 @@ if(NOT BROTLI_DISABLE_TESTS)
foreach(INPUT ${COMPATIBILITY_INPUTS})
add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
COMMAND "${CMAKE_COMMAND}"
- -DBROTLI_WRAPPER=${BROTLI_WINE}
+ -DBROTLI_WRAPPER=${BROTLI_WRAPPER}
+ -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
-DBROTLI_CLI=$<TARGET_FILE:brotli>
-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
diff --git a/METADATA b/METADATA
index bbb2a02..68e065a 100644
--- a/METADATA
+++ b/METADATA
@@ -9,10 +9,10 @@ third_party {
type: GIT
value: "https://github.com/google/brotli.git"
}
- version: "v1.0.6"
+ version: "v1.0.7"
last_upgrade_date {
year: 2018
- month: 9
- day: 25
+ month: 10
+ day: 29
}
}
diff --git a/Makefile b/Makefile
index c48d798..4890940 100644
--- a/Makefile
+++ b/Makefile
@@ -15,6 +15,18 @@ ifeq ($(os), Darwin)
CPPFLAGS += -DOS_MACOSX
endif
+ifneq ($(strip $(CROSS_COMPILE)), )
+ CC=$(CROSS_COMPILE)-gcc
+ ARCH=$(firstword $(subst -, ,$(CROSS_COMPILE)))
+ BROTLI_WRAPPER="qemu-$(ARCH) -L /usr/$(CROSS_COMPILE)"
+endif
+
+# The arm-linux-gnueabi compiler defaults to Armv5. Since we only support Armv7
+# and beyond, we need to select Armv7 explicitly with march.
+ifeq ($(ARCH), arm)
+ CFLAGS += -march=armv7-a -mfloat-abi=hard -mfpu=neon
+endif
+
all: test
@:
@@ -31,8 +43,8 @@ lib: $(LIBOBJECTS)
ar -crs $(LIB_A) $(LIBOBJECTS)
test: $(EXECUTABLE)
- tests/compatibility_test.sh
- tests/roundtrip_test.sh
+ tests/compatibility_test.sh $(BROTLI_WRAPPER)
+ tests/roundtrip_test.sh $(BROTLI_WRAPPER)
clean:
rm -rf $(BINDIR) $(LIB_A)
diff --git a/c/common/platform.h b/c/common/platform.h
index 0d84b19..84c448c 100755
--- a/c/common/platform.h
+++ b/c/common/platform.h
@@ -71,7 +71,7 @@ OR:
*/
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
- BROTLI_SUNPRO_VERSION_CHECK(5, 12, 0) || \
+ BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
BROTLI_TI_VERSION_CHECK(7, 3, 0) || \
@@ -180,6 +180,12 @@ OR:
#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE
#endif
+#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
+#define BROTLI_ALIGNED(N) __attribute__((aligned(N)))
+#else
+#define BROTLI_ALIGNED(N)
+#endif
+
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \
(defined(M_ARM) && (M_ARM == 7))
#define BROTLI_TARGET_ARMV7
@@ -197,6 +203,10 @@ OR:
#endif /* ARMv8 */
+#if defined(__ARM_NEON__) || defined(__ARM_NEON)
+#define BROTLI_TARGET_NEON
+#endif
+
#if defined(__i386) || defined(_M_IX86)
#define BROTLI_TARGET_X86
#endif
@@ -343,7 +353,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
-typedef __attribute__((aligned(1))) uint64_t brotli_unaligned_uint64_t;
+typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
diff --git a/c/common/transform.c b/c/common/transform.c
index 4184ae5..426e635 100755
--- a/c/common/transform.c
+++ b/c/common/transform.c
@@ -191,11 +191,11 @@ static int ToUpperCase(uint8_t* p) {
}
int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len,
- const BrotliTransforms* transforms, int transfom_idx) {
+ const BrotliTransforms* transforms, int transform_idx) {
int idx = 0;
- const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transfom_idx);
- uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transfom_idx);
- const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transfom_idx);
+ const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transform_idx);
+ uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transform_idx);
+ const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transform_idx);
{
int prefix_len = *prefix++;
while (prefix_len--) { dst[idx++] = *prefix++; }
diff --git a/c/common/version.h b/c/common/version.h
index 1ba0806..0d0d0c7 100644
--- a/c/common/version.h
+++ b/c/common/version.h
@@ -14,13 +14,13 @@
BrotliEncoderVersion methods. */
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
-#define BROTLI_VERSION 0x1000006
+#define BROTLI_VERSION 0x1000007
/* 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
*/
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
-#define BROTLI_ABI_VERSION 0x1006000
+#define BROTLI_ABI_VERSION 0x1007000
#endif /* BROTLI_COMMON_VERSION_H_ */
diff --git a/c/dec/decode.c b/c/dec/decode.c
index 674b829..08bd76c 100644
--- a/c/dec/decode.c
+++ b/c/dec/decode.c
@@ -6,10 +6,6 @@
#include <brotli/decode.h>
-#if defined(__ARM_NEON__)
-#include <arm_neon.h>
-#endif
-
#include <stdlib.h> /* free, malloc */
#include <string.h> /* memcpy, memset */
@@ -24,6 +20,10 @@
#include "./prefix.h"
#include "./state.h"
+#if defined(BROTLI_TARGET_NEON)
+#include <arm_neon.h>
+#endif
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
@@ -167,7 +167,7 @@ static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s,
}
static BROTLI_INLINE void memmove16(uint8_t* dst, uint8_t* src) {
-#if defined(__ARM_NEON__)
+#if defined(BROTLI_TARGET_NEON)
vst1q_u8(dst, vld1q_u8(src));
#else
uint32_t buffer[4];
@@ -347,15 +347,17 @@ static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength(
static BROTLI_INLINE uint32_t DecodeSymbol(uint32_t bits,
const HuffmanCode* table,
BrotliBitReader* br) {
- table += bits & HUFFMAN_TABLE_MASK;
- if (table->bits > HUFFMAN_TABLE_BITS) {
- uint32_t nbits = table->bits - HUFFMAN_TABLE_BITS;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, bits & HUFFMAN_TABLE_MASK);
+ if (BROTLI_HC_FAST_LOAD_BITS(table) > HUFFMAN_TABLE_BITS) {
+ uint32_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS;
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
- table += table->value;
- table += (bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table,
+ BROTLI_HC_FAST_LOAD_VALUE(table) +
+ ((bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits)));
}
- BrotliDropBits(br, table->bits);
- return table->value;
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
+ return BROTLI_HC_FAST_LOAD_VALUE(table);
}
/* Reads and decodes the next Huffman code from bit-stream.
@@ -371,19 +373,20 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol(
const HuffmanCode* table, BrotliBitReader* br, uint32_t* result) {
uint32_t val;
uint32_t available_bits = BrotliGetAvailableBits(br);
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
if (available_bits == 0) {
- if (table->bits == 0) {
- *result = table->value;
+ if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) {
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
return BROTLI_TRUE;
}
return BROTLI_FALSE; /* No valid bits at all. */
}
val = (uint32_t)BrotliGetBitsUnmasked(br);
- table += val & HUFFMAN_TABLE_MASK;
- if (table->bits <= HUFFMAN_TABLE_BITS) {
- if (table->bits <= available_bits) {
- BrotliDropBits(br, table->bits);
- *result = table->value;
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK);
+ if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) {
+ if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) {
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table));
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
return BROTLI_TRUE;
} else {
return BROTLI_FALSE; /* Not enough bits for the first level. */
@@ -394,15 +397,15 @@ static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol(
}
/* Speculatively drop HUFFMAN_TABLE_BITS. */
- val = (val & BitMask(table->bits)) >> HUFFMAN_TABLE_BITS;
+ val = (val & BitMask(BROTLI_HC_FAST_LOAD_BITS(table))) >> HUFFMAN_TABLE_BITS;
available_bits -= HUFFMAN_TABLE_BITS;
- table += table->value + val;
- if (available_bits < table->bits) {
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + val);
+ if (available_bits < BROTLI_HC_FAST_LOAD_BITS(table)) {
return BROTLI_FALSE; /* Not enough bits for the second level. */
}
- BrotliDropBits(br, HUFFMAN_TABLE_BITS + table->bits);
- *result = table->value;
+ BrotliDropBits(br, HUFFMAN_TABLE_BITS + BROTLI_HC_FAST_LOAD_BITS(table));
+ *result = BROTLI_HC_FAST_LOAD_VALUE(table);
return BROTLI_TRUE;
}
@@ -425,9 +428,10 @@ static BROTLI_INLINE void PreloadSymbol(int safe,
if (safe) {
return;
}
- table += BrotliGetBits(br, HUFFMAN_TABLE_BITS);
- *bits = table->bits;
- *value = table->value;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ BROTLI_HC_ADJUST_TABLE_INDEX(table, BrotliGetBits(br, HUFFMAN_TABLE_BITS));
+ *bits = BROTLI_HC_FAST_LOAD_BITS(table);
+ *value = BROTLI_HC_FAST_LOAD_VALUE(table);
}
/* Decodes the next Huffman code using data prepared by PreloadSymbol.
@@ -441,10 +445,11 @@ static BROTLI_INLINE uint32_t ReadPreloadedSymbol(const HuffmanCode* table,
uint32_t val = BrotliGet16BitsUnmasked(br);
const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value;
uint32_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS));
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext);
BrotliDropBits(br, HUFFMAN_TABLE_BITS);
- ext += (val >> HUFFMAN_TABLE_BITS) & mask;
- BrotliDropBits(br, ext->bits);
- result = ext->value;
+ BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask);
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(ext));
+ result = BROTLI_HC_FAST_LOAD_VALUE(ext);
} else {
BrotliDropBits(br, *bits);
}
@@ -597,6 +602,7 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
while (symbol < alphabet_size && space > 0) {
const HuffmanCode* p = s->table;
uint32_t code_len;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
if (!BrotliCheckInputAmount(br, BROTLI_SHORT_FILL_BIT_WINDOW_READ)) {
s->symbol = symbol;
s->repeat = repeat;
@@ -606,10 +612,10 @@ static BrotliDecoderErrorCode ReadSymbolCodeLengths(
return BROTLI_DECODER_NEEDS_MORE_INPUT;
}
BrotliFillBitWindow16(br);
- p += BrotliGetBitsUnmasked(br) &
- BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
- BrotliDropBits(br, p->bits); /* Use 1..5 bits. */
- code_len = p->value; /* code_len == 0..17 */
+ BROTLI_HC_ADJUST_TABLE_INDEX(p, BrotliGetBitsUnmasked(br) &
+ BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); /* Use 1..5 bits. */
+ code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
ProcessSingleCodeLength(code_len, &symbol, &repeat, &space,
&prev_code_len, symbol_lists, code_length_histo, next_symbol);
@@ -637,31 +643,34 @@ static BrotliDecoderErrorCode SafeReadSymbolCodeLengths(
uint32_t code_len;
uint32_t available_bits;
uint32_t bits = 0;
+ BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p);
if (get_byte && !BrotliPullByte(br)) return BROTLI_DECODER_NEEDS_MORE_INPUT;
get_byte = BROTLI_FALSE;
available_bits = BrotliGetAvailableBits(br);
if (available_bits != 0) {
bits = (uint32_t)BrotliGetBitsUnmasked(br);
}
- p += bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH);
- if (p->bits > available_bits) {
+ BROTLI_HC_ADJUST_TABLE_INDEX(p,
+ bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH));
+ if (BROTLI_HC_FAST_LOAD_BITS(p) > available_bits) {
get_byte = BROTLI_TRUE;
continue;
}
- code_len = p->value; /* code_len == 0..17 */
+ code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */
if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) {
- BrotliDropBits(br, p->bits);
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p));
ProcessSingleCodeLength(code_len, &s->symbol, &s->repeat, &s->space,
&s->prev_code_len, s->symbol_lists, s->code_length_histo,
s->next_symbol);
} else { /* code_len == 16..17, extra_bits == 2..3 */
uint32_t extra_bits = code_len - 14U;
- uint32_t repeat_delta = (bits >> p->bits) & BitMask(extra_bits);
- if (available_bits < p->bits + extra_bits) {
+ uint32_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) &
+ BitMask(extra_bits);
+ if (available_bits < BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits) {
get_byte = BROTLI_TRUE;
continue;
}
- BrotliDropBits(br, p->bits + extra_bits);
+ BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits);
ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size,
&s->symbol, &s->repeat, &s->space, &s->prev_code_len,
&s->repeat_code_len, s->symbol_lists, s->code_length_histo,
diff --git a/c/dec/huffman.c b/c/dec/huffman.c
index c5eafad..30c40d3 100644
--- a/c/dec/huffman.c
+++ b/c/dec/huffman.c
@@ -142,8 +142,7 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
/* Special case: all symbols but one have 0 code length. */
if (offset[0] == 0) {
- code.bits = 0;
- code.value = (uint16_t)sorted[0];
+ code = ConstructHuffmanCode(0, (uint16_t)sorted[0]);
for (key = 0; key < (brotli_reg_t)table_size; ++key) {
table[key] = code;
}
@@ -157,9 +156,8 @@ void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table,
bits = 1;
step = 2;
do {
- code.bits = (uint8_t)bits;
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
- code.value = (uint16_t)sorted[symbol++];
+ code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]);
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
key += key_step;
}
@@ -211,11 +209,10 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
bits = 1;
step = 2;
do {
- code.bits = (uint8_t)bits;
symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1);
for (bits_count = count[bits]; bits_count != 0; --bits_count) {
symbol = symbol_lists[symbol];
- code.value = (uint16_t)symbol;
+ code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol);
ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code);
key += key_step;
}
@@ -244,14 +241,13 @@ uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
total_size += table_size;
sub_key = BrotliReverseBits(key);
key += key_step;
- root_table[sub_key].bits = (uint8_t)(table_bits + root_bits);
- root_table[sub_key].value =
- (uint16_t)(((size_t)(table - root_table)) - sub_key);
+ root_table[sub_key] = ConstructHuffmanCode(
+ (uint8_t)(table_bits + root_bits),
+ (uint16_t)(((size_t)(table - root_table)) - sub_key));
sub_key = 0;
}
- code.bits = (uint8_t)(len - root_bits);
symbol = symbol_lists[symbol];
- code.value = (uint16_t)symbol;
+ code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol);
ReplicateValue(
&table[BrotliReverseBits(sub_key)], step, table_size, code);
sub_key += sub_key_step;
@@ -270,35 +266,28 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
const uint32_t goal_size = 1U << root_bits;
switch (num_symbols) {
case 0:
- table[0].bits = 0;
- table[0].value = val[0];
+ table[0] = ConstructHuffmanCode(0, val[0]);
break;
case 1:
- table[0].bits = 1;
- table[1].bits = 1;
if (val[1] > val[0]) {
- table[0].value = val[0];
- table[1].value = val[1];
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[1] = ConstructHuffmanCode(1, val[1]);
} else {
- table[0].value = val[1];
- table[1].value = val[0];
+ table[0] = ConstructHuffmanCode(1, val[1]);
+ table[1] = ConstructHuffmanCode(1, val[0]);
}
table_size = 2;
break;
case 2:
- table[0].bits = 1;
- table[0].value = val[0];
- table[2].bits = 1;
- table[2].value = val[0];
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[2] = ConstructHuffmanCode(1, val[0]);
if (val[2] > val[1]) {
- table[1].value = val[1];
- table[3].value = val[2];
+ table[1] = ConstructHuffmanCode(2, val[1]);
+ table[3] = ConstructHuffmanCode(2, val[2]);
} else {
- table[1].value = val[2];
- table[3].value = val[1];
+ table[1] = ConstructHuffmanCode(2, val[2]);
+ table[3] = ConstructHuffmanCode(2, val[1]);
}
- table[1].bits = 2;
- table[3].bits = 2;
table_size = 4;
break;
case 3: {
@@ -312,33 +301,27 @@ uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
}
}
}
- for (i = 0; i < 4; ++i) {
- table[i].bits = 2;
- }
- table[0].value = val[0];
- table[2].value = val[1];
- table[1].value = val[2];
- table[3].value = val[3];
+ table[0] = ConstructHuffmanCode(2, val[0]);
+ table[2] = ConstructHuffmanCode(2, val[1]);
+ table[1] = ConstructHuffmanCode(2, val[2]);
+ table[3] = ConstructHuffmanCode(2, val[3]);
table_size = 4;
break;
}
case 4: {
- int i;
if (val[3] < val[2]) {
uint16_t t = val[3];
val[3] = val[2];
val[2] = t;
}
- for (i = 0; i < 7; ++i) {
- table[i].value = val[0];
- table[i].bits = (uint8_t)(1 + (i & 1));
- }
- table[1].value = val[1];
- table[3].value = val[2];
- table[5].value = val[1];
- table[7].value = val[3];
- table[3].bits = 3;
- table[7].bits = 3;
+ table[0] = ConstructHuffmanCode(1, val[0]);
+ table[1] = ConstructHuffmanCode(2, val[1]);
+ table[2] = ConstructHuffmanCode(1, val[0]);
+ table[3] = ConstructHuffmanCode(3, val[2]);
+ table[4] = ConstructHuffmanCode(1, val[0]);
+ table[5] = ConstructHuffmanCode(2, val[1]);
+ table[6] = ConstructHuffmanCode(1, val[0]);
+ table[7] = ConstructHuffmanCode(3, val[3]);
table_size = 8;
break;
}
diff --git a/c/dec/huffman.h b/c/dec/huffman.h
index 521ec6e..b9f0716 100644
--- a/c/dec/huffman.h
+++ b/c/dec/huffman.h
@@ -33,11 +33,66 @@ static const uint16_t kMaxHuffmanTableSize[] = {
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5
+#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \
+ BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0))
+#define BROTLI_HUFFMAN_CODE_FAST_LOAD
+#endif
+
+#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD)
+/* Do not create this struct directly - use the ConstructHuffmanCode
+ * constructor below! */
typedef struct {
uint8_t bits; /* number of bits used for this symbol */
uint16_t value; /* symbol value or table offset */
} HuffmanCode;
+static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
+ const uint16_t value) {
+ HuffmanCode h;
+ h.bits = bits;
+ h.value = value;
+ return h;
+}
+
+/* Please use the following macros to optimize HuffmanCode accesses in hot
+ * paths.
+ *
+ * For example, assuming |table| contains a HuffmanCode pointer:
+ *
+ * BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table);
+ * BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table);
+ * *bits = BROTLI_HC_GET_BITS(table);
+ * *value = BROTLI_HC_GET_VALUE(table);
+ * BROTLI_HC_ADJUST_TABLE_INDEX(table, offset);
+ * *bits2 = BROTLI_HC_GET_BITS(table);
+ * *value2 = BROTLI_HC_GET_VALUE(table);
+ *
+ */
+
+#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H)
+#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V)
+
+/* These must be given a HuffmanCode pointer! */
+#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits)
+#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value)
+
+#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
+
+typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode;
+
+static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits,
+ const uint16_t value) {
+ return ((value & 0xFFFF) << 16) | (bits & 0xFF);
+}
+
+#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H)
+#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H)
+
+/* These must be given a HuffmanCode pointer! */
+#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF)
+#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16)
+#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */
+
/* Builds Huffman lookup table assuming code lengths are in symbol order. */
BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table,
const uint8_t* const code_lengths, uint16_t* count);
diff --git a/c/enc/backward_references_hq.c b/c/enc/backward_references_hq.c
index e7486c4..96b0e70 100644
--- a/c/enc/backward_references_hq.c
+++ b/c/enc/backward_references_hq.c
@@ -330,7 +330,7 @@ static size_t ComputeMinimumCopyLength(const float start_cost,
REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */
static uint32_t ComputeDistanceShortcut(const size_t block_start,
const size_t pos,
- const size_t max_backward,
+ const size_t max_backward_limit,
const size_t gap,
const ZopfliNode* nodes) {
const size_t clen = ZopfliNodeCopyLength(&nodes[pos]);
@@ -338,13 +338,13 @@ static uint32_t ComputeDistanceShortcut(const size_t block_start,
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
- this or greater than |max_backward| are static dictionary references, and
- do not update the last distances. Also distance code 0 (last distance)
- does not update the last distances. */
+ 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 &&
- dist <= max_backward + gap &&
+ dist <= max_backward_limit + gap &&
ZopfliNodeDistanceCode(&nodes[pos]) > 0) {
return (uint32_t)pos;
} else {
@@ -454,9 +454,11 @@ static size_t UpdateNodes(
break;
}
if (BROTLI_PREDICT_FALSE(backward > max_distance + gap)) {
+ /* Word dictionary -> ignore. */
continue;
}
if (backward <= max_distance) {
+ /* Regular backward reference. */
if (prev_ix >= cur_ix) {
continue;
}
@@ -564,14 +566,10 @@ static size_t ComputeShortestPathFromNodes(size_t num_bytes,
/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */
void BrotliZopfliCreateCommands(const size_t num_bytes,
- const size_t block_start,
- const size_t max_backward_limit,
- const ZopfliNode* nodes,
- int* dist_cache,
- size_t* last_insert_len,
- const BrotliEncoderParams* params,
- Command* commands,
- size_t* num_literals) {
+ const size_t block_start, const ZopfliNode* nodes, int* dist_cache,
+ size_t* last_insert_len, const BrotliEncoderParams* params,
+ Command* commands, size_t* num_literals) {
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
size_t pos = 0;
uint32_t offset = nodes[0].u.next;
size_t i;
@@ -610,18 +608,12 @@ void BrotliZopfliCreateCommands(const size_t num_bytes,
*last_insert_len += num_bytes - pos;
}
-static size_t ZopfliIterate(size_t num_bytes,
- size_t position,
- const uint8_t* ringbuffer,
- size_t ringbuffer_mask,
- const BrotliEncoderParams* params,
- const size_t max_backward_limit,
- const size_t gap,
- const int* dist_cache,
- const ZopfliCostModel* model,
- const uint32_t* num_matches,
- const BackwardMatch* matches,
- ZopfliNode* nodes) {
+static size_t ZopfliIterate(size_t num_bytes, size_t position,
+ const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params, const size_t gap, const int* dist_cache,
+ const ZopfliCostModel* model, const uint32_t* num_matches,
+ const BackwardMatch* matches, ZopfliNode* nodes) {
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t max_zopfli_len = MaxZopfliLen(params);
StartPosQueue queue;
size_t cur_match_pos = 0;
@@ -645,8 +637,8 @@ static size_t ZopfliIterate(size_t num_bytes,
while (skip) {
i++;
if (i + 3 >= num_bytes) break;
- EvaluateNode(position, i, max_backward_limit, gap, dist_cache, model,
- &queue, nodes);
+ EvaluateNode(position, i, max_backward_limit, gap,
+ dist_cache, model, &queue, nodes);
cur_match_pos += num_matches[i];
skip--;
}
@@ -656,11 +648,11 @@ static size_t ZopfliIterate(size_t num_bytes,
}
/* 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, const BrotliEncoderParams* params,
- const size_t max_backward_limit, const int* dist_cache, HasherHandle hasher,
- ZopfliNode* nodes) {
+size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params,
+ const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes) {
+ const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t max_zopfli_len = MaxZopfliLen(params);
ZopfliCostModel model;
StartPosQueue queue;
@@ -681,9 +673,11 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
const size_t pos = position + i;
const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit);
size_t skip;
- size_t num_matches = FindAllMatchesH10(hasher, &params->dictionary,
- ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance, gap,
- params, &matches[lz_matches_offset]);
+ size_t num_matches;
+ num_matches = FindAllMatchesH10(hasher,
+ &params->dictionary,
+ ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance,
+ gap, params, &matches[lz_matches_offset]);
if (num_matches > 0 &&
BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) {
matches[0] = matches[num_matches - 1];
@@ -704,8 +698,8 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
while (skip) {
i++;
if (i + HashTypeLengthH10() - 1 >= num_bytes) break;
- EvaluateNode(position, i, max_backward_limit, gap, dist_cache, &model,
- &queue, nodes);
+ EvaluateNode(position, i, max_backward_limit, gap,
+ dist_cache, &model, &queue, nodes);
skip--;
}
}
@@ -714,28 +708,27 @@ size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
return ComputeShortestPathFromNodes(num_bytes, nodes);
}
-void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
- size_t num_bytes, size_t position, const uint8_t* ringbuffer,
- size_t ringbuffer_mask, const BrotliEncoderParams* params,
+void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
- const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
ZopfliNode* nodes;
nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1);
if (BROTLI_IS_OOM(m)) return;
BrotliInitZopfliNodes(nodes, num_bytes + 1);
- *num_commands += BrotliZopfliComputeShortestPath(m,
- num_bytes, position, ringbuffer, ringbuffer_mask,
- params, max_backward_limit, dist_cache, hasher, nodes);
+ *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes,
+ position, ringbuffer, ringbuffer_mask, params,
+ dist_cache, hasher, nodes);
if (BROTLI_IS_OOM(m)) return;
- BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit, nodes,
- dist_cache, last_insert_len, params, commands, num_literals);
+ BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache,
+ last_insert_len, params, commands, num_literals);
BROTLI_FREE(m, nodes);
}
-void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
- size_t num_bytes, size_t position, const uint8_t* ringbuffer,
- size_t ringbuffer_mask, const BrotliEncoderParams* params,
+void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params,
HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
@@ -767,8 +760,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches);
if (BROTLI_IS_OOM(m)) return;
num_found_matches = FindAllMatchesH10(hasher,
- &params->dictionary, ringbuffer, ringbuffer_mask, pos, max_length,
- max_distance, gap, params, &matches[cur_match_pos + shadow_matches]);
+ &params->dictionary,
+ ringbuffer, ringbuffer_mask, pos, max_length,
+ max_distance, gap, params,
+ &matches[cur_match_pos + shadow_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]) <=
@@ -814,10 +809,10 @@ void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
*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, max_backward_limit, gap, dist_cache,
- &model, num_matches, matches, nodes);
- BrotliZopfliCreateCommands(num_bytes, position, max_backward_limit,
- nodes, dist_cache, last_insert_len, params, commands, num_literals);
+ 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);
BROTLI_FREE(m, nodes);
diff --git a/c/enc/backward_references_hq.h b/c/enc/backward_references_hq.h
index 7c38bd6..1e4275d 100644
--- a/c/enc/backward_references_hq.h
+++ b/c/enc/backward_references_hq.h
@@ -74,15 +74,14 @@ BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
(1) nodes[i].copy_length() >= 2
(2) nodes[i].command_length() <= i and
(3) nodes[i - nodes[i].command_length()].cost < kInfinity */
-BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(MemoryManager* m,
- size_t num_bytes, size_t position, const uint8_t* ringbuffer,
- size_t ringbuffer_mask, const BrotliEncoderParams* params,
- const size_t max_backward_limit, const int* dist_cache, HasherHandle hasher,
- ZopfliNode* nodes);
+BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath(
+ MemoryManager* m, size_t num_bytes,
+ size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
+ const BrotliEncoderParams* params,
+ const int* dist_cache, HasherHandle hasher, ZopfliNode* nodes);
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
- const size_t num_bytes, const size_t block_start,
- const size_t max_backward_limit, const ZopfliNode* nodes,
+ const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes,
int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params,
Command* commands, size_t* num_literals);
diff --git a/c/enc/backward_references_inc.h b/c/enc/backward_references_inc.h
index 38a48d3..c18cdb0 100644
--- a/c/enc/backward_references_inc.h
+++ b/c/enc/backward_references_inc.h
@@ -10,9 +10,9 @@
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask,
- const BrotliEncoderParams* params, HasherHandle hasher, int* dist_cache,
- size_t* last_insert_len, Command* commands, size_t* num_commands,
- size_t* num_literals) {
+ const BrotliEncoderParams* params,
+ HasherHandle hasher, int* dist_cache, size_t* last_insert_len,
+ Command* commands, size_t* num_commands, size_t* num_literals) {
/* Set maximum distance, see section 9.1. of the spec. */
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
@@ -42,9 +42,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
sr.distance = 0;
sr.score = kMinScore;
FN(FindLongestMatch)(hasher, &params->dictionary,
- ringbuffer, ringbuffer_mask, dist_cache, position,
- max_length, max_distance, gap,
- params->dist.max_distance, &sr);
+ ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
+ max_distance, gap, 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;
@@ -58,7 +57,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
sr2.distance = 0;
sr2.score = kMinScore;
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
- FN(FindLongestMatch)(hasher, &params->dictionary,
+ FN(FindLongestMatch)(hasher,
+ &params->dictionary,
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
max_distance, gap, params->dist.max_distance, &sr2);
if (sr2.score >= sr.score + cost_diff_lazy) {
@@ -80,8 +80,8 @@ static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
{
/* The first 16 codes are special short-codes,
and the minimum offset is 1. */
- size_t distance_code =
- ComputeDistanceCode(sr.distance, max_distance + gap, dist_cache);
+ size_t distance_code = ComputeDistanceCode(
+ sr.distance, max_distance + gap, dist_cache);
if ((sr.distance <= (max_distance + gap)) && distance_code > 0) {
dist_cache[3] = dist_cache[2];
dist_cache[2] = dist_cache[1];
diff --git a/c/enc/encode.c b/c/enc/encode.c
index ec56da2..141e70a 100644
--- a/c/enc/encode.c
+++ b/c/enc/encode.c
@@ -496,6 +496,8 @@ static void DecideOverLiteralContextModeling(const uint8_t* input,
static BROTLI_BOOL ShouldCompress(
const uint8_t* data, const size_t mask, const uint64_t last_flush_pos,
const size_t bytes, const size_t num_literals, const size_t num_commands) {
+ /* TODO: find more precise minimal block overhead. */
+ if (bytes <= 2) return BROTLI_FALSE;
if (num_commands < (bytes >> 8) + 2) {
if (num_literals > 0.99 * (double)bytes) {
uint32_t literal_histo[256] = { 0 };
@@ -674,12 +676,14 @@ static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) {
if (BROTLI_IS_OOM(&s->memory_manager_)) return BROTLI_FALSE;
if (s->is_initialized_) return BROTLI_TRUE;
+ s->last_bytes_bits_ = 0;
+ s->last_bytes_ = 0;
+ s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
+
SanitizeParams(&s->params);
s->params.lgblock = ComputeLgBlock(&s->params);
ChooseDistanceParams(&s->params);
- s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX;
-
RingBufferSetup(&s->params, &s->ringbuffer_);
/* Initialize last byte with stream header. */
@@ -1029,23 +1033,20 @@ static BROTLI_BOOL EncodeData(
if (s->params.quality == ZOPFLIFICATION_QUALITY) {
BROTLI_DCHECK(s->params.hasher.type == 10);
- BrotliCreateZopfliBackwardReferences(m,
- bytes, wrapped_last_processed_pos,
+ BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
} else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) {
BROTLI_DCHECK(s->params.hasher.type == 10);
- BrotliCreateHqZopfliBackwardReferences(m,
- bytes, wrapped_last_processed_pos,
+ BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
} else {
- BrotliCreateBackwardReferences(
- bytes, wrapped_last_processed_pos,
+ BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos,
data, mask, &s->params, s->hasher_, s->dist_cache_,
&s->last_insert_len_, &s->commands_[s->num_commands_],
&s->num_commands_, &s->num_literals_);
@@ -1166,7 +1167,6 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
MemoryManager* m = &memory_manager;
const size_t mask = BROTLI_SIZE_MAX >> 1;
- const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(lgwin);
int dist_cache[4] = { 4, 11, 15, 16 };
int saved_dist_cache[4] = { 4, 11, 15, 16 };
BROTLI_BOOL ok = BROTLI_TRUE;
@@ -1176,8 +1176,8 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
uint8_t last_bytes_bits;
HasherHandle hasher = NULL;
- const size_t hasher_eff_size =
- BROTLI_MIN(size_t, input_size, max_backward_limit + BROTLI_WINDOW_GAP);
+ const size_t hasher_eff_size = BROTLI_MIN(size_t,
+ input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
BrotliEncoderParams params;
@@ -1238,9 +1238,9 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
BrotliInitZopfliNodes(nodes, block_size + 1);
StitchToPreviousBlockH10(hasher, block_size, block_start,
input_buffer, mask);
- path_size = BrotliZopfliComputeShortestPath(m,
- block_size, block_start, input_buffer, mask, &params,
- max_backward_limit, dist_cache, hasher, nodes);
+ path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
+ input_buffer, mask, &params, dist_cache, hasher,
+ nodes);
if (BROTLI_IS_OOM(m)) goto oom;
/* We allocate a command buffer in the first iteration of this loop that
will be likely big enough for the whole metablock, so that for most
@@ -1262,10 +1262,8 @@ static BROTLI_BOOL BrotliCompressBufferQuality10(
}
commands = new_commands;
}
- BrotliZopfliCreateCommands(block_size, block_start, max_backward_limit,
- &nodes[0], dist_cache, &last_insert_len,
- &params, &commands[num_commands],
- &num_literals);
+ BrotliZopfliCreateCommands(block_size, block_start, &nodes[0], dist_cache,
+ &last_insert_len, &params, &commands[num_commands], &num_literals);
num_commands += path_size;
block_start += block_size;
metablock_size += block_size;
diff --git a/c/enc/hash.h b/c/enc/hash.h
index 2602490..8c5a7bb 100644
--- a/c/enc/hash.h
+++ b/c/enc/hash.h
@@ -149,9 +149,9 @@ static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
}
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
- const BrotliEncoderDictionary* dictionary, size_t item, const uint8_t* data,
- size_t max_length, size_t max_backward, size_t max_distance,
- HasherSearchResult* out) {
+ const BrotliEncoderDictionary* dictionary, size_t item,
+ const uint8_t* data, size_t max_length, size_t max_backward,
+ size_t max_distance, HasherSearchResult* out) {
size_t len;
size_t word_idx;
size_t offset;
@@ -208,7 +208,8 @@ static BROTLI_INLINE void SearchInStaticDictionary(
self->dict_num_lookups++;
if (item != 0) {
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
- dictionary, item, data, max_length, max_backward, max_distance, out);
+ dictionary, item, data,
+ max_length, max_backward, max_distance, out);
if (item_matches) {
self->dict_num_matches++;
}
diff --git a/c/enc/hash_composite_inc.h b/c/enc/hash_composite_inc.h
index f829a97..b266aa2 100755
--- a/c/enc/hash_composite_inc.h
+++ b/c/enc/hash_composite_inc.h
@@ -121,13 +121,16 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
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 gap,
- const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
+ const size_t max_length, const size_t max_backward,
+ const size_t gap, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
HashComposite* self = FN(Self)(handle);
FN_A(FindLongestMatch)(self->ha, dictionary, data, ring_buffer_mask,
- distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out);
+ distance_cache, cur_ix, max_length, max_backward, gap,
+ max_distance, out);
FN_B(FindLongestMatch)(self->hb, dictionary, data, ring_buffer_mask,
- distance_cache, cur_ix, max_length, max_backward, gap, max_distance, out);
+ distance_cache, cur_ix, max_length, max_backward, gap,
+ max_distance, out);
}
#undef HashComposite
diff --git a/c/enc/hash_longest_match64_inc.h b/c/enc/hash_longest_match64_inc.h
index e099edf..cb953a6 100644
--- a/c/enc/hash_longest_match64_inc.h
+++ b/c/enc/hash_longest_match64_inc.h
@@ -161,8 +161,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
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 gap,
- const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
+ const size_t max_length, const size_t max_backward,
+ const size_t gap, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
diff --git a/c/enc/hash_longest_match_inc.h b/c/enc/hash_longest_match_inc.h
index 951d7a4..457f5a9 100644
--- a/c/enc/hash_longest_match_inc.h
+++ b/c/enc/hash_longest_match_inc.h
@@ -154,8 +154,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
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 gap,
- const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
+ const size_t max_length, const size_t max_backward,
+ const size_t gap, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
HasherCommon* common = GetHasherCommon(handle);
HashLongestMatch* self = FN(Self)(handle);
uint16_t* num = FN(Num)(self);
diff --git a/c/enc/hash_rolling_inc.h b/c/enc/hash_rolling_inc.h
index 4d5d14a..17f8a40 100755
--- a/c/enc/hash_rolling_inc.h
+++ b/c/enc/hash_rolling_inc.h
@@ -155,8 +155,9 @@ static BROTLI_INLINE void FN(FindLongestMatch)(HasherHandle handle,
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 gap,
- const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) {
+ const size_t max_length, const size_t max_backward,
+ const size_t gap, const size_t max_distance,
+ HasherSearchResult* BROTLI_RESTRICT out) {
HashRolling* self = FN(Self)(handle);
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
size_t pos = self->next_ix;
diff --git a/c/enc/hash_to_binary_tree_inc.h b/c/enc/hash_to_binary_tree_inc.h
index 48097b1..7fb0356 100644
--- a/c/enc/hash_to_binary_tree_inc.h
+++ b/c/enc/hash_to_binary_tree_inc.h
@@ -202,8 +202,9 @@ static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
static BROTLI_INLINE size_t FN(FindAllMatches)(HasherHandle handle,
const BrotliEncoderDictionary* dictionary, const uint8_t* data,
const size_t ring_buffer_mask, const size_t cur_ix,
- const size_t max_length, const size_t max_backward, const size_t gap,
- const BrotliEncoderParams* params, BackwardMatch* matches) {
+ const size_t max_length, const size_t max_backward,
+ const size_t gap, const BrotliEncoderParams* params,
+ BackwardMatch* matches) {
BackwardMatch* const orig_matches = matches;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
size_t best_len = 1;
diff --git a/c/tools/brotli.c b/c/tools/brotli.c
index ea4fdac..ce05b64 100644
--- a/c/tools/brotli.c
+++ b/c/tools/brotli.c
@@ -943,10 +943,9 @@ static BROTLI_BOOL CompressFiles(Context* context) {
uint32_t lgwin = DEFAULT_LGWIN;
/* Use file size to limit lgwin. */
if (context->input_file_length >= 0) {
- int32_t size = 1 << BROTLI_MIN_WINDOW_BITS;
lgwin = BROTLI_MIN_WINDOW_BITS;
- while (size < context->input_file_length) {
- size <<= 1;
+ while (BROTLI_MAX_BACKWARD_LIMIT(lgwin) <
+ (uint64_t)context->input_file_length) {
lgwin++;
if (lgwin == BROTLI_MAX_WINDOW_BITS) break;
}
diff --git a/java/BUILD b/java/BUILD
index a00e2d0..f7dd0c0 100644
--- a/java/BUILD
+++ b/java/BUILD
@@ -6,7 +6,7 @@ package(
genrule(
name = "copy_link_jni_header",
- srcs = ["@openjdk_linux//:jni_h"],
+ srcs = ["@openjdk_jni_h//file"],
outs = ["jni/jni.h"],
cmd = "cp -f $< $@",
)
@@ -14,12 +14,12 @@ genrule(
genrule(
name = "copy_link_jni_md_header",
srcs = select({
- "@org_brotli//:darwin": ["@openjdk_macos//:jni_md_h"],
- "@org_brotli//:darwin_x86_64": ["@openjdk_macos//:jni_md_h"],
- "@org_brotli//:windows_msys": ["@openjdk_win//:jni_md_h"],
- "@org_brotli//:windows_msvc": ["@openjdk_win//:jni_md_h"],
- "@org_brotli//:windows": ["@openjdk_win//:jni_md_h"],
- "//conditions:default": ["@openjdk_linux//:jni_md_h"],
+ "@org_brotli//:darwin": ["@openjdk_macosx_jni_md_h//file"],
+ "@org_brotli//:darwin_x86_64": ["@openjdk_macosx_jni_md_h//file"],
+ "@org_brotli//:windows_msys": ["@openjdk_windows_jni_md_h//file"],
+ "@org_brotli//:windows_msvc": ["@openjdk_windows_jni_md_h//file"],
+ "@org_brotli//:windows": ["@openjdk_windows_jni_md_h//file"],
+ "//conditions:default": ["@openjdk_solaris_jni_md_h//file"],
}),
outs = ["jni/jni_md.h"],
cmd = "cp -f $< $@",
@@ -42,21 +42,21 @@ cc_library(
cc_binary(
name = "brotli_jni.dll",
srcs = [
+ "//org/brotli/wrapper/common:jni_src",
+ "//org/brotli/wrapper/dec:jni_src",
+ "//org/brotli/wrapper/enc:jni_src",
"@org_brotli//:common_headers",
"@org_brotli//:common_sources",
"@org_brotli//:dec_headers",
"@org_brotli//:dec_sources",
"@org_brotli//:enc_headers",
"@org_brotli//:enc_sources",
- "//org/brotli/wrapper/common:jni_src",
- "//org/brotli/wrapper/dec:jni_src",
- "//org/brotli/wrapper/enc:jni_src",
],
+ linkshared = 1,
deps = [
- "@org_brotli//:brotli_inc",
":jni_inc",
+ "@org_brotli//:brotli_inc",
],
- linkshared = 1,
)
########################################################
@@ -65,22 +65,22 @@ cc_binary(
cc_binary(
name = "brotli_jni_no_dictionary_data.dll",
srcs = [
+ "//org/brotli/wrapper/common:jni_src",
+ "//org/brotli/wrapper/dec:jni_src",
+ "//org/brotli/wrapper/enc:jni_src",
"@org_brotli//:common_headers",
"@org_brotli//:common_sources",
"@org_brotli//:dec_headers",
"@org_brotli//:dec_sources",
"@org_brotli//:enc_headers",
"@org_brotli//:enc_sources",
- "//org/brotli/wrapper/common:jni_src",
- "//org/brotli/wrapper/dec:jni_src",
- "//org/brotli/wrapper/enc:jni_src",
],
defines = [
"BROTLI_EXTERNAL_DICTIONARY_DATA=",
],
+ linkshared = 1,
deps = [
- "@org_brotli//:brotli_inc",
":jni_inc",
+ "@org_brotli//:brotli_inc",
],
- linkshared = 1,
)
diff --git a/java/WORKSPACE b/java/WORKSPACE
index ab3f8b1..06fbdfe 100644
--- a/java/WORKSPACE
+++ b/java/WORKSPACE
@@ -10,60 +10,32 @@ maven_jar(
artifact = "junit:junit:4.12",
)
-new_http_archive(
- name = "openjdk_linux",
- urls = [
- "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
- "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
- "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-linux_x64.tar.gz",
- ],
- sha256 = "7e6284739c0e5b7142bc7a9adc61ced70dc5bb26b130b582b18e809013bcb251",
- build_file_content = """
-package(
- default_visibility = ["//visibility:public"],
-)
-filegroup(
- name = "jni_h",
- srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/jni.h"],
-)
-filegroup(
- name = "jni_md_h",
- srcs = ["zulu8.23.0.3-jdk8.0.144-linux_x64/include/linux/jni_md.h"],
-)""",
-)
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_file")
-new_http_archive(
- name = "openjdk_macos",
- urls = [
- "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
- "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
- "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-macosx_x64.zip",
- ],
- sha256 = "ff533364c9cbd3b271ab5328efe28e2dd6d7bae5b630098a5683f742ecf0709d",
- build_file_content = """
-package(
- default_visibility = ["//visibility:public"],
+http_file(
+ name = "openjdk_jni_h",
+ downloaded_file_path = "jni.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/share/javavm/export/jni.h"],
+ sha256 = "ed99792df48670072b78028faf704a8dcb6868fe140ccc7eced9b01dfa62fef4",
)
-filegroup(
- name = "jni_md_h",
- srcs = ["zulu8.23.0.3-jdk8.0.144-macosx_x64/include/darwin/jni_md.h"],
-)""",
+
+http_file(
+ name = "openjdk_solaris_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/solaris/javavm/export/jni_md.h"],
+ sha256 = "ecbe6944fe1a4290644d5a6b3c8f68576798a53b9da12cd31c58c48569595ff7",
)
-new_http_archive(
- name = "openjdk_win",
- urls = [
- "https://mirror.bazel.build/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
- "https://bazel-mirror.storage.googleapis.com/openjdk/azul-zulu-8.23.0.3-jdk8.0.144/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
- "https://cdn.azul.com/zulu/bin/zulu8.23.0.3-jdk8.0.144-win_x64.zip",
- ],
- sha256 = "f1d9d3341ef7c8c9baff3597953e99a6a7c64f8608ee62c03fdd7574b7655c02",
- build_file_content = """
-package(
- default_visibility = ["//visibility:public"],
+http_file(
+ name = "openjdk_macosx_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/macosx/javavm/export/jni_md.h"],
+ sha256 = "8f718071022e7e7f2fc9a229984b7e83582db91ed83861b49ce1461436fe8dc4",
)
-filegroup(
- name = "jni_md_h",
- srcs = ["zulu8.23.0.3-jdk8.0.144-win_x64/include/win32/jni_md.h"],
-)""",
+
+http_file(
+ name = "openjdk_windows_jni_md_h",
+ downloaded_file_path = "jni_md.h",
+ urls = ["https://hg.openjdk.java.net/jdk8/jdk8/jdk/raw-file/687fd7c7986d/src/windows/javavm/export/jni_md.h"],
+ sha256 = "5479fb385ea1e11619f5c0cdfd9ccb3ea3a3fea0f5bc6176fb3ce62be29d759b",
)
diff --git a/scripts/.travis.sh b/scripts/.travis.sh
index 6387e22..367cdfa 100755
--- a/scripts/.travis.sh
+++ b/scripts/.travis.sh
@@ -40,9 +40,9 @@ case "$1" in
if [ "${CROSS_COMPILE}" = "yes" ]; then
CMAKE_FLAGS="-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER -DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY -DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY -DCMAKE_SYSTEM_NAME=Windows -DCMAKE_RC_COMPILER=${RC_COMPILER}"
fi
- cmake ${CMAKE_FLAGS} -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" -DENABLE_SANITIZER="${SANITIZER}" -DCMAKE_C_FLAGS="${CFLAGS}" ..
- make VERBOSE=1
- ctest -V
+ cmake ${CMAKE_FLAGS} -DCMAKE_C_COMPILER="$CC" -DCMAKE_CXX_COMPILER="$CXX" -DENABLE_SANITIZER="${SANITIZER}" -DCMAKE_C_FLAGS="${CFLAGS}" .. || exit 1
+ make VERBOSE=1 || exit 1
+ ctest -V || exit 1
;;
"python")
python setup.py test
diff --git a/scripts/appveyor.yml b/scripts/appveyor.yml
index abfb58f..e22a8c6 100644
--- a/scripts/appveyor.yml
+++ b/scripts/appveyor.yml
@@ -54,7 +54,7 @@ install:
)
)
- IF "%BUILD_SYSTEM%"=="bazel" (
- appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/0.14.1/bazel-0.14.1-windows-x86_64.exe -FileName bazel.exe
+ appveyor DownloadFile https://github.com/bazelbuild/bazel/releases/download/0.18.0/bazel-0.18.0-windows-x86_64.exe -FileName bazel.exe
)
before_build:
diff --git a/tests/compatibility_test.sh b/tests/compatibility_test.sh
index 4026fd9..c5af8bf 100755
--- a/tests/compatibility_test.sh
+++ b/tests/compatibility_test.sh
@@ -2,10 +2,13 @@
#
# Test that the brotli command-line tool can decompress old brotli-compressed
# files.
+#
+# The first argument may be a wrapper for brotli, such as 'qemu-arm'.
set -o errexit
-BROTLI=bin/brotli
+BROTLI_WRAPPER=$1
+BROTLI="${BROTLI_WRAPPER} bin/brotli"
TMP_DIR=bin/tmp
for file in tests/testdata/*.compressed*; do
diff --git a/tests/roundtrip_test.sh b/tests/roundtrip_test.sh
index 6c92418..90027af 100755
--- a/tests/roundtrip_test.sh
+++ b/tests/roundtrip_test.sh
@@ -1,10 +1,13 @@
#!/usr/bin/env bash
#
# Roundtrip test for the brotli command-line tool.
+#
+# The first argument may be a wrapper for brotli, such as 'qemu-arm'.
set -o errexit
-BROTLI=bin/brotli
+BROTLI_WRAPPER=$1
+BROTLI="${BROTLI_WRAPPER} bin/brotli"
TMP_DIR=bin/tmp
INPUTS="""
tests/testdata/alice29.txt
diff --git a/tests/run-compatibility-test.cmake b/tests/run-compatibility-test.cmake
index fd49db8..f594d98 100644
--- a/tests/run-compatibility-test.cmake
+++ b/tests/run-compatibility-test.cmake
@@ -2,6 +2,8 @@ string(REGEX REPLACE "([a-zA-Z0-9\\.]+)\\.compressed(\\.[0-9]+)?$" "\\1" REFEREN
string(REGEX REPLACE "\\.compressed" "" OUTPUT_FILE "${INPUT}")
get_filename_component(OUTPUT_NAME "${OUTPUT_FILE}" NAME)
+set(ENV{QEMU_LD_PREFIX} "${BROTLI_WRAPPER_LD_PREFIX}")
+
execute_process(
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --decompress ${INPUT} --output=${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}.unbr
diff --git a/tests/run-roundtrip-test.cmake b/tests/run-roundtrip-test.cmake
index 08d4e01..39303d3 100644
--- a/tests/run-roundtrip-test.cmake
+++ b/tests/run-roundtrip-test.cmake
@@ -1,3 +1,5 @@
+set(ENV{QEMU_LD_PREFIX} "${BROTLI_WRAPPER_LD_PREFIX}")
+
execute_process(
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
COMMAND ${BROTLI_WRAPPER} ${BROTLI_CLI} --force --quality=${QUALITY} ${INPUT} --output=${OUTPUT}.br