225 lines
10 KiB
Python
225 lines
10 KiB
Python
|
# -*- coding: utf-8 -*-
|
||
|
import sys
|
||
|
|
||
|
from cffi import FFI
|
||
|
ffi = FFI()
|
||
|
|
||
|
libraries = ['libbrotli']
|
||
|
if 'win32' not in str(sys.platform).lower():
|
||
|
libraries.append('stdc++')
|
||
|
|
||
|
|
||
|
ffi.set_source(
|
||
|
"_brotli",
|
||
|
"""#include <brotli/decode.h>
|
||
|
#include <brotli/encode.h>
|
||
|
""",
|
||
|
libraries=libraries,
|
||
|
include_dirs=["libbrotli", "libbrotli/include"]
|
||
|
)
|
||
|
|
||
|
ffi.cdef("""
|
||
|
/* common/types.h */
|
||
|
typedef bool BROTLI_BOOL;
|
||
|
#define BROTLI_TRUE ...
|
||
|
#define BROTLI_FALSE ...
|
||
|
|
||
|
/* dec/state.h */
|
||
|
/* Allocating function pointer. Function MUST return 0 in the case of
|
||
|
failure. Otherwise it MUST return a valid pointer to a memory region of
|
||
|
at least size length. Neither items nor size are allowed to be 0.
|
||
|
opaque argument is a pointer provided by client and could be used to
|
||
|
bind function to specific object (memory pool). */
|
||
|
typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
|
||
|
|
||
|
/* Deallocating function pointer. Function SHOULD be no-op in the case the
|
||
|
address is 0. */
|
||
|
typedef void (*brotli_free_func)(void* opaque, void* address);
|
||
|
|
||
|
/* dec/decode.h */
|
||
|
|
||
|
typedef enum {
|
||
|
/* Decoding error, e.g. corrupt input or memory allocation problem */
|
||
|
BROTLI_DECODER_RESULT_ERROR = 0,
|
||
|
/* Decoding successfully completed */
|
||
|
BROTLI_DECODER_RESULT_SUCCESS = 1,
|
||
|
/* Partially done; should be called again with more input */
|
||
|
BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2,
|
||
|
/* Partially done; should be called again with more output */
|
||
|
BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3
|
||
|
} BrotliDecoderResult;
|
||
|
|
||
|
typedef enum {...} BrotliDecoderErrorCode;
|
||
|
typedef ... BrotliDecoderState;
|
||
|
|
||
|
/* Creates the instance of BrotliDecoderState and initializes it.
|
||
|
|alloc_func| and |free_func| MUST be both zero or both non-zero. In the
|
||
|
case they are both zero, default memory allocators are used. |opaque| is
|
||
|
passed to |alloc_func| and |free_func| when they are called. */
|
||
|
BrotliDecoderState* BrotliDecoderCreateInstance(brotli_alloc_func,
|
||
|
brotli_free_func,
|
||
|
void *);
|
||
|
|
||
|
/* Deinitializes and frees BrotliDecoderState instance. */
|
||
|
void BrotliDecoderDestroyInstance(BrotliDecoderState* state);
|
||
|
|
||
|
/* Decompresses the data. Supports partial input and output.
|
||
|
|
||
|
Must be called with an allocated input buffer in |*next_in| and an
|
||
|
allocated output buffer in |*next_out|. The values |*available_in| and
|
||
|
|*available_out| must specify the allocated size in |*next_in| and
|
||
|
|*next_out| respectively.
|
||
|
|
||
|
After each call, |*available_in| will be decremented by the amount of
|
||
|
input bytes consumed, and the |*next_in| pointer will be incremented by
|
||
|
that amount. Similarly, |*available_out| will be decremented by the
|
||
|
amount of output bytes written, and the |*next_out| pointer will be
|
||
|
incremented by that amount. |total_out|, if it is not a null-pointer,
|
||
|
will be set to the number of bytes decompressed since the last state
|
||
|
initialization.
|
||
|
|
||
|
Input is never overconsumed, so |next_in| and |available_in| could be
|
||
|
passed to the next consumer after decoding is complete. */
|
||
|
BrotliDecoderResult BrotliDecoderDecompressStream(BrotliDecoderState* s,
|
||
|
size_t* available_in,
|
||
|
const uint8_t** next_in,
|
||
|
size_t* available_out,
|
||
|
uint8_t** next_out,
|
||
|
size_t* total_out);
|
||
|
|
||
|
/* Fills the new state with a dictionary for LZ77, warming up the
|
||
|
ringbuffer, e.g. for custom static dictionaries for data formats.
|
||
|
Not to be confused with the built-in transformable dictionary of Brotli.
|
||
|
|size| should be less or equal to 2^24 (16MiB), otherwise the dictionary
|
||
|
will be ignored. The dictionary must exist in memory until decoding is
|
||
|
done and is owned by the caller. To use:
|
||
|
1) Allocate and initialize state with BrotliCreateInstance
|
||
|
2) Use BrotliSetCustomDictionary
|
||
|
3) Use BrotliDecompressStream
|
||
|
4) Clean up and free state with BrotliDestroyState
|
||
|
*/
|
||
|
void BrotliDecoderSetCustomDictionary(
|
||
|
BrotliDecoderState* s, size_t size, const uint8_t* dict);
|
||
|
|
||
|
/* Returns true, if decoder has some unconsumed output.
|
||
|
Otherwise returns false. */
|
||
|
BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s);
|
||
|
|
||
|
/* Returns true, if decoder has already received some input bytes.
|
||
|
Otherwise returns false. */
|
||
|
BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* s);
|
||
|
|
||
|
/* Returns true, if decoder is in a state where we reached the end of the
|
||
|
input and produced all of the output; returns false otherwise. */
|
||
|
BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s);
|
||
|
|
||
|
/* Returns detailed error code after BrotliDecompressStream returns
|
||
|
BROTLI_DECODER_RESULT_ERROR. */
|
||
|
BrotliDecoderErrorCode BrotliDecoderGetErrorCode(
|
||
|
const BrotliDecoderState* s);
|
||
|
|
||
|
const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
|
||
|
|
||
|
/* enc/encode.h */
|
||
|
typedef ... BrotliEncoderState;
|
||
|
|
||
|
typedef enum BrotliEncoderParameter {
|
||
|
BROTLI_PARAM_MODE = 0,
|
||
|
/* Controls the compression-speed vs compression-density tradeoffs. The
|
||
|
higher the quality, the slower the compression. Range is 0 to 11. */
|
||
|
BROTLI_PARAM_QUALITY = 1,
|
||
|
/* Base 2 logarithm of the sliding window size. Range is 10 to 24. */
|
||
|
BROTLI_PARAM_LGWIN = 2,
|
||
|
/* Base 2 logarithm of the maximum input block size. Range is 16 to 24.
|
||
|
If set to 0, the value will be set based on the quality. */
|
||
|
BROTLI_PARAM_LGBLOCK = 3
|
||
|
} BrotliEncoderParameter;
|
||
|
|
||
|
typedef enum BrotliEncoderMode {
|
||
|
/* Default compression mode. The compressor does not know anything in
|
||
|
advance about the properties of the input. */
|
||
|
BROTLI_MODE_GENERIC = 0,
|
||
|
/* Compression mode for UTF-8 format text input. */
|
||
|
BROTLI_MODE_TEXT = 1,
|
||
|
/* Compression mode used in WOFF 2.0. */
|
||
|
BROTLI_MODE_FONT = 2
|
||
|
} BrotliEncoderMode;
|
||
|
|
||
|
int BROTLI_DEFAULT_QUALITY = 11;
|
||
|
int BROTLI_DEFAULT_WINDOW = 22;
|
||
|
#define BROTLI_DEFAULT_MODE ...
|
||
|
|
||
|
typedef enum BrotliEncoderOperation {
|
||
|
BROTLI_OPERATION_PROCESS = 0,
|
||
|
/* Request output stream to flush. Performed when input stream is
|
||
|
depleted and there is enough space in output stream. */
|
||
|
BROTLI_OPERATION_FLUSH = 1,
|
||
|
/* Request output stream to finish. Performed when input stream is
|
||
|
depleted and there is enough space in output stream. */
|
||
|
BROTLI_OPERATION_FINISH = 2
|
||
|
} BrotliEncoderOperation;
|
||
|
|
||
|
/* Creates the instance of BrotliEncoderState and initializes it.
|
||
|
|alloc_func| and |free_func| MUST be both zero or both non-zero. In the
|
||
|
case they are both zero, default memory allocators are used. |opaque| is
|
||
|
passed to |alloc_func| and |free_func| when they are called. */
|
||
|
BrotliEncoderState* BrotliEncoderCreateInstance(brotli_alloc_func,
|
||
|
brotli_free_func,
|
||
|
void *);
|
||
|
|
||
|
/* Deinitializes and frees BrotliEncoderState instance. */
|
||
|
void BrotliEncoderDestroyInstance(BrotliEncoderState* state);
|
||
|
|
||
|
/* Compresses the data in |input_buffer| into |encoded_buffer|, and sets
|
||
|
|*encoded_size| to the compressed length.
|
||
|
BROTLI_DEFAULT_QUALITY, BROTLI_DEFAULT_WINDOW and BROTLI_DEFAULT_MODE
|
||
|
should be used as |quality|, |lgwin| and |mode| if there are no specific
|
||
|
requirements to encoder speed and compression ratio.
|
||
|
If compression fails, |*encoded_size| is set to 0.
|
||
|
If BrotliEncoderMaxCompressedSize(|input_size|) is not zero, then
|
||
|
|*encoded_size| is never set to the bigger value.
|
||
|
Returns false if there was an error and true otherwise. */
|
||
|
BROTLI_BOOL BrotliEncoderCompress(int quality,
|
||
|
int lgwin,
|
||
|
BrotliEncoderMode mode,
|
||
|
size_t input_size,
|
||
|
const uint8_t* input_buffer,
|
||
|
size_t* encoded_size,
|
||
|
uint8_t* encoded_buffer);
|
||
|
|
||
|
BROTLI_BOOL BrotliEncoderCompressStream(BrotliEncoderState* s,
|
||
|
BrotliEncoderOperation op,
|
||
|
size_t* available_in,
|
||
|
const uint8_t** next_in,
|
||
|
size_t* available_out,
|
||
|
uint8_t** next_out,
|
||
|
size_t* total_out);
|
||
|
|
||
|
BROTLI_BOOL BrotliEncoderSetParameter(BrotliEncoderState* state,
|
||
|
BrotliEncoderParameter p,
|
||
|
uint32_t value);
|
||
|
|
||
|
/* Fills the new state with a dictionary for LZ77, warming up the
|
||
|
ringbuffer, e.g. for custom static dictionaries for data formats.
|
||
|
Not to be confused with the built-in transformable dictionary of Brotli.
|
||
|
To decode, use BrotliSetCustomDictionary() of the decoder with the same
|
||
|
dictionary. */
|
||
|
void BrotliEncoderSetCustomDictionary(BrotliEncoderState* state,
|
||
|
size_t size,
|
||
|
const uint8_t* dict);
|
||
|
|
||
|
/* Check if encoder is in "finished" state, i.e. no more input is
|
||
|
acceptable and no more output will be produced.
|
||
|
Works only with BrotliEncoderCompressStream workflow.
|
||
|
Returns 1 if stream is finished and 0 otherwise. */
|
||
|
BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* s);
|
||
|
|
||
|
/* Check if encoder has more output bytes in internal buffer.
|
||
|
Works only with BrotliEncoderCompressStream workflow.
|
||
|
Returns 1 if has more output (in internal buffer) and 0 otherwise. */
|
||
|
BROTLI_BOOL BrotliEncoderHasMoreOutput(BrotliEncoderState* s);
|
||
|
""")
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
ffi.compile()
|