-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Recompression #824
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: recompression
Are you sure you want to change the base?
Recompression #824
Changes from 12 commits
1073576
2b23df6
78e60c6
3219988
e7f7a6c
2c1aaf9
3b7288f
c2369f7
bbbecc1
51ccb89
75b92f5
a0d3169
1f224d1
85da9f6
f1f207b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
# Copyright 2020 Google Inc. All Rights Reserved. | ||
# | ||
# Licensed under the Apache License, Version 2.0 (the "License"); | ||
# you may not use this file except in compliance with the License. | ||
# You may obtain a copy of the License at | ||
# | ||
# http://www.apache.org/licenses/LICENSE-2.0 | ||
# | ||
# Unless required by applicable law or agreed to in writing, software | ||
# distributed under the License is distributed on an "AS IS" BASIS, | ||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
# See the License for the specific language governing permissions and | ||
# limitations under the License. | ||
|
||
CXX=g++ | ||
CXXFLAGS=-g -Wall -MMD -std=c++11 | ||
LDLIBS=-lstdc++ -lbrotlienc -lbrotlidec -lz | ||
|
||
all: example | ||
|
||
#example.o: example.cc | ||
# g++ -std=c++11 -c example.cc | ||
|
||
example: example.o | ||
|
||
clean: | ||
rm example.o example |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,6 +8,7 @@ | |
|
||
#include <stdlib.h> /* free, malloc */ | ||
#include <string.h> /* memcpy, memset */ | ||
#include <stdio.h> /* fprintf */ ///!!!! | ||
|
||
#include "../common/constants.h" | ||
#include "../common/context.h" | ||
|
@@ -70,6 +71,10 @@ BROTLI_BOOL BrotliDecoderSetParameter( | |
state->large_window = TO_BROTLI_BOOL(!!value); | ||
return BROTLI_TRUE; | ||
|
||
case BROTLI_DECODER_PARAM_SAVE_INFO: | ||
state->save_info_for_recompression = TO_BROTLI_BOOL(!!value); | ||
return BROTLI_TRUE; | ||
|
||
default: return BROTLI_FALSE; | ||
} | ||
} | ||
|
@@ -125,6 +130,7 @@ static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( | |
return BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; | ||
|
||
default: | ||
|
||
return BROTLI_DECODER_RESULT_ERROR; | ||
} | ||
} | ||
|
@@ -1194,41 +1200,72 @@ static BROTLI_INLINE void PrepareLiteralDecoding(BrotliDecoderState* s) { | |
/* Decodes the block type and updates the state for literal context. | ||
Reads 3..54 bits. */ | ||
static BROTLI_INLINE BROTLI_BOOL DecodeLiteralBlockSwitchInternal( | ||
int safe, BrotliDecoderState* s) { | ||
int safe, BrotliDecoderState* s, int position) { | ||
if (!DecodeBlockTypeAndLength(safe, s, 0)) { | ||
return BROTLI_FALSE; | ||
} | ||
/* If needed save the end of a previous block and the start of a new block */ | ||
if (s->save_info_for_recompression) { | ||
/* Save the end only if previously saved a start */ | ||
if (s->saved_position_literals_begin) { | ||
s->literals_block_splits.positions_end[s->literals_block_splits.num_blocks] = position; | ||
s->literals_block_splits.num_blocks++; | ||
} | ||
s->literals_block_splits.positions_begin[s->literals_block_splits.num_blocks] = position; | ||
s->literals_block_splits.types[s->literals_block_splits.num_blocks] = | ||
s->block_type_rb[0 * 2 + 1] + | ||
riknel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
s->literals_block_splits.num_types_prev_metablocks; | ||
s->literals_block_splits.num_types = | ||
BROTLI_MAX(size_t, s->literals_block_splits.num_types, | ||
s->literals_block_splits.types[s->literals_block_splits.num_blocks] + 1); | ||
} | ||
PrepareLiteralDecoding(s); | ||
return BROTLI_TRUE; | ||
} | ||
|
||
static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) { | ||
DecodeLiteralBlockSwitchInternal(0, s); | ||
static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s, int position) { | ||
DecodeLiteralBlockSwitchInternal(0, s, position); | ||
} | ||
|
||
static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch( | ||
BrotliDecoderState* s) { | ||
return DecodeLiteralBlockSwitchInternal(1, s); | ||
BrotliDecoderState* s, int position) { | ||
return DecodeLiteralBlockSwitchInternal(1, s, position); | ||
} | ||
|
||
/* Block switch for insert/copy length. | ||
Reads 3..54 bits. */ | ||
static BROTLI_INLINE BROTLI_BOOL DecodeCommandBlockSwitchInternal( | ||
int safe, BrotliDecoderState* s) { | ||
int safe, BrotliDecoderState* s, int position) { | ||
if (!DecodeBlockTypeAndLength(safe, s, 1)) { | ||
return BROTLI_FALSE; | ||
} | ||
s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]]; | ||
/* If needed save the start of a previous block and the start of a new block */ | ||
if (s->save_info_for_recompression) { | ||
/* Save the end only if previously saved a start */ | ||
if (s->saved_position_lengths_begin) { | ||
s->insert_copy_length_block_splits.positions_end[s->insert_copy_length_block_splits.num_blocks] = position; | ||
riknel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
s->insert_copy_length_block_splits.num_blocks++; | ||
} | ||
s->insert_copy_length_block_splits.positions_begin[s->insert_copy_length_block_splits.num_blocks] = position; | ||
s->insert_copy_length_block_splits.types[s->insert_copy_length_block_splits.num_blocks] = | ||
s->block_type_rb[3] + | ||
riknel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
s->insert_copy_length_block_splits.num_types_prev_metablocks; | ||
s->insert_copy_length_block_splits.num_types = | ||
BROTLI_MAX(size_t, s->insert_copy_length_block_splits.num_types, | ||
s->insert_copy_length_block_splits.types[s->insert_copy_length_block_splits.num_blocks] + 1); | ||
} | ||
return BROTLI_TRUE; | ||
} | ||
|
||
static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s) { | ||
DecodeCommandBlockSwitchInternal(0, s); | ||
static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s, | ||
int position) { | ||
DecodeCommandBlockSwitchInternal(0, s, position); | ||
} | ||
|
||
static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeCommandBlockSwitch( | ||
BrotliDecoderState* s) { | ||
return DecodeCommandBlockSwitchInternal(1, s); | ||
BrotliDecoderState* s, int position) { | ||
return DecodeCommandBlockSwitchInternal(1, s, position); | ||
} | ||
|
||
/* Block switch for distance codes. | ||
|
@@ -1736,7 +1773,6 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( | |
int i = s->loop_counter; | ||
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; | ||
BrotliBitReader* br = &s->br; | ||
|
||
if (!CheckInputAmount(safe, br, 28)) { | ||
result = BROTLI_DECODER_NEEDS_MORE_INPUT; | ||
goto saveStateAndReturn; | ||
|
@@ -1768,7 +1804,7 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( | |
goto saveStateAndReturn; | ||
} | ||
if (BROTLI_PREDICT_FALSE(s->block_length[1] == 0)) { | ||
BROTLI_SAFE(DecodeCommandBlockSwitch(s)); | ||
BROTLI_SAFE(DecodeCommandBlockSwitch(s, pos + (s->rb_roundtrips << s->window_bits))); | ||
goto CommandBegin; | ||
} | ||
/* Read the insert/copy length in the command. */ | ||
|
@@ -1796,7 +1832,7 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( | |
goto saveStateAndReturn; | ||
} | ||
if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { | ||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); | ||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s, pos + (s->rb_roundtrips << s->window_bits))); | ||
PreloadSymbol(safe, s->literal_htree, br, &bits, &value); | ||
if (!s->trivial_literal_context) goto CommandInner; | ||
} | ||
|
@@ -1832,7 +1868,7 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( | |
goto saveStateAndReturn; | ||
} | ||
if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { | ||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); | ||
BROTLI_SAFE(DecodeLiteralBlockSwitch(s, pos + (s->rb_roundtrips << s->window_bits))); | ||
if (s->trivial_literal_context) goto CommandInner; | ||
} | ||
context = BROTLI_CONTEXT(p1, p2, s->context_lookup); | ||
|
@@ -1889,6 +1925,14 @@ static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( | |
s->max_distance = | ||
(pos < s->max_backward_distance) ? pos : s->max_backward_distance; | ||
} | ||
/* Save backward reference info if needed */ | ||
if (s->save_info_for_recompression) { | ||
s->commands[s->commands_size].copy_len = s->copy_length; | ||
s->commands[s->commands_size].distance = s->distance_code; | ||
s->commands[s->commands_size].position = pos + (s->rb_roundtrips << s->window_bits); | ||
s->commands[s->commands_size].max_distance = s->max_distance; | ||
++s->commands_size; | ||
riknel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
i = s->copy_length; | ||
/* Apply copy of LZ77 back-reference, or static dictionary reference if | ||
the distance is larger than the max LZ77 distance */ | ||
|
@@ -2033,14 +2077,20 @@ static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands( | |
|
||
BrotliDecoderResult BrotliDecoderDecompress( | ||
size_t encoded_size, const uint8_t* encoded_buffer, size_t* decoded_size, | ||
uint8_t* decoded_buffer) { | ||
uint8_t* decoded_buffer, BROTLI_BOOL save_info_for_recompression, | ||
BackwardReferenceFromDecoder** backward_references, | ||
size_t* backward_references_size, | ||
BlockSplitFromDecoder* literals_block_splits, | ||
BlockSplitFromDecoder* insert_copy_length_block_splits) { | ||
BrotliDecoderState s; | ||
BrotliDecoderResult result; | ||
size_t total_out = 0; | ||
size_t available_in = encoded_size; | ||
const uint8_t* next_in = encoded_buffer; | ||
size_t available_out = *decoded_size; | ||
uint8_t* next_out = decoded_buffer; | ||
s.save_info_for_recompression = save_info_for_recompression; | ||
|
||
if (!BrotliDecoderStateInit(&s, 0, 0, 0)) { | ||
return BROTLI_DECODER_RESULT_ERROR; | ||
} | ||
|
@@ -2051,6 +2101,14 @@ BrotliDecoderResult BrotliDecoderDecompress( | |
if (result != BROTLI_DECODER_RESULT_SUCCESS) { | ||
result = BROTLI_DECODER_RESULT_ERROR; | ||
} | ||
if (s.save_info_for_recompression) { | ||
*backward_references = s.commands; | ||
*backward_references_size = s.commands_size; | ||
*literals_block_splits = s.literals_block_splits; | ||
*insert_copy_length_block_splits = s.insert_copy_length_block_splits; | ||
} | ||
|
||
|
||
riknel marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
return result; | ||
} | ||
|
||
|
@@ -2070,6 +2128,12 @@ BrotliDecoderResult BrotliDecoderDecompressStream( | |
size_t* available_out, uint8_t** next_out, size_t* total_out) { | ||
BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; | ||
BrotliBitReader* br = &s->br; | ||
/* Will save a commands here to use for the recompression */ | ||
if (s->save_info_for_recompression && !s->commands) { | ||
s->commands = (BackwardReferenceFromDecoder*)BROTLI_DECODER_ALLOC( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we be using this ALLOC function instead of malloc elsewhere? If so, maybe add a TODO to make sure this happens as part of productization? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Everything inside decoder/encoder should allocate/free memory via macros to allow "custom memory manager" feature. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Inside Encoder/Decoder I'm using Brotli allocation, malloc is used only in testing and in compress_similar_files.h file as they are not a part of the library. However, when compress_similar_files.h will be a part of the library then Brotli macros should be used |
||
s, sizeof(BackwardReferenceFromDecoder) * (int)((float)*available_in)); | ||
s->commands_alloc_size = *available_in; | ||
} | ||
/* Ensure that |total_out| is set, even if no data will ever be pushed out. */ | ||
if (total_out) { | ||
*total_out = s->partial_pos_out; | ||
|
Uh oh!
There was an error while loading. Please reload this page.