aboutsummaryrefslogtreecommitdiff
path: root/c/enc
diff options
context:
space:
mode:
authorEvgenii Kliuchnikov <eustas.ru@gmail.com>2022-11-17 13:03:09 +0000
committerEvgenii Kliuchnikov <eustas.ru@gmail.com>2022-11-17 13:03:09 +0000
commita8f5813b843b7ec469dbd3d8a6a8743395359964 (patch)
treee349a984eac9404db22a662e579fe47953dc47fe /c/enc
parent388d0d53fb29271492537015beeed91b74076411 (diff)
downloadbrotli-a8f5813b843b7ec469dbd3d8a6a8743395359964.zip
brotli-a8f5813b843b7ec469dbd3d8a6a8743395359964.tar.gz
brotli-a8f5813b843b7ec469dbd3d8a6a8743395359964.tar.bz2
Update
Documentation: - add note that brotli is a "stream" format, not an archive-like - regenerate .1 with Pandoc Build: - drop legacy "BROTLI_BUILD_PORTABLE" option - drop "BROTLI_SANITIZED" definition Code: - c: comb includes - c/enc: extract encoder state into separate header - c/enc: drop designated q10 codepath - c/enc: dealing better with flushing of empty stream - fix MSVC compilation API: - py: use library version instead of one in version.h - c: add plugable API to report consumed input / produced output - c/java: support "lean" prepared dictionaries (without copy of source)
Diffstat (limited to 'c/enc')
-rw-r--r--c/enc/backward_references.c3
-rw-r--r--c/enc/backward_references.h3
-rw-r--r--c/enc/backward_references_hq.c3
-rw-r--r--c/enc/backward_references_hq.h3
-rw-r--r--c/enc/bit_cost.c3
-rw-r--r--c/enc/bit_cost.h3
-rw-r--r--c/enc/block_splitter.h3
-rw-r--r--c/enc/brotli_bit_stream.c3
-rw-r--r--c/enc/brotli_bit_stream.h3
-rw-r--r--c/enc/cluster.c3
-rw-r--r--c/enc/cluster.h3
-rw-r--r--c/enc/command.h3
-rw-r--r--c/enc/compound_dictionary.c25
-rw-r--r--c/enc/compound_dictionary.h22
-rw-r--r--c/enc/compress_fragment.c3
-rw-r--r--c/enc/compress_fragment.h3
-rw-r--r--c/enc/compress_fragment_two_pass.c3
-rw-r--r--c/enc/compress_fragment_two_pass.h3
-rw-r--r--c/enc/encode.c419
-rw-r--r--c/enc/encoder_dict.h8
-rw-r--r--c/enc/entropy_encode.c3
-rw-r--r--c/enc/entropy_encode.h3
-rw-r--r--c/enc/entropy_encode_static.h3
-rw-r--r--c/enc/fast_log.h3
-rw-r--r--c/enc/find_match_length.h3
-rw-r--r--c/enc/hash.h28
-rw-r--r--c/enc/histogram.h3
-rw-r--r--c/enc/literal_cost.c3
-rw-r--r--c/enc/literal_cost.h3
-rw-r--r--c/enc/memory.c3
-rw-r--r--c/enc/memory.h3
-rw-r--r--c/enc/metablock.c3
-rw-r--r--c/enc/metablock.h3
-rw-r--r--c/enc/params.h1
-rw-r--r--c/enc/prefix.h3
-rw-r--r--c/enc/quality.h3
-rw-r--r--c/enc/ringbuffer.h3
-rw-r--r--c/enc/state.h104
-rw-r--r--c/enc/static_dict.h3
-rw-r--r--c/enc/utf8_util.h3
-rw-r--r--c/enc/write_bits.h3
41 files changed, 312 insertions, 397 deletions
diff --git a/c/enc/backward_references.c b/c/enc/backward_references.c
index 2cf01d8..ff5b7be 100644
--- a/c/enc/backward_references.c
+++ b/c/enc/backward_references.c
@@ -8,10 +8,11 @@
#include "backward_references.h"
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "command.h"
#include "compound_dictionary.h"
#include "dictionary_hash.h"
diff --git a/c/enc/backward_references.h b/c/enc/backward_references.h
index b051e18..20fb98a 100644
--- a/c/enc/backward_references.h
+++ b/c/enc/backward_references.h
@@ -9,11 +9,12 @@
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
+#include <brotli/types.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"
diff --git a/c/enc/backward_references_hq.c b/c/enc/backward_references_hq.c
index c6a6c8c..6325032 100644
--- a/c/enc/backward_references_hq.c
+++ b/c/enc/backward_references_hq.c
@@ -10,9 +10,10 @@
#include <string.h> /* memcpy, memset */
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "command.h"
#include "compound_dictionary.h"
#include "encoder_dict.h"
diff --git a/c/enc/backward_references_hq.h b/c/enc/backward_references_hq.h
index c9dcc80..8acf975 100644
--- a/c/enc/backward_references_hq.h
+++ b/c/enc/backward_references_hq.h
@@ -9,11 +9,12 @@
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
+#include <brotli/types.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"
diff --git a/c/enc/bit_cost.c b/c/enc/bit_cost.c
index 8ca4ab1..6b7c904 100644
--- a/c/enc/bit_cost.c
+++ b/c/enc/bit_cost.c
@@ -8,9 +8,10 @@
#include "bit_cost.h"
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "fast_log.h"
#include "histogram.h"
diff --git a/c/enc/bit_cost.h b/c/enc/bit_cost.h
index 4cf3b18..f6f2773 100644
--- a/c/enc/bit_cost.h
+++ b/c/enc/bit_cost.h
@@ -9,8 +9,9 @@
#ifndef BROTLI_ENC_BIT_COST_H_
#define BROTLI_ENC_BIT_COST_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "fast_log.h"
#include "histogram.h"
diff --git a/c/enc/block_splitter.h b/c/enc/block_splitter.h
index 1de072f..6046b90 100644
--- a/c/enc/block_splitter.h
+++ b/c/enc/block_splitter.h
@@ -9,8 +9,9 @@
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
#define BROTLI_ENC_BLOCK_SPLITTER_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "command.h"
#include "memory.h"
#include "quality.h"
diff --git a/c/enc/brotli_bit_stream.c b/c/enc/brotli_bit_stream.c
index d105102..5fa0c69 100644
--- a/c/enc/brotli_bit_stream.c
+++ b/c/enc/brotli_bit_stream.c
@@ -12,10 +12,11 @@
#include <string.h> /* memcpy, memset */
+#include <brotli/types.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"
diff --git a/c/enc/brotli_bit_stream.h b/c/enc/brotli_bit_stream.h
index 4285b7f..a289509 100644
--- a/c/enc/brotli_bit_stream.h
+++ b/c/enc/brotli_bit_stream.h
@@ -16,9 +16,10 @@
#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
+#include <brotli/types.h>
+
#include "../common/context.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "command.h"
#include "entropy_encode.h"
#include "memory.h"
diff --git a/c/enc/cluster.c b/c/enc/cluster.c
index b86bbfb..b0faf81 100644
--- a/c/enc/cluster.c
+++ b/c/enc/cluster.c
@@ -8,8 +8,9 @@
#include "cluster.h"
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "bit_cost.h" /* BrotliPopulationCost */
#include "fast_log.h"
#include "histogram.h"
diff --git a/c/enc/cluster.h b/c/enc/cluster.h
index 107e8a3..013629c 100644
--- a/c/enc/cluster.h
+++ b/c/enc/cluster.h
@@ -9,8 +9,9 @@
#ifndef BROTLI_ENC_CLUSTER_H_
#define BROTLI_ENC_CLUSTER_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "histogram.h"
#include "memory.h"
diff --git a/c/enc/command.h b/c/enc/command.h
index 43e35d7..ba4de7e 100644
--- a/c/enc/command.h
+++ b/c/enc/command.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_COMMAND_H_
#define BROTLI_ENC_COMMAND_H_
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "fast_log.h"
#include "params.h"
#include "prefix.h"
diff --git a/c/enc/compound_dictionary.c b/c/enc/compound_dictionary.c
index d82772f..824e515 100644
--- a/c/enc/compound_dictionary.c
+++ b/c/enc/compound_dictionary.c
@@ -6,8 +6,9 @@
#include "compound_dictionary.h"
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "memory.h"
#include "quality.h"
@@ -33,7 +34,7 @@ static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
uint32_t* slot_offsets = NULL;
uint16_t* heads = NULL;
uint32_t* items = NULL;
- uint8_t* source_copy = NULL;
+ const uint8_t** source_ref = NULL;
uint32_t i;
uint32_t* slot_size = NULL;
uint32_t* slot_limit = NULL;
@@ -97,7 +98,7 @@ static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
/* 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) +
- source_size;
+ sizeof(uint8_t*);
result = (PreparedDictionary*)BROTLI_ALLOC(m, uint8_t, alloc_size);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(result)) {
@@ -107,14 +108,15 @@ static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
slot_offsets = (uint32_t*)(&result[1]);
heads = (uint16_t*)(&slot_offsets[num_slots]);
items = (uint32_t*)(&heads[num_buckets]);
- source_copy = (uint8_t*)(&items[total_items]);
+ source_ref = (const uint8_t**)(&items[total_items]);
- result->magic = kPreparedDictionaryMagic;
- result->source_offset = 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) {
@@ -145,7 +147,6 @@ static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m,
}
BROTLI_FREE(m, flat);
- memcpy(source_copy, source, source_size);
return result;
}
@@ -192,8 +193,14 @@ BROTLI_BOOL AttachPreparedDictionary(
uint32_t* slot_offsets = (uint32_t*)(&dictionary[1]);
uint16_t* heads = (uint16_t*)(&slot_offsets[1u << dictionary->slot_bits]);
uint32_t* items = (uint32_t*)(&heads[1u << dictionary->bucket_bits]);
- compound->chunk_source[index] =
- (const uint8_t*)(&items[dictionary->source_offset]);
+ 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;
diff --git a/c/enc/compound_dictionary.h b/c/enc/compound_dictionary.h
index 60b12d2..9c531d5 100644
--- a/c/enc/compound_dictionary.h
+++ b/c/enc/compound_dictionary.h
@@ -7,19 +7,32 @@
#ifndef BROTLI_ENC_PREPARED_DICTIONARY_H_
#define BROTLI_ENC_PREPARED_DICTIONARY_H_
-#include "../common/platform.h"
-#include "../common/constants.h"
#include <brotli/shared_dictionary.h>
#include <brotli/types.h>
+
+#include "../common/platform.h"
+#include "../common/constants.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 source_offset;
+ uint32_t num_items;
uint32_t source_size;
uint32_t hash_bits;
uint32_t bucket_bits;
@@ -31,7 +44,8 @@ typedef struct PreparedDictionary {
/* uint16_t heads[1 << bucket_bits]; */
/* uint32_t items[variable]; */
- /* uint8_t source[source_size] */
+ /* [maybe] uint8_t* source_ref, depending on magic. */
+ /* [maybe] uint8_t source[source_size], depending on magic. */
} PreparedDictionary;
BROTLI_INTERNAL PreparedDictionary* CreatePreparedDictionary(MemoryManager* m,
diff --git a/c/enc/compress_fragment.c b/c/enc/compress_fragment.c
index 1f478ca..13890ea 100644
--- a/c/enc/compress_fragment.c
+++ b/c/enc/compress_fragment.c
@@ -16,8 +16,9 @@
#include <string.h> /* memcmp, memcpy, memset */
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "brotli_bit_stream.h"
#include "entropy_encode.h"
#include "fast_log.h"
diff --git a/c/enc/compress_fragment.h b/c/enc/compress_fragment.h
index 099a979..9c0780f 100644
--- a/c/enc/compress_fragment.h
+++ b/c/enc/compress_fragment.h
@@ -12,9 +12,10 @@
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "entropy_encode.h"
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/enc/compress_fragment_two_pass.c b/c/enc/compress_fragment_two_pass.c
index 4cbb418..a762679 100644
--- a/c/enc/compress_fragment_two_pass.c
+++ b/c/enc/compress_fragment_two_pass.c
@@ -14,9 +14,10 @@
#include <string.h> /* memcmp, memcpy, memset */
+#include <brotli/types.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"
diff --git a/c/enc/compress_fragment_two_pass.h b/c/enc/compress_fragment_two_pass.h
index f5d0741..6d28d9b 100644
--- a/c/enc/compress_fragment_two_pass.h
+++ b/c/enc/compress_fragment_two_pass.h
@@ -13,9 +13,10 @@
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "entropy_encode.h"
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/enc/encode.c b/c/enc/encode.c
index afceba4..a8ac09a 100644
--- a/c/enc/encode.c
+++ b/c/enc/encode.c
@@ -30,6 +30,7 @@
#include "memory.h"
#include "metablock.h"
#include "prefix.h"
+#include "state.h"
#include "quality.h"
#include "ringbuffer.h"
#include "utf8_util.h"
@@ -41,84 +42,6 @@ extern "C" {
#define COPY_ARRAY(dst, src) memcpy(dst, src, sizeof(src));
-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_;
-
- uint8_t* next_out_;
- size_t available_out_;
- size_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;
-
static size_t InputBlockSize(BrotliEncoderState* s) {
return (size_t)1 << s->params.lgblock;
}
@@ -780,6 +703,7 @@ static void BrotliEncoderInitState(BrotliEncoderState* s) {
s->two_pass_arena_ = NULL;
s->command_buf_ = NULL;
s->literal_buf_ = NULL;
+ s->total_in_ = 0;
s->next_out_ = NULL;
s->available_out_ = 0;
s->total_out_ = 0;
@@ -816,12 +740,26 @@ BrotliEncoderState* BrotliEncoderCreateInstance(
return state;
}
+#ifdef BROTLI_REPORTING
+/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */
+void BrotliEncoderOnFinish(const BrotliEncoderState* s);
+#define BROTLI_ENCODER_ON_FINISH(s) BrotliEncoderOnFinish(s);
+#else
+#if !defined(BROTLI_ENCODER_ON_FINISH)
+#define BROTLI_ENCODER_ON_FINISH(s) (void)(s);
+#endif
+#endif
+
static void BrotliEncoderCleanupState(BrotliEncoderState* s) {
MemoryManager* m = &s->memory_manager_;
+
+ BROTLI_ENCODER_ON_FINISH(s);
+
if (BROTLI_IS_OOM(m)) {
BrotliWipeOutMemoryManager(m);
return;
}
+
BROTLI_FREE(m, s->storage_);
BROTLI_FREE(m, s->commands_);
RingBufferFree(m, &s->ringbuffer_);
@@ -1006,10 +944,38 @@ static BROTLI_BOOL EncodeData(
MemoryManager* m = &s->memory_manager_;
ContextType literal_context_mode;
ContextLut literal_context_lut;
+ BROTLI_BOOL fast_compress =
+ s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
+ s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY;
data = s->ringbuffer_.buffer_;
mask = s->ringbuffer_.mask_;
+ if (delta == 0) { /* No new input; still might want to flush or finish. */
+ if (!data) { /* No input has been processed so far. */
+ if (is_last) { /* Emit complete finalized stream. */
+ BROTLI_DCHECK(s->last_bytes_bits_ <= 14);
+ s->last_bytes_ |= (uint16_t)(3u << s->last_bytes_bits_);
+ s->last_bytes_bits_ = (uint8_t)(s->last_bytes_bits_ + 2u);
+ s->tiny_buf_.u8[0] = (uint8_t)s->last_bytes_;
+ s->tiny_buf_.u8[1] = (uint8_t)(s->last_bytes_ >> 8);
+ *output = s->tiny_buf_.u8;
+ *out_size = (s->last_bytes_bits_ + 7u) >> 3u;
+ return BROTLI_TRUE;
+ } else { /* No data, not last -> no-op. */
+ *out_size = 0;
+ return BROTLI_TRUE;
+ }
+ } else {
+ /* Fast compress performs flush every block -> flush is no-op. */
+ if (!is_last && (!force_flush || fast_compress)) { /* Another no-op. */
+ *out_size = 0;
+ return BROTLI_TRUE;
+ }
+ }
+ }
+ BROTLI_DCHECK(data);
+
if (s->params.quality > s->params.dictionary.max_quality) return BROTLI_FALSE;
/* Adding more blocks after "last" block is forbidden. */
if (s->is_last_block_emitted_) return BROTLI_FALSE;
@@ -1030,19 +996,12 @@ static BROTLI_BOOL EncodeData(
}
}
- if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
- s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
+ if (fast_compress) {
uint8_t* storage;
size_t storage_ix = s->last_bytes_bits_;
size_t table_size;
int* table;
- if (delta == 0 && !is_last) {
- /* We have no new input data and we don't have to finish the stream, so
- nothing to do. */
- *out_size = 0;
- return BROTLI_TRUE;
- }
storage = GetBrotliStorage(s, 2 * bytes + 503);
if (BROTLI_IS_OOM(m)) return BROTLI_FALSE;
storage[0] = (uint8_t)s->last_bytes_;
@@ -1238,242 +1197,6 @@ static size_t WriteMetadataHeader(
return (storage_ix + 7u) >> 3;
}
-static BROTLI_NOINLINE BROTLI_BOOL BrotliCompressBufferQuality10(
- int lgwin, size_t input_size, const uint8_t* input_buffer,
- size_t* encoded_size, uint8_t* encoded_buffer) {
- MemoryManager* m =
- (MemoryManager*)BrotliBootstrapAlloc(sizeof(MemoryManager), 0, 0, 0);
-
- const size_t mask = BROTLI_SIZE_MAX >> 1;
- int dist_cache[4] = { 4, 11, 15, 16 };
- int saved_dist_cache[4] = { 4, 11, 15, 16 };
- BROTLI_BOOL ok = BROTLI_TRUE;
- const size_t max_out_size = *encoded_size;
- size_t total_out_size = 0;
- uint16_t last_bytes;
- uint8_t last_bytes_bits;
-
- const size_t hasher_eff_size = BROTLI_MIN(size_t,
- input_size, BROTLI_MAX_BACKWARD_LIMIT(lgwin) + BROTLI_WINDOW_GAP);
-
- const int lgmetablock = BROTLI_MIN(int, 24, lgwin + 1);
- size_t max_block_size;
- const size_t max_metablock_size = (size_t)1 << lgmetablock;
- const size_t max_literals_per_metablock = max_metablock_size / 8;
- const size_t max_commands_per_metablock = max_metablock_size / 8;
- size_t metablock_start = 0;
- uint8_t prev_byte = 0;
- uint8_t prev_byte2 = 0;
-
- BrotliEncoderParams* params = NULL;
- Hasher* hasher = NULL;
-
- if (m == NULL) return BROTLI_FALSE;
- BrotliInitMemoryManager(m, 0, 0, 0);
- params = BROTLI_ALLOC(m, BrotliEncoderParams, 2);
- hasher = BROTLI_ALLOC(m, Hasher, 1);
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(params) || BROTLI_IS_NULL(hasher)) {
- goto oom;
- }
- BrotliEncoderInitParams(params);
- HasherInit(hasher);
-
- params->quality = 10;
- params->lgwin = lgwin;
- if (lgwin > BROTLI_MAX_WINDOW_BITS) {
- params->large_window = BROTLI_TRUE;
- }
- SanitizeParams(params);
- params->lgblock = ComputeLgBlock(params);
- ChooseDistanceParams(params);
- max_block_size = (size_t)1 << params->lgblock;
-
- /* Since default static dictionary is used we assume that
- * params->quality < params->dictionary.max_quality. */
-
- BROTLI_DCHECK(input_size <= mask + 1);
- EncodeWindowBits(lgwin, params->large_window, &last_bytes, &last_bytes_bits);
- InitOrStitchToPreviousBlock(m, hasher, input_buffer, mask, params,
- 0, hasher_eff_size, BROTLI_TRUE);
- if (BROTLI_IS_OOM(m)) goto oom;
-
- while (ok && metablock_start < input_size) {
- const size_t metablock_end =
- BROTLI_MIN(size_t, input_size, metablock_start + max_metablock_size);
- const size_t expected_num_commands =
- (metablock_end - metablock_start) / 12 + 16;
- Command* commands = 0;
- size_t num_commands = 0;
- size_t last_insert_len = 0;
- size_t num_literals = 0;
- size_t metablock_size = 0;
- size_t cmd_alloc_size = 0;
- BROTLI_BOOL is_last;
- uint8_t* storage;
- size_t storage_ix;
-
- ContextType literal_context_mode = ChooseContextMode(params,
- input_buffer, metablock_start, mask, metablock_end - metablock_start);
- ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode);
-
- size_t block_start;
- for (block_start = metablock_start; block_start < metablock_end; ) {
- size_t block_size =
- BROTLI_MIN(size_t, metablock_end - block_start, max_block_size);
- ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, block_size + 1);
- size_t path_size;
- size_t new_cmd_alloc_size;
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) goto oom;
- BrotliInitZopfliNodes(nodes, block_size + 1);
- StitchToPreviousBlockH10(&hasher->privat._H10, block_size, block_start,
- input_buffer, mask);
- path_size = BrotliZopfliComputeShortestPath(m, block_size, block_start,
- input_buffer, mask, literal_context_lut, 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
- inputs we will not have to reallocate in later iterations. We do the
- allocation here and not before the loop, because if the input is small,
- this will be allocated after the Zopfli cost model is freed, so this
- will not increase peak memory usage.
- TODO(eustas): If the first allocation is too small, increase command
- buffer size exponentially. */
- new_cmd_alloc_size = BROTLI_MAX(size_t, expected_num_commands,
- num_commands + path_size + 1);
- if (cmd_alloc_size != new_cmd_alloc_size) {
- Command* new_commands = BROTLI_ALLOC(m, Command, new_cmd_alloc_size);
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) goto oom;
- cmd_alloc_size = new_cmd_alloc_size;
- if (commands) {
- memcpy(new_commands, commands, sizeof(Command) * num_commands);
- BROTLI_FREE(m, commands);
- }
- commands = new_commands;
- }
- 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;
- BROTLI_FREE(m, nodes);
- if (num_literals > max_literals_per_metablock ||
- num_commands > max_commands_per_metablock) {
- break;
- }
- }
-
- if (last_insert_len > 0) {
- InitInsertCommand(&commands[num_commands++], last_insert_len);
- num_literals += last_insert_len;
- }
-
- is_last = TO_BROTLI_BOOL(metablock_start + metablock_size == input_size);
- storage = NULL;
- storage_ix = last_bytes_bits;
-
- if (metablock_size == 0) {
- /* Write the ISLAST and ISEMPTY bits. */
- storage = BROTLI_ALLOC(m, uint8_t, 16);
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
- storage[0] = (uint8_t)last_bytes;
- storage[1] = (uint8_t)(last_bytes >> 8);
- BrotliWriteBits(2, 3, &storage_ix, storage);
- storage_ix = (storage_ix + 7u) & ~7u;
- } else if (!ShouldCompress(input_buffer, mask, metablock_start,
- metablock_size, num_literals, num_commands)) {
- /* Restore the distance cache, as its last update by
- CreateBackwardReferences is now unused. */
- memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
- storage = BROTLI_ALLOC(m, uint8_t, metablock_size + 16);
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
- storage[0] = (uint8_t)last_bytes;
- storage[1] = (uint8_t)(last_bytes >> 8);
- BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
- metablock_start, mask, metablock_size,
- &storage_ix, storage);
- } else {
- MetaBlockSplit mb;
- BrotliEncoderParams* block_params = params + 1;
- *block_params = *params; /* shallow copy */
- InitMetaBlockSplit(&mb);
- BrotliBuildMetaBlock(m, input_buffer, metablock_start, mask,
- block_params,
- prev_byte, prev_byte2,
- commands, num_commands,
- literal_context_mode,
- &mb);
- if (BROTLI_IS_OOM(m)) goto oom;
- {
- /* The number of distance symbols effectively used for distance
- histograms. It might be less than distance alphabet size
- for "Large Window Brotli" (32-bit). */
- BrotliOptimizeHistograms(block_params->dist.alphabet_size_limit, &mb);
- }
- storage = BROTLI_ALLOC(m, uint8_t, 2 * metablock_size + 503);
- if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(storage)) goto oom;
- storage[0] = (uint8_t)last_bytes;
- storage[1] = (uint8_t)(last_bytes >> 8);
- BrotliStoreMetaBlock(m, input_buffer, metablock_start, metablock_size,
- mask, prev_byte, prev_byte2,
- is_last,
- block_params,
- literal_context_mode,
- commands, num_commands,
- &mb,
- &storage_ix, storage);
- if (BROTLI_IS_OOM(m)) goto oom;
- if (metablock_size + 4 < (storage_ix >> 3)) {
- /* Restore the distance cache and last byte. */
- memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0]));
- storage[0] = (uint8_t)last_bytes;
- storage[1] = (uint8_t)(last_bytes >> 8);
- storage_ix = last_bytes_bits;
- BrotliStoreUncompressedMetaBlock(is_last, input_buffer,
- metablock_start, mask,
- metablock_size, &storage_ix, storage);
- }
- DestroyMetaBlockSplit(m, &mb);
- }
- last_bytes = (uint16_t)(storage[storage_ix >> 3]);
- last_bytes_bits = storage_ix & 7u;
- metablock_start += metablock_size;
- if (metablock_start < input_size) {
- prev_byte = input_buffer[metablock_start - 1];
- prev_byte2 = input_buffer[metablock_start - 2];
- }
- /* Save the state of the distance cache in case we need to restore it for
- emitting an uncompressed block. */
- memcpy(saved_dist_cache, dist_cache, 4 * sizeof(dist_cache[0]));
-
- {
- const size_t out_size = storage_ix >> 3;
- total_out_size += out_size;
- if (total_out_size <= max_out_size) {
- memcpy(encoded_buffer, storage, out_size);
- encoded_buffer += out_size;
- } else {
- ok = BROTLI_FALSE;
- }
- }
- BROTLI_FREE(m, storage);
- BROTLI_FREE(m, commands);
- }
-
- *encoded_size = total_out_size;
- DestroyHasher(m, hasher);
- BROTLI_FREE(m, hasher);
- BrotliEncoderCleanupParams(m, params);
- BROTLI_FREE(m, params);
- BrotliBootstrapFree(m, m);
- return ok;
-
-oom:
- BrotliWipeOutMemoryManager(m);
- BrotliBootstrapFree(m, m);
- return BROTLI_FALSE;
-}
-
size_t BrotliEncoderMaxCompressedSize(size_t input_size) {
/* [window bits / empty metadata] + N * [uncompressed] + [last empty] */
size_t num_large_blocks = input_size >> 14;
@@ -1539,17 +1262,6 @@ BROTLI_BOOL BrotliEncoderCompress(
*encoded_buffer = 6;
return BROTLI_TRUE;
}
- if (quality == 10) {
- /* TODO(eustas): Implement this direct path for all quality levels. */
- const int lg_win = BROTLI_MIN(int, BROTLI_LARGE_MAX_WINDOW_BITS,
- BROTLI_MAX(int, 16, lgwin));
- int ok = BrotliCompressBufferQuality10(lg_win, input_size, input_buffer,
- encoded_size, encoded_buffer);
- if (!ok || (max_out_size && *encoded_size > max_out_size)) {
- goto fallback;
- }
- return BROTLI_TRUE;
- }
s = BrotliEncoderCreateInstance(0, 0, 0);
if (!s) {
@@ -1561,6 +1273,7 @@ BROTLI_BOOL BrotliEncoderCompress(
uint8_t* next_out = encoded_buffer;
size_t total_out = 0;
BROTLI_BOOL result = BROTLI_FALSE;
+ /* TODO(eustas): check that parameters are sane. */
BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)quality);
BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin);
BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, (uint32_t)mode);
@@ -1612,6 +1325,18 @@ static void InjectBytePaddingBlock(BrotliEncoderState* s) {
s->available_out_ += (seal_bits + 7) >> 3;
}
+/* Fills the |total_out|, if it is not NULL. */
+static void SetTotalOut(BrotliEncoderState* s, size_t* total_out) {
+ if (total_out) {
+ /* Saturating conversion uint64_t -> size_t */
+ size_t result = (size_t)-1;
+ if (s->total_out_ < result) {
+ result = (size_t)s->total_out_;
+ }
+ *total_out = result;
+ }
+}
+
/* Injects padding bits or pushes compressed data to output.
Returns false if nothing is done. */
static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s,
@@ -1631,7 +1356,7 @@ static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s,
s->next_out_ += copy_output_size;
s->available_out_ -= copy_output_size;
s->total_out_ += copy_output_size;
- if (total_out) *total_out = s->total_out_;
+ SetTotalOut(s, total_out);
return BROTLI_TRUE;
}
@@ -1740,6 +1465,7 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
if (block_size != 0) {
*next_in += block_size;
*available_in -= block_size;
+ s->total_in_ += block_size;
}
if (inplace) {
size_t out_bytes = storage_ix >> 3;
@@ -1748,7 +1474,7 @@ static BROTLI_BOOL BrotliEncoderCompressStreamFast(
*next_out += out_bytes;
*available_out -= out_bytes;
s->total_out_ += out_bytes;
- if (total_out) *total_out = s->total_out_;
+ SetTotalOut(s, total_out);
} else {
size_t out_bytes = storage_ix >> 3;
s->next_out_ = storage;
@@ -1817,6 +1543,7 @@ static BROTLI_BOOL ProcessMetadata(
memcpy(*next_out, *next_in, copy);
*next_in += copy;
*available_in -= copy;
+ s->total_in_ += copy; /* not actually data input, though */
s->remaining_metadata_bytes_ -= copy;
*next_out += copy;
*available_out -= copy;
@@ -1827,6 +1554,7 @@ static BROTLI_BOOL ProcessMetadata(
memcpy(s->next_out_, *next_in, copy);
*next_in += copy;
*available_in -= copy;
+ s->total_in_ += copy; /* not actually data input, though */
s->remaining_metadata_bytes_ -= copy;
s->available_out_ = copy;
}
@@ -1854,7 +1582,7 @@ static void UpdateSizeHint(BrotliEncoderState* s, size_t available_in) {
BROTLI_BOOL BrotliEncoderCompressStream(
BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in,
- const uint8_t** next_in, size_t* available_out,uint8_t** next_out,
+ const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
size_t* total_out) {
if (!EnsureInitialized(s)) return BROTLI_FALSE;
@@ -1896,6 +1624,7 @@ BROTLI_BOOL BrotliEncoderCompressStream(
CopyInputToRingBuffer(s, copy_input_size, *next_in);
*next_in += copy_input_size;
*available_in -= copy_input_size;
+ s->total_in_ += copy_input_size;
if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size);
continue;
}
@@ -2021,7 +1750,7 @@ void BrotliEncoderDestroyPreparedDictionary(
}
if (dict->dictionary == NULL) {
/* This should never ever happen. */
- } else if (*dict->dictionary == kPreparedDictionaryMagic) {
+ } else if (*dict->dictionary == kLeanPreparedDictionaryMagic) {
DestroyPreparedDictionary(
&dict->memory_manager_, (PreparedDictionary*)dict->dictionary);
} else if (*dict->dictionary == kSharedDictionaryMagic) {
@@ -2029,7 +1758,8 @@ void BrotliEncoderDestroyPreparedDictionary(
(SharedEncoderDictionary*)dict->dictionary);
BrotliFree(&dict->memory_manager_, dict->dictionary);
} else {
- /* This should never ever happen. */
+ /* There is also kPreparedDictionaryMagic, but such instances should be
+ * constructed and destroyed by different means. */
}
dict->dictionary = NULL;
BrotliDestroyManagedDictionary(dict);
@@ -2048,7 +1778,8 @@ BROTLI_BOOL BrotliEncoderAttachPreparedDictionary(BrotliEncoderState* state,
dict = (BrotliEncoderPreparedDictionary*)managed_dictionary->dictionary;
}
current = &state->params.dictionary;
- if (magic == kPreparedDictionaryMagic) {
+ if (magic == kPreparedDictionaryMagic ||
+ magic == kLeanPreparedDictionaryMagic) {
const PreparedDictionary* prepared = (const PreparedDictionary*)dict;
if (!AttachPreparedDictionary(&current->compound, prepared)) {
return BROTLI_FALSE;
@@ -2176,7 +1907,15 @@ size_t BrotliEncoderGetPreparedDictionarySize(
return sizeof(PreparedDictionary) + dictionary->source_size +
(sizeof(uint32_t) << dictionary->slot_bits) +
(sizeof(uint16_t) << dictionary->bucket_bits) +
- (sizeof(uint32_t) * dictionary->source_offset) + overhead;
+ (sizeof(uint32_t) * dictionary->num_items) + overhead;
+ } else if (magic == kLeanPreparedDictionaryMagic) {
+ const PreparedDictionary* dictionary =
+ (const PreparedDictionary*)prepared;
+ /* Keep in sync with step 3 of CreatePreparedDictionary */
+ return sizeof(PreparedDictionary) + sizeof(uint8_t*) +
+ (sizeof(uint32_t) << dictionary->slot_bits) +
+ (sizeof(uint16_t) << dictionary->bucket_bits) +
+ (sizeof(uint32_t) * dictionary->num_items) + overhead;
} else if (magic == kSharedDictionaryMagic) {
const SharedEncoderDictionary* dictionary =
(const SharedEncoderDictionary*)prepared;
diff --git a/c/enc/encoder_dict.h b/c/enc/encoder_dict.h
index b5b591d..b291f98 100644
--- a/c/enc/encoder_dict.h
+++ b/c/enc/encoder_dict.h
@@ -7,10 +7,11 @@
#ifndef BROTLI_ENC_ENCODER_DICT_H_
#define BROTLI_ENC_ENCODER_DICT_H_
-#include "../common/dictionary.h"
-#include "../common/platform.h"
#include <brotli/shared_dictionary.h>
#include <brotli/types.h>
+
+#include "../common/dictionary.h"
+#include "../common/platform.h"
#include "compound_dictionary.h"
#include "memory.h"
#include "static_dict_lut.h"
@@ -103,9 +104,6 @@ typedef struct ContextualEncoderDictionary {
BrotliEncoderDictionary* instances_;
} ContextualEncoderDictionary;
-static const uint32_t kSharedDictionaryMagic = 0xDEBCEDE1;
-static const uint32_t kManagedDictionaryMagic = 0xDEBCEDE2;
-
typedef struct SharedEncoderDictionary {
/* Magic value to distinguish this struct from PreparedDictionary for
certain external usages. */
diff --git a/c/enc/entropy_encode.c b/c/enc/entropy_encode.c
index b2dcbbd..9aed43b 100644
--- a/c/enc/entropy_encode.c
+++ b/c/enc/entropy_encode.c
@@ -10,9 +10,10 @@
#include <string.h> /* memset */
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
diff --git a/c/enc/entropy_encode.h b/c/enc/entropy_encode.h
index 9618e1d..e1c779c 100644
--- a/c/enc/entropy_encode.h
+++ b/c/enc/entropy_encode.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
#define BROTLI_ENC_ENTROPY_ENCODE_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/entropy_encode_static.h b/c/enc/entropy_encode_static.h
index 2be1c6d..ecff1fe 100644
--- a/c/enc/entropy_encode_static.h
+++ b/c/enc/entropy_encode_static.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "write_bits.h"
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/enc/fast_log.h b/c/enc/fast_log.h
index 2094f13..f82f4cf 100644
--- a/c/enc/fast_log.h
+++ b/c/enc/fast_log.h
@@ -11,9 +11,10 @@
#include <math.h>
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/find_match_length.h b/c/enc/find_match_length.h
index f8853a7..dee0414 100644
--- a/c/enc/find_match_length.h
+++ b/c/enc/find_match_length.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/hash.h b/c/enc/hash.h
index 9ead9e6..fc6e334 100644
--- a/c/enc/hash.h
+++ b/c/enc/hash.h
@@ -13,10 +13,12 @@
#include <stdlib.h> /* exit */
#include <string.h> /* memcmp, memset */
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
-#include <brotli/types.h>
+#include "compound_dictionary.h"
#include "encoder_dict.h"
#include "fast_log.h"
#include "find_match_length.h"
@@ -511,7 +513,6 @@ static BROTLI_INLINE void FindCompoundDictionaryMatch(
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_offset = self->source_offset;
const uint32_t source_size = self->source_size;
const size_t boundary = distance_offset - source_size;
const uint32_t hash_bits = self->hash_bits;
@@ -525,7 +526,7 @@ static BROTLI_INLINE void FindCompoundDictionaryMatch(
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
const uint16_t* heads = (uint16_t*)(&slot_offsets[1u << slot_bits]);
const uint32_t* items = (uint32_t*)(&heads[1u << bucket_bits]);
- const uint8_t* source = (uint8_t*)(&items[source_offset]);
+ const uint8_t* source = NULL;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
score_t best_score = out->score;
@@ -539,6 +540,15 @@ static BROTLI_INLINE void FindCompoundDictionaryMatch(
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);
+ }
+
for (i = 0; i < 4; ++i) {
const size_t distance = (size_t)distance_cache[i];
size_t offset;
@@ -608,7 +618,6 @@ static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
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_offset = self->source_offset;
const uint32_t source_size = self->source_size;
const uint32_t hash_bits = self->hash_bits;
const uint32_t bucket_bits = self->bucket_bits;
@@ -621,7 +630,7 @@ static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
const uint32_t* slot_offsets = (uint32_t*)(&self[1]);
const uint16_t* heads = (uint16_t*)(&slot_offsets[1u << slot_bits]);
const uint32_t* items = (uint32_t*)(&heads[1u << bucket_bits]);
- const uint8_t* source = (uint8_t*)(&items[source_offset]);
+ const uint8_t* source = NULL;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
size_t best_len = min_length;
@@ -634,6 +643,15 @@ static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches(
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);
+ }
+
while (item == 0) {
size_t offset;
size_t distance;
diff --git a/c/enc/histogram.h b/c/enc/histogram.h
index b213a8b..d1abd97 100644
--- a/c/enc/histogram.h
+++ b/c/enc/histogram.h
@@ -11,10 +11,11 @@
#include <string.h> /* memset */
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "block_splitter.h"
#include "command.h"
diff --git a/c/enc/literal_cost.c b/c/enc/literal_cost.c
index 4e5068e..2ac847f 100644
--- a/c/enc/literal_cost.c
+++ b/c/enc/literal_cost.c
@@ -11,8 +11,9 @@
#include <string.h> /* memset */
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "fast_log.h"
#include "utf8_util.h"
diff --git a/c/enc/literal_cost.h b/c/enc/literal_cost.h
index efc8e17..284a8e5 100644
--- a/c/enc/literal_cost.h
+++ b/c/enc/literal_cost.h
@@ -10,9 +10,10 @@
#ifndef BROTLI_ENC_LITERAL_COST_H_
#define BROTLI_ENC_LITERAL_COST_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/memory.c b/c/enc/memory.c
index f3afebc..51e1b7f 100644
--- a/c/enc/memory.c
+++ b/c/enc/memory.c
@@ -12,9 +12,10 @@
#include <stdlib.h> /* exit, free, malloc */
#include <string.h> /* memcpy */
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/memory.h b/c/enc/memory.h
index 13b23d4..cbe4e30 100644
--- a/c/enc/memory.h
+++ b/c/enc/memory.h
@@ -11,9 +11,10 @@
#include <string.h> /* memcpy */
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/metablock.c b/c/enc/metablock.c
index 47b577b..0c5c078 100644
--- a/c/enc/metablock.c
+++ b/c/enc/metablock.c
@@ -9,10 +9,11 @@
#include "metablock.h"
+#include <brotli/types.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"
diff --git a/c/enc/metablock.h b/c/enc/metablock.h
index 50bd294..db38f8f 100644
--- a/c/enc/metablock.h
+++ b/c/enc/metablock.h
@@ -10,9 +10,10 @@
#ifndef BROTLI_ENC_METABLOCK_H_
#define BROTLI_ENC_METABLOCK_H_
+#include <brotli/types.h>
+
#include "../common/context.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "block_splitter.h"
#include "command.h"
#include "histogram.h"
diff --git a/c/enc/params.h b/c/enc/params.h
index cc74279..baeb319 100644
--- a/c/enc/params.h
+++ b/c/enc/params.h
@@ -10,6 +10,7 @@
#define BROTLI_ENC_PARAMS_H_
#include <brotli/encode.h>
+
#include "encoder_dict.h"
typedef struct BrotliHasherParams {
diff --git a/c/enc/prefix.h b/c/enc/prefix.h
index b58d50b..0f006f1 100644
--- a/c/enc/prefix.h
+++ b/c/enc/prefix.h
@@ -10,9 +10,10 @@
#ifndef BROTLI_ENC_PREFIX_H_
#define BROTLI_ENC_PREFIX_H_
+#include <brotli/types.h>
+
#include "../common/constants.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "fast_log.h"
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/enc/quality.h b/c/enc/quality.h
index 392ab00..99891b4 100644
--- a/c/enc/quality.h
+++ b/c/enc/quality.h
@@ -10,8 +10,9 @@
#ifndef BROTLI_ENC_QUALITY_H_
#define BROTLI_ENC_QUALITY_H_
-#include "../common/platform.h"
#include <brotli/encode.h>
+
+#include "../common/platform.h"
#include "params.h"
#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
diff --git a/c/enc/ringbuffer.h b/c/enc/ringbuffer.h
index 0db88cf..27245b7 100644
--- a/c/enc/ringbuffer.h
+++ b/c/enc/ringbuffer.h
@@ -11,8 +11,9 @@
#include <string.h> /* memcpy */
-#include "../common/platform.h"
#include <brotli/types.h>
+
+#include "../common/platform.h"
#include "memory.h"
#include "quality.h"
diff --git a/c/enc/state.h b/c/enc/state.h
new file mode 100644
index 0000000..cb82987
--- /dev/null
+++ b/c/enc/state.h
@@ -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 <brotli/types.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_
diff --git a/c/enc/static_dict.h b/c/enc/static_dict.h
index f572bc6..ab83220 100644
--- a/c/enc/static_dict.h
+++ b/c/enc/static_dict.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_STATIC_DICT_H_
#define BROTLI_ENC_STATIC_DICT_H_
+#include <brotli/types.h>
+
#include "../common/dictionary.h"
#include "../common/platform.h"
-#include <brotli/types.h>
#include "encoder_dict.h"
#if defined(__cplusplus) || defined(c_plusplus)
diff --git a/c/enc/utf8_util.h b/c/enc/utf8_util.h
index 8fda80c..a38a953 100644
--- a/c/enc/utf8_util.h
+++ b/c/enc/utf8_util.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_UTF8_UTIL_H_
#define BROTLI_ENC_UTF8_UTIL_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
diff --git a/c/enc/write_bits.h b/c/enc/write_bits.h
index f6f88b4..242754b 100644
--- a/c/enc/write_bits.h
+++ b/c/enc/write_bits.h
@@ -9,9 +9,10 @@
#ifndef BROTLI_ENC_WRITE_BITS_H_
#define BROTLI_ENC_WRITE_BITS_H_
-#include "../common/platform.h"
#include <brotli/types.h>
+#include "../common/platform.h"
+
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif