[add] first

This commit is contained in:
2023-10-08 10:24:48 +08:00
commit b1ae0510a9
1048 changed files with 3254361 additions and 0 deletions
@@ -0,0 +1,29 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_TARGET_ANDROID
#define IL2CPP_USES_POSIX_CLASS_LIBRARY_PAL 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_LCHFLAGS 1
#define IL2CPP_HAVE_FUTIMENS 1
#define IL2CPP_HAVE_STAT_TIM 1
#include <sys/sendfile.h>
#define IL2CPP_HAVE_SENDFILE_4 1
#define IL2CPP_HAVE_SYS_UN 1
// On Android, we are not allowed to modify permissions, but the copy should still succeed;
// see https://github.com/mono/mono/issues/17133 for details.
#define IL2CPP_CANNOT_MODIFY_FILE_PERMISSIONS 1
#define stat_ stat
#define fstat_ fstat
#define lstat_ lstat
#include <dirent.h>
#endif // IL2CPP_TARGET_ANDROID
+5
View File
@@ -0,0 +1,5 @@
#include "il2cpp-config.h"
#if IL2CPP_DEBUG
void il2cpp_assert(const char* assertion, const char* file, unsigned int line);
#endif
+176
View File
@@ -0,0 +1,176 @@
#pragma once
#include <stdint.h>
#include "utils/NonCopyable.h"
#include "c-api/Atomic-c-api.h"
namespace il2cpp
{
namespace os
{
class Atomic : public il2cpp::utils::NonCopyable
{
public:
// All 32bit atomics must be performed on 4-byte aligned addresses. All 64bit atomics must be
// performed on 8-byte aligned addresses.
// Add and Add64 return the *result* of the addition, not the old value! (i.e. they work like
// InterlockedAdd and __sync_add_and_fetch).
static inline void FullMemoryBarrier()
{
UnityPalFullMemoryBarrier();
}
static inline int32_t Add(int32_t* location1, int32_t value)
{
return UnityPalAdd(location1, value);
}
static inline uint32_t Add(uint32_t* location1, uint32_t value)
{
return (uint32_t)Add((int32_t*)location1, (int32_t)value);
}
#if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
static inline int64_t Add64(int64_t* location1, int64_t value)
{
return UnityPalAdd64(location1, value);
}
#endif
template<typename T>
static inline T* CompareExchangePointer(T** dest, T* newValue, T* oldValue)
{
return static_cast<T*>(UnityPalCompareExchangePointer((void**)dest, newValue, oldValue));
}
template<typename T>
static inline T* ExchangePointer(T** dest, T* newValue)
{
return static_cast<T*>(UnityPalExchangePointer((void**)dest, newValue));
}
static inline int64_t Read64(int64_t* addr)
{
return UnityPalRead64(addr);
}
static inline uint64_t Read64(uint64_t* addr)
{
return (uint64_t)Read64((int64_t*)addr);
}
static inline int32_t LoadRelaxed(const int32_t* addr)
{
return UnityPalLoadRelaxed(addr);
}
template<typename T>
static inline T* LoadPointerRelaxed(const T* const * addr)
{
return (T*)Baselib_atomic_load_ptr_relaxed((const intptr_t*)addr);
}
template<typename T>
static inline T* ReadPointer(T** pointer)
{
#if IL2CPP_SIZEOF_VOID_P == 4
return reinterpret_cast<T*>(Add(reinterpret_cast<int32_t*>(pointer), 0));
#else
return reinterpret_cast<T*>(Read64(reinterpret_cast<int64_t*>(pointer)));
#endif
}
static inline int32_t Increment(int32_t* value)
{
return UnityPalIncrement(value);
}
static inline uint32_t Increment(uint32_t* value)
{
return (uint32_t)Increment((int32_t*)value);
}
#if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
static inline int64_t Increment64(int64_t* value)
{
return UnityPalIncrement64(value);
}
static inline uint64_t Increment64(uint64_t* value)
{
return (uint64_t)Increment64((int64_t*)value);
}
#endif
static inline int32_t Decrement(int32_t* value)
{
return UnityPalDecrement(value);
}
static inline uint32_t Decrement(uint32_t* value)
{
return (uint32_t)Decrement((int32_t*)value);
}
#if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
static inline int64_t Decrement64(int64_t* value)
{
return UnityPalDecrement64(value);
}
static inline uint64_t Decrement64(uint64_t* value)
{
return (uint64_t)Decrement64((int64_t*)value);
}
#endif
static inline int32_t CompareExchange(int32_t* dest, int32_t exchange, int32_t comparand)
{
return UnityPalCompareExchange(dest, exchange, comparand);
}
static inline uint32_t CompareExchange(uint32_t* value, uint32_t newValue, uint32_t oldValue)
{
return (uint32_t)CompareExchange((int32_t*)value, newValue, oldValue);
}
static inline int64_t CompareExchange64(int64_t* dest, int64_t exchange, int64_t comparand)
{
return UnityPalCompareExchange64(dest, exchange, comparand);
}
static inline uint64_t CompareExchange64(uint64_t* value, uint64_t newValue, uint64_t oldValue)
{
return (uint64_t)CompareExchange64((int64_t*)value, newValue, oldValue);
}
static inline int32_t Exchange(int32_t* dest, int32_t exchange)
{
return UnityPalExchange(dest, exchange);
}
static inline uint32_t Exchange(uint32_t* value, uint32_t newValue)
{
return (uint32_t)Exchange((int32_t*)value, newValue);
}
#if IL2CPP_ENABLE_INTERLOCKED_64_REQUIRED_ALIGNMENT
static inline int64_t Exchange64(int64_t* dest, int64_t exchange)
{
return UnityPalExchange64(dest, exchange);
}
static inline uint64_t Exchange64(uint64_t* value, uint64_t newValue)
{
return (uint64_t)Exchange64((int64_t*)value, newValue);
}
#endif
};
}
}
@@ -0,0 +1,42 @@
#pragma once
#include "il2cpp-config.h"
#include "il2cpp-string-types.h"
#include "os/c-api/OSGlobalEnums.h"
#include "os/Directory.h"
#include "os/ErrorCodes.h"
#include "os/File.h"
#include <cstdint>
#include <set>
namespace il2cpp
{
namespace os
{
class BrokeredFileSystem
{
public:
// Folders
static int CreateDirectoryW(const UTF16String& path);
static int RemoveDirectoryW(const UTF16String& path);
static std::set<std::string> GetFileSystemEntries(const UTF16String& path, const UTF16String& pathWithPattern, int32_t attributes, int32_t attributeMask, int* error);
static os::ErrorCode FindFirstFileW(Directory::FindHandle* findHandle, const utils::StringView<Il2CppNativeChar>& searchPathWithPattern, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
static os::ErrorCode FindNextFileW(Directory::FindHandle* findHandle, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
static os::ErrorCode FindClose(void* osHandle);
// Files
static bool CopyFileW(const UTF16String& source, const UTF16String& destination, bool overwrite, int* error);
static bool MoveFileW(const UTF16String& source, const UTF16String& destination, int* error);
static int DeleteFileW(const UTF16String& path);
static UnityPalFileAttributes GetFileAttributesW(const UTF16String& path, int* error);
static bool SetFileAttributesW(const UTF16String& path, UnityPalFileAttributes attributes, int* error);
static bool GetFileStat(const std::string& utf8Path, const UTF16String& path, FileStat* stat, int* error);
static FileHandle* Open(const UTF16String& path, uint32_t desiredAccess, uint32_t shareMode, uint32_t creationDisposition, uint32_t flagsAndAttributes, int* error);
// Cleanup
static void CleanupStatics();
};
}
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "il2cpp-config.h"
#include "il2cpp-windowsruntime-types.h"
namespace il2cpp
{
namespace os
{
class COM
{
public:
static il2cpp_hresult_t CreateInstance(const Il2CppGuid& clsid, Il2CppIUnknown** object);
static il2cpp_hresult_t CreateFreeThreadedMarshaler(Il2CppIUnknown* outer, Il2CppIUnknown** marshal);
// variant
static void VariantInit(Il2CppVariant* variant);
static il2cpp_hresult_t VariantClear(Il2CppVariant* variant);
// safe array
static Il2CppSafeArray* SafeArrayCreate(uint16_t type, uint32_t dimension_count, Il2CppSafeArrayBound* bounds);
static il2cpp_hresult_t SafeArrayDestroy(Il2CppSafeArray* safeArray);
static il2cpp_hresult_t SafeArrayAccessData(Il2CppSafeArray* safeArray, void** data);
static il2cpp_hresult_t SafeArrayUnaccessData(Il2CppSafeArray* safeArray);
static il2cpp_hresult_t SafeArrayGetVartype(Il2CppSafeArray* safeArray, uint16_t* type);
static uint32_t SafeArrayGetDim(Il2CppSafeArray* safeArray);
static il2cpp_hresult_t SafeArrayGetLBound(Il2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
static il2cpp_hresult_t SafeArrayGetUBound(Il2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
};
} /* namespace os */
} /* namespace il2cpp*/
#pragma once
@@ -0,0 +1,206 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @file
* Common constants used in decoder and encoder API.
*/
#include "il2cpp-config.h"
#ifndef BROTLI_COMMON_CONSTANTS_H_
#define BROTLI_COMMON_CONSTANTS_H_
#include "./platform.h"
#include <brotli/port.h>
#include <brotli/types.h>
/* Specification: 7.3. Encoding of the context map */
#define BROTLI_CONTEXT_MAP_MAX_RLE 16
/* Specification: 2. Compressed representation overview */
#define BROTLI_MAX_NUMBER_OF_BLOCK_TYPES 256
/* Specification: 3.3. Alphabet sizes: insert-and-copy length */
#define BROTLI_NUM_LITERAL_SYMBOLS 256
#define BROTLI_NUM_COMMAND_SYMBOLS 704
#define BROTLI_NUM_BLOCK_LEN_SYMBOLS 26
#define BROTLI_MAX_CONTEXT_MAP_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + \
BROTLI_CONTEXT_MAP_MAX_RLE)
#define BROTLI_MAX_BLOCK_TYPE_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 2)
/* Specification: 3.5. Complex prefix codes */
#define BROTLI_REPEAT_PREVIOUS_CODE_LENGTH 16
#define BROTLI_REPEAT_ZERO_CODE_LENGTH 17
#define BROTLI_CODE_LENGTH_CODES (BROTLI_REPEAT_ZERO_CODE_LENGTH + 1)
/* "code length of 8 is repeated" */
#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8
/* "Large Window Brotli" */
/**
* The theoretical maximum number of distance bits specified for large window
* brotli, for 64-bit encoders and decoders. Even when in practice 32-bit
* encoders and decoders only support up to 30 max distance bits, the value is
* set to 62 because it affects the large window brotli file format.
* Specifically, it affects the encoding of simple huffman tree for distances,
* see Specification RFC 7932 chapter 3.4.
*/
#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U
#define BROTLI_LARGE_MIN_WBITS 10
/**
* The maximum supported large brotli window bits by the encoder and decoder.
* Large window brotli allows up to 62 bits, however the current encoder and
* decoder, designed for 32-bit integers, only support up to 30 bits maximum.
*/
#define BROTLI_LARGE_MAX_WBITS 30
/* Specification: 4. Encoding of distances */
#define BROTLI_NUM_DISTANCE_SHORT_CODES 16
/**
* Maximal number of "postfix" bits.
*
* Number of "postfix" bits is stored as 2 bits in meta-block header.
*/
#define BROTLI_MAX_NPOSTFIX 3
#define BROTLI_MAX_NDIRECT 120
#define BROTLI_MAX_DISTANCE_BITS 24U
#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \
BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \
((MAXNBITS) << ((NPOSTFIX) + 1)))
/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */
#define BROTLI_NUM_DISTANCE_SYMBOLS \
BROTLI_DISTANCE_ALPHABET_SIZE( \
BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS)
/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932
brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and
NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */
#define BROTLI_MAX_DISTANCE 0x3FFFFFC
/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit
allows safe distance calculation without overflows, given the distance
alphabet size is limited to corresponding size
(see kLargeWindowDistanceCodeLimits). */
#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC
/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */
#define BROTLI_NUM_INS_COPY_CODES 24
/* 7.1. Context modes and context ID lookup for literals */
/* "context IDs for literals are in the range of 0..63" */
#define BROTLI_LITERAL_CONTEXT_BITS 6
/* 7.2. Context ID for distances */
#define BROTLI_DISTANCE_CONTEXT_BITS 2
/* 9.1. Format of the Stream Header */
/* Number of slack bytes for window size. Don't confuse
with BROTLI_NUM_DISTANCE_SHORT_CODES. */
#define BROTLI_WINDOW_GAP 16
#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP)
#ifndef DLLEXPORT
#define DLLEXPORT __attribute__ ((__visibility__ ("default")))
#endif
typedef struct BrotliDistanceCodeLimit {
uint32_t max_alphabet_size;
uint32_t max_distance;
} BrotliDistanceCodeLimit;
/* This function calculates maximal size of distance alphabet, such that the
distances greater than the given values can not be represented.
This limits are designed to support fast and safe 32-bit decoders.
"32-bit" means that signed integer values up to ((1 << 31) - 1) could be
safely expressed.
Brotli distance alphabet symbols do not represent consecutive distance
ranges. Each distance alphabet symbol (excluding direct distances and short
codes), represent interleaved (for NPOSTFIX > 0) range of distances.
A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved
range. Two consecutive groups require the same amount of "extra bits".
It is important that distance alphabet represents complete "groups".
To avoid complex logic on encoder side about interleaved ranges
it was decided to restrict both sides to complete distance code "groups".
*/
BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit(
uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) {
BrotliDistanceCodeLimit result;
/* Marking this function as unused, because not all files
including "constants.h" use it -> compiler warns about that. */
BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit);
if (max_distance <= ndirect) {
/* This case never happens / exists only for the sake of completeness. */
result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES;
result.max_distance = max_distance;
return result;
} else {
/* The first prohibited value. */
uint32_t forbidden_distance = max_distance + 1;
/* Subtract "directly" encoded region. */
uint32_t offset = forbidden_distance - ndirect - 1;
uint32_t ndistbits = 0;
uint32_t tmp;
uint32_t half;
uint32_t group;
/* Postfix for the last dcode in the group. */
uint32_t postfix = (1u << npostfix) - 1;
uint32_t extra;
uint32_t start;
/* Remove postfix and "head-start". */
offset = (offset >> npostfix) + 4;
/* Calculate the number of distance bits. */
tmp = offset / 2;
/* Poor-man's log2floor, to avoid extra dependencies. */
while (tmp != 0) {ndistbits++; tmp = tmp >> 1;}
/* One bit is covered with subrange addressing ("half"). */
ndistbits--;
/* Find subrange. */
half = (offset >> ndistbits) & 1;
/* Calculate the "group" part of dcode. */
group = ((ndistbits - 1) << 1) | half;
/* Calculated "group" covers the prohibited distance value. */
if (group == 0) {
/* This case is added for correctness; does not occur for limit > 128. */
result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES;
result.max_distance = ndirect;
return result;
}
/* Decrement "group", so it is the last permitted "group". */
group--;
/* After group was decremented, ndistbits and half must be recalculated. */
ndistbits = (group >> 1) + 1;
/* The last available distance in the subrange has all extra bits set. */
extra = (1u << ndistbits) - 1;
/* Calculate region start. NB: ndistbits >= 1. */
start = (1u << (ndistbits + 1)) - 4;
/* Move to subregion. */
start += (group & 1) << ndistbits;
/* Calculate the alphabet size. */
result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect +
BROTLI_NUM_DISTANCE_SHORT_CODES + 1;
/* Calculate the maximal distance representable by alphabet. */
result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1;
return result;
}
}
/* Represents the range of values belonging to a prefix code:
[offset, offset + 2^nbits) */
typedef struct {
uint16_t offset;
uint8_t nbits;
} BrotliPrefixCodeRange;
/* "Soft-private", it is exported, but not "advertised" as API. */
BROTLI_COMMON_API extern const BrotliPrefixCodeRange
_kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS];
#endif /* BROTLI_COMMON_CONSTANTS_H_ */
@@ -0,0 +1,113 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Lookup table to map the previous two bytes to a context id.
There are four different context modeling modes defined here:
CONTEXT_LSB6: context id is the least significant 6 bits of the last byte,
CONTEXT_MSB6: context id is the most significant 6 bits of the last byte,
CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text,
CONTEXT_SIGNED: second-order context model tuned for signed integers.
If |p1| and |p2| are the previous two bytes, and |mode| is current context
mode, we calculate the context as:
context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256].
For CONTEXT_UTF8 mode, if the previous two bytes are ASCII characters
(i.e. < 128), this will be equivalent to
context = 4 * context1(p1) + context2(p2),
where context1 is based on the previous byte in the following way:
0 : non-ASCII control
1 : \t, \n, \r
2 : space
3 : other punctuation
4 : " '
5 : %
6 : ( < [ {
7 : ) > ] }
8 : , ; :
9 : .
10 : =
11 : number
12 : upper-case vowel
13 : upper-case consonant
14 : lower-case vowel
15 : lower-case consonant
and context2 is based on the second last byte:
0 : control, space
1 : punctuation
2 : upper-case letter, number
3 : lower-case letter
If the last byte is ASCII, and the second last byte is not (in a valid UTF8
stream it will be a continuation byte, value between 128 and 191), the
context is the same as if the second last byte was an ASCII control or space.
If the last byte is a UTF8 lead byte (value >= 192), then the next byte will
be a continuation byte and the context id is 2 or 3 depending on the LSB of
the last byte and to a lesser extent on the second last byte if it is ASCII.
If the last byte is a UTF8 continuation byte, the second last byte can be:
- continuation byte: the next byte is probably ASCII or lead byte (assuming
4-byte UTF8 characters are rare) and the context id is 0 or 1.
- lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1
- lead byte (208 - 255): next byte is continuation byte, context is 2 or 3
The possible value combinations of the previous two bytes, the range of
context ids and the type of the next byte is summarized in the table below:
|--------\-----------------------------------------------------------------|
| \ Last byte |
| Second \---------------------------------------------------------------|
| last byte \ ASCII | cont. byte | lead byte |
| \ (0-127) | (128-191) | (192-) |
|=============|===================|=====================|==================|
| ASCII | next: ASCII/lead | not valid | next: cont. |
| (0-127) | context: 4 - 63 | | context: 2 - 3 |
|-------------|-------------------|---------------------|------------------|
| cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. |
| (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 |
|-------------|-------------------|---------------------|------------------|
| lead byte | not valid | next: ASCII/lead | not valid |
| (192-207) | | context: 0 - 1 | |
|-------------|-------------------|---------------------|------------------|
| lead byte | not valid | next: cont. | not valid |
| (208-) | | context: 2 - 3 | |
|-------------|-------------------|---------------------|------------------|
*/
#ifndef BROTLI_COMMON_CONTEXT_H_
#define BROTLI_COMMON_CONTEXT_H_
#include <brotli/port.h>
#include <brotli/types.h>
typedef enum ContextType {
CONTEXT_LSB6 = 0,
CONTEXT_MSB6 = 1,
CONTEXT_UTF8 = 2,
CONTEXT_SIGNED = 3
} ContextType;
/* "Soft-private", it is exported, but not "advertised" as API. */
/* Common context lookup table for all context modes. */
BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048];
typedef const uint8_t* ContextLut;
/* typeof(MODE) == ContextType; returns ContextLut */
#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9])
/* typeof(LUT) == ContextLut */
#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2])
#endif /* BROTLI_COMMON_CONTEXT_H_ */
@@ -0,0 +1,64 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Collection of static dictionary words. */
#ifndef BROTLI_COMMON_DICTIONARY_H_
#define BROTLI_COMMON_DICTIONARY_H_
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct BrotliDictionary {
/**
* Number of bits to encode index of dictionary word in a bucket.
*
* Specification: Appendix A. Static Dictionary Data
*
* Words in a dictionary are bucketed by length.
* @c 0 means that there are no words of a given length.
* Dictionary consists of words with length of [4..24] bytes.
* Values at [0..3] and [25..31] indices should not be addressed.
*/
uint8_t size_bits_by_length[32];
/* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */
uint32_t offsets_by_length[32];
/* assert(data_size == offsets_by_length[31]) */
size_t data_size;
/* Data array is not bound, and should obey to size_bits_by_length values.
Specified size matches default (RFC 7932) dictionary. Its size is
defined by data_size */
const uint8_t* data;
} BrotliDictionary;
BROTLI_COMMON_API const BrotliDictionary* BrotliGetDictionary(void);
/**
* Sets dictionary data.
*
* When dictionary data is already set / present, this method is no-op.
*
* Dictionary data MUST be provided before BrotliGetDictionary is invoked.
* This method is used ONLY in multi-client environment (e.g. C + Java),
* to reduce storage by sharing single dictionary between implementations.
*/
BROTLI_COMMON_API void BrotliSetDictionaryData(const uint8_t* data);
#define BROTLI_MIN_DICTIONARY_WORD_LENGTH 4
#define BROTLI_MAX_DICTIONARY_WORD_LENGTH 24
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_COMMON_DICTIONARY_H_ */
@@ -0,0 +1,594 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Macros for compiler / platform specific features and build options.
Build options are:
* BROTLI_BUILD_32_BIT disables 64-bit optimizations
* BROTLI_BUILD_64_BIT forces to use 64-bit optimizations
* BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations
* BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations
* BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations
* BROTLI_BUILD_PORTABLE disables dangerous optimizations, like unaligned
read and overlapping memcpy; this reduces decompression speed by 5%
* BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs
* BROTLI_DEBUG dumps file name and line number when decoder detects stream
or memory error
* BROTLI_ENABLE_LOG enables asserts and dumps various state information
*/
#ifndef BROTLI_COMMON_PLATFORM_H_
#define BROTLI_COMMON_PLATFORM_H_
#include <string.h> /* memcpy */
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(OS_LINUX) || defined(OS_CYGWIN) || defined(__EMSCRIPTEN__)
#include <endian.h>
#elif defined(OS_FREEBSD)
#include <machine/endian.h>
#elif defined(OS_MACOSX)
#include <machine/endian.h>
/* Let's try and follow the Linux convention */
#define BROTLI_X_BYTE_ORDER BYTE_ORDER
#define BROTLI_X_LITTLE_ENDIAN LITTLE_ENDIAN
#define BROTLI_X_BIG_ENDIAN BIG_ENDIAN
#endif
#if BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
#include <intrin.h>
#endif
#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG)
#include <assert.h>
#include <stdio.h>
#endif
/* The following macros were borrowed from https://github.com/nemequ/hedley
* with permission of original author - Evan Nemerson <evan@nemerson.com> */
/* >>> >>> >>> hedley macros */
/* Define "BROTLI_PREDICT_TRUE" and "BROTLI_PREDICT_FALSE" macros for capable
compilers.
To apply compiler hint, enclose the branching condition into macros, like this:
if (BROTLI_PREDICT_TRUE(zero == 0)) {
// main execution path
} else {
// compiler should place this code outside of main execution path
}
OR:
if (BROTLI_PREDICT_FALSE(something_rare_or_unexpected_happens)) {
// compiler should place this code outside of main execution path
}
*/
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 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) || \
BROTLI_TINYC_VERSION_CHECK(0, 9, 27)
#define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#else
#define BROTLI_PREDICT_FALSE(x) (x)
#define BROTLI_PREDICT_TRUE(x) (x)
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(__cplusplus)
#define BROTLI_RESTRICT restrict
#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) || \
BROTLI_MSVC_VERSION_CHECK(14, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
BROTLI_PGI_VERSION_CHECK(17, 10, 0) || \
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
BROTLI_IAR_VERSION_CHECK(8, 0, 0) || \
(BROTLI_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus))
#define BROTLI_RESTRICT __restrict
#elif BROTLI_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus)
#define BROTLI_RESTRICT _Restrict
#else
#define BROTLI_RESTRICT
#endif
#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \
(defined(__cplusplus) && (__cplusplus >= 199711L))
#define BROTLI_MAYBE_INLINE inline
#elif defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__) || \
BROTLI_ARM_VERSION_CHECK(6, 2, 0)
#define BROTLI_MAYBE_INLINE __inline__
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_TI_VERSION_CHECK(8, 0, 0)
#define BROTLI_MAYBE_INLINE __inline
#else
#define BROTLI_MAYBE_INLINE
#endif
#if BROTLI_GNUC_HAS_ATTRIBUTE(always_inline, 4, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#define BROTLI_INLINE BROTLI_MAYBE_INLINE __attribute__((__always_inline__))
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
#define BROTLI_INLINE BROTLI_MAYBE_INLINE __forceinline
#elif BROTLI_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus)
#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("FUNC_ALWAYS_INLINE;")
#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("inline=forced")
#else
#define BROTLI_INLINE BROTLI_MAYBE_INLINE
#endif
#if BROTLI_GNUC_HAS_ATTRIBUTE(noinline, 4, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__))
#define BROTLI_NOINLINE __attribute__((__noinline__))
#elif BROTLI_MSVC_VERSION_CHECK(13, 10, 0)
#define BROTLI_NOINLINE __declspec(noinline)
#elif BROTLI_PGI_VERSION_CHECK(10, 2, 0)
#define BROTLI_NOINLINE _Pragma("noinline")
#elif BROTLI_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus)
#define BROTLI_NOINLINE _Pragma("FUNC_CANNOT_INLINE;")
#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0)
#define BROTLI_NOINLINE _Pragma("inline=never")
#else
#define BROTLI_NOINLINE
#endif
/* BROTLI_INTERNAL could be defined to override visibility, e.g. for tests. */
#if !defined(BROTLI_INTERNAL)
#if defined(_WIN32) || defined(__CYGWIN__)
#define BROTLI_INTERNAL
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
#define BROTLI_INTERNAL __attribute__ ((visibility ("hidden")))
#else
#define BROTLI_INTERNAL
#endif
#endif
/* <<< <<< <<< end of hedley macros. */
#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE __attribute__ ((unused))
#else
#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
#endif /* ARMv7 */
#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \
defined(__aarch64__) || defined(__ARM64_ARCH_8__)
#define BROTLI_TARGET_ARMV8_ANY
#if defined(__ARM_32BIT_STATE)
#define BROTLI_TARGET_ARMV8_32
#elif defined(__ARM_64BIT_STATE)
#define BROTLI_TARGET_ARMV8_64
#endif
#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
#if defined(__x86_64__) || defined(_M_X64)
#define BROTLI_TARGET_X64
#endif
#if defined(__PPC64__)
#define BROTLI_TARGET_POWERPC64
#endif
#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64
#define BROTLI_TARGET_RISCV64
#endif
#if defined(BROTLI_BUILD_64_BIT)
#define BROTLI_64_BITS 1
#elif defined(BROTLI_BUILD_32_BIT)
#define BROTLI_64_BITS 0
#elif defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \
defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64)
#define BROTLI_64_BITS 1
#else
#define BROTLI_64_BITS 0
#endif
#if (BROTLI_64_BITS)
#define brotli_reg_t uint64_t
#else
#define brotli_reg_t uint32_t
#endif
#if defined(BROTLI_BUILD_BIG_ENDIAN)
#define BROTLI_BIG_ENDIAN 1
#elif defined(BROTLI_BUILD_LITTLE_ENDIAN)
#define BROTLI_LITTLE_ENDIAN 1
#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL)
/* Just break elif chain. */
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define BROTLI_LITTLE_ENDIAN 1
#elif defined(_WIN32) || defined(BROTLI_TARGET_X64)
/* Win32 & x64 can currently always be assumed to be little endian */
#define BROTLI_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
#define BROTLI_BIG_ENDIAN 1
#elif defined(BROTLI_X_BYTE_ORDER)
#if BROTLI_X_BYTE_ORDER == BROTLI_X_LITTLE_ENDIAN
#define BROTLI_LITTLE_ENDIAN 1
#elif BROTLI_X_BYTE_ORDER == BROTLI_X_BIG_ENDIAN
#define BROTLI_BIG_ENDIAN 1
#endif
#endif /* BROTLI_X_BYTE_ORDER */
#if !defined(BROTLI_LITTLE_ENDIAN)
#define BROTLI_LITTLE_ENDIAN 0
#endif
#if !defined(BROTLI_BIG_ENDIAN)
#define BROTLI_BIG_ENDIAN 0
#endif
#if defined(BROTLI_X_BYTE_ORDER)
#undef BROTLI_X_BYTE_ORDER
#undef BROTLI_X_LITTLE_ENDIAN
#undef BROTLI_X_BIG_ENDIAN
#endif
#if defined(BROTLI_BUILD_PORTABLE)
#define BROTLI_ALIGNED_READ (!!1)
#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \
defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \
defined(BROTLI_TARGET_RISCV64)
/* Allow unaligned read only for white-listed CPUs. */
#define BROTLI_ALIGNED_READ (!!0)
#else
#define BROTLI_ALIGNED_READ (!!1)
#endif
#if BROTLI_ALIGNED_READ
/* Portable unaligned memory access: read / write values via memcpy. */
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
memcpy(p, &v, sizeof v);
}
#else /* BROTLI_ALIGNED_READ */
/* Unaligned memory access is allowed: just cast pointer to requested type. */
#if BROTLI_SANITIZED
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
will miss a bug if 08 is the first unaddressable byte.
ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
miss a race between this access and some other accesses to 08.
MemorySanitizer will correctly propagate the shadow on unaligned stores
and correctly report bugs on unaligned loads, but it may not properly
update and report the origin of the uninitialized memory.
For all three tools, replacing an unaligned access with a tool-specific
callback solves the problem. */
#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */
uint16_t __sanitizer_unaligned_load16(const void* p);
uint32_t __sanitizer_unaligned_load32(const void* p);
uint64_t __sanitizer_unaligned_load64(const void* p);
void __sanitizer_unaligned_store64(void* p, uint64_t v);
#if defined(__cplusplus)
} /* extern "C" */
#endif /* __cplusplus */
#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
#else /* BROTLI_SANITIZED */
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
return *(const uint16_t*)p;
}
static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) {
return *(const uint32_t*)p;
}
#if (BROTLI_64_BITS)
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return *(const uint64_t*)p;
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
*(uint64_t*)p = v;
}
#else /* BROTLI_64_BITS */
/* Avoid emitting LDRD / STRD, which require properly aligned address. */
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
typedef BROTLI_ALIGNED(1) uint64_t brotli_unaligned_uint64_t;
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
return (uint64_t) ((const brotli_unaligned_uint64_t*) p)[0];
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
dwords[0] = (brotli_unaligned_uint64_t) v;
}
#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
uint64_t v;
memcpy(&v, p, sizeof(uint64_t));
return v;
}
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
memcpy(p, &v, sizeof(uint64_t));
}
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
#endif /* BROTLI_64_BITS */
#endif /* BROTLI_SANITIZED */
#endif /* BROTLI_ALIGNED_READ */
#if BROTLI_LITTLE_ENDIAN
/* Straight endianness. Just read / write values. */
#define BROTLI_UNALIGNED_LOAD16LE BrotliUnalignedRead16
#define BROTLI_UNALIGNED_LOAD32LE BrotliUnalignedRead32
#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64
#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64
#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */
/* Explain compiler to byte-swap values. */
#define BROTLI_BSWAP16_(V) ((uint16_t)( \
(((V) & 0xFFU) << 8) | \
(((V) >> 8) & 0xFFU)))
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
uint16_t value = BrotliUnalignedRead16(p);
return BROTLI_BSWAP16_(value);
}
#define BROTLI_BSWAP32_(V) ( \
(((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \
(((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU))
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
uint32_t value = BrotliUnalignedRead32(p);
return BROTLI_BSWAP32_(value);
}
#define BROTLI_BSWAP64_(V) ( \
(((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \
(((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \
(((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \
(((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU))
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
uint64_t value = BrotliUnalignedRead64(p);
return BROTLI_BSWAP64_(value);
}
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
uint64_t value = BROTLI_BSWAP64_(v);
BrotliUnalignedWrite64(p, value);
}
#else /* BROTLI_LITTLE_ENDIAN */
/* Read / store values byte-wise; hopefully compiler will understand. */
static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) {
const uint8_t* in = (const uint8_t*)p;
return (uint16_t)(in[0] | (in[1] << 8));
}
static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) {
const uint8_t* in = (const uint8_t*)p;
uint32_t value = (uint32_t)(in[0]);
value |= (uint32_t)(in[1]) << 8;
value |= (uint32_t)(in[2]) << 16;
value |= (uint32_t)(in[3]) << 24;
return value;
}
static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) {
const uint8_t* in = (const uint8_t*)p;
uint64_t value = (uint64_t)(in[0]);
value |= (uint64_t)(in[1]) << 8;
value |= (uint64_t)(in[2]) << 16;
value |= (uint64_t)(in[3]) << 24;
value |= (uint64_t)(in[4]) << 32;
value |= (uint64_t)(in[5]) << 40;
value |= (uint64_t)(in[6]) << 48;
value |= (uint64_t)(in[7]) << 56;
return value;
}
static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) {
uint8_t* out = (uint8_t*)p;
out[0] = (uint8_t)v;
out[1] = (uint8_t)(v >> 8);
out[2] = (uint8_t)(v >> 16);
out[3] = (uint8_t)(v >> 24);
out[4] = (uint8_t)(v >> 32);
out[5] = (uint8_t)(v >> 40);
out[6] = (uint8_t)(v >> 48);
out[7] = (uint8_t)(v >> 56);
}
#endif /* BROTLI_LITTLE_ENDIAN */
/* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_IS_CONSTANT(x) (!!__builtin_constant_p(x))
#else
#define BROTLI_IS_CONSTANT(x) (!!0)
#endif
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
#define BROTLI_HAS_UBFX (!!1)
#else
#define BROTLI_HAS_UBFX (!!0)
#endif
#if defined(BROTLI_ENABLE_LOG)
#define BROTLI_LOG(x) printf x
#else
#define BROTLI_LOG(x)
#endif
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
#define BROTLI_DCHECK(x) assert(x)
static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) {
fprintf(stderr, "%s:%d (%s)\n", f, l, fn);
fflush(stderr);
}
#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__)
#else
#define BROTLI_DCHECK(x)
#define BROTLI_DUMP() (void)(0)
#endif
/* TODO: add appropriate icc/sunpro/arm/ibm/ti checks. */
#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \
!defined(BROTLI_BUILD_NO_RBIT)
#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY)
/* TODO: detect ARMv6T2 and enable this code for it. */
static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) {
brotli_reg_t output;
__asm__("rbit %0, %1\n" : "=r"(output) : "r"(input));
return output;
}
#define BROTLI_RBIT(x) BrotliRBit(x)
#endif /* armv7 / armv8 */
#endif /* gcc || clang */
#if !defined(BROTLI_RBIT)
static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ }
#endif /* BROTLI_RBIT */
#define BROTLI_REPEAT(N, X) { \
if ((N & 1) != 0) {X;} \
if ((N & 2) != 0) {X; X;} \
if ((N & 4) != 0) {X; X; X; X;} \
}
#define BROTLI_UNUSED(X) (void)(X)
#define BROTLI_MIN_MAX(T) \
static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \
static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; }
BROTLI_MIN_MAX(double) BROTLI_MIN_MAX(float) BROTLI_MIN_MAX(int)
BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t)
#undef BROTLI_MIN_MAX
#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B)))
#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B)))
#define BROTLI_SWAP(T, A, I, J) { \
T __brotli_swap_tmp = (A)[(I)]; \
(A)[(I)] = (A)[(J)]; \
(A)[(J)] = __brotli_swap_tmp; \
}
#if BROTLI_64_BITS
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_TZCNT64 __builtin_ctzll
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
#if defined(BROTLI_TARGET_X64)
#define BROTLI_TZCNT64 _tzcnt_u64
#else /* BROTLI_TARGET_X64 */
static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) {
uint32_t lsb;
_BitScanForward64(&lsb, x);
return lsb;
}
#define BROTLI_TZCNT64 BrotliBsf64Msvc
#endif /* BROTLI_TARGET_X64 */
#endif /* __builtin_ctzll */
#endif /* BROTLI_64_BITS */
#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0)
#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x))
#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0)
static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) {
unsigned long msb;
_BitScanReverse(&msb, x);
return (uint32_t)msb;
}
#define BROTLI_BSR32 BrotliBsr32Msvc
#endif /* __builtin_clz */
/* Default brotli_alloc_func */
BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size);
/* Default brotli_free_func */
BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address);
BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) {
BROTLI_UNUSED(&BrotliSuppressUnusedFunctions);
BROTLI_UNUSED(&BrotliUnalignedRead16);
BROTLI_UNUSED(&BrotliUnalignedRead32);
BROTLI_UNUSED(&BrotliUnalignedRead64);
BROTLI_UNUSED(&BrotliUnalignedWrite64);
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD16LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE);
BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE);
BROTLI_UNUSED(&BrotliRBit);
BROTLI_UNUSED(&brotli_min_double);
BROTLI_UNUSED(&brotli_max_double);
BROTLI_UNUSED(&brotli_min_float);
BROTLI_UNUSED(&brotli_max_float);
BROTLI_UNUSED(&brotli_min_int);
BROTLI_UNUSED(&brotli_max_int);
BROTLI_UNUSED(&brotli_min_size_t);
BROTLI_UNUSED(&brotli_max_size_t);
BROTLI_UNUSED(&brotli_min_uint32_t);
BROTLI_UNUSED(&brotli_max_uint32_t);
BROTLI_UNUSED(&brotli_min_uint8_t);
BROTLI_UNUSED(&brotli_max_uint8_t);
BROTLI_UNUSED(&BrotliDefaultAllocFunc);
BROTLI_UNUSED(&BrotliDefaultFreeFunc);
#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG)
BROTLI_UNUSED(&BrotliDump);
#endif
}
#endif /* BROTLI_COMMON_PLATFORM_H_ */
@@ -0,0 +1,85 @@
/* transforms is a part of ABI, but not API.
It means that there are some functions that are supposed to be in "common"
library, but header itself is not placed into include/brotli. This way,
aforementioned functions will be available only to brotli internals.
*/
#ifndef BROTLI_COMMON_TRANSFORM_H_
#define BROTLI_COMMON_TRANSFORM_H_
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
enum BrotliWordTransformType {
BROTLI_TRANSFORM_IDENTITY = 0,
BROTLI_TRANSFORM_OMIT_LAST_1 = 1,
BROTLI_TRANSFORM_OMIT_LAST_2 = 2,
BROTLI_TRANSFORM_OMIT_LAST_3 = 3,
BROTLI_TRANSFORM_OMIT_LAST_4 = 4,
BROTLI_TRANSFORM_OMIT_LAST_5 = 5,
BROTLI_TRANSFORM_OMIT_LAST_6 = 6,
BROTLI_TRANSFORM_OMIT_LAST_7 = 7,
BROTLI_TRANSFORM_OMIT_LAST_8 = 8,
BROTLI_TRANSFORM_OMIT_LAST_9 = 9,
BROTLI_TRANSFORM_UPPERCASE_FIRST = 10,
BROTLI_TRANSFORM_UPPERCASE_ALL = 11,
BROTLI_TRANSFORM_OMIT_FIRST_1 = 12,
BROTLI_TRANSFORM_OMIT_FIRST_2 = 13,
BROTLI_TRANSFORM_OMIT_FIRST_3 = 14,
BROTLI_TRANSFORM_OMIT_FIRST_4 = 15,
BROTLI_TRANSFORM_OMIT_FIRST_5 = 16,
BROTLI_TRANSFORM_OMIT_FIRST_6 = 17,
BROTLI_TRANSFORM_OMIT_FIRST_7 = 18,
BROTLI_TRANSFORM_OMIT_FIRST_8 = 19,
BROTLI_TRANSFORM_OMIT_FIRST_9 = 20,
BROTLI_TRANSFORM_SHIFT_FIRST = 21,
BROTLI_TRANSFORM_SHIFT_ALL = 22,
BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */
};
#define BROTLI_TRANSFORMS_MAX_CUT_OFF BROTLI_TRANSFORM_OMIT_LAST_9
typedef struct BrotliTransforms {
uint16_t prefix_suffix_size;
/* Last character must be null, so prefix_suffix_size must be at least 1. */
const uint8_t* prefix_suffix;
const uint16_t* prefix_suffix_map;
uint32_t num_transforms;
/* Each entry is a [prefix_id, transform, suffix_id] triplet. */
const uint8_t* transforms;
/* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL,
must be NULL if and only if no such transforms are present. */
const uint8_t* params;
/* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""].
0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""].
-1, if cut-off transform does not exist. */
int16_t cutOffTransforms[BROTLI_TRANSFORMS_MAX_CUT_OFF + 1];
} BrotliTransforms;
/* T is BrotliTransforms*; result is uint8_t. */
#define BROTLI_TRANSFORM_PREFIX_ID(T, I) ((T)->transforms[((I) * 3) + 0])
#define BROTLI_TRANSFORM_TYPE(T, I) ((T)->transforms[((I) * 3) + 1])
#define BROTLI_TRANSFORM_SUFFIX_ID(T, I) ((T)->transforms[((I) * 3) + 2])
/* T is BrotliTransforms*; result is const uint8_t*. */
#define BROTLI_TRANSFORM_PREFIX(T, I) (&(T)->prefix_suffix[ \
(T)->prefix_suffix_map[BROTLI_TRANSFORM_PREFIX_ID(T, I)]])
#define BROTLI_TRANSFORM_SUFFIX(T, I) (&(T)->prefix_suffix[ \
(T)->prefix_suffix_map[BROTLI_TRANSFORM_SUFFIX_ID(T, I)]])
BROTLI_COMMON_API const BrotliTransforms* BrotliGetTransforms(void);
BROTLI_COMMON_API int BrotliTransformDictionaryWord(
uint8_t* dst, const uint8_t* word, int len,
const BrotliTransforms* transforms, int transform_idx);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_COMMON_TRANSFORM_H_ */
@@ -0,0 +1,26 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Version definition. */
#ifndef BROTLI_COMMON_VERSION_H_
#define BROTLI_COMMON_VERSION_H_
/* This macro should only be used when library is compiled together with client.
If library is dynamically linked, use BrotliDecoderVersion and
BrotliEncoderVersion methods. */
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
#define BROTLI_VERSION 0x1000009
/* 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 0x1009000
#endif /* BROTLI_COMMON_VERSION_H_ */
@@ -0,0 +1,351 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Bit reading helpers */
#ifndef BROTLI_DEC_BIT_READER_H_
#define BROTLI_DEC_BIT_READER_H_
#include <string.h> /* memcpy */
#include "../common/constants.h"
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1)
BROTLI_INTERNAL extern const uint32_t kBrotliBitMask[33];
static BROTLI_INLINE uint32_t BitMask(uint32_t n) {
if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) {
/* Masking with this expression turns to a single
"Unsigned Bit Field Extract" UBFX instruction on ARM. */
return ~((0xFFFFFFFFu) << n);
} else {
return kBrotliBitMask[n];
}
}
typedef struct {
brotli_reg_t val_; /* pre-fetched bits */
uint32_t bit_pos_; /* current bit-reading position in val_ */
const uint8_t* next_in; /* the byte we're reading from */
size_t avail_in;
} BrotliBitReader;
typedef struct {
brotli_reg_t val_;
uint32_t bit_pos_;
const uint8_t* next_in;
size_t avail_in;
} BrotliBitReaderState;
/* Initializes the BrotliBitReader fields. */
BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* const br);
/* Ensures that accumulator is not empty.
May consume up to sizeof(brotli_reg_t) - 1 bytes of input.
Returns BROTLI_FALSE if data is required but there is no input available.
For BROTLI_ALIGNED_READ this function also prepares bit reader for aligned
reading. */
BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br);
/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden
the main code-path. Never called for RFC brotli streams, required only for
"large-window" mode and other extensions. */
BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val);
static BROTLI_INLINE void BrotliBitReaderSaveState(
BrotliBitReader* const from, BrotliBitReaderState* to) {
to->val_ = from->val_;
to->bit_pos_ = from->bit_pos_;
to->next_in = from->next_in;
to->avail_in = from->avail_in;
}
static BROTLI_INLINE void BrotliBitReaderRestoreState(
BrotliBitReader* const to, BrotliBitReaderState* from) {
to->val_ = from->val_;
to->bit_pos_ = from->bit_pos_;
to->next_in = from->next_in;
to->avail_in = from->avail_in;
}
static BROTLI_INLINE uint32_t BrotliGetAvailableBits(
const BrotliBitReader* br) {
return (BROTLI_64_BITS ? 64 : 32) - br->bit_pos_;
}
/* Returns amount of unread bytes the bit reader still has buffered from the
BrotliInput, including whole bytes in br->val_. Result is capped with
maximal ring-buffer size (larger number won't be utilized anyway). */
static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) {
static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS;
if (br->avail_in > kCap) return kCap;
return br->avail_in + (BrotliGetAvailableBits(br) >> 3);
}
/* Checks if there is at least |num| bytes left in the input ring-buffer
(excluding the bits remaining in br->val_). */
static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount(
BrotliBitReader* const br, size_t num) {
return TO_BROTLI_BOOL(br->avail_in >= num);
}
/* Guarantees that there are at least |n_bits| + 1 bits in accumulator.
Precondition: accumulator contains at least 1 bit.
|n_bits| should be in the range [1..24] for regular build. For portable
non-64-bit little-endian build only 16 bits are safe to request. */
static BROTLI_INLINE void BrotliFillBitWindow(
BrotliBitReader* const br, uint32_t n_bits) {
#if (BROTLI_64_BITS)
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
if (br->bit_pos_ >= 56) {
br->val_ >>= 56;
br->bit_pos_ ^= 56; /* here same as -= 56 because of the if condition */
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 8;
br->avail_in -= 7;
br->next_in += 7;
}
} else if (
!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 16)) {
if (br->bit_pos_ >= 48) {
br->val_ >>= 48;
br->bit_pos_ ^= 48; /* here same as -= 48 because of the if condition */
br->val_ |= BROTLI_UNALIGNED_LOAD64LE(br->next_in) << 16;
br->avail_in -= 6;
br->next_in += 6;
}
} else {
if (br->bit_pos_ >= 32) {
br->val_ >>= 32;
br->bit_pos_ ^= 32; /* here same as -= 32 because of the if condition */
br->val_ |= ((uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in)) << 32;
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
}
}
#else
if (!BROTLI_ALIGNED_READ && BROTLI_IS_CONSTANT(n_bits) && (n_bits <= 8)) {
if (br->bit_pos_ >= 24) {
br->val_ >>= 24;
br->bit_pos_ ^= 24; /* here same as -= 24 because of the if condition */
br->val_ |= BROTLI_UNALIGNED_LOAD32LE(br->next_in) << 8;
br->avail_in -= 3;
br->next_in += 3;
}
} else {
if (br->bit_pos_ >= 16) {
br->val_ >>= 16;
br->bit_pos_ ^= 16; /* here same as -= 16 because of the if condition */
br->val_ |= ((uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in)) << 16;
br->avail_in -= BROTLI_SHORT_FILL_BIT_WINDOW_READ;
br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ;
}
}
#endif
}
/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no
more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */
static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) {
BrotliFillBitWindow(br, 17);
}
/* Tries to pull one byte of input to accumulator.
Returns BROTLI_FALSE if there is no input available. */
static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) {
if (br->avail_in == 0) {
return BROTLI_FALSE;
}
br->val_ >>= 8;
#if (BROTLI_64_BITS)
br->val_ |= ((uint64_t)*br->next_in) << 56;
#else
br->val_ |= ((uint32_t)*br->next_in) << 24;
#endif
br->bit_pos_ -= 8;
--br->avail_in;
++br->next_in;
return BROTLI_TRUE;
}
/* Returns currently available bits.
The number of valid bits could be calculated by BrotliGetAvailableBits. */
static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked(
BrotliBitReader* const br) {
return br->val_ >> br->bit_pos_;
}
/* Like BrotliGetBits, but does not mask the result.
The result contains at least 16 valid bits. */
static BROTLI_INLINE uint32_t BrotliGet16BitsUnmasked(
BrotliBitReader* const br) {
BrotliFillBitWindow(br, 16);
return (uint32_t)BrotliGetBitsUnmasked(br);
}
/* Returns the specified number of bits from |br| without advancing bit
position. */
static BROTLI_INLINE uint32_t BrotliGetBits(
BrotliBitReader* const br, uint32_t n_bits) {
BrotliFillBitWindow(br, n_bits);
return (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
}
/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there
is not enough input. */
static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
while (BrotliGetAvailableBits(br) < n_bits) {
if (!BrotliPullByte(br)) {
return BROTLI_FALSE;
}
}
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
return BROTLI_TRUE;
}
/* Advances the bit pos by |n_bits|. */
static BROTLI_INLINE void BrotliDropBits(
BrotliBitReader* const br, uint32_t n_bits) {
br->bit_pos_ += n_bits;
}
static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) {
uint32_t unused_bytes = BrotliGetAvailableBits(br) >> 3;
uint32_t unused_bits = unused_bytes << 3;
br->avail_in += unused_bytes;
br->next_in -= unused_bytes;
if (unused_bits == sizeof(br->val_) << 3) {
br->val_ = 0;
} else {
br->val_ <<= unused_bits;
}
br->bit_pos_ += unused_bits;
}
/* Reads the specified number of bits from |br| and advances the bit pos.
Precondition: accumulator MUST contain at least |n_bits|. */
static BROTLI_INLINE void BrotliTakeBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
*val = (uint32_t)BrotliGetBitsUnmasked(br) & BitMask(n_bits);
BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n",
(int)br->avail_in, (int)br->bit_pos_, (int)n_bits, (int)*val));
BrotliDropBits(br, n_bits);
}
/* Reads the specified number of bits from |br| and advances the bit pos.
Assumes that there is enough input to perform BrotliFillBitWindow.
Up to 24 bits are allowed to be requested from this method. */
static BROTLI_INLINE uint32_t BrotliReadBits24(
BrotliBitReader* const br, uint32_t n_bits) {
BROTLI_DCHECK(n_bits <= 24);
if (BROTLI_64_BITS || (n_bits <= 16)) {
uint32_t val;
BrotliFillBitWindow(br, n_bits);
BrotliTakeBits(br, n_bits, &val);
return val;
} else {
uint32_t low_val;
uint32_t high_val;
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, 16, &low_val);
BrotliFillBitWindow(br, 8);
BrotliTakeBits(br, n_bits - 16, &high_val);
return low_val | (high_val << 16);
}
}
/* Same as BrotliReadBits24, but allows reading up to 32 bits. */
static BROTLI_INLINE uint32_t BrotliReadBits32(
BrotliBitReader* const br, uint32_t n_bits) {
BROTLI_DCHECK(n_bits <= 32);
if (BROTLI_64_BITS || (n_bits <= 16)) {
uint32_t val;
BrotliFillBitWindow(br, n_bits);
BrotliTakeBits(br, n_bits, &val);
return val;
} else {
uint32_t low_val;
uint32_t high_val;
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, 16, &low_val);
BrotliFillBitWindow(br, 16);
BrotliTakeBits(br, n_bits - 16, &high_val);
return low_val | (high_val << 16);
}
}
/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there
is not enough input. |n_bits| MUST be positive.
Up to 24 bits are allowed to be requested from this method. */
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
BROTLI_DCHECK(n_bits <= 24);
while (BrotliGetAvailableBits(br) < n_bits) {
if (!BrotliPullByte(br)) {
return BROTLI_FALSE;
}
}
BrotliTakeBits(br, n_bits, val);
return BROTLI_TRUE;
}
/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */
static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32(
BrotliBitReader* const br, uint32_t n_bits, uint32_t* val) {
BROTLI_DCHECK(n_bits <= 32);
if (BROTLI_64_BITS || (n_bits <= 24)) {
while (BrotliGetAvailableBits(br) < n_bits) {
if (!BrotliPullByte(br)) {
return BROTLI_FALSE;
}
}
BrotliTakeBits(br, n_bits, val);
return BROTLI_TRUE;
} else {
return BrotliSafeReadBits32Slow(br, n_bits, val);
}
}
/* Advances the bit reader position to the next byte boundary and verifies
that any skipped bits are set to zero. */
static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) {
uint32_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7;
uint32_t pad_bits = 0;
if (pad_bits_count != 0) {
BrotliTakeBits(br, pad_bits_count, &pad_bits);
}
return TO_BROTLI_BOOL(pad_bits == 0);
}
/* Copies remaining input bytes stored in the bit reader to the output. Value
|num| may not be larger than BrotliGetRemainingBytes. The bit reader must be
warmed up again after this. */
static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest,
BrotliBitReader* br, size_t num) {
while (BrotliGetAvailableBits(br) >= 8 && num > 0) {
*dest = (uint8_t)BrotliGetBitsUnmasked(br);
BrotliDropBits(br, 8);
++dest;
--num;
}
memcpy(dest, br->next_in, num);
br->avail_in -= num;
br->next_in += num;
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_DEC_BIT_READER_H_ */
@@ -0,0 +1,121 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Utilities for building Huffman decoding tables. */
#ifndef BROTLI_DEC_HUFFMAN_H_
#define BROTLI_DEC_HUFFMAN_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15
/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */
#define BROTLI_HUFFMAN_MAX_SIZE_26 396
/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */
#define BROTLI_HUFFMAN_MAX_SIZE_258 632
/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */
#define BROTLI_HUFFMAN_MAX_SIZE_272 646
#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 (HuffmanCode) ((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);
/* Builds Huffman lookup table assuming code lengths are in symbol order.
Returns size of resulting table. */
BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table,
int root_bits, const uint16_t* const symbol_lists, uint16_t* count);
/* Builds a simple Huffman table. The |num_symbols| parameter is to be
interpreted as follows: 0 means 1 symbol, 1 means 2 symbols,
2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2],
4 means 4 symbols with lengths [1, 2, 3, 3]. */
BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table,
int root_bits, uint16_t* symbols, uint32_t num_symbols);
/* Contains a collection of Huffman trees with the same alphabet size. */
/* alphabet_size_limit is needed due to simple codes, since
log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */
typedef struct {
HuffmanCode** htrees;
HuffmanCode* codes;
uint16_t alphabet_size_max;
uint16_t alphabet_size_limit;
uint16_t num_htrees;
} HuffmanTreeGroup;
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_DEC_HUFFMAN_H_ */
@@ -0,0 +1,732 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Lookup tables to map prefix codes to value ranges. This is used during
decoding of the block lengths, literal insertion lengths and copy lengths. */
#ifndef BROTLI_DEC_PREFIX_H_
#define BROTLI_DEC_PREFIX_H_
#include "../common/constants.h"
#include <brotli/types.h>
typedef struct CmdLutElement {
uint8_t insert_len_extra_bits;
uint8_t copy_len_extra_bits;
int8_t distance_code;
uint8_t context;
uint16_t insert_len_offset;
uint16_t copy_len_offset;
} CmdLutElement;
static const CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = {
{ 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 },
{ 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 },
{ 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 },
{ 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 },
{ 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 },
{ 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 },
{ 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 },
{ 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 },
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 },
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 },
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 },
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 },
{ 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 },
{ 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 },
{ 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 },
{ 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 },
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 },
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 },
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 },
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 },
{ 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 },
{ 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 },
{ 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 },
{ 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 },
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 },
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 },
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 },
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 },
{ 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 },
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0000, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0000, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 },
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0001, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0001, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 },
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0002, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0002, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 },
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0003, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0003, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 },
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0004, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0004, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 },
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000a },
{ 0x00, 0x01, 0, 0x03, 0x0005, 0x000c },
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x000e },
{ 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 },
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 },
{ 0x00, 0x03, 0, 0x03, 0x0005, 0x001e },
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 },
{ 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 },
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000a },
{ 0x01, 0x01, 0, 0x03, 0x0006, 0x000c },
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x000e },
{ 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 },
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 },
{ 0x01, 0x03, 0, 0x03, 0x0006, 0x001e },
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 },
{ 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 },
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000a },
{ 0x01, 0x01, 0, 0x03, 0x0008, 0x000c },
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x000e },
{ 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 },
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 },
{ 0x01, 0x03, 0, 0x03, 0x0008, 0x001e },
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 },
{ 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 },
{ 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 },
{ 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 },
{ 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 },
{ 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 },
{ 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 },
{ 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 },
{ 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 },
{ 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 },
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 },
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 },
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 },
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 },
{ 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 },
{ 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 },
{ 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 },
{ 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 },
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 },
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 },
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 },
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 },
{ 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 },
{ 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 },
{ 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 },
{ 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 },
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 },
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 },
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 },
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 },
{ 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 },
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0000, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0000, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 },
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0001, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0001, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 },
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0002, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0002, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 },
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0003, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0003, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 },
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0004, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0004, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 },
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000a },
{ 0x00, 0x01, -1, 0x03, 0x0005, 0x000c },
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x000e },
{ 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 },
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 },
{ 0x00, 0x03, -1, 0x03, 0x0005, 0x001e },
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 },
{ 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 },
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000a },
{ 0x01, 0x01, -1, 0x03, 0x0006, 0x000c },
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x000e },
{ 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 },
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 },
{ 0x01, 0x03, -1, 0x03, 0x0006, 0x001e },
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 },
{ 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 },
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000a },
{ 0x01, 0x01, -1, 0x03, 0x0008, 0x000c },
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x000e },
{ 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 },
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 },
{ 0x01, 0x03, -1, 0x03, 0x0008, 0x001e },
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 },
{ 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 },
{ 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 },
{ 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 },
{ 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 },
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 },
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 },
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 },
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 },
{ 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 },
{ 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 },
{ 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 },
{ 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 },
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 },
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 },
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 },
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 },
{ 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 },
{ 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 },
{ 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 },
{ 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 },
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 },
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 },
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 },
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 },
{ 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 },
{ 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 },
{ 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 },
{ 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 },
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 },
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 },
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 },
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 },
{ 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 },
{ 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 },
{ 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 },
{ 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 },
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 },
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 },
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 },
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 },
{ 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 },
{ 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 },
{ 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 },
{ 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 },
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 },
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 },
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 },
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 },
{ 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 },
{ 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 },
{ 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 },
{ 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 },
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 },
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 },
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 },
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 },
{ 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 },
{ 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 },
{ 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 },
{ 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 },
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 },
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 },
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 },
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 },
{ 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 },
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000a },
{ 0x02, 0x01, -1, 0x03, 0x000a, 0x000c },
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x000e },
{ 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 },
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 },
{ 0x02, 0x03, -1, 0x03, 0x000a, 0x001e },
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 },
{ 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 },
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000a },
{ 0x02, 0x01, -1, 0x03, 0x000e, 0x000c },
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x000e },
{ 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 },
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 },
{ 0x02, 0x03, -1, 0x03, 0x000e, 0x001e },
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 },
{ 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 },
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000a },
{ 0x03, 0x01, -1, 0x03, 0x0012, 0x000c },
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x000e },
{ 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 },
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 },
{ 0x03, 0x03, -1, 0x03, 0x0012, 0x001e },
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 },
{ 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 },
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000a },
{ 0x03, 0x01, -1, 0x03, 0x001a, 0x000c },
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x000e },
{ 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 },
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 },
{ 0x03, 0x03, -1, 0x03, 0x001a, 0x001e },
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 },
{ 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 },
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000a },
{ 0x04, 0x01, -1, 0x03, 0x0022, 0x000c },
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x000e },
{ 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 },
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 },
{ 0x04, 0x03, -1, 0x03, 0x0022, 0x001e },
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 },
{ 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 },
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000a },
{ 0x04, 0x01, -1, 0x03, 0x0032, 0x000c },
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x000e },
{ 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 },
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 },
{ 0x04, 0x03, -1, 0x03, 0x0032, 0x001e },
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 },
{ 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 },
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000a },
{ 0x05, 0x01, -1, 0x03, 0x0042, 0x000c },
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x000e },
{ 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 },
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 },
{ 0x05, 0x03, -1, 0x03, 0x0042, 0x001e },
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 },
{ 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 },
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000a },
{ 0x05, 0x01, -1, 0x03, 0x0062, 0x000c },
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x000e },
{ 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 },
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 },
{ 0x05, 0x03, -1, 0x03, 0x0062, 0x001e },
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 },
{ 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 },
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 },
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 },
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 },
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 },
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 },
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 },
{ 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 },
{ 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 },
{ 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 },
{ 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 },
{ 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 },
{ 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 },
{ 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 },
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 },
{ 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 },
{ 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 },
{ 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 },
{ 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 },
{ 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 },
{ 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 },
{ 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 },
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 },
{ 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 },
{ 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 },
{ 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 },
{ 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 },
{ 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 },
{ 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 },
{ 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 },
{ 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 },
{ 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 },
{ 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 },
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 },
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 },
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 },
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 },
{ 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 },
{ 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 },
{ 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 },
{ 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 },
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 },
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 },
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 },
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 },
{ 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 },
{ 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 },
{ 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 },
{ 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 },
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 },
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 },
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 },
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 },
{ 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 },
{ 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 },
{ 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 },
{ 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 },
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 },
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 },
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 },
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 },
{ 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 },
{ 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 },
{ 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 },
{ 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 },
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 },
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 },
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 },
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 },
{ 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 },
{ 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 },
{ 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 },
{ 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 },
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 },
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 },
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 },
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 },
{ 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 },
{ 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 },
{ 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 },
{ 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 },
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 },
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 },
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 },
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 },
{ 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 },
{ 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 },
{ 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 },
{ 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 },
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 },
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 },
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 },
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 },
{ 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 },
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 },
{ 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 },
{ 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 },
{ 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 },
{ 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 },
{ 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 },
{ 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 },
{ 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 },
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 },
{ 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 },
{ 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 },
{ 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 },
{ 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 },
{ 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 },
{ 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 },
{ 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 },
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 },
{ 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 },
{ 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 },
{ 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 },
{ 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 },
{ 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 },
{ 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 },
{ 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 },
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 },
{ 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 },
{ 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 },
{ 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 },
{ 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 },
{ 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 },
{ 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 },
{ 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 },
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 },
{ 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 },
{ 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 },
{ 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 },
{ 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 },
{ 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 },
{ 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 },
{ 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 },
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 },
{ 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 },
{ 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 },
{ 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 },
{ 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 },
{ 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 },
{ 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 },
{ 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 },
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 },
{ 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 },
{ 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 },
{ 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 },
{ 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 },
{ 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 },
{ 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 },
{ 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 },
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 },
{ 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 },
{ 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 },
{ 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 },
{ 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 },
{ 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 },
{ 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 },
{ 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 },
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000a },
{ 0x06, 0x01, -1, 0x03, 0x0082, 0x000c },
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x000e },
{ 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 },
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 },
{ 0x06, 0x03, -1, 0x03, 0x0082, 0x001e },
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 },
{ 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 },
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a },
{ 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c },
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e },
{ 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 },
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 },
{ 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e },
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 },
{ 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 },
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000a },
{ 0x08, 0x01, -1, 0x03, 0x0142, 0x000c },
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x000e },
{ 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 },
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 },
{ 0x08, 0x03, -1, 0x03, 0x0142, 0x001e },
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 },
{ 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 },
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000a },
{ 0x09, 0x01, -1, 0x03, 0x0242, 0x000c },
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x000e },
{ 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 },
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 },
{ 0x09, 0x03, -1, 0x03, 0x0242, 0x001e },
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 },
{ 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 },
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a },
{ 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c },
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e },
{ 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 },
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 },
{ 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e },
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 },
{ 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 },
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a },
{ 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c },
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e },
{ 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 },
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 },
{ 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e },
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 },
{ 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 },
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a },
{ 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c },
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e },
{ 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 },
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 },
{ 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e },
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 },
{ 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 },
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000a },
{ 0x18, 0x01, -1, 0x03, 0x5842, 0x000c },
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x000e },
{ 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 },
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 },
{ 0x18, 0x03, -1, 0x03, 0x5842, 0x001e },
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 },
{ 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 },
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 },
{ 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 },
{ 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 },
{ 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 },
{ 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 },
{ 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 },
{ 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 },
{ 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 },
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 },
{ 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 },
{ 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 },
{ 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 },
{ 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 },
{ 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 },
{ 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 },
{ 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 },
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 },
{ 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 },
{ 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 },
{ 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 },
{ 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 },
{ 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 },
{ 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 },
{ 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 },
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 },
{ 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 },
{ 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 },
{ 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 },
{ 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 },
{ 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 },
{ 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 },
{ 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 },
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 },
{ 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 },
{ 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 },
{ 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 },
{ 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 },
{ 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 },
{ 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 },
{ 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 },
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 },
{ 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 },
{ 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 },
{ 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 },
{ 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 },
{ 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 },
{ 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 },
{ 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 },
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 },
{ 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 },
{ 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 },
{ 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 },
{ 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 },
{ 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 },
{ 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 },
{ 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 },
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 },
{ 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 },
{ 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 },
{ 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 },
{ 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 },
{ 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 },
{ 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 },
{ 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 },
};
#endif /* BROTLI_DEC_PREFIX_H_ */
@@ -0,0 +1,365 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Brotli state for partial streaming decoding. */
#ifndef BROTLI_DEC_STATE_H_
#define BROTLI_DEC_STATE_H_
#include "../common/constants.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include "../common/transform.h"
#include <brotli/types.h>
#include "./bit_reader.h"
#include "./huffman.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Graphviz diagram that describes state transitions:
digraph States {
graph [compound=true]
concentrate=true
node [shape="box"]
UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE}
subgraph cluster_metablock_workflow {
style="rounded"
label=< <B>METABLOCK CYCLE</B> >
METABLOCK_BEGIN -> METABLOCK_HEADER
METABLOCK_HEADER:sw -> METADATA
METABLOCK_HEADER:s -> UNCOMPRESSED
METABLOCK_HEADER:se -> METABLOCK_DONE:ne
METADATA:s -> METABLOCK_DONE:w
UNCOMPRESSED:s -> METABLOCK_DONE:n
METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"]
}
INITIALIZE -> METABLOCK_BEGIN
METABLOCK_DONE -> DONE
subgraph cluster_compressed_metablock {
style="rounded"
label=< <B>COMPRESSED METABLOCK</B> >
subgraph cluster_command {
style="rounded"
label=< <B>HOT LOOP</B> >
_METABLOCK_DONE_PORT_ [shape=point style=invis]
{
// Set different shape for nodes returning from "compressed metablock".
node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS;
CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1;
}
CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY
// IO ("write") nodes are not in the hot loop!
CMD_INNER_WRITE [style=dashed]
CMD_INNER -> CMD_INNER_WRITE
CMD_POST_WRITE_1 [style=dashed]
CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1
CMD_POST_WRITE_2 [style=dashed]
CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2
CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"]
CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS}
[constraint="false"]
CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"]
CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"]
CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"]
CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"]
{rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS;
CMD_POST_WRAP_COPY}
{rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2}
{CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} ->
_METABLOCK_DONE_PORT_ [style=invis]
{CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_
[constraint="false" style=invis]
}
BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n
HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3
HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1
CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP
TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e
BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n
HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"]
{rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3}
{rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2;
TREE_GROUP}
}
METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n
_METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se
[constraint="false" ltail=cluster_command]
UNINITED [shape=Mdiamond];
DONE [shape=Msquare];
}
*/
typedef enum {
BROTLI_STATE_UNINITED,
BROTLI_STATE_LARGE_WINDOW_BITS,
BROTLI_STATE_INITIALIZE,
BROTLI_STATE_METABLOCK_BEGIN,
BROTLI_STATE_METABLOCK_HEADER,
BROTLI_STATE_METABLOCK_HEADER_2,
BROTLI_STATE_CONTEXT_MODES,
BROTLI_STATE_COMMAND_BEGIN,
BROTLI_STATE_COMMAND_INNER,
BROTLI_STATE_COMMAND_POST_DECODE_LITERALS,
BROTLI_STATE_COMMAND_POST_WRAP_COPY,
BROTLI_STATE_UNCOMPRESSED,
BROTLI_STATE_METADATA,
BROTLI_STATE_COMMAND_INNER_WRITE,
BROTLI_STATE_METABLOCK_DONE,
BROTLI_STATE_COMMAND_POST_WRITE_1,
BROTLI_STATE_COMMAND_POST_WRITE_2,
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER,
BROTLI_STATE_HUFFMAN_CODE_0,
BROTLI_STATE_HUFFMAN_CODE_1,
BROTLI_STATE_HUFFMAN_CODE_2,
BROTLI_STATE_HUFFMAN_CODE_3,
BROTLI_STATE_CONTEXT_MAP_1,
BROTLI_STATE_CONTEXT_MAP_2,
BROTLI_STATE_TREE_GROUP,
BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY,
BROTLI_STATE_DONE
} BrotliRunningState;
typedef enum {
BROTLI_STATE_METABLOCK_HEADER_NONE,
BROTLI_STATE_METABLOCK_HEADER_EMPTY,
BROTLI_STATE_METABLOCK_HEADER_NIBBLES,
BROTLI_STATE_METABLOCK_HEADER_SIZE,
BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED,
BROTLI_STATE_METABLOCK_HEADER_RESERVED,
BROTLI_STATE_METABLOCK_HEADER_BYTES,
BROTLI_STATE_METABLOCK_HEADER_METADATA
} BrotliRunningMetablockHeaderState;
typedef enum {
BROTLI_STATE_UNCOMPRESSED_NONE,
BROTLI_STATE_UNCOMPRESSED_WRITE
} BrotliRunningUncompressedState;
typedef enum {
BROTLI_STATE_TREE_GROUP_NONE,
BROTLI_STATE_TREE_GROUP_LOOP
} BrotliRunningTreeGroupState;
typedef enum {
BROTLI_STATE_CONTEXT_MAP_NONE,
BROTLI_STATE_CONTEXT_MAP_READ_PREFIX,
BROTLI_STATE_CONTEXT_MAP_HUFFMAN,
BROTLI_STATE_CONTEXT_MAP_DECODE,
BROTLI_STATE_CONTEXT_MAP_TRANSFORM
} BrotliRunningContextMapState;
typedef enum {
BROTLI_STATE_HUFFMAN_NONE,
BROTLI_STATE_HUFFMAN_SIMPLE_SIZE,
BROTLI_STATE_HUFFMAN_SIMPLE_READ,
BROTLI_STATE_HUFFMAN_SIMPLE_BUILD,
BROTLI_STATE_HUFFMAN_COMPLEX,
BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS
} BrotliRunningHuffmanState;
typedef enum {
BROTLI_STATE_DECODE_UINT8_NONE,
BROTLI_STATE_DECODE_UINT8_SHORT,
BROTLI_STATE_DECODE_UINT8_LONG
} BrotliRunningDecodeUint8State;
typedef enum {
BROTLI_STATE_READ_BLOCK_LENGTH_NONE,
BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX
} BrotliRunningReadBlockLengthState;
typedef struct BrotliMetablockHeaderArena {
BrotliRunningTreeGroupState substate_tree_group;
BrotliRunningContextMapState substate_context_map;
BrotliRunningHuffmanState substate_huffman;
uint32_t sub_loop_counter;
uint32_t repeat_code_len;
uint32_t prev_code_len;
/* For ReadHuffmanCode. */
uint32_t symbol;
uint32_t repeat;
uint32_t space;
/* Huffman table for "histograms". */
HuffmanCode table[32];
/* List of heads of symbol chains. */
uint16_t* symbol_lists;
/* Storage from symbol_lists. */
uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 +
BROTLI_NUM_COMMAND_SYMBOLS];
/* Tails of symbol chains. */
int next_symbol[32];
uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES];
/* Population counts for the code lengths. */
uint16_t code_length_histo[16];
/* For HuffmanTreeGroupDecode. */
int htree_index;
HuffmanCode* next;
/* For DecodeContextMap. */
uint32_t context_index;
uint32_t max_run_length_prefix;
uint32_t code;
HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272];
} BrotliMetablockHeaderArena;
typedef struct BrotliMetablockBodyArena {
uint8_t dist_extra_bits[544];
uint32_t dist_offset[544];
} BrotliMetablockBodyArena;
struct BrotliDecoderStateStruct {
BrotliRunningState state;
/* This counter is reused for several disjoint loops. */
int loop_counter;
BrotliBitReader br;
brotli_alloc_func alloc_func;
brotli_free_func free_func;
void* memory_manager_opaque;
/* Temporary storage for remaining input. Brotli stream format is designed in
a way, that 64 bits are enough to make progress in decoding. */
union {
uint64_t u64;
uint8_t u8[8];
} buffer;
uint32_t buffer_length;
int pos;
int max_backward_distance;
int max_distance;
int ringbuffer_size;
int ringbuffer_mask;
int dist_rb_idx;
int dist_rb[4];
int error_code;
uint8_t* ringbuffer;
uint8_t* ringbuffer_end;
HuffmanCode* htree_command;
const uint8_t* context_lookup;
uint8_t* context_map_slice;
uint8_t* dist_context_map_slice;
/* This ring buffer holds a few past copy distances that will be used by
some special distance codes. */
HuffmanTreeGroup literal_hgroup;
HuffmanTreeGroup insert_copy_hgroup;
HuffmanTreeGroup distance_hgroup;
HuffmanCode* block_type_trees;
HuffmanCode* block_len_trees;
/* This is true if the literal context map histogram type always matches the
block type. It is then not needed to keep the context (faster decoding). */
int trivial_literal_context;
/* Distance context is actual after command is decoded and before distance is
computed. After distance computation it is used as a temporary variable. */
int distance_context;
int meta_block_remaining_len;
uint32_t block_length_index;
uint32_t block_length[3];
uint32_t num_block_types[3];
uint32_t block_type_rb[6];
uint32_t distance_postfix_bits;
uint32_t num_direct_distance_codes;
uint32_t num_dist_htrees;
uint8_t* dist_context_map;
HuffmanCode* literal_htree;
uint8_t dist_htree_index;
int copy_length;
int distance_code;
/* For partial write operations. */
size_t rb_roundtrips; /* how many times we went around the ring-buffer */
size_t partial_pos_out; /* how much output to the user in total */
/* For InverseMoveToFrontTransform. */
uint32_t mtf_upper_bound;
uint32_t mtf[64 + 1];
/* Less used attributes are at the end of this struct. */
/* States inside function calls. */
BrotliRunningMetablockHeaderState substate_metablock_header;
BrotliRunningUncompressedState substate_uncompressed;
BrotliRunningDecodeUint8State substate_decode_uint8;
BrotliRunningReadBlockLengthState substate_read_block_length;
unsigned int is_last_metablock : 1;
unsigned int is_uncompressed : 1;
unsigned int is_metadata : 1;
unsigned int should_wrap_ringbuffer : 1;
unsigned int canny_ringbuffer_allocation : 1;
unsigned int large_window : 1;
unsigned int size_nibbles : 8;
uint32_t window_bits;
int new_ringbuffer_size;
uint32_t num_literal_htrees;
uint8_t* context_map;
uint8_t* context_modes;
const BrotliDictionary* dictionary;
const BrotliTransforms* transforms;
uint32_t trivial_literal_contexts[8]; /* 256 bits */
union {
BrotliMetablockHeaderArena header;
BrotliMetablockBodyArena body;
} arena;
};
typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal;
#define BrotliDecoderState BrotliDecoderStateInternal
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s,
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s);
BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s);
BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock(
BrotliDecoderState* s);
BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(
BrotliDecoderState* s, HuffmanTreeGroup* group, uint32_t alphabet_size_max,
uint32_t alphabet_size_limit, uint32_t ntrees);
#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L)
#define BROTLI_DECODER_FREE(S, X) { \
S->free_func(S->memory_manager_opaque, X); \
X = NULL; \
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_DEC_STATE_H_ */
@@ -0,0 +1,39 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Function to find backward reference copies. */
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_
#define BROTLI_ENC_BACKWARD_REFERENCES_H_
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./command.h"
#include "./hash.h"
#include "./quality.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* "commands" points to the next output command to write to, "*num_commands" is
initially the total amount of commands output by previous
CreateBackwardReferences calls, and must be incremented by the amount written
by this call. */
BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_BACKWARD_REFERENCES_H_ */
@@ -0,0 +1,95 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Function to find backward reference copies. */
#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./command.h"
#include "./hash.h"
#include "./memory.h"
#include "./quality.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m,
size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m,
size_t num_bytes,
size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals);
typedef struct ZopfliNode {
/* Best length to get up to this byte (not including this byte itself)
highest 7 bit is used to reconstruct the length code. */
uint32_t length;
/* Distance associated with the length. */
uint32_t distance;
/* Number of literal inserts before this copy; highest 5 bits contain
distance short code + 1 (or zero if no short code). */
uint32_t dcode_insert_length;
/* This union holds information used by dynamic-programming. During forward
pass |cost| it used to store the goal function. When node is processed its
|cost| is invalidated in favor of |shortcut|. On path back-tracing pass
|next| is assigned the offset to next node on the path. */
union {
/* Smallest cost to get to this byte from the beginning, as found so far. */
float cost;
/* Offset to the next node on the path. Equals to command_length() of the
next node on the path. For last node equals to BROTLI_UINT32_MAX */
uint32_t next;
/* Node position that provides next distance for distance cache. */
uint32_t shortcut;
} u;
} ZopfliNode;
BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length);
/* Computes the shortest path of commands from position to at most
position + num_bytes.
On return, path->size() is the number of commands found and path[i] is the
length of the i-th command (copy length plus insert length).
Note that the sum of the lengths of all commands can be less than num_bytes.
On return, the nodes[0..num_bytes] array will have the following
"ZopfliNode array invariant":
For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then
(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,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
const int* dist_cache, Hasher* hasher, ZopfliNode* nodes);
BROTLI_INTERNAL void BrotliZopfliCreateCommands(
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);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ */
@@ -0,0 +1,163 @@
/* NOLINT(build/header_guard) */
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: EXPORT_FN, FN */
static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)(
size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask,
ContextLut literal_context_lut, const BrotliEncoderParams* params,
Hasher* hasher, int* dist_cache, size_t* last_insert_len,
Command* commands, size_t* num_commands, size_t* num_literals) {
HASHER()* privat = &hasher->privat.FN(_);
/* Set maximum distance, see section 9.1. of the spec. */
const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin);
const size_t position_offset = params->stream_offset;
const Command* const orig_commands = commands;
size_t insert_length = *last_insert_len;
const size_t pos_end = position + num_bytes;
const size_t store_end = num_bytes >= FN(StoreLookahead)() ?
position + num_bytes - FN(StoreLookahead)() + 1 : position;
/* For speed up heuristics for random data. */
const size_t random_heuristics_window_size =
LiteralSpreeLengthForSparseSearch(params);
size_t apply_random_heuristics = position + random_heuristics_window_size;
const size_t gap = 0;
/* Minimum score to accept a backward reference. */
const score_t kMinScore = BROTLI_SCORE_BASE + 100;
BROTLI_UNUSED(literal_context_lut);
FN(PrepareDistanceCache)(privat, dist_cache);
while (position + FN(HashTypeLength)() < pos_end) {
size_t max_length = pos_end - position;
size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit);
size_t dictionary_start = BROTLI_MIN(size_t,
position + position_offset, max_backward_limit);
HasherSearchResult sr;
sr.len = 0;
sr.len_code_delta = 0;
sr.distance = 0;
sr.score = kMinScore;
FN(FindLongestMatch)(privat, &params->dictionary,
ringbuffer, ringbuffer_mask, dist_cache, position, max_length,
max_distance, dictionary_start + 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;
--max_length;
for (;; --max_length) {
const score_t cost_diff_lazy = 175;
HasherSearchResult sr2;
sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ?
BROTLI_MIN(size_t, sr.len - 1, max_length) : 0;
sr2.len_code_delta = 0;
sr2.distance = 0;
sr2.score = kMinScore;
max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit);
dictionary_start = BROTLI_MIN(size_t,
position + 1 + position_offset, max_backward_limit);
FN(FindLongestMatch)(privat,
&params->dictionary,
ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length,
max_distance, dictionary_start + gap, params->dist.max_distance,
&sr2);
if (sr2.score >= sr.score + cost_diff_lazy) {
/* Ok, let's just write one byte for now and start a match from the
next byte. */
++position;
++insert_length;
sr = sr2;
if (++delayed_backward_references_in_row < 4 &&
position + FN(HashTypeLength)() < pos_end) {
continue;
}
}
break;
}
apply_random_heuristics =
position + 2 * sr.len + random_heuristics_window_size;
dictionary_start = BROTLI_MIN(size_t,
position + position_offset, max_backward_limit);
{
/* The first 16 codes are special short-codes,
and the minimum offset is 1. */
size_t distance_code = ComputeDistanceCode(
sr.distance, dictionary_start + gap, dist_cache);
if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) {
dist_cache[3] = dist_cache[2];
dist_cache[2] = dist_cache[1];
dist_cache[1] = dist_cache[0];
dist_cache[0] = (int)sr.distance;
FN(PrepareDistanceCache)(privat, dist_cache);
}
InitCommand(commands++, &params->dist, insert_length,
sr.len, sr.len_code_delta, distance_code);
}
*num_literals += insert_length;
insert_length = 0;
/* Put the hash keys into the table, if there are enough bytes left.
Depending on the hasher implementation, it can push all positions
in the given range or only a subset of them.
Avoid hash poisoning with RLE data. */
{
size_t range_start = position + 2;
size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end);
if (sr.distance < (sr.len >> 2)) {
range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t,
range_start, position + sr.len - (sr.distance << 2)));
}
FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start,
range_end);
}
position += sr.len;
} else {
++insert_length;
++position;
/* If we have not seen matches for a long time, we can skip some
match lookups. Unsuccessful match lookups are very very expensive
and this kind of a heuristic speeds up compression quite
a lot. */
if (position > apply_random_heuristics) {
/* Going through uncompressible data, jump. */
if (position >
apply_random_heuristics + 4 * random_heuristics_window_size) {
/* It is quite a long time since we saw a copy, so we assume
that this data is not compressible, and store hashes less
often. Hashes of non compressible data are less likely to
turn out to be useful in the future, too, so we store less of
them to not to flood out the hash table of good compressible
data. */
const size_t kMargin =
BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4);
size_t pos_jump =
BROTLI_MIN(size_t, position + 16, pos_end - kMargin);
for (; position < pos_jump; position += 4) {
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
insert_length += 4;
}
} else {
const size_t kMargin =
BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2);
size_t pos_jump =
BROTLI_MIN(size_t, position + 8, pos_end - kMargin);
for (; position < pos_jump; position += 2) {
FN(Store)(privat, ringbuffer, ringbuffer_mask, position);
insert_length += 2;
}
}
}
}
}
insert_length += pos_end - position;
*last_insert_len = insert_length;
*num_commands += (size_t)(commands - orig_commands);
}
@@ -0,0 +1,63 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Functions to estimate the bit cost of Huffman trees. */
#ifndef BROTLI_ENC_BIT_COST_H_
#define BROTLI_ENC_BIT_COST_H_
#include "../common/platform.h"
#include <brotli/types.h>
#include "./fast_log.h"
#include "./histogram.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static BROTLI_INLINE double ShannonEntropy(
const uint32_t* population, size_t size, size_t* total) {
size_t sum = 0;
double retval = 0;
const uint32_t* population_end = population + size;
size_t p;
if (size & 1) {
goto odd_number_of_elements_left;
}
while (population < population_end) {
p = *population++;
sum += p;
retval -= (double)p * FastLog2(p);
odd_number_of_elements_left:
p = *population++;
sum += p;
retval -= (double)p * FastLog2(p);
}
if (sum) retval += (double)sum * FastLog2(sum);
*total = sum;
return retval;
}
static BROTLI_INLINE double BitsEntropy(
const uint32_t* population, size_t size) {
size_t sum;
double retval = ShannonEntropy(population, size, &sum);
if (retval < sum) {
/* At least one bit per literal is needed. */
retval = (double)sum;
}
return retval;
}
BROTLI_INTERNAL double BrotliPopulationCostLiteral(const HistogramLiteral*);
BROTLI_INTERNAL double BrotliPopulationCostCommand(const HistogramCommand*);
BROTLI_INTERNAL double BrotliPopulationCostDistance(const HistogramDistance*);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_BIT_COST_H_ */
@@ -0,0 +1,127 @@
/* NOLINT(build/header_guard) */
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN */
#define HistogramType FN(Histogram)
double FN(BrotliPopulationCost)(const HistogramType* histogram) {
static const double kOneSymbolHistogramCost = 12;
static const double kTwoSymbolHistogramCost = 20;
static const double kThreeSymbolHistogramCost = 28;
static const double kFourSymbolHistogramCost = 37;
const size_t data_size = FN(HistogramDataSize)();
int count = 0;
size_t s[5];
double bits = 0.0;
size_t i;
if (histogram->total_count_ == 0) {
return kOneSymbolHistogramCost;
}
for (i = 0; i < data_size; ++i) {
if (histogram->data_[i] > 0) {
s[count] = i;
++count;
if (count > 4) break;
}
}
if (count == 1) {
return kOneSymbolHistogramCost;
}
if (count == 2) {
return (kTwoSymbolHistogramCost + (double)histogram->total_count_);
}
if (count == 3) {
const uint32_t histo0 = histogram->data_[s[0]];
const uint32_t histo1 = histogram->data_[s[1]];
const uint32_t histo2 = histogram->data_[s[2]];
const uint32_t histomax =
BROTLI_MAX(uint32_t, histo0, BROTLI_MAX(uint32_t, histo1, histo2));
return (kThreeSymbolHistogramCost +
2 * (histo0 + histo1 + histo2) - histomax);
}
if (count == 4) {
uint32_t histo[4];
uint32_t h23;
uint32_t histomax;
for (i = 0; i < 4; ++i) {
histo[i] = histogram->data_[s[i]];
}
/* Sort */
for (i = 0; i < 4; ++i) {
size_t j;
for (j = i + 1; j < 4; ++j) {
if (histo[j] > histo[i]) {
BROTLI_SWAP(uint32_t, histo, j, i);
}
}
}
h23 = histo[2] + histo[3];
histomax = BROTLI_MAX(uint32_t, h23, histo[0]);
return (kFourSymbolHistogramCost +
3 * h23 + 2 * (histo[0] + histo[1]) - histomax);
}
{
/* In this loop we compute the entropy of the histogram and simultaneously
build a simplified histogram of the code length codes where we use the
zero repeat code 17, but we don't use the non-zero repeat code 16. */
size_t max_depth = 1;
uint32_t depth_histo[BROTLI_CODE_LENGTH_CODES] = { 0 };
const double log2total = FastLog2(histogram->total_count_);
for (i = 0; i < data_size;) {
if (histogram->data_[i] > 0) {
/* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) =
= log2(total_count) - log2(count(symbol)) */
double log2p = log2total - FastLog2(histogram->data_[i]);
/* Approximate the bit depth by round(-log2(P(symbol))) */
size_t depth = (size_t)(log2p + 0.5);
bits += histogram->data_[i] * log2p;
if (depth > 15) {
depth = 15;
}
if (depth > max_depth) {
max_depth = depth;
}
++depth_histo[depth];
++i;
} else {
/* Compute the run length of zeros and add the appropriate number of 0
and 17 code length codes to the code length code histogram. */
uint32_t reps = 1;
size_t k;
for (k = i + 1; k < data_size && histogram->data_[k] == 0; ++k) {
++reps;
}
i += reps;
if (i == data_size) {
/* Don't add any cost for the last zero run, since these are encoded
only implicitly. */
break;
}
if (reps < 3) {
depth_histo[0] += reps;
} else {
reps -= 2;
while (reps > 0) {
++depth_histo[BROTLI_REPEAT_ZERO_CODE_LENGTH];
/* Add the 3 extra bits for the 17 code length code. */
bits += 3;
reps >>= 3;
}
}
}
}
/* Add the estimated encoding cost of the code length code histogram. */
bits += (double)(18 + 2 * max_depth);
/* Add the entropy of the code length code histogram. */
bits += BitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES);
}
return bits;
}
#undef HistogramType
@@ -0,0 +1,34 @@
/* NOLINT(build/header_guard) */
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN */
#define HistogramType FN(Histogram)
/* Creates entropy codes for all block types and stores them to the bit
stream. */
static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self,
const HistogramType* histograms, const size_t histograms_size,
const size_t alphabet_size, HuffmanTree* tree,
size_t* storage_ix, uint8_t* storage) {
const size_t table_size = histograms_size * self->histogram_length_;
self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size);
self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size);
if (BROTLI_IS_OOM(m)) return;
{
size_t i;
for (i = 0; i < histograms_size; ++i) {
size_t ix = i * self->histogram_length_;
BuildAndStoreHuffmanTree(&histograms[i].data_[0], self->histogram_length_,
alphabet_size, tree, &self->depths_[ix], &self->bits_[ix],
storage_ix, storage);
}
}
}
#undef HistogramType
@@ -0,0 +1,51 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Block split point selection utilities. */
#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_
#define BROTLI_ENC_BLOCK_SPLITTER_H_
#include "../common/platform.h"
#include <brotli/types.h>
#include "./command.h"
#include "./memory.h"
#include "./quality.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct BlockSplit {
size_t num_types; /* Amount of distinct types */
size_t num_blocks; /* Amount of values in types and length */
uint8_t* types;
uint32_t* lengths;
size_t types_alloc_size;
size_t lengths_alloc_size;
} BlockSplit;
BROTLI_INTERNAL void BrotliInitBlockSplit(BlockSplit* self);
BROTLI_INTERNAL void BrotliDestroyBlockSplit(MemoryManager* m,
BlockSplit* self);
BROTLI_INTERNAL void BrotliSplitBlock(MemoryManager* m,
const Command* cmds,
const size_t num_commands,
const uint8_t* data,
const size_t offset,
const size_t mask,
const BrotliEncoderParams* params,
BlockSplit* literal_split,
BlockSplit* insert_and_copy_split,
BlockSplit* dist_split);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_BLOCK_SPLITTER_H_ */
@@ -0,0 +1,440 @@
/* NOLINT(build/header_guard) */
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, DataType */
#define HistogramType FN(Histogram)
static void FN(InitialEntropyCodes)(const DataType* data, size_t length,
size_t stride,
size_t num_histograms,
HistogramType* histograms) {
uint32_t seed = 7;
size_t block_length = length / num_histograms;
size_t i;
FN(ClearHistograms)(histograms, num_histograms);
for (i = 0; i < num_histograms; ++i) {
size_t pos = length * i / num_histograms;
if (i != 0) {
pos += MyRand(&seed) % block_length;
}
if (pos + stride >= length) {
pos = length - stride - 1;
}
FN(HistogramAddVector)(&histograms[i], data + pos, stride);
}
}
static void FN(RandomSample)(uint32_t* seed,
const DataType* data,
size_t length,
size_t stride,
HistogramType* sample) {
size_t pos = 0;
if (stride >= length) {
stride = length;
} else {
pos = MyRand(seed) % (length - stride + 1);
}
FN(HistogramAddVector)(sample, data + pos, stride);
}
static void FN(RefineEntropyCodes)(const DataType* data, size_t length,
size_t stride,
size_t num_histograms,
HistogramType* histograms) {
size_t iters =
kIterMulForRefining * length / stride + kMinItersForRefining;
uint32_t seed = 7;
size_t iter;
iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms;
for (iter = 0; iter < iters; ++iter) {
HistogramType sample;
FN(HistogramClear)(&sample);
FN(RandomSample)(&seed, data, length, stride, &sample);
FN(HistogramAddHistogram)(&histograms[iter % num_histograms], &sample);
}
}
/* Assigns a block id from the range [0, num_histograms) to each data element
in data[0..length) and fills in block_id[0..length) with the assigned values.
Returns the number of blocks, i.e. one plus the number of block switches. */
static size_t FN(FindBlocks)(const DataType* data, const size_t length,
const double block_switch_bitcost,
const size_t num_histograms,
const HistogramType* histograms,
double* insert_cost,
double* cost,
uint8_t* switch_signal,
uint8_t* block_id) {
const size_t data_size = FN(HistogramDataSize)();
const size_t bitmaplen = (num_histograms + 7) >> 3;
size_t num_blocks = 1;
size_t i;
size_t j;
BROTLI_DCHECK(num_histograms <= 256);
if (num_histograms <= 1) {
for (i = 0; i < length; ++i) {
block_id[i] = 0;
}
return 1;
}
memset(insert_cost, 0, sizeof(insert_cost[0]) * data_size * num_histograms);
for (i = 0; i < num_histograms; ++i) {
insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_);
}
for (i = data_size; i != 0;) {
--i;
for (j = 0; j < num_histograms; ++j) {
insert_cost[i * num_histograms + j] =
insert_cost[j] - BitCost(histograms[j].data_[i]);
}
}
memset(cost, 0, sizeof(cost[0]) * num_histograms);
memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmaplen);
/* After each iteration of this loop, cost[k] will contain the difference
between the minimum cost of arriving at the current byte position using
entropy code k, and the minimum cost of arriving at the current byte
position. This difference is capped at the block switch cost, and if it
reaches block switch cost, it means that when we trace back from the last
position, we need to switch here. */
for (i = 0; i < length; ++i) {
const size_t byte_ix = i;
size_t ix = byte_ix * bitmaplen;
size_t insert_cost_ix = data[byte_ix] * num_histograms;
double min_cost = 1e99;
double block_switch_cost = block_switch_bitcost;
size_t k;
for (k = 0; k < num_histograms; ++k) {
/* We are coding the symbol in data[byte_ix] with entropy code k. */
cost[k] += insert_cost[insert_cost_ix + k];
if (cost[k] < min_cost) {
min_cost = cost[k];
block_id[byte_ix] = (uint8_t)k;
}
}
/* More blocks for the beginning. */
if (byte_ix < 2000) {
block_switch_cost *= 0.77 + 0.07 * (double)byte_ix / 2000;
}
for (k = 0; k < num_histograms; ++k) {
cost[k] -= min_cost;
if (cost[k] >= block_switch_cost) {
const uint8_t mask = (uint8_t)(1u << (k & 7));
cost[k] = block_switch_cost;
BROTLI_DCHECK((k >> 3) < bitmaplen);
switch_signal[ix + (k >> 3)] |= mask;
}
}
}
{ /* Trace back from the last position and switch at the marked places. */
size_t byte_ix = length - 1;
size_t ix = byte_ix * bitmaplen;
uint8_t cur_id = block_id[byte_ix];
while (byte_ix > 0) {
const uint8_t mask = (uint8_t)(1u << (cur_id & 7));
BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmaplen);
--byte_ix;
ix -= bitmaplen;
if (switch_signal[ix + (cur_id >> 3)] & mask) {
if (cur_id != block_id[byte_ix]) {
cur_id = block_id[byte_ix];
++num_blocks;
}
}
block_id[byte_ix] = cur_id;
}
}
return num_blocks;
}
static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length,
uint16_t* new_id, const size_t num_histograms) {
static const uint16_t kInvalidId = 256;
uint16_t next_id = 0;
size_t i;
for (i = 0; i < num_histograms; ++i) {
new_id[i] = kInvalidId;
}
for (i = 0; i < length; ++i) {
BROTLI_DCHECK(block_ids[i] < num_histograms);
if (new_id[block_ids[i]] == kInvalidId) {
new_id[block_ids[i]] = next_id++;
}
}
for (i = 0; i < length; ++i) {
block_ids[i] = (uint8_t)new_id[block_ids[i]];
BROTLI_DCHECK(block_ids[i] < num_histograms);
}
BROTLI_DCHECK(next_id <= num_histograms);
return next_id;
}
static void FN(BuildBlockHistograms)(const DataType* data, const size_t length,
const uint8_t* block_ids,
const size_t num_histograms,
HistogramType* histograms) {
size_t i;
FN(ClearHistograms)(histograms, num_histograms);
for (i = 0; i < length; ++i) {
FN(HistogramAdd)(&histograms[block_ids[i]], data[i]);
}
}
static void FN(ClusterBlocks)(MemoryManager* m,
const DataType* data, const size_t length,
const size_t num_blocks,
uint8_t* block_ids,
BlockSplit* split) {
uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks);
uint32_t* block_lengths = BROTLI_ALLOC(m, uint32_t, num_blocks);
const size_t expected_num_clusters = CLUSTERS_PER_BATCH *
(num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH;
size_t all_histograms_size = 0;
size_t all_histograms_capacity = expected_num_clusters;
HistogramType* all_histograms =
BROTLI_ALLOC(m, HistogramType, all_histograms_capacity);
size_t cluster_size_size = 0;
size_t cluster_size_capacity = expected_num_clusters;
uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, cluster_size_capacity);
size_t num_clusters = 0;
HistogramType* histograms = BROTLI_ALLOC(m, HistogramType,
BROTLI_MIN(size_t, num_blocks, HISTOGRAMS_PER_BATCH));
size_t max_num_pairs =
HISTOGRAMS_PER_BATCH * HISTOGRAMS_PER_BATCH / 2;
size_t pairs_capacity = max_num_pairs + 1;
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity);
size_t pos = 0;
uint32_t* clusters;
size_t num_final_clusters;
static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
uint32_t* new_index;
size_t i;
uint32_t sizes[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t new_clusters[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t symbols[HISTOGRAMS_PER_BATCH] = { 0 };
uint32_t remap[HISTOGRAMS_PER_BATCH] = { 0 };
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) ||
BROTLI_IS_NULL(block_lengths) || BROTLI_IS_NULL(all_histograms) ||
BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) ||
BROTLI_IS_NULL(pairs)) {
return;
}
memset(block_lengths, 0, num_blocks * sizeof(uint32_t));
{
size_t block_idx = 0;
for (i = 0; i < length; ++i) {
BROTLI_DCHECK(block_idx < num_blocks);
++block_lengths[block_idx];
if (i + 1 == length || block_ids[i] != block_ids[i + 1]) {
++block_idx;
}
}
BROTLI_DCHECK(block_idx == num_blocks);
}
for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) {
const size_t num_to_combine =
BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH);
size_t num_new_clusters;
size_t j;
for (j = 0; j < num_to_combine; ++j) {
size_t k;
FN(HistogramClear)(&histograms[j]);
for (k = 0; k < block_lengths[i + j]; ++k) {
FN(HistogramAdd)(&histograms[j], data[pos++]);
}
histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]);
new_clusters[j] = (uint32_t)j;
symbols[j] = (uint32_t)j;
sizes[j] = 1;
}
num_new_clusters = FN(BrotliHistogramCombine)(
histograms, sizes, symbols, new_clusters, pairs, num_to_combine,
num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs);
BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms,
all_histograms_capacity, all_histograms_size + num_new_clusters);
BROTLI_ENSURE_CAPACITY(m, uint32_t, cluster_size,
cluster_size_capacity, cluster_size_size + num_new_clusters);
if (BROTLI_IS_OOM(m)) return;
for (j = 0; j < num_new_clusters; ++j) {
all_histograms[all_histograms_size++] = histograms[new_clusters[j]];
cluster_size[cluster_size_size++] = sizes[new_clusters[j]];
remap[new_clusters[j]] = (uint32_t)j;
}
for (j = 0; j < num_to_combine; ++j) {
histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]];
}
num_clusters += num_new_clusters;
BROTLI_DCHECK(num_clusters == cluster_size_size);
BROTLI_DCHECK(num_clusters == all_histograms_size);
}
BROTLI_FREE(m, histograms);
max_num_pairs =
BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters);
if (pairs_capacity < max_num_pairs + 1) {
BROTLI_FREE(m, pairs);
pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return;
}
clusters = BROTLI_ALLOC(m, uint32_t, num_clusters);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return;
for (i = 0; i < num_clusters; ++i) {
clusters[i] = (uint32_t)i;
}
num_final_clusters = FN(BrotliHistogramCombine)(
all_histograms, cluster_size, histogram_symbols, clusters, pairs,
num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES,
max_num_pairs);
BROTLI_FREE(m, pairs);
BROTLI_FREE(m, cluster_size);
new_index = BROTLI_ALLOC(m, uint32_t, num_clusters);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return;
for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex;
pos = 0;
{
uint32_t next_index = 0;
for (i = 0; i < num_blocks; ++i) {
HistogramType histo;
size_t j;
uint32_t best_out;
double best_bits;
FN(HistogramClear)(&histo);
for (j = 0; j < block_lengths[i]; ++j) {
FN(HistogramAdd)(&histo, data[pos++]);
}
best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1];
best_bits =
FN(BrotliHistogramBitCostDistance)(&histo, &all_histograms[best_out]);
for (j = 0; j < num_final_clusters; ++j) {
const double cur_bits = FN(BrotliHistogramBitCostDistance)(
&histo, &all_histograms[clusters[j]]);
if (cur_bits < best_bits) {
best_bits = cur_bits;
best_out = clusters[j];
}
}
histogram_symbols[i] = best_out;
if (new_index[best_out] == kInvalidIndex) {
new_index[best_out] = next_index++;
}
}
}
BROTLI_FREE(m, clusters);
BROTLI_FREE(m, all_histograms);
BROTLI_ENSURE_CAPACITY(
m, uint8_t, split->types, split->types_alloc_size, num_blocks);
BROTLI_ENSURE_CAPACITY(
m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks);
if (BROTLI_IS_OOM(m)) return;
{
uint32_t cur_length = 0;
size_t block_idx = 0;
uint8_t max_type = 0;
for (i = 0; i < num_blocks; ++i) {
cur_length += block_lengths[i];
if (i + 1 == num_blocks ||
histogram_symbols[i] != histogram_symbols[i + 1]) {
const uint8_t id = (uint8_t)new_index[histogram_symbols[i]];
split->types[block_idx] = id;
split->lengths[block_idx] = cur_length;
max_type = BROTLI_MAX(uint8_t, max_type, id);
cur_length = 0;
++block_idx;
}
}
split->num_blocks = block_idx;
split->num_types = (size_t)max_type + 1;
}
BROTLI_FREE(m, new_index);
BROTLI_FREE(m, block_lengths);
BROTLI_FREE(m, histogram_symbols);
}
static void FN(SplitByteVector)(MemoryManager* m,
const DataType* data, const size_t length,
const size_t literals_per_histogram,
const size_t max_histograms,
const size_t sampling_stride_length,
const double block_switch_cost,
const BrotliEncoderParams* params,
BlockSplit* split) {
const size_t data_size = FN(HistogramDataSize)();
size_t num_histograms = length / literals_per_histogram + 1;
HistogramType* histograms;
if (num_histograms > max_histograms) {
num_histograms = max_histograms;
}
if (length == 0) {
split->num_types = 1;
return;
} else if (length < kMinLengthForBlockSplitting) {
BROTLI_ENSURE_CAPACITY(m, uint8_t,
split->types, split->types_alloc_size, split->num_blocks + 1);
BROTLI_ENSURE_CAPACITY(m, uint32_t,
split->lengths, split->lengths_alloc_size, split->num_blocks + 1);
if (BROTLI_IS_OOM(m)) return;
split->num_types = 1;
split->types[split->num_blocks] = 0;
split->lengths[split->num_blocks] = (uint32_t)length;
split->num_blocks++;
return;
}
histograms = BROTLI_ALLOC(m, HistogramType, num_histograms);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return;
/* Find good entropy codes. */
FN(InitialEntropyCodes)(data, length,
sampling_stride_length,
num_histograms, histograms);
FN(RefineEntropyCodes)(data, length,
sampling_stride_length,
num_histograms, histograms);
{
/* Find a good path through literals with the good entropy codes. */
uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length);
size_t num_blocks = 0;
const size_t bitmaplen = (num_histograms + 7) >> 3;
double* insert_cost = BROTLI_ALLOC(m, double, data_size * num_histograms);
double* cost = BROTLI_ALLOC(m, double, num_histograms);
uint8_t* switch_signal = BROTLI_ALLOC(m, uint8_t, length * bitmaplen);
uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms);
const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10;
size_t i;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) ||
BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) ||
BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) {
return;
}
for (i = 0; i < iters; ++i) {
num_blocks = FN(FindBlocks)(data, length,
block_switch_cost,
num_histograms, histograms,
insert_cost, cost, switch_signal,
block_ids);
num_histograms = FN(RemapBlockIds)(block_ids, length,
new_id, num_histograms);
FN(BuildBlockHistograms)(data, length, block_ids,
num_histograms, histograms);
}
BROTLI_FREE(m, insert_cost);
BROTLI_FREE(m, cost);
BROTLI_FREE(m, switch_signal);
BROTLI_FREE(m, new_id);
BROTLI_FREE(m, histograms);
FN(ClusterBlocks)(m, data, length, num_blocks, block_ids, split);
if (BROTLI_IS_OOM(m)) return;
BROTLI_FREE(m, block_ids);
}
}
#undef HistogramType
@@ -0,0 +1,84 @@
/* Copyright 2014 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Functions to convert brotli-related data structures into the
brotli bit stream. The functions here operate under
assumption that there is enough space in the storage, i.e., there are
no out-of-range checks anywhere.
These functions do bit addressing into a byte array. The byte array
is called "storage" and the index to the bit is called storage_ix
in function arguments. */
#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_
#define BROTLI_ENC_BROTLI_BIT_STREAM_H_
#include "../common/context.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./command.h"
#include "./entropy_encode.h"
#include "./memory.h"
#include "./metablock.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* All Store functions here will use a storage_ix, which is always the bit
position for the current storage. */
BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num,
HuffmanTree* tree, size_t* storage_ix, uint8_t* storage);
BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast(
MemoryManager* m, const uint32_t* histogram, const size_t histogram_total,
const size_t max_bits, uint8_t* depth, uint16_t* bits, size_t* storage_ix,
uint8_t* storage);
/* REQUIRES: length > 0 */
/* REQUIRES: length <= (1 << 24) */
BROTLI_INTERNAL void BrotliStoreMetaBlock(MemoryManager* m,
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last,
const BrotliEncoderParams* params, ContextType literal_context_mode,
const Command* commands, size_t n_commands, const MetaBlockSplit* mb,
size_t* storage_ix, uint8_t* storage);
/* Stores the meta-block without doing any block splitting, just collects
one histogram per block category and uses that for entropy coding.
REQUIRES: length > 0
REQUIRES: length <= (1 << 24) */
BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m,
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
const Command* commands, size_t n_commands,
size_t* storage_ix, uint8_t* storage);
/* Same as above, but uses static prefix codes for histograms with a only a few
symbols, and uses static code length prefix codes for all other histograms.
REQUIRES: length > 0
REQUIRES: length <= (1 << 24) */
BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m,
const uint8_t* input, size_t start_pos, size_t length, size_t mask,
BROTLI_BOOL is_last, const BrotliEncoderParams* params,
const Command* commands, size_t n_commands,
size_t* storage_ix, uint8_t* storage);
/* This is for storing uncompressed blocks (simple raw storage of
bytes-as-bytes).
REQUIRES: length > 0
REQUIRES: length <= (1 << 24) */
BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock(
BROTLI_BOOL is_final_block, const uint8_t* BROTLI_RESTRICT input,
size_t position, size_t mask, size_t len,
size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_BROTLI_BIT_STREAM_H_ */
@@ -0,0 +1,48 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Functions for clustering similar histograms together. */
#ifndef BROTLI_ENC_CLUSTER_H_
#define BROTLI_ENC_CLUSTER_H_
#include "../common/platform.h"
#include <brotli/types.h>
#include "./histogram.h"
#include "./memory.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct HistogramPair {
uint32_t idx1;
uint32_t idx2;
double cost_combo;
double cost_diff;
} HistogramPair;
#define CODE(X) /* Declaration */;
#define FN(X) X ## Literal
#include "./cluster_inc.h" /* NOLINT(build/include) */
#undef FN
#define FN(X) X ## Command
#include "./cluster_inc.h" /* NOLINT(build/include) */
#undef FN
#define FN(X) X ## Distance
#include "./cluster_inc.h" /* NOLINT(build/include) */
#undef FN
#undef CODE
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_CLUSTER_H_ */
@@ -0,0 +1,320 @@
/* NOLINT(build/header_guard) */
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, CODE */
#define HistogramType FN(Histogram)
/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if
it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */
BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)(
const HistogramType* out, const uint32_t* cluster_size, uint32_t idx1,
uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs,
size_t* num_pairs) CODE({
BROTLI_BOOL is_good_pair = BROTLI_FALSE;
HistogramPair p;
p.idx1 = p.idx2 = 0;
p.cost_diff = p.cost_combo = 0;
if (idx1 == idx2) {
return;
}
if (idx2 < idx1) {
uint32_t t = idx2;
idx2 = idx1;
idx1 = t;
}
p.idx1 = idx1;
p.idx2 = idx2;
p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]);
p.cost_diff -= out[idx1].bit_cost_;
p.cost_diff -= out[idx2].bit_cost_;
if (out[idx1].total_count_ == 0) {
p.cost_combo = out[idx2].bit_cost_;
is_good_pair = BROTLI_TRUE;
} else if (out[idx2].total_count_ == 0) {
p.cost_combo = out[idx1].bit_cost_;
is_good_pair = BROTLI_TRUE;
} else {
double threshold = *num_pairs == 0 ? 1e99 :
BROTLI_MAX(double, 0.0, pairs[0].cost_diff);
HistogramType combo = out[idx1];
double cost_combo;
FN(HistogramAddHistogram)(&combo, &out[idx2]);
cost_combo = FN(BrotliPopulationCost)(&combo);
if (cost_combo < threshold - p.cost_diff) {
p.cost_combo = cost_combo;
is_good_pair = BROTLI_TRUE;
}
}
if (is_good_pair) {
p.cost_diff += p.cost_combo;
if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) {
/* Replace the top of the queue if needed. */
if (*num_pairs < max_num_pairs) {
pairs[*num_pairs] = pairs[0];
++(*num_pairs);
}
pairs[0] = p;
} else if (*num_pairs < max_num_pairs) {
pairs[*num_pairs] = p;
++(*num_pairs);
}
}
})
BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out,
uint32_t* cluster_size,
uint32_t* symbols,
uint32_t* clusters,
HistogramPair* pairs,
size_t num_clusters,
size_t symbols_size,
size_t max_clusters,
size_t max_num_pairs) CODE({
double cost_diff_threshold = 0.0;
size_t min_cluster_size = 1;
size_t num_pairs = 0;
{
/* We maintain a vector of histogram pairs, with the property that the pair
with the maximum bit cost reduction is the first. */
size_t idx1;
for (idx1 = 0; idx1 < num_clusters; ++idx1) {
size_t idx2;
for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) {
FN(BrotliCompareAndPushToQueue)(out, cluster_size, clusters[idx1],
clusters[idx2], max_num_pairs, &pairs[0], &num_pairs);
}
}
}
while (num_clusters > min_cluster_size) {
uint32_t best_idx1;
uint32_t best_idx2;
size_t i;
if (pairs[0].cost_diff >= cost_diff_threshold) {
cost_diff_threshold = 1e99;
min_cluster_size = max_clusters;
continue;
}
/* Take the best pair from the top of heap. */
best_idx1 = pairs[0].idx1;
best_idx2 = pairs[0].idx2;
FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]);
out[best_idx1].bit_cost_ = pairs[0].cost_combo;
cluster_size[best_idx1] += cluster_size[best_idx2];
for (i = 0; i < symbols_size; ++i) {
if (symbols[i] == best_idx2) {
symbols[i] = best_idx1;
}
}
for (i = 0; i < num_clusters; ++i) {
if (clusters[i] == best_idx2) {
memmove(&clusters[i], &clusters[i + 1],
(num_clusters - i - 1) * sizeof(clusters[0]));
break;
}
}
--num_clusters;
{
/* Remove pairs intersecting the just combined best pair. */
size_t copy_to_idx = 0;
for (i = 0; i < num_pairs; ++i) {
HistogramPair* p = &pairs[i];
if (p->idx1 == best_idx1 || p->idx2 == best_idx1 ||
p->idx1 == best_idx2 || p->idx2 == best_idx2) {
/* Remove invalid pair from the queue. */
continue;
}
if (HistogramPairIsLess(&pairs[0], p)) {
/* Replace the top of the queue if needed. */
HistogramPair front = pairs[0];
pairs[0] = *p;
pairs[copy_to_idx] = front;
} else {
pairs[copy_to_idx] = *p;
}
++copy_to_idx;
}
num_pairs = copy_to_idx;
}
/* Push new pairs formed with the combined histogram to the heap. */
for (i = 0; i < num_clusters; ++i) {
FN(BrotliCompareAndPushToQueue)(out, cluster_size, best_idx1, clusters[i],
max_num_pairs, &pairs[0], &num_pairs);
}
}
return num_clusters;
})
/* What is the bit cost of moving histogram from cur_symbol to candidate. */
BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)(
const HistogramType* histogram, const HistogramType* candidate) CODE({
if (histogram->total_count_ == 0) {
return 0.0;
} else {
HistogramType tmp = *histogram;
FN(HistogramAddHistogram)(&tmp, candidate);
return FN(BrotliPopulationCost)(&tmp) - candidate->bit_cost_;
}
})
/* Find the best 'out' histogram for each of the 'in' histograms.
When called, clusters[0..num_clusters) contains the unique values from
symbols[0..in_size), but this property is not preserved in this function.
Note: we assume that out[]->bit_cost_ is already up-to-date. */
BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in,
size_t in_size, const uint32_t* clusters, size_t num_clusters,
HistogramType* out, uint32_t* symbols) CODE({
size_t i;
for (i = 0; i < in_size; ++i) {
uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1];
double best_bits =
FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out]);
size_t j;
for (j = 0; j < num_clusters; ++j) {
const double cur_bits =
FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]]);
if (cur_bits < best_bits) {
best_bits = cur_bits;
best_out = clusters[j];
}
}
symbols[i] = best_out;
}
/* Recompute each out based on raw and symbols. */
for (i = 0; i < num_clusters; ++i) {
FN(HistogramClear)(&out[clusters[i]]);
}
for (i = 0; i < in_size; ++i) {
FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]);
}
})
/* Reorders elements of the out[0..length) array and changes values in
symbols[0..length) array in the following way:
* when called, symbols[] contains indexes into out[], and has N unique
values (possibly N < length)
* on return, symbols'[i] = f(symbols[i]) and
out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length,
where f is a bijection between the range of symbols[] and [0..N), and
the first occurrences of values in symbols'[i] come in consecutive
increasing order.
Returns N, the number of unique values in symbols[]. */
BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m,
HistogramType* out, uint32_t* symbols, size_t length) CODE({
static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX;
uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length);
uint32_t next_index;
HistogramType* tmp;
size_t i;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0;
for (i = 0; i < length; ++i) {
new_index[i] = kInvalidIndex;
}
next_index = 0;
for (i = 0; i < length; ++i) {
if (new_index[symbols[i]] == kInvalidIndex) {
new_index[symbols[i]] = next_index;
++next_index;
}
}
/* TODO: by using idea of "cycle-sort" we can avoid allocation of
tmp and reduce the number of copying by the factor of 2. */
tmp = BROTLI_ALLOC(m, HistogramType, next_index);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0;
next_index = 0;
for (i = 0; i < length; ++i) {
if (new_index[symbols[i]] == next_index) {
tmp[next_index] = out[symbols[i]];
++next_index;
}
symbols[i] = new_index[symbols[i]];
}
BROTLI_FREE(m, new_index);
for (i = 0; i < next_index; ++i) {
out[i] = tmp[i];
}
BROTLI_FREE(m, tmp);
return next_index;
})
BROTLI_INTERNAL void FN(BrotliClusterHistograms)(
MemoryManager* m, const HistogramType* in, const size_t in_size,
size_t max_histograms, HistogramType* out, size_t* out_size,
uint32_t* histogram_symbols) CODE({
uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size);
uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size);
size_t num_clusters = 0;
const size_t max_input_histograms = 64;
size_t pairs_capacity = max_input_histograms * max_input_histograms / 2;
/* For the first pass of clustering, we allow all pairs. */
HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1);
size_t i;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) ||
BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)) {
return;
}
for (i = 0; i < in_size; ++i) {
cluster_size[i] = 1;
}
for (i = 0; i < in_size; ++i) {
out[i] = in[i];
out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]);
histogram_symbols[i] = (uint32_t)i;
}
for (i = 0; i < in_size; i += max_input_histograms) {
size_t num_to_combine =
BROTLI_MIN(size_t, in_size - i, max_input_histograms);
size_t num_new_clusters;
size_t j;
for (j = 0; j < num_to_combine; ++j) {
clusters[num_clusters + j] = (uint32_t)(i + j);
}
num_new_clusters =
FN(BrotliHistogramCombine)(out, cluster_size,
&histogram_symbols[i],
&clusters[num_clusters], pairs,
num_to_combine, num_to_combine,
max_histograms, pairs_capacity);
num_clusters += num_new_clusters;
}
{
/* For the second pass, we limit the total number of histogram pairs.
After this limit is reached, we only keep searching for the best pair. */
size_t max_num_pairs = BROTLI_MIN(size_t,
64 * num_clusters, (num_clusters / 2) * num_clusters);
BROTLI_ENSURE_CAPACITY(
m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1);
if (BROTLI_IS_OOM(m)) return;
/* Collapse similar histograms. */
num_clusters = FN(BrotliHistogramCombine)(out, cluster_size,
histogram_symbols, clusters,
pairs, num_clusters, in_size,
max_histograms, max_num_pairs);
}
BROTLI_FREE(m, pairs);
BROTLI_FREE(m, cluster_size);
/* Find the optimal map from original histograms to the final ones. */
FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters,
out, histogram_symbols);
BROTLI_FREE(m, clusters);
/* Convert the context map to a canonical form. */
*out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size);
if (BROTLI_IS_OOM(m)) return;
})
#undef HistogramType
@@ -0,0 +1,190 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* This class models a sequence of literals and a backward reference copy. */
#ifndef BROTLI_ENC_COMMAND_H_
#define BROTLI_ENC_COMMAND_H_
#include "../common/constants.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./fast_log.h"
#include "./params.h"
#include "./prefix.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
BROTLI_INTERNAL extern const uint32_t
kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES];
BROTLI_INTERNAL extern const uint32_t
kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES];
static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) {
if (insertlen < 6) {
return (uint16_t)insertlen;
} else if (insertlen < 130) {
uint32_t nbits = Log2FloorNonZero(insertlen - 2) - 1u;
return (uint16_t)((nbits << 1) + ((insertlen - 2) >> nbits) + 2);
} else if (insertlen < 2114) {
return (uint16_t)(Log2FloorNonZero(insertlen - 66) + 10);
} else if (insertlen < 6210) {
return 21u;
} else if (insertlen < 22594) {
return 22u;
} else {
return 23u;
}
}
static BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) {
if (copylen < 10) {
return (uint16_t)(copylen - 2);
} else if (copylen < 134) {
uint32_t nbits = Log2FloorNonZero(copylen - 6) - 1u;
return (uint16_t)((nbits << 1) + ((copylen - 6) >> nbits) + 4);
} else if (copylen < 2118) {
return (uint16_t)(Log2FloorNonZero(copylen - 70) + 12);
} else {
return 23u;
}
}
static BROTLI_INLINE uint16_t CombineLengthCodes(
uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) {
uint16_t bits64 =
(uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u));
if (use_last_distance && inscode < 8u && copycode < 16u) {
return (copycode < 8u) ? bits64 : (bits64 | 64u);
} else {
/* Specification: 5 Encoding of ... (last table) */
/* offset = 2 * index, where index is in range [0..8] */
uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u));
/* All values in specification are K * 64,
where K = [2, 3, 6, 4, 5, 8, 7, 9, 10],
i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9],
K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D.
All values in D require only 2 bits to encode.
Magic constant is shifted 6 bits left, to avoid final multiplication. */
offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u);
return (uint16_t)(offset | bits64);
}
}
static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen,
BROTLI_BOOL use_last_distance,
uint16_t* code) {
uint16_t inscode = GetInsertLengthCode(insertlen);
uint16_t copycode = GetCopyLengthCode(copylen);
*code = CombineLengthCodes(inscode, copycode, use_last_distance);
}
static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) {
return kBrotliInsBase[inscode];
}
static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) {
return kBrotliInsExtra[inscode];
}
static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) {
return kBrotliCopyBase[copycode];
}
static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) {
return kBrotliCopyExtra[copycode];
}
typedef struct Command {
uint32_t insert_len_;
/* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */
uint32_t copy_len_;
/* Stores distance extra bits. */
uint32_t dist_extra_;
uint16_t cmd_prefix_;
/* Stores distance code in low 10 bits
and number of extra bits in high 6 bits. */
uint16_t dist_prefix_;
} Command;
/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */
static BROTLI_INLINE void InitCommand(Command* self,
const BrotliDistanceParams* dist, size_t insertlen,
size_t copylen, int copylen_code_delta, size_t distance_code) {
/* Don't rely on signed int representation, use honest casts. */
uint32_t delta = (uint8_t)((int8_t)copylen_code_delta);
self->insert_len_ = (uint32_t)insertlen;
self->copy_len_ = (uint32_t)(copylen | (delta << 25));
/* The distance prefix and extra bits are stored in this Command as if
npostfix and ndirect were 0, they are only recomputed later after the
clustering if needed. */
PrefixEncodeCopyDistance(
distance_code, dist->num_direct_distance_codes,
dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_);
GetLengthCode(
insertlen, (size_t)((int)copylen + copylen_code_delta),
TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_);
}
static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) {
self->insert_len_ = (uint32_t)insertlen;
self->copy_len_ = 4 << 25;
self->dist_extra_ = 0;
self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES;
GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_);
}
static BROTLI_INLINE uint32_t CommandRestoreDistanceCode(
const Command* self, const BrotliDistanceParams* dist) {
if ((self->dist_prefix_ & 0x3FFu) <
BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) {
return self->dist_prefix_ & 0x3FFu;
} else {
uint32_t dcode = self->dist_prefix_ & 0x3FFu;
uint32_t nbits = self->dist_prefix_ >> 10;
uint32_t extra = self->dist_extra_;
uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U;
uint32_t hcode = (dcode - dist->num_direct_distance_codes -
BROTLI_NUM_DISTANCE_SHORT_CODES) >>
dist->distance_postfix_bits;
uint32_t lcode = (dcode - dist->num_direct_distance_codes -
BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask;
uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U;
return ((offset + extra) << dist->distance_postfix_bits) + lcode +
dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES;
}
}
static BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) {
uint32_t r = self->cmd_prefix_ >> 6;
uint32_t c = self->cmd_prefix_ & 7;
if ((r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2)) {
return c;
}
return 3;
}
static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) {
return self->copy_len_ & 0x1FFFFFF;
}
static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) {
uint32_t modifier = self->copy_len_ >> 25;
int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1)));
return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta);
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_COMMAND_H_ */
@@ -0,0 +1,61 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Function for fast encoding of an input fragment, independently from the input
history. This function uses one-pass processing: when we find a backward
match, we immediately emit the corresponding command and literal codes to
the bit stream. */
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_
#define BROTLI_ENC_COMPRESS_FRAGMENT_H_
#include "../common/platform.h"
#include <brotli/types.h>
#include "./memory.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Compresses "input" string to the "*storage" buffer as one or more complete
meta-blocks, and updates the "*storage_ix" bit position.
If "is_last" is 1, emits an additional empty last meta-block.
"cmd_depth" and "cmd_bits" contain the command and distance prefix codes
(see comment in encode.h) used for the encoding of this input fragment.
If "is_last" is 0, they are updated to reflect the statistics
of this input fragment, to be used for the encoding of the next fragment.
"*cmd_code_numbits" is the number of bits of the compressed representation
of the command and distance prefix codes, and "cmd_code" is an array of
at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed
command and distance prefix codes. If "is_last" is 0, these are also
updated to represent the updated "cmd_depth" and "cmd_bits".
REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two
OUTPUT: maximal copy distance <= |input_size|
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
BROTLI_INTERNAL void BrotliCompressFragmentFast(MemoryManager* m,
const uint8_t* input,
size_t input_size,
BROTLI_BOOL is_last,
int* table, size_t table_size,
uint8_t cmd_depth[128],
uint16_t cmd_bits[128],
size_t* cmd_code_numbits,
uint8_t* cmd_code,
size_t* storage_ix,
uint8_t* storage);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_H_ */
@@ -0,0 +1,54 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Function for fast encoding of an input fragment, independently from the input
history. This function uses two-pass processing: in the first pass we save
the found backward matches and literal bytes into a buffer, and in the
second pass we emit them into the bit stream using prefix codes built based
on the actual command and literal byte histograms. */
#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_
#include "../common/platform.h"
#include <brotli/types.h>
#include "./memory.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17;
/* Compresses "input" string to the "*storage" buffer as one or more complete
meta-blocks, and updates the "*storage_ix" bit position.
If "is_last" is 1, emits an additional empty last meta-block.
REQUIRES: "input_size" is greater than zero, or "is_last" is 1.
REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24).
REQUIRES: "command_buf" and "literal_buf" point to at least
kCompressFragmentTwoPassBlockSize long arrays.
REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero.
REQUIRES: "table_size" is a power of two
OUTPUT: maximal copy distance <= |input_size|
OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */
BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(MemoryManager* m,
const uint8_t* input,
size_t input_size,
BROTLI_BOOL is_last,
uint32_t* command_buf,
uint8_t* literal_buf,
int* table,
size_t table_size,
size_t* storage_ix,
uint8_t* storage);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_ */
@@ -0,0 +1,25 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Hash table on the 4-byte prefixes of static dictionary words. */
#ifndef BROTLI_ENC_DICTIONARY_HASH_H_
#define BROTLI_ENC_DICTIONARY_HASH_H_
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
extern const uint16_t kStaticDictionaryHashWords[32768];
extern const uint8_t kStaticDictionaryHashLengths[32768];
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_DICTIONARY_HASH_H_ */
@@ -0,0 +1,43 @@
/* Copyright 2017 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
#ifndef BROTLI_ENC_ENCODER_DICT_H_
#define BROTLI_ENC_ENCODER_DICT_H_
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./static_dict_lut.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Dictionary data (words and transforms) for 1 possible context */
typedef struct BrotliEncoderDictionary {
const BrotliDictionary* words;
uint32_t num_transforms;
/* cut off for fast encoder */
uint32_t cutoffTransformsCount;
uint64_t cutoffTransforms;
/* from dictionary_hash.h, for fast encoder */
const uint16_t* hash_table_words;
const uint8_t* hash_table_lengths;
/* from static_dict_lut.h, for slow encoder */
const uint16_t* buckets;
const DictWord* dict_words;
} BrotliEncoderDictionary;
BROTLI_INTERNAL void BrotliInitEncoderDictionary(BrotliEncoderDictionary* dict);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_ENCODER_DICT_H_ */
@@ -0,0 +1,122 @@
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Entropy encoding (Huffman) utilities. */
#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_
#define BROTLI_ENC_ENTROPY_ENCODE_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* A node of a Huffman tree. */
typedef struct HuffmanTree {
uint32_t total_count_;
int16_t index_left_;
int16_t index_right_or_value_;
} HuffmanTree;
static BROTLI_INLINE void InitHuffmanTree(HuffmanTree* self, uint32_t count,
int16_t left, int16_t right) {
self->total_count_ = count;
self->index_left_ = left;
self->index_right_or_value_ = right;
}
/* Returns 1 is assignment of depths succeeded, otherwise 0. */
BROTLI_INTERNAL BROTLI_BOOL BrotliSetDepth(
int p, HuffmanTree* pool, uint8_t* depth, int max_depth);
/* This function will create a Huffman tree.
The (data,length) contains the population counts.
The tree_limit is the maximum bit depth of the Huffman codes.
The depth contains the tree, i.e., how many bits are used for
the symbol.
The actual Huffman tree is constructed in the tree[] array, which has to
be at least 2 * length + 1 long.
See http://en.wikipedia.org/wiki/Huffman_coding */
BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t* data,
const size_t length,
const int tree_limit,
HuffmanTree* tree,
uint8_t* depth);
/* Change the population counts in a way that the consequent
Huffman tree compression, especially its RLE-part will be more
likely to compress this data more efficiently.
length contains the size of the histogram.
counts contains the population counts.
good_for_rle is a buffer of at least length size */
BROTLI_INTERNAL void BrotliOptimizeHuffmanCountsForRle(
size_t length, uint32_t* counts, uint8_t* good_for_rle);
/* Write a Huffman tree from bit depths into the bit-stream representation
of a Huffman tree. The generated Huffman tree is to be compressed once
more using a Huffman tree */
BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth,
size_t num,
size_t* tree_size,
uint8_t* tree,
uint8_t* extra_bits_data);
/* Get the actual bit values for a tree of bit depths. */
BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth,
size_t len,
uint16_t* bits);
BROTLI_INTERNAL extern const size_t kBrotliShellGaps[6];
/* Input size optimized Shell sort. */
typedef BROTLI_BOOL (*HuffmanTreeComparator)(
const HuffmanTree*, const HuffmanTree*);
static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items,
const size_t n, HuffmanTreeComparator comparator) {
if (n < 13) {
/* Insertion sort. */
size_t i;
for (i = 1; i < n; ++i) {
HuffmanTree tmp = items[i];
size_t k = i;
size_t j = i - 1;
while (comparator(&tmp, &items[j])) {
items[k] = items[j];
k = j;
if (!j--) break;
}
items[k] = tmp;
}
return;
} else {
/* Shell sort. */
int g = n < 57 ? 2 : 0;
for (; g < 6; ++g) {
size_t gap = kBrotliShellGaps[g];
size_t i;
for (i = gap; i < n; ++i) {
size_t j = i;
HuffmanTree tmp = items[i];
for (; j >= gap && comparator(&tmp, &items[j - gap]); j -= gap) {
items[j] = items[j - gap];
}
items[j] = tmp;
}
}
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_ENTROPY_ENCODE_H_ */
@@ -0,0 +1,539 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Static entropy codes used for faster meta-block encoding. */
#ifndef BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_
#include "../common/constants.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./write_bits.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static const uint8_t kCodeLengthDepth[18] = {
4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4,
};
static const uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
};
static const uint8_t kStaticDistanceCodeDepth[64] = {
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
};
static const uint32_t kCodeLengthBits[18] = {
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7,
};
static BROTLI_INLINE void StoreStaticCodeLengthCode(
size_t* storage_ix, uint8_t* storage) {
BrotliWriteBits(
40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage);
}
static const uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x00000017, 0x00000027,
0x00000037, 0x00000047, 0x00000057, 0x00000067, 0x00000077, 0x00000770,
0x00000b87, 0x00001387, 0x00001b87, 0x00002387, 0x00002b87, 0x00003387,
0x00003b87, 0x00000397, 0x00000b97, 0x00001397, 0x00001b97, 0x00002397,
0x00002b97, 0x00003397, 0x00003b97, 0x000003a7, 0x00000ba7, 0x000013a7,
0x00001ba7, 0x000023a7, 0x00002ba7, 0x000033a7, 0x00003ba7, 0x000003b7,
0x00000bb7, 0x000013b7, 0x00001bb7, 0x000023b7, 0x00002bb7, 0x000033b7,
0x00003bb7, 0x000003c7, 0x00000bc7, 0x000013c7, 0x00001bc7, 0x000023c7,
0x00002bc7, 0x000033c7, 0x00003bc7, 0x000003d7, 0x00000bd7, 0x000013d7,
0x00001bd7, 0x000023d7, 0x00002bd7, 0x000033d7, 0x00003bd7, 0x000003e7,
0x00000be7, 0x000013e7, 0x00001be7, 0x000023e7, 0x00002be7, 0x000033e7,
0x00003be7, 0x000003f7, 0x00000bf7, 0x000013f7, 0x00001bf7, 0x000023f7,
0x00002bf7, 0x000033f7, 0x00003bf7, 0x0001c387, 0x0005c387, 0x0009c387,
0x000dc387, 0x0011c387, 0x0015c387, 0x0019c387, 0x001dc387, 0x0001cb87,
0x0005cb87, 0x0009cb87, 0x000dcb87, 0x0011cb87, 0x0015cb87, 0x0019cb87,
0x001dcb87, 0x0001d387, 0x0005d387, 0x0009d387, 0x000dd387, 0x0011d387,
0x0015d387, 0x0019d387, 0x001dd387, 0x0001db87, 0x0005db87, 0x0009db87,
0x000ddb87, 0x0011db87, 0x0015db87, 0x0019db87, 0x001ddb87, 0x0001e387,
0x0005e387, 0x0009e387, 0x000de387, 0x0011e387, 0x0015e387, 0x0019e387,
0x001de387, 0x0001eb87, 0x0005eb87, 0x0009eb87, 0x000deb87, 0x0011eb87,
0x0015eb87, 0x0019eb87, 0x001deb87, 0x0001f387, 0x0005f387, 0x0009f387,
0x000df387, 0x0011f387, 0x0015f387, 0x0019f387, 0x001df387, 0x0001fb87,
0x0005fb87, 0x0009fb87, 0x000dfb87, 0x0011fb87, 0x0015fb87, 0x0019fb87,
0x001dfb87, 0x0001c397, 0x0005c397, 0x0009c397, 0x000dc397, 0x0011c397,
0x0015c397, 0x0019c397, 0x001dc397, 0x0001cb97, 0x0005cb97, 0x0009cb97,
0x000dcb97, 0x0011cb97, 0x0015cb97, 0x0019cb97, 0x001dcb97, 0x0001d397,
0x0005d397, 0x0009d397, 0x000dd397, 0x0011d397, 0x0015d397, 0x0019d397,
0x001dd397, 0x0001db97, 0x0005db97, 0x0009db97, 0x000ddb97, 0x0011db97,
0x0015db97, 0x0019db97, 0x001ddb97, 0x0001e397, 0x0005e397, 0x0009e397,
0x000de397, 0x0011e397, 0x0015e397, 0x0019e397, 0x001de397, 0x0001eb97,
0x0005eb97, 0x0009eb97, 0x000deb97, 0x0011eb97, 0x0015eb97, 0x0019eb97,
0x001deb97, 0x0001f397, 0x0005f397, 0x0009f397, 0x000df397, 0x0011f397,
0x0015f397, 0x0019f397, 0x001df397, 0x0001fb97, 0x0005fb97, 0x0009fb97,
0x000dfb97, 0x0011fb97, 0x0015fb97, 0x0019fb97, 0x001dfb97, 0x0001c3a7,
0x0005c3a7, 0x0009c3a7, 0x000dc3a7, 0x0011c3a7, 0x0015c3a7, 0x0019c3a7,
0x001dc3a7, 0x0001cba7, 0x0005cba7, 0x0009cba7, 0x000dcba7, 0x0011cba7,
0x0015cba7, 0x0019cba7, 0x001dcba7, 0x0001d3a7, 0x0005d3a7, 0x0009d3a7,
0x000dd3a7, 0x0011d3a7, 0x0015d3a7, 0x0019d3a7, 0x001dd3a7, 0x0001dba7,
0x0005dba7, 0x0009dba7, 0x000ddba7, 0x0011dba7, 0x0015dba7, 0x0019dba7,
0x001ddba7, 0x0001e3a7, 0x0005e3a7, 0x0009e3a7, 0x000de3a7, 0x0011e3a7,
0x0015e3a7, 0x0019e3a7, 0x001de3a7, 0x0001eba7, 0x0005eba7, 0x0009eba7,
0x000deba7, 0x0011eba7, 0x0015eba7, 0x0019eba7, 0x001deba7, 0x0001f3a7,
0x0005f3a7, 0x0009f3a7, 0x000df3a7, 0x0011f3a7, 0x0015f3a7, 0x0019f3a7,
0x001df3a7, 0x0001fba7, 0x0005fba7, 0x0009fba7, 0x000dfba7, 0x0011fba7,
0x0015fba7, 0x0019fba7, 0x001dfba7, 0x0001c3b7, 0x0005c3b7, 0x0009c3b7,
0x000dc3b7, 0x0011c3b7, 0x0015c3b7, 0x0019c3b7, 0x001dc3b7, 0x0001cbb7,
0x0005cbb7, 0x0009cbb7, 0x000dcbb7, 0x0011cbb7, 0x0015cbb7, 0x0019cbb7,
0x001dcbb7, 0x0001d3b7, 0x0005d3b7, 0x0009d3b7, 0x000dd3b7, 0x0011d3b7,
0x0015d3b7, 0x0019d3b7, 0x001dd3b7, 0x0001dbb7, 0x0005dbb7, 0x0009dbb7,
0x000ddbb7, 0x0011dbb7, 0x0015dbb7, 0x0019dbb7, 0x001ddbb7, 0x0001e3b7,
0x0005e3b7, 0x0009e3b7, 0x000de3b7, 0x0011e3b7, 0x0015e3b7, 0x0019e3b7,
0x001de3b7, 0x0001ebb7, 0x0005ebb7, 0x0009ebb7, 0x000debb7, 0x0011ebb7,
0x0015ebb7, 0x0019ebb7, 0x001debb7, 0x0001f3b7, 0x0005f3b7, 0x0009f3b7,
0x000df3b7, 0x0011f3b7, 0x0015f3b7, 0x0019f3b7, 0x001df3b7, 0x0001fbb7,
0x0005fbb7, 0x0009fbb7, 0x000dfbb7, 0x0011fbb7, 0x0015fbb7, 0x0019fbb7,
0x001dfbb7, 0x0001c3c7, 0x0005c3c7, 0x0009c3c7, 0x000dc3c7, 0x0011c3c7,
0x0015c3c7, 0x0019c3c7, 0x001dc3c7, 0x0001cbc7, 0x0005cbc7, 0x0009cbc7,
0x000dcbc7, 0x0011cbc7, 0x0015cbc7, 0x0019cbc7, 0x001dcbc7, 0x0001d3c7,
0x0005d3c7, 0x0009d3c7, 0x000dd3c7, 0x0011d3c7, 0x0015d3c7, 0x0019d3c7,
0x001dd3c7, 0x0001dbc7, 0x0005dbc7, 0x0009dbc7, 0x000ddbc7, 0x0011dbc7,
0x0015dbc7, 0x0019dbc7, 0x001ddbc7, 0x0001e3c7, 0x0005e3c7, 0x0009e3c7,
0x000de3c7, 0x0011e3c7, 0x0015e3c7, 0x0019e3c7, 0x001de3c7, 0x0001ebc7,
0x0005ebc7, 0x0009ebc7, 0x000debc7, 0x0011ebc7, 0x0015ebc7, 0x0019ebc7,
0x001debc7, 0x0001f3c7, 0x0005f3c7, 0x0009f3c7, 0x000df3c7, 0x0011f3c7,
0x0015f3c7, 0x0019f3c7, 0x001df3c7, 0x0001fbc7, 0x0005fbc7, 0x0009fbc7,
0x000dfbc7, 0x0011fbc7, 0x0015fbc7, 0x0019fbc7, 0x001dfbc7, 0x0001c3d7,
0x0005c3d7, 0x0009c3d7, 0x000dc3d7, 0x0011c3d7, 0x0015c3d7, 0x0019c3d7,
0x001dc3d7, 0x0001cbd7, 0x0005cbd7, 0x0009cbd7, 0x000dcbd7, 0x0011cbd7,
0x0015cbd7, 0x0019cbd7, 0x001dcbd7, 0x0001d3d7, 0x0005d3d7, 0x0009d3d7,
0x000dd3d7, 0x0011d3d7, 0x0015d3d7, 0x0019d3d7, 0x001dd3d7, 0x0001dbd7,
0x0005dbd7, 0x0009dbd7, 0x000ddbd7, 0x0011dbd7, 0x0015dbd7, 0x0019dbd7,
0x001ddbd7, 0x0001e3d7, 0x0005e3d7, 0x0009e3d7, 0x000de3d7, 0x0011e3d7,
0x0015e3d7, 0x0019e3d7, 0x001de3d7, 0x0001ebd7, 0x0005ebd7, 0x0009ebd7,
0x000debd7, 0x0011ebd7, 0x0015ebd7, 0x0019ebd7, 0x001debd7, 0x0001f3d7,
0x0005f3d7, 0x0009f3d7, 0x000df3d7, 0x0011f3d7, 0x0015f3d7, 0x0019f3d7,
0x001df3d7, 0x0001fbd7, 0x0005fbd7, 0x0009fbd7, 0x000dfbd7, 0x0011fbd7,
0x0015fbd7, 0x0019fbd7, 0x001dfbd7, 0x0001c3e7, 0x0005c3e7, 0x0009c3e7,
0x000dc3e7, 0x0011c3e7, 0x0015c3e7, 0x0019c3e7, 0x001dc3e7, 0x0001cbe7,
0x0005cbe7, 0x0009cbe7, 0x000dcbe7, 0x0011cbe7, 0x0015cbe7, 0x0019cbe7,
0x001dcbe7, 0x0001d3e7, 0x0005d3e7, 0x0009d3e7, 0x000dd3e7, 0x0011d3e7,
0x0015d3e7, 0x0019d3e7, 0x001dd3e7, 0x0001dbe7, 0x0005dbe7, 0x0009dbe7,
0x000ddbe7, 0x0011dbe7, 0x0015dbe7, 0x0019dbe7, 0x001ddbe7, 0x0001e3e7,
0x0005e3e7, 0x0009e3e7, 0x000de3e7, 0x0011e3e7, 0x0015e3e7, 0x0019e3e7,
0x001de3e7, 0x0001ebe7, 0x0005ebe7, 0x0009ebe7, 0x000debe7, 0x0011ebe7,
0x0015ebe7, 0x0019ebe7, 0x001debe7, 0x0001f3e7, 0x0005f3e7, 0x0009f3e7,
0x000df3e7, 0x0011f3e7, 0x0015f3e7, 0x0019f3e7, 0x001df3e7, 0x0001fbe7,
0x0005fbe7, 0x0009fbe7, 0x000dfbe7, 0x0011fbe7, 0x0015fbe7, 0x0019fbe7,
0x001dfbe7, 0x0001c3f7, 0x0005c3f7, 0x0009c3f7, 0x000dc3f7, 0x0011c3f7,
0x0015c3f7, 0x0019c3f7, 0x001dc3f7, 0x0001cbf7, 0x0005cbf7, 0x0009cbf7,
0x000dcbf7, 0x0011cbf7, 0x0015cbf7, 0x0019cbf7, 0x001dcbf7, 0x0001d3f7,
0x0005d3f7, 0x0009d3f7, 0x000dd3f7, 0x0011d3f7, 0x0015d3f7, 0x0019d3f7,
0x001dd3f7, 0x0001dbf7, 0x0005dbf7, 0x0009dbf7, 0x000ddbf7, 0x0011dbf7,
0x0015dbf7, 0x0019dbf7, 0x001ddbf7, 0x0001e3f7, 0x0005e3f7, 0x0009e3f7,
0x000de3f7, 0x0011e3f7, 0x0015e3f7, 0x0019e3f7, 0x001de3f7, 0x0001ebf7,
0x0005ebf7, 0x0009ebf7, 0x000debf7, 0x0011ebf7, 0x0015ebf7, 0x0019ebf7,
0x001debf7, 0x0001f3f7, 0x0005f3f7, 0x0009f3f7, 0x000df3f7, 0x0011f3f7,
0x0015f3f7, 0x0019f3f7, 0x001df3f7, 0x0001fbf7, 0x0005fbf7, 0x0009fbf7,
0x000dfbf7, 0x0011fbf7, 0x0015fbf7, 0x0019fbf7, 0x001dfbf7, 0x00e1c387,
0x02e1c387, 0x04e1c387, 0x06e1c387, 0x08e1c387, 0x0ae1c387, 0x0ce1c387,
0x0ee1c387, 0x00e5c387, 0x02e5c387, 0x04e5c387, 0x06e5c387, 0x08e5c387,
0x0ae5c387, 0x0ce5c387, 0x0ee5c387, 0x00e9c387, 0x02e9c387, 0x04e9c387,
0x06e9c387, 0x08e9c387, 0x0ae9c387, 0x0ce9c387, 0x0ee9c387, 0x00edc387,
0x02edc387, 0x04edc387, 0x06edc387, 0x08edc387, 0x0aedc387, 0x0cedc387,
0x0eedc387, 0x00f1c387, 0x02f1c387, 0x04f1c387, 0x06f1c387, 0x08f1c387,
0x0af1c387, 0x0cf1c387, 0x0ef1c387, 0x00f5c387, 0x02f5c387, 0x04f5c387,
0x06f5c387, 0x08f5c387, 0x0af5c387, 0x0cf5c387, 0x0ef5c387, 0x00f9c387,
0x02f9c387, 0x04f9c387, 0x06f9c387, 0x08f9c387, 0x0af9c387, 0x0cf9c387,
0x0ef9c387, 0x00fdc387, 0x02fdc387, 0x04fdc387, 0x06fdc387, 0x08fdc387,
0x0afdc387, 0x0cfdc387, 0x0efdc387, 0x00e1cb87, 0x02e1cb87, 0x04e1cb87,
0x06e1cb87, 0x08e1cb87, 0x0ae1cb87, 0x0ce1cb87, 0x0ee1cb87, 0x00e5cb87,
0x02e5cb87, 0x04e5cb87, 0x06e5cb87, 0x08e5cb87, 0x0ae5cb87, 0x0ce5cb87,
0x0ee5cb87, 0x00e9cb87, 0x02e9cb87, 0x04e9cb87, 0x06e9cb87, 0x08e9cb87,
0x0ae9cb87, 0x0ce9cb87, 0x0ee9cb87, 0x00edcb87, 0x02edcb87, 0x04edcb87,
0x06edcb87, 0x08edcb87, 0x0aedcb87, 0x0cedcb87, 0x0eedcb87, 0x00f1cb87,
0x02f1cb87, 0x04f1cb87, 0x06f1cb87, 0x08f1cb87, 0x0af1cb87, 0x0cf1cb87,
0x0ef1cb87, 0x00f5cb87, 0x02f5cb87, 0x04f5cb87, 0x06f5cb87, 0x08f5cb87,
0x0af5cb87, 0x0cf5cb87, 0x0ef5cb87, 0x00f9cb87, 0x02f9cb87, 0x04f9cb87,
0x06f9cb87, 0x08f9cb87,
};
static const uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
0, 4, 8, 7, 7, 7, 7, 7, 7, 7, 7, 11, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
};
static const uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
0x0000000b, 0x0000001b, 0x0000002b, 0x0000003b, 0x000002cb, 0x000006cb,
0x00000acb, 0x00000ecb, 0x000002db, 0x000006db, 0x00000adb, 0x00000edb,
0x000002eb, 0x000006eb, 0x00000aeb, 0x00000eeb, 0x000002fb, 0x000006fb,
0x00000afb, 0x00000efb, 0x0000b2cb, 0x0001b2cb, 0x0002b2cb, 0x0003b2cb,
0x0000b6cb, 0x0001b6cb, 0x0002b6cb, 0x0003b6cb, 0x0000bacb, 0x0001bacb,
0x0002bacb, 0x0003bacb, 0x0000becb, 0x0001becb, 0x0002becb, 0x0003becb,
0x0000b2db, 0x0001b2db, 0x0002b2db, 0x0003b2db, 0x0000b6db, 0x0001b6db,
0x0002b6db, 0x0003b6db, 0x0000badb, 0x0001badb, 0x0002badb, 0x0003badb,
0x0000bedb, 0x0001bedb, 0x0002bedb, 0x0003bedb, 0x0000b2eb, 0x0001b2eb,
0x0002b2eb, 0x0003b2eb, 0x0000b6eb, 0x0001b6eb, 0x0002b6eb, 0x0003b6eb,
0x0000baeb, 0x0001baeb, 0x0002baeb, 0x0003baeb, 0x0000beeb, 0x0001beeb,
0x0002beeb, 0x0003beeb, 0x0000b2fb, 0x0001b2fb, 0x0002b2fb, 0x0003b2fb,
0x0000b6fb, 0x0001b6fb, 0x0002b6fb, 0x0003b6fb, 0x0000bafb, 0x0001bafb,
0x0002bafb, 0x0003bafb, 0x0000befb, 0x0001befb, 0x0002befb, 0x0003befb,
0x002cb2cb, 0x006cb2cb, 0x00acb2cb, 0x00ecb2cb, 0x002db2cb, 0x006db2cb,
0x00adb2cb, 0x00edb2cb, 0x002eb2cb, 0x006eb2cb, 0x00aeb2cb, 0x00eeb2cb,
0x002fb2cb, 0x006fb2cb, 0x00afb2cb, 0x00efb2cb, 0x002cb6cb, 0x006cb6cb,
0x00acb6cb, 0x00ecb6cb, 0x002db6cb, 0x006db6cb, 0x00adb6cb, 0x00edb6cb,
0x002eb6cb, 0x006eb6cb, 0x00aeb6cb, 0x00eeb6cb, 0x002fb6cb, 0x006fb6cb,
0x00afb6cb, 0x00efb6cb, 0x002cbacb, 0x006cbacb, 0x00acbacb, 0x00ecbacb,
0x002dbacb, 0x006dbacb, 0x00adbacb, 0x00edbacb, 0x002ebacb, 0x006ebacb,
0x00aebacb, 0x00eebacb, 0x002fbacb, 0x006fbacb, 0x00afbacb, 0x00efbacb,
0x002cbecb, 0x006cbecb, 0x00acbecb, 0x00ecbecb, 0x002dbecb, 0x006dbecb,
0x00adbecb, 0x00edbecb, 0x002ebecb, 0x006ebecb, 0x00aebecb, 0x00eebecb,
0x002fbecb, 0x006fbecb, 0x00afbecb, 0x00efbecb, 0x002cb2db, 0x006cb2db,
0x00acb2db, 0x00ecb2db, 0x002db2db, 0x006db2db, 0x00adb2db, 0x00edb2db,
0x002eb2db, 0x006eb2db, 0x00aeb2db, 0x00eeb2db, 0x002fb2db, 0x006fb2db,
0x00afb2db, 0x00efb2db, 0x002cb6db, 0x006cb6db, 0x00acb6db, 0x00ecb6db,
0x002db6db, 0x006db6db, 0x00adb6db, 0x00edb6db, 0x002eb6db, 0x006eb6db,
0x00aeb6db, 0x00eeb6db, 0x002fb6db, 0x006fb6db, 0x00afb6db, 0x00efb6db,
0x002cbadb, 0x006cbadb, 0x00acbadb, 0x00ecbadb, 0x002dbadb, 0x006dbadb,
0x00adbadb, 0x00edbadb, 0x002ebadb, 0x006ebadb, 0x00aebadb, 0x00eebadb,
0x002fbadb, 0x006fbadb, 0x00afbadb, 0x00efbadb, 0x002cbedb, 0x006cbedb,
0x00acbedb, 0x00ecbedb, 0x002dbedb, 0x006dbedb, 0x00adbedb, 0x00edbedb,
0x002ebedb, 0x006ebedb, 0x00aebedb, 0x00eebedb, 0x002fbedb, 0x006fbedb,
0x00afbedb, 0x00efbedb, 0x002cb2eb, 0x006cb2eb, 0x00acb2eb, 0x00ecb2eb,
0x002db2eb, 0x006db2eb, 0x00adb2eb, 0x00edb2eb, 0x002eb2eb, 0x006eb2eb,
0x00aeb2eb, 0x00eeb2eb, 0x002fb2eb, 0x006fb2eb, 0x00afb2eb, 0x00efb2eb,
0x002cb6eb, 0x006cb6eb, 0x00acb6eb, 0x00ecb6eb, 0x002db6eb, 0x006db6eb,
0x00adb6eb, 0x00edb6eb, 0x002eb6eb, 0x006eb6eb, 0x00aeb6eb, 0x00eeb6eb,
0x002fb6eb, 0x006fb6eb, 0x00afb6eb, 0x00efb6eb, 0x002cbaeb, 0x006cbaeb,
0x00acbaeb, 0x00ecbaeb, 0x002dbaeb, 0x006dbaeb, 0x00adbaeb, 0x00edbaeb,
0x002ebaeb, 0x006ebaeb, 0x00aebaeb, 0x00eebaeb, 0x002fbaeb, 0x006fbaeb,
0x00afbaeb, 0x00efbaeb, 0x002cbeeb, 0x006cbeeb, 0x00acbeeb, 0x00ecbeeb,
0x002dbeeb, 0x006dbeeb, 0x00adbeeb, 0x00edbeeb, 0x002ebeeb, 0x006ebeeb,
0x00aebeeb, 0x00eebeeb, 0x002fbeeb, 0x006fbeeb, 0x00afbeeb, 0x00efbeeb,
0x002cb2fb, 0x006cb2fb, 0x00acb2fb, 0x00ecb2fb, 0x002db2fb, 0x006db2fb,
0x00adb2fb, 0x00edb2fb, 0x002eb2fb, 0x006eb2fb, 0x00aeb2fb, 0x00eeb2fb,
0x002fb2fb, 0x006fb2fb, 0x00afb2fb, 0x00efb2fb, 0x002cb6fb, 0x006cb6fb,
0x00acb6fb, 0x00ecb6fb, 0x002db6fb, 0x006db6fb, 0x00adb6fb, 0x00edb6fb,
0x002eb6fb, 0x006eb6fb, 0x00aeb6fb, 0x00eeb6fb, 0x002fb6fb, 0x006fb6fb,
0x00afb6fb, 0x00efb6fb, 0x002cbafb, 0x006cbafb, 0x00acbafb, 0x00ecbafb,
0x002dbafb, 0x006dbafb, 0x00adbafb, 0x00edbafb, 0x002ebafb, 0x006ebafb,
0x00aebafb, 0x00eebafb, 0x002fbafb, 0x006fbafb, 0x00afbafb, 0x00efbafb,
0x002cbefb, 0x006cbefb, 0x00acbefb, 0x00ecbefb, 0x002dbefb, 0x006dbefb,
0x00adbefb, 0x00edbefb, 0x002ebefb, 0x006ebefb, 0x00aebefb, 0x00eebefb,
0x002fbefb, 0x006fbefb, 0x00afbefb, 0x00efbefb, 0x0b2cb2cb, 0x1b2cb2cb,
0x2b2cb2cb, 0x3b2cb2cb, 0x0b6cb2cb, 0x1b6cb2cb, 0x2b6cb2cb, 0x3b6cb2cb,
0x0bacb2cb, 0x1bacb2cb, 0x2bacb2cb, 0x3bacb2cb, 0x0becb2cb, 0x1becb2cb,
0x2becb2cb, 0x3becb2cb, 0x0b2db2cb, 0x1b2db2cb, 0x2b2db2cb, 0x3b2db2cb,
0x0b6db2cb, 0x1b6db2cb, 0x2b6db2cb, 0x3b6db2cb, 0x0badb2cb, 0x1badb2cb,
0x2badb2cb, 0x3badb2cb, 0x0bedb2cb, 0x1bedb2cb, 0x2bedb2cb, 0x3bedb2cb,
0x0b2eb2cb, 0x1b2eb2cb, 0x2b2eb2cb, 0x3b2eb2cb, 0x0b6eb2cb, 0x1b6eb2cb,
0x2b6eb2cb, 0x3b6eb2cb, 0x0baeb2cb, 0x1baeb2cb, 0x2baeb2cb, 0x3baeb2cb,
0x0beeb2cb, 0x1beeb2cb, 0x2beeb2cb, 0x3beeb2cb, 0x0b2fb2cb, 0x1b2fb2cb,
0x2b2fb2cb, 0x3b2fb2cb, 0x0b6fb2cb, 0x1b6fb2cb, 0x2b6fb2cb, 0x3b6fb2cb,
0x0bafb2cb, 0x1bafb2cb, 0x2bafb2cb, 0x3bafb2cb, 0x0befb2cb, 0x1befb2cb,
0x2befb2cb, 0x3befb2cb, 0x0b2cb6cb, 0x1b2cb6cb, 0x2b2cb6cb, 0x3b2cb6cb,
0x0b6cb6cb, 0x1b6cb6cb, 0x2b6cb6cb, 0x3b6cb6cb, 0x0bacb6cb, 0x1bacb6cb,
0x2bacb6cb, 0x3bacb6cb, 0x0becb6cb, 0x1becb6cb, 0x2becb6cb, 0x3becb6cb,
0x0b2db6cb, 0x1b2db6cb, 0x2b2db6cb, 0x3b2db6cb, 0x0b6db6cb, 0x1b6db6cb,
0x2b6db6cb, 0x3b6db6cb, 0x0badb6cb, 0x1badb6cb, 0x2badb6cb, 0x3badb6cb,
0x0bedb6cb, 0x1bedb6cb, 0x2bedb6cb, 0x3bedb6cb, 0x0b2eb6cb, 0x1b2eb6cb,
0x2b2eb6cb, 0x3b2eb6cb, 0x0b6eb6cb, 0x1b6eb6cb, 0x2b6eb6cb, 0x3b6eb6cb,
0x0baeb6cb, 0x1baeb6cb, 0x2baeb6cb, 0x3baeb6cb, 0x0beeb6cb, 0x1beeb6cb,
0x2beeb6cb, 0x3beeb6cb, 0x0b2fb6cb, 0x1b2fb6cb, 0x2b2fb6cb, 0x3b2fb6cb,
0x0b6fb6cb, 0x1b6fb6cb, 0x2b6fb6cb, 0x3b6fb6cb, 0x0bafb6cb, 0x1bafb6cb,
0x2bafb6cb, 0x3bafb6cb, 0x0befb6cb, 0x1befb6cb, 0x2befb6cb, 0x3befb6cb,
0x0b2cbacb, 0x1b2cbacb, 0x2b2cbacb, 0x3b2cbacb, 0x0b6cbacb, 0x1b6cbacb,
0x2b6cbacb, 0x3b6cbacb, 0x0bacbacb, 0x1bacbacb, 0x2bacbacb, 0x3bacbacb,
0x0becbacb, 0x1becbacb, 0x2becbacb, 0x3becbacb, 0x0b2dbacb, 0x1b2dbacb,
0x2b2dbacb, 0x3b2dbacb, 0x0b6dbacb, 0x1b6dbacb, 0x2b6dbacb, 0x3b6dbacb,
0x0badbacb, 0x1badbacb, 0x2badbacb, 0x3badbacb, 0x0bedbacb, 0x1bedbacb,
0x2bedbacb, 0x3bedbacb, 0x0b2ebacb, 0x1b2ebacb, 0x2b2ebacb, 0x3b2ebacb,
0x0b6ebacb, 0x1b6ebacb, 0x2b6ebacb, 0x3b6ebacb, 0x0baebacb, 0x1baebacb,
0x2baebacb, 0x3baebacb, 0x0beebacb, 0x1beebacb, 0x2beebacb, 0x3beebacb,
0x0b2fbacb, 0x1b2fbacb, 0x2b2fbacb, 0x3b2fbacb, 0x0b6fbacb, 0x1b6fbacb,
0x2b6fbacb, 0x3b6fbacb, 0x0bafbacb, 0x1bafbacb, 0x2bafbacb, 0x3bafbacb,
0x0befbacb, 0x1befbacb, 0x2befbacb, 0x3befbacb, 0x0b2cbecb, 0x1b2cbecb,
0x2b2cbecb, 0x3b2cbecb, 0x0b6cbecb, 0x1b6cbecb, 0x2b6cbecb, 0x3b6cbecb,
0x0bacbecb, 0x1bacbecb, 0x2bacbecb, 0x3bacbecb, 0x0becbecb, 0x1becbecb,
0x2becbecb, 0x3becbecb, 0x0b2dbecb, 0x1b2dbecb, 0x2b2dbecb, 0x3b2dbecb,
0x0b6dbecb, 0x1b6dbecb, 0x2b6dbecb, 0x3b6dbecb, 0x0badbecb, 0x1badbecb,
0x2badbecb, 0x3badbecb, 0x0bedbecb, 0x1bedbecb, 0x2bedbecb, 0x3bedbecb,
0x0b2ebecb, 0x1b2ebecb, 0x2b2ebecb, 0x3b2ebecb, 0x0b6ebecb, 0x1b6ebecb,
0x2b6ebecb, 0x3b6ebecb, 0x0baebecb, 0x1baebecb, 0x2baebecb, 0x3baebecb,
0x0beebecb, 0x1beebecb, 0x2beebecb, 0x3beebecb, 0x0b2fbecb, 0x1b2fbecb,
0x2b2fbecb, 0x3b2fbecb, 0x0b6fbecb, 0x1b6fbecb, 0x2b6fbecb, 0x3b6fbecb,
0x0bafbecb, 0x1bafbecb, 0x2bafbecb, 0x3bafbecb, 0x0befbecb, 0x1befbecb,
0x2befbecb, 0x3befbecb, 0x0b2cb2db, 0x1b2cb2db, 0x2b2cb2db, 0x3b2cb2db,
0x0b6cb2db, 0x1b6cb2db, 0x2b6cb2db, 0x3b6cb2db, 0x0bacb2db, 0x1bacb2db,
0x2bacb2db, 0x3bacb2db, 0x0becb2db, 0x1becb2db, 0x2becb2db, 0x3becb2db,
0x0b2db2db, 0x1b2db2db, 0x2b2db2db, 0x3b2db2db, 0x0b6db2db, 0x1b6db2db,
0x2b6db2db, 0x3b6db2db, 0x0badb2db, 0x1badb2db, 0x2badb2db, 0x3badb2db,
0x0bedb2db, 0x1bedb2db, 0x2bedb2db, 0x3bedb2db, 0x0b2eb2db, 0x1b2eb2db,
0x2b2eb2db, 0x3b2eb2db, 0x0b6eb2db, 0x1b6eb2db, 0x2b6eb2db, 0x3b6eb2db,
0x0baeb2db, 0x1baeb2db, 0x2baeb2db, 0x3baeb2db, 0x0beeb2db, 0x1beeb2db,
0x2beeb2db, 0x3beeb2db, 0x0b2fb2db, 0x1b2fb2db, 0x2b2fb2db, 0x3b2fb2db,
0x0b6fb2db, 0x1b6fb2db, 0x2b6fb2db, 0x3b6fb2db, 0x0bafb2db, 0x1bafb2db,
0x2bafb2db, 0x3bafb2db, 0x0befb2db, 0x1befb2db, 0x2befb2db, 0x3befb2db,
0x0b2cb6db, 0x1b2cb6db, 0x2b2cb6db, 0x3b2cb6db, 0x0b6cb6db, 0x1b6cb6db,
0x2b6cb6db, 0x3b6cb6db, 0x0bacb6db, 0x1bacb6db, 0x2bacb6db, 0x3bacb6db,
0x0becb6db, 0x1becb6db, 0x2becb6db, 0x3becb6db, 0x0b2db6db, 0x1b2db6db,
0x2b2db6db, 0x3b2db6db, 0x0b6db6db, 0x1b6db6db, 0x2b6db6db, 0x3b6db6db,
0x0badb6db, 0x1badb6db, 0x2badb6db, 0x3badb6db, 0x0bedb6db, 0x1bedb6db,
0x2bedb6db, 0x3bedb6db, 0x0b2eb6db, 0x1b2eb6db, 0x2b2eb6db, 0x3b2eb6db,
0x0b6eb6db, 0x1b6eb6db, 0x2b6eb6db, 0x3b6eb6db, 0x0baeb6db, 0x1baeb6db,
0x2baeb6db, 0x3baeb6db,
};
static const uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = {
6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
18, 18, 18, 18, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24,
24, 24, 24, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
};
static const uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = {
0, 256, 128, 384, 64, 320, 192, 448,
32, 288, 160, 416, 96, 352, 224, 480,
16, 272, 144, 400, 80, 336, 208, 464,
48, 304, 176, 432, 112, 368, 240, 496,
8, 264, 136, 392, 72, 328, 200, 456,
40, 296, 168, 424, 104, 360, 232, 488,
24, 280, 152, 408, 88, 344, 216, 472,
56, 312, 184, 440, 120, 376, 248, 504,
4, 260, 132, 388, 68, 324, 196, 452,
36, 292, 164, 420, 100, 356, 228, 484,
20, 276, 148, 404, 84, 340, 212, 468,
52, 308, 180, 436, 116, 372, 244, 500,
12, 268, 140, 396, 76, 332, 204, 460,
44, 300, 172, 428, 108, 364, 236, 492,
28, 284, 156, 412, 92, 348, 220, 476,
60, 316, 188, 444, 124, 380, 252, 508,
2, 258, 130, 386, 66, 322, 194, 450,
34, 290, 162, 418, 98, 354, 226, 482,
18, 274, 146, 402, 82, 338, 210, 466,
50, 306, 178, 434, 114, 370, 242, 498,
10, 266, 138, 394, 74, 330, 202, 458,
42, 298, 170, 426, 106, 362, 234, 490,
26, 282, 154, 410, 90, 346, 218, 474,
58, 314, 186, 442, 122, 378, 250, 506,
6, 262, 134, 390, 70, 326, 198, 454,
38, 294, 166, 422, 102, 358, 230, 486,
22, 278, 150, 406, 86, 342, 214, 470,
54, 310, 182, 438, 118, 374, 246, 502,
14, 270, 142, 398, 78, 334, 206, 462,
46, 302, 174, 430, 110, 366, 238, 494,
30, 286, 158, 414, 94, 350, 222, 478,
62, 318, 190, 446, 126, 382, 254, 510,
1, 257, 129, 385, 65, 321, 193, 449,
33, 289, 161, 417, 97, 353, 225, 481,
17, 273, 145, 401, 81, 337, 209, 465,
49, 305, 177, 433, 113, 369, 241, 497,
9, 265, 137, 393, 73, 329, 201, 457,
41, 297, 169, 425, 105, 361, 233, 489,
25, 281, 153, 409, 89, 345, 217, 473,
57, 313, 185, 441, 121, 377, 249, 505,
5, 261, 133, 389, 69, 325, 197, 453,
37, 293, 165, 421, 101, 357, 229, 485,
21, 277, 149, 405, 85, 341, 213, 469,
53, 309, 181, 437, 117, 373, 245, 501,
13, 269, 141, 397, 77, 333, 205, 461,
45, 301, 173, 429, 109, 365, 237, 493,
29, 285, 157, 413, 93, 349, 221, 477,
61, 317, 189, 445, 125, 381, 253, 509,
3, 259, 131, 387, 67, 323, 195, 451,
35, 291, 163, 419, 99, 355, 227, 483,
19, 275, 147, 403, 83, 339, 211, 467,
51, 307, 179, 435, 115, 371, 243, 499,
11, 267, 139, 395, 75, 331, 203, 459,
43, 299, 171, 427, 107, 363, 235, 491,
27, 283, 155, 411, 91, 347, 219, 475,
59, 315, 187, 443, 123, 379, 251, 507,
7, 1031, 519, 1543, 263, 1287, 775, 1799,
135, 1159, 647, 1671, 391, 1415, 903, 1927,
71, 1095, 583, 1607, 327, 1351, 839, 1863,
199, 1223, 711, 1735, 455, 1479, 967, 1991,
39, 1063, 551, 1575, 295, 1319, 807, 1831,
167, 1191, 679, 1703, 423, 1447, 935, 1959,
103, 1127, 615, 1639, 359, 1383, 871, 1895,
231, 1255, 743, 1767, 487, 1511, 999, 2023,
23, 1047, 535, 1559, 279, 1303, 791, 1815,
151, 1175, 663, 1687, 407, 1431, 919, 1943,
87, 1111, 599, 1623, 343, 1367, 855, 1879,
215, 1239, 727, 1751, 471, 1495, 983, 2007,
55, 1079, 567, 1591, 311, 1335, 823, 1847,
183, 1207, 695, 1719, 439, 1463, 951, 1975,
119, 1143, 631, 1655, 375, 1399, 887, 1911,
247, 1271, 759, 1783, 503, 1527, 1015, 2039,
15, 1039, 527, 1551, 271, 1295, 783, 1807,
143, 1167, 655, 1679, 399, 1423, 911, 1935,
79, 1103, 591, 1615, 335, 1359, 847, 1871,
207, 1231, 719, 1743, 463, 1487, 975, 1999,
47, 1071, 559, 1583, 303, 1327, 815, 1839,
175, 1199, 687, 1711, 431, 1455, 943, 1967,
111, 1135, 623, 1647, 367, 1391, 879, 1903,
239, 1263, 751, 1775, 495, 1519, 1007, 2031,
31, 1055, 543, 1567, 287, 1311, 799, 1823,
159, 1183, 671, 1695, 415, 1439, 927, 1951,
95, 1119, 607, 1631, 351, 1375, 863, 1887,
223, 1247, 735, 1759, 479, 1503, 991, 2015,
63, 1087, 575, 1599, 319, 1343, 831, 1855,
191, 1215, 703, 1727, 447, 1471, 959, 1983,
127, 1151, 639, 1663, 383, 1407, 895, 1919,
255, 1279, 767, 1791, 511, 1535, 1023, 2047,
};
static BROTLI_INLINE void StoreStaticCommandHuffmanTree(
size_t* storage_ix, uint8_t* storage) {
BrotliWriteBits(
56, BROTLI_MAKE_UINT64_T(0x926244U, 0x16307003U), storage_ix, storage);
BrotliWriteBits(3, 0x00000000U, storage_ix, storage);
}
static const uint16_t kStaticDistanceCodeBits[64] = {
0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60,
2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62,
1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61,
3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63,
};
static BROTLI_INLINE void StoreStaticDistanceHuffmanTree(
size_t* storage_ix, uint8_t* storage) {
BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage);
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_ */
@@ -0,0 +1,66 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Utilities for fast computation of logarithms. */
#ifndef BROTLI_ENC_FAST_LOG_H_
#define BROTLI_ENC_FAST_LOG_H_
#include <math.h>
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) {
#if defined(BROTLI_BSR32)
return BROTLI_BSR32((uint32_t)n);
#else
uint32_t result = 0;
while (n >>= 1) result++;
return result;
#endif
}
#define BROTLI_LOG2_TABLE_SIZE 256
/* A lookup table for small values of log2(int) to be used in entropy
computation. */
BROTLI_INTERNAL extern const double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE];
/* Visual Studio 2012 and Android API levels < 18 do not have the log2()
* function defined, so we use log() and a multiplication instead. */
#if !defined(BROTLI_HAVE_LOG2)
#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \
(defined(__ANDROID_API__) && __ANDROID_API__ < 18))
#define BROTLI_HAVE_LOG2 0
#else
#define BROTLI_HAVE_LOG2 1
#endif
#endif
#define LOG_2_INV 1.4426950408889634
/* Faster logarithm for small integers, with the property of log2(0) == 0. */
static BROTLI_INLINE double FastLog2(size_t v) {
if (v < BROTLI_LOG2_TABLE_SIZE) {
return kBrotliLog2Table[v];
}
#if !(BROTLI_HAVE_LOG2)
return log((double)v) * LOG_2_INV;
#else
return log2((double)v);
#endif
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_FAST_LOG_H_ */
@@ -0,0 +1,79 @@
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Function to find maximal matching prefixes of strings. */
#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_
#define BROTLI_ENC_FIND_MATCH_LENGTH_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Separate implementation for little-endian 64-bit targets, for speed. */
#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
const uint8_t* s2,
size_t limit) {
size_t matched = 0;
size_t limit2 = (limit >> 3) + 1; /* + 1 is for pre-decrement in while */
while (BROTLI_PREDICT_TRUE(--limit2)) {
if (BROTLI_PREDICT_FALSE(BROTLI_UNALIGNED_LOAD64LE(s2) ==
BROTLI_UNALIGNED_LOAD64LE(s1 + matched))) {
s2 += 8;
matched += 8;
} else {
uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^
BROTLI_UNALIGNED_LOAD64LE(s1 + matched);
size_t matching_bits = (size_t)BROTLI_TZCNT64(x);
matched += matching_bits >> 3;
return matched;
}
}
limit = (limit & 7) + 1; /* + 1 is for pre-decrement in while */
while (--limit) {
if (BROTLI_PREDICT_TRUE(s1[matched] == *s2)) {
++s2;
++matched;
} else {
return matched;
}
}
return matched;
}
#else
static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1,
const uint8_t* s2,
size_t limit) {
size_t matched = 0;
const uint8_t* s2_limit = s2 + limit;
const uint8_t* s2_ptr = s2;
/* Find out how long the match is. We loop over the data 32 bits at a
time until we find a 32-bit block that doesn't match; then we find
the first non-matching bit and use that to calculate the total
length of the match. */
while (s2_ptr <= s2_limit - 4 &&
BrotliUnalignedRead32(s2_ptr) ==
BrotliUnalignedRead32(s1 + matched)) {
s2_ptr += 4;
matched += 4;
}
while ((s2_ptr < s2_limit) && (s1[matched] == *s2_ptr)) {
++s2_ptr;
++matched;
}
return matched;
}
#endif
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_FIND_MATCH_LENGTH_H_ */
@@ -0,0 +1,488 @@
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data. */
#ifndef BROTLI_ENC_HASH_H_
#define BROTLI_ENC_HASH_H_
#include <string.h> /* memcmp, memset */
#include "../common/constants.h"
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./encoder_dict.h"
#include "./fast_log.h"
#include "./find_match_length.h"
#include "./memory.h"
#include "./quality.h"
#include "./static_dict.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct {
/* Dynamically allocated area; first member for quickest access. */
void* extra;
size_t dict_num_lookups;
size_t dict_num_matches;
BrotliHasherParams params;
/* False if hasher needs to be "prepared" before use. */
BROTLI_BOOL is_prepared_;
} HasherCommon;
#define score_t size_t
static const uint32_t kCutoffTransformsCount = 10;
/* 0, 12, 27, 23, 42, 63, 56, 48, 59, 64 */
/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */
static const uint64_t kCutoffTransforms =
BROTLI_MAKE_UINT64_T(0x071B520A, 0xDA2D3200);
typedef struct HasherSearchResult {
size_t len;
size_t distance;
score_t score;
int len_code_delta; /* == len_code - len */
} HasherSearchResult;
/* kHashMul32 multiplier has these properties:
* The multiplier must be odd. Otherwise we may lose the highest bit.
* No long streaks of ones or zeros.
* There is no effort to ensure that it is a prime, the oddity is enough
for this use.
* The number has been tuned heuristically against compression benchmarks. */
static const uint32_t kHashMul32 = 0x1E35A7BD;
static const uint64_t kHashMul64 = BROTLI_MAKE_UINT64_T(0x1E35A7BD, 0x1E35A7BD);
static const uint64_t kHashMul64Long =
BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u);
static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return h >> (32 - 14);
}
static BROTLI_INLINE void PrepareDistanceCache(
int* BROTLI_RESTRICT distance_cache, const int num_distances) {
if (num_distances > 4) {
int last_distance = distance_cache[0];
distance_cache[4] = last_distance - 1;
distance_cache[5] = last_distance + 1;
distance_cache[6] = last_distance - 2;
distance_cache[7] = last_distance + 2;
distance_cache[8] = last_distance - 3;
distance_cache[9] = last_distance + 3;
if (num_distances > 10) {
int next_last_distance = distance_cache[1];
distance_cache[10] = next_last_distance - 1;
distance_cache[11] = next_last_distance + 1;
distance_cache[12] = next_last_distance - 2;
distance_cache[13] = next_last_distance + 2;
distance_cache[14] = next_last_distance - 3;
distance_cache[15] = next_last_distance + 3;
}
}
}
#define BROTLI_LITERAL_BYTE_SCORE 135
#define BROTLI_DISTANCE_BIT_PENALTY 30
/* Score must be positive after applying maximal penalty. */
#define BROTLI_SCORE_BASE (BROTLI_DISTANCE_BIT_PENALTY * 8 * sizeof(size_t))
/* Usually, we always choose the longest backward reference. This function
allows for the exception of that rule.
If we choose a backward reference that is further away, it will
usually be coded with more bits. We approximate this by assuming
log2(distance). If the distance can be expressed in terms of the
last four distances, we use some heuristic constants to estimate
the bits cost. For the first up to four literals we use the bit
cost of the literals from the literal cost model, after that we
use the average bit cost of the cost model.
This function is used to sometimes discard a longer backward reference
when it is not much longer and the bit cost for encoding it is more
than the saved literals.
backward_reference_offset MUST be positive. */
static BROTLI_INLINE score_t BackwardReferenceScore(
size_t copy_length, size_t backward_reference_offset) {
return BROTLI_SCORE_BASE + BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length -
BROTLI_DISTANCE_BIT_PENALTY * Log2FloorNonZero(backward_reference_offset);
}
static BROTLI_INLINE score_t BackwardReferenceScoreUsingLastDistance(
size_t copy_length) {
return BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length +
BROTLI_SCORE_BASE + 15;
}
static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance(
size_t distance_short_code) {
return (score_t)39 + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE);
}
static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem(
const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx,
const uint8_t* data, size_t max_length, size_t max_backward,
size_t max_distance, HasherSearchResult* out) {
size_t offset;
size_t matchlen;
size_t backward;
score_t score;
offset = dictionary->words->offsets_by_length[len] + len * word_idx;
if (len > max_length) {
return BROTLI_FALSE;
}
matchlen =
FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len);
if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) {
return BROTLI_FALSE;
}
{
size_t cut = len - matchlen;
size_t transform_id = (cut << 2) +
(size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F);
backward = max_backward + 1 + word_idx +
(transform_id << dictionary->words->size_bits_by_length[len]);
}
if (backward > max_distance) {
return BROTLI_FALSE;
}
score = BackwardReferenceScore(matchlen, backward);
if (score < out->score) {
return BROTLI_FALSE;
}
out->len = matchlen;
out->len_code_delta = (int)len - (int)matchlen;
out->distance = backward;
out->score = score;
return BROTLI_TRUE;
}
static BROTLI_INLINE void SearchInStaticDictionary(
const BrotliEncoderDictionary* dictionary,
HasherCommon* common, const uint8_t* data, size_t max_length,
size_t max_backward, size_t max_distance,
HasherSearchResult* out, BROTLI_BOOL shallow) {
size_t key;
size_t i;
if (common->dict_num_matches < (common->dict_num_lookups >> 7)) {
return;
}
key = Hash14(data) << 1;
for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) {
common->dict_num_lookups++;
if (dictionary->hash_table_lengths[key] != 0) {
BROTLI_BOOL item_matches = TestStaticDictionaryItem(
dictionary, dictionary->hash_table_lengths[key],
dictionary->hash_table_words[key], data,
max_length, max_backward, max_distance, out);
if (item_matches) {
common->dict_num_matches++;
}
}
}
}
typedef struct BackwardMatch {
uint32_t distance;
uint32_t length_and_code;
} BackwardMatch;
static BROTLI_INLINE void InitBackwardMatch(BackwardMatch* self,
size_t dist, size_t len) {
self->distance = (uint32_t)dist;
self->length_and_code = (uint32_t)(len << 5);
}
static BROTLI_INLINE void InitDictionaryBackwardMatch(BackwardMatch* self,
size_t dist, size_t len, size_t len_code) {
self->distance = (uint32_t)dist;
self->length_and_code =
(uint32_t)((len << 5) | (len == len_code ? 0 : len_code));
}
static BROTLI_INLINE size_t BackwardMatchLength(const BackwardMatch* self) {
return self->length_and_code >> 5;
}
static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) {
size_t code = self->length_and_code & 31;
return code ? code : BackwardMatchLength(self);
}
#define EXPAND_CAT(a, b) CAT(a, b)
#define CAT(a, b) a ## b
#define FN(X) EXPAND_CAT(X, HASHER())
#define HASHER() H10
#define BUCKET_BITS 17
#define MAX_TREE_SEARCH_DEPTH 64
#define MAX_TREE_COMP_LENGTH 128
#include "./hash_to_binary_tree_inc.h" /* NOLINT(build/include) */
#undef MAX_TREE_SEARCH_DEPTH
#undef MAX_TREE_COMP_LENGTH
#undef BUCKET_BITS
#undef HASHER
/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */
#define MAX_NUM_MATCHES_H10 128
/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression
a little faster (0.5% - 1%) and it compresses 0.15% better on small text
and HTML inputs. */
#define HASHER() H2
#define BUCKET_BITS 16
#define BUCKET_SWEEP_BITS 0
#define HASH_LEN 5
#define USE_DICTIONARY 1
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef BUCKET_SWEEP_BITS
#undef USE_DICTIONARY
#undef HASHER
#define HASHER() H3
#define BUCKET_SWEEP_BITS 1
#define USE_DICTIONARY 0
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
#define HASHER() H4
#define BUCKET_BITS 17
#define BUCKET_SWEEP_BITS 2
#define USE_DICTIONARY 1
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef HASH_LEN
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
#define HASHER() H5
#include "./hash_longest_match_inc.h" /* NOLINT(build/include) */
#undef HASHER
#define HASHER() H6
#include "./hash_longest_match64_inc.h" /* NOLINT(build/include) */
#undef HASHER
#define BUCKET_BITS 15
#define NUM_LAST_DISTANCES_TO_CHECK 4
#define NUM_BANKS 1
#define BANK_BITS 16
#define HASHER() H40
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
#undef HASHER
#undef NUM_LAST_DISTANCES_TO_CHECK
#define NUM_LAST_DISTANCES_TO_CHECK 10
#define HASHER() H41
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
#undef HASHER
#undef NUM_LAST_DISTANCES_TO_CHECK
#undef NUM_BANKS
#undef BANK_BITS
#define NUM_LAST_DISTANCES_TO_CHECK 16
#define NUM_BANKS 512
#define BANK_BITS 9
#define HASHER() H42
#include "./hash_forgetful_chain_inc.h" /* NOLINT(build/include) */
#undef HASHER
#undef NUM_LAST_DISTANCES_TO_CHECK
#undef NUM_BANKS
#undef BANK_BITS
#undef BUCKET_BITS
#define HASHER() H54
#define BUCKET_BITS 20
#define BUCKET_SWEEP_BITS 2
#define HASH_LEN 7
#define USE_DICTIONARY 0
#include "./hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */
#undef USE_DICTIONARY
#undef HASH_LEN
#undef BUCKET_SWEEP_BITS
#undef BUCKET_BITS
#undef HASHER
/* fast large window hashers */
#define HASHER() HROLLING_FAST
#define CHUNKLEN 32
#define JUMP 4
#define NUMBUCKETS 16777216
#define MASK ((NUMBUCKETS * 64) - 1)
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
#undef JUMP
#undef HASHER
#define HASHER() HROLLING
#define JUMP 1
#include "./hash_rolling_inc.h" /* NOLINT(build/include) */
#undef MASK
#undef NUMBUCKETS
#undef JUMP
#undef CHUNKLEN
#undef HASHER
#define HASHER() H35
#define HASHER_A H3
#define HASHER_B HROLLING_FAST
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
#undef HASHER_A
#undef HASHER_B
#undef HASHER
#define HASHER() H55
#define HASHER_A H54
#define HASHER_B HROLLING_FAST
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
#undef HASHER_A
#undef HASHER_B
#undef HASHER
#define HASHER() H65
#define HASHER_A H6
#define HASHER_B HROLLING
#include "./hash_composite_inc.h" /* NOLINT(build/include) */
#undef HASHER_A
#undef HASHER_B
#undef HASHER
#undef FN
#undef CAT
#undef EXPAND_CAT
#define FOR_SIMPLE_HASHERS(H) H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54)
#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65)
#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H)
#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10)
typedef struct {
HasherCommon common;
union {
#define MEMBER_(N) \
H ## N _H ## N;
FOR_ALL_HASHERS(MEMBER_)
#undef MEMBER_
} privat;
} Hasher;
/* MUST be invoked before any other method. */
static BROTLI_INLINE void HasherInit(Hasher* hasher) {
hasher->common.extra = NULL;
}
static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) {
if (hasher->common.extra == NULL) return;
BROTLI_FREE(m, hasher->common.extra);
}
static BROTLI_INLINE void HasherReset(Hasher* hasher) {
hasher->common.is_prepared_ = BROTLI_FALSE;
}
static BROTLI_INLINE size_t HasherSize(const BrotliEncoderParams* params,
BROTLI_BOOL one_shot, const size_t input_size) {
switch (params->hasher.type) {
#define SIZE_(N) \
case N: \
return HashMemAllocInBytesH ## N(params, one_shot, input_size);
FOR_ALL_HASHERS(SIZE_)
#undef SIZE_
default:
break;
}
return 0; /* Default case. */
}
static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher,
BrotliEncoderParams* params, const uint8_t* data, size_t position,
size_t input_size, BROTLI_BOOL is_last) {
BROTLI_BOOL one_shot = (position == 0 && is_last);
if (hasher->common.extra == NULL) {
size_t alloc_size;
ChooseHasher(params, &params->hasher);
alloc_size = HasherSize(params, one_shot, input_size);
hasher->common.extra = BROTLI_ALLOC(m, uint8_t, alloc_size);
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra)) return;
hasher->common.params = params->hasher;
switch (hasher->common.params.type) {
#define INITIALIZE_(N) \
case N: \
InitializeH ## N(&hasher->common, \
&hasher->privat._H ## N, params); \
break;
FOR_ALL_HASHERS(INITIALIZE_);
#undef INITIALIZE_
default:
break;
}
HasherReset(hasher);
}
if (!hasher->common.is_prepared_) {
switch (hasher->common.params.type) {
#define PREPARE_(N) \
case N: \
PrepareH ## N( \
&hasher->privat._H ## N, \
one_shot, input_size, data); \
break;
FOR_ALL_HASHERS(PREPARE_)
#undef PREPARE_
default: break;
}
if (position == 0) {
hasher->common.dict_num_lookups = 0;
hasher->common.dict_num_matches = 0;
}
hasher->common.is_prepared_ = BROTLI_TRUE;
}
}
static BROTLI_INLINE void InitOrStitchToPreviousBlock(
MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask,
BrotliEncoderParams* params, size_t position, size_t input_size,
BROTLI_BOOL is_last) {
HasherSetup(m, hasher, params, data, position, input_size, is_last);
if (BROTLI_IS_OOM(m)) return;
switch (hasher->common.params.type) {
#define INIT_(N) \
case N: \
StitchToPreviousBlockH ## N( \
&hasher->privat._H ## N, \
input_size, position, data, mask); \
break;
FOR_ALL_HASHERS(INIT_)
#undef INIT_
default: break;
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_HASH_H_ */
@@ -0,0 +1,125 @@
/* NOLINT(build/header_guard) */
/* Copyright 2018 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, HASHER_A, HASHER_B */
/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A
and HASHER_B. */
#define HashComposite HASHER()
#define FN_A(X) EXPAND_CAT(X, HASHER_A)
#define FN_B(X) EXPAND_CAT(X, HASHER_B)
static BROTLI_INLINE size_t FN(HashTypeLength)(void) {
size_t a = FN_A(HashTypeLength)();
size_t b = FN_B(HashTypeLength)();
return a > b ? a : b;
}
static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
size_t a = FN_A(StoreLookahead)();
size_t b = FN_B(StoreLookahead)();
return a > b ? a : b;
}
typedef struct HashComposite {
HASHER_A ha;
HASHER_B hb;
HasherCommon hb_common;
/* Shortcuts. */
void* extra;
HasherCommon* common;
BROTLI_BOOL fresh;
const BrotliEncoderParams* params;
} HashComposite;
static void FN(Initialize)(HasherCommon* common,
HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) {
self->common = common;
self->extra = common->extra;
self->hb_common = *self->common;
self->fresh = BROTLI_TRUE;
self->params = params;
/* TODO: Initialize of the hashers is defered to Prepare (and params
remembered here) because we don't get the one_shot and input_size params
here that are needed to know the memory size of them. Instead provide
those params to all hashers FN(Initialize) */
}
static void FN(Prepare)(
HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
if (self->fresh) {
self->fresh = BROTLI_FALSE;
self->hb_common.extra = (uint8_t*)self->extra +
FN_A(HashMemAllocInBytes)(self->params, one_shot, input_size);
FN_A(Initialize)(self->common, &self->ha, self->params);
FN_B(Initialize)(&self->hb_common, &self->hb, self->params);
}
FN_A(Prepare)(&self->ha, one_shot, input_size, data);
FN_B(Prepare)(&self->hb, one_shot, input_size, data);
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
return FN_A(HashMemAllocInBytes)(params, one_shot, input_size) +
FN_B(HashMemAllocInBytes)(params, one_shot, input_size);
}
static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
FN_A(Store)(&self->ha, data, mask, ix);
FN_B(Store)(&self->hb, data, mask, ix);
}
static BROTLI_INLINE void FN(StoreRange)(
HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix_start,
const size_t ix_end) {
FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end);
FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end);
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashComposite* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position,
ringbuffer, ring_buffer_mask);
FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position,
ringbuffer, ring_buffer_mask);
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) {
FN_A(PrepareDistanceCache)(&self->ha, distance_cache);
FN_B(PrepareDistanceCache)(&self->hb, distance_cache);
}
static BROTLI_INLINE void FN(FindLongestMatch)(
HashComposite* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
max_distance, out);
FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask,
distance_cache, cur_ix, max_length, max_backward, dictionary_distance,
max_distance, out);
}
#undef HashComposite
@@ -0,0 +1,293 @@
/* NOLINT(build/header_guard) */
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, BUCKET_BITS, NUM_BANKS, BANK_BITS,
NUM_LAST_DISTANCES_TO_CHECK */
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data.
Hashes are stored in chains which are bucketed to groups. Group of chains
share a storage "bank". When more than "bank size" chain nodes are added,
oldest nodes are replaced; this way several chains may share a tail. */
#define HashForgetfulChain HASHER()
#define BANK_SIZE (1 << BANK_BITS)
/* Number of hash buckets. */
#define BUCKET_SIZE (1 << BUCKET_BITS)
#define CAPPED_CHAINS 0
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
/* HashBytes is the function that chooses the bucket to place the address in.*/
static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return h >> (32 - BUCKET_BITS);
}
typedef struct FN(Slot) {
uint16_t delta;
uint16_t next;
} FN(Slot);
typedef struct FN(Bank) {
FN(Slot) slots[BANK_SIZE];
} FN(Bank);
typedef struct HashForgetfulChain {
uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */
size_t max_hops;
/* Shortcuts. */
void* extra;
HasherCommon* common;
/* --- Dynamic size members --- */
/* uint32_t addr[BUCKET_SIZE]; */
/* uint16_t head[BUCKET_SIZE]; */
/* Truncated hash used for quick rejection of "distance cache" candidates. */
/* uint8_t tiny_hash[65536];*/
/* FN(Bank) banks[NUM_BANKS]; */
} HashForgetfulChain;
static uint32_t* FN(Addr)(void* extra) {
return (uint32_t*)extra;
}
static uint16_t* FN(Head)(void* extra) {
return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]);
}
static uint8_t* FN(TinyHash)(void* extra) {
return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]);
}
static FN(Bank)* FN(Banks)(void* extra) {
return (FN(Bank)*)(&FN(TinyHash)(extra)[65536]);
}
static void FN(Initialize)(
HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common = common;
self->extra = common->extra;
self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4);
}
static void FN(Prepare)(
HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = BUCKET_SIZE >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
size_t i;
for (i = 0; i < input_size; ++i) {
size_t bucket = FN(HashBytes)(&data[i]);
/* See InitEmpty comment. */
addr[bucket] = 0xCCCCCCCC;
head[bucket] = 0xCCCC;
}
} else {
/* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position
processed by hasher never reaches 3GB + 64M; this makes all new chains
to be terminated after the first node. */
memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE);
memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE);
}
memset(tiny_hash, 0, sizeof(uint8_t) * 65536);
memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx));
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(uint32_t) * BUCKET_SIZE + sizeof(uint16_t) * BUCKET_SIZE +
sizeof(uint8_t) * 65536 + sizeof(FN(Bank)) * NUM_BANKS;
}
/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend
node to corresponding chain; also update tiny_hash for current position. */
static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra);
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
const size_t key = FN(HashBytes)(&data[ix & mask]);
const size_t bank = key & (NUM_BANKS - 1);
const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1);
size_t delta = ix - addr[key];
tiny_hash[(uint16_t)ix] = (uint8_t)key;
if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF;
banks[bank].slots[idx].delta = (uint16_t)delta;
banks[bank].slots[idx].next = head[key];
addr[key] = (uint32_t)ix;
head[key] = (uint16_t)idx;
}
static BROTLI_INLINE void FN(StoreRange)(
HashForgetfulChain* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashForgetfulChain* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3);
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2);
FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashForgetfulChain* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK);
}
/* Find a longest backward match of &data[cur_ix] up to the length of
max_length and stores the position cur_ix in the hash table.
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
values; if this method is invoked repeatedly with the same distance
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
Does not look for matches longer than max_length.
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(
HashForgetfulChain* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache,
const size_t cur_ix, const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra);
uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra);
uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra);
FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra);
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
score_t best_score = out->score;
size_t best_len = out->len;
size_t i;
const size_t key = FN(HashBytes)(&data[cur_ix_masked]);
const uint8_t tiny_hash = (uint8_t)(key);
out->len = 0;
out->len_code_delta = 0;
/* Try last distance first. */
for (i = 0; i < NUM_LAST_DISTANCES_TO_CHECK; ++i) {
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (cur_ix - backward);
/* For distance code 0 we want to consider 2-byte matches. */
if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue;
if (prev_ix >= cur_ix || backward > max_backward) {
continue;
}
prev_ix &= ring_buffer_mask;
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 2) {
score_t score = BackwardReferenceScoreUsingLastDistance(len);
if (best_score < score) {
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
}
{
const size_t bank = key & (NUM_BANKS - 1);
size_t backward = 0;
size_t hops = self->max_hops;
size_t delta = cur_ix - addr[key];
size_t slot = head[key];
while (hops--) {
size_t prev_ix;
size_t last = slot;
backward += delta;
if (backward > max_backward || (CAPPED_CHAINS && !delta)) break;
prev_ix = (cur_ix - backward) & ring_buffer_mask;
slot = banks[bank].slots[last].next;
delta = banks[bank].slots[last].delta;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
continue;
}
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 4) {
/* Comparing for >= 3 does not change the semantics, but just saves
for a few unnecessary binary logarithms in backward reference
score, since we are not interested in such short matches. */
score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
FN(Store)(self, data, ring_buffer_mask, cur_ix);
}
if (out->score == min_score) {
SearchInStaticDictionary(dictionary,
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
#undef BANK_SIZE
#undef BUCKET_SIZE
#undef CAPPED_CHAINS
#undef HashForgetfulChain
@@ -0,0 +1,267 @@
/* NOLINT(build/header_guard) */
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN */
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data.
This is a hash map of fixed size (bucket_size_) to a ring buffer of
fixed size (block_size_). The ring buffer contains the last block_size_
index positions of the given hash key in the compressed data. */
#define HashLongestMatch HASHER()
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
/* HashBytes is the function that chooses the bucket to place the address in. */
static BROTLI_INLINE uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data,
const uint64_t mask,
const int shift) {
const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(data) & mask) * kHashMul64Long;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return (uint32_t)(h >> shift);
}
typedef struct HashLongestMatch {
/* Number of hash buckets. */
size_t bucket_size_;
/* Only block_size_ newest backward references are kept,
and the older are forgotten. */
size_t block_size_;
/* Left-shift for computing hash bucket index from hash value. */
int hash_shift_;
/* Mask for selecting the next 4-8 bytes of input */
uint64_t hash_mask_;
/* Mask for accessing entries in a block (in a ring-buffer manner). */
uint32_t block_mask_;
int block_bits_;
int num_last_distances_to_check_;
/* Shortcuts. */
HasherCommon* common_;
/* --- Dynamic size members --- */
/* Number of entries in a particular bucket. */
uint16_t* num_; /* uint16_t[bucket_size]; */
/* Buckets containing block_size_ of backward references. */
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
} HashLongestMatch;
static void FN(Initialize)(
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common_ = common;
BROTLI_UNUSED(params);
self->hash_shift_ = 64 - common->params.bucket_bits;
self->hash_mask_ = (~((uint64_t)0U)) >> (64 - 8 * common->params.hash_len);
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
self->block_bits_ = common->params.block_bits;
self->block_size_ = (size_t)1 << common->params.block_bits;
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
self->num_last_distances_to_check_ =
common->params.num_last_distances_to_check;
self->num_ = (uint16_t*)common->extra;
self->buckets_ = (uint32_t*)&self->num_[self->bucket_size_];
}
static void FN(Prepare)(
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint16_t* BROTLI_RESTRICT num = self->num_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
size_t i;
for (i = 0; i < input_size; ++i) {
const uint32_t key = FN(HashBytes)(&data[i], self->hash_mask_,
self->hash_shift_);
num[key] = 0;
}
} else {
memset(num, 0, self->bucket_size_ * sizeof(num[0]));
}
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
size_t block_size = (size_t)1 << params->hasher.block_bits;
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(uint16_t) * bucket_size +
sizeof(uint32_t) * bucket_size * block_size;
}
/* Look at 4 bytes at &data[ix & mask].
Compute a hash from these, and store the value of ix at that position. */
static BROTLI_INLINE void FN(Store)(
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_mask_,
self->hash_shift_);
const size_t minor_ix = num[key] & self->block_mask_;
const size_t offset = minor_ix + (key << self->block_bits_);
++num[key];
buckets[offset] = (uint32_t)ix;
}
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatch* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashLongestMatch* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
}
/* Find a longest backward match of &data[cur_ix] up to the length of
max_length and stores the position cur_ix in the hash table.
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
values; if this method is invoked repeatedly with the same distance
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
Does not look for matches longer than max_length.
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(
HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
score_t best_score = out->score;
size_t best_len = out->len;
size_t i;
out->len = 0;
out->len_code_delta = 0;
/* Try last distance first. */
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (size_t)(cur_ix - backward);
if (prev_ix >= cur_ix) {
continue;
}
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
continue;
}
prev_ix &= ring_buffer_mask;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
continue;
}
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 3 || (len == 2 && i < 2)) {
/* Comparing for >= 2 does not change the semantics, but just saves for
a few unnecessary binary logarithms in backward reference score,
since we are not interested in such short matches. */
score_t score = BackwardReferenceScoreUsingLastDistance(len);
if (best_score < score) {
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
}
{
const uint32_t key = FN(HashBytes)(
&data[cur_ix_masked], self->hash_mask_, self->hash_shift_);
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
const size_t down =
(num[key] > self->block_size_) ?
(num[key] - self->block_size_) : 0u;
for (i = num[key]; i > down;) {
size_t prev_ix = bucket[--i & self->block_mask_];
const size_t backward = cur_ix - prev_ix;
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
break;
}
prev_ix &= ring_buffer_mask;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
continue;
}
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 4) {
/* Comparing for >= 3 does not change the semantics, but just saves
for a few unnecessary binary logarithms in backward reference
score, since we are not interested in such short matches. */
score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
++num[key];
}
if (min_score == out->score) {
SearchInStaticDictionary(dictionary,
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
#undef HashLongestMatch
@@ -0,0 +1,262 @@
/* NOLINT(build/header_guard) */
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN */
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data.
This is a hash map of fixed size (bucket_size_) to a ring buffer of
fixed size (block_size_). The ring buffer contains the last block_size_
index positions of the given hash key in the compressed data. */
#define HashLongestMatch HASHER()
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
/* HashBytes is the function that chooses the bucket to place the address in. */
static uint32_t FN(HashBytes)(
const uint8_t* BROTLI_RESTRICT data, const int shift) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return (uint32_t)(h >> shift);
}
typedef struct HashLongestMatch {
/* Number of hash buckets. */
size_t bucket_size_;
/* Only block_size_ newest backward references are kept,
and the older are forgotten. */
size_t block_size_;
/* Left-shift for computing hash bucket index from hash value. */
int hash_shift_;
/* Mask for accessing entries in a block (in a ring-buffer manner). */
uint32_t block_mask_;
int block_bits_;
int num_last_distances_to_check_;
/* Shortcuts. */
HasherCommon* common_;
/* --- Dynamic size members --- */
/* Number of entries in a particular bucket. */
uint16_t* num_; /* uint16_t[bucket_size]; */
/* Buckets containing block_size_ of backward references. */
uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */
} HashLongestMatch;
static BROTLI_INLINE uint16_t* FN(Num)(void* extra) {
return (uint16_t*)extra;
}
static void FN(Initialize)(
HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common_ = common;
BROTLI_UNUSED(params);
self->hash_shift_ = 32 - common->params.bucket_bits;
self->bucket_size_ = (size_t)1 << common->params.bucket_bits;
self->block_size_ = (size_t)1 << common->params.block_bits;
self->block_mask_ = (uint32_t)(self->block_size_ - 1);
self->num_ = (uint16_t*)common->extra;
self->buckets_ = (uint32_t*)(&self->num_[self->bucket_size_]);
self->block_bits_ = common->params.block_bits;
self->num_last_distances_to_check_ =
common->params.num_last_distances_to_check;
}
static void FN(Prepare)(
HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint16_t* BROTLI_RESTRICT num = self->num_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = self->bucket_size_ >> 6;
if (one_shot && input_size <= partial_prepare_threshold) {
size_t i;
for (i = 0; i < input_size; ++i) {
const uint32_t key = FN(HashBytes)(&data[i], self->hash_shift_);
num[key] = 0;
}
} else {
memset(num, 0, self->bucket_size_ * sizeof(num[0]));
}
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
size_t bucket_size = (size_t)1 << params->hasher.bucket_bits;
size_t block_size = (size_t)1 << params->hasher.block_bits;
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(uint16_t) * bucket_size +
sizeof(uint32_t) * bucket_size * block_size;
}
/* Look at 4 bytes at &data[ix & mask].
Compute a hash from these, and store the value of ix at that position. */
static BROTLI_INLINE void FN(Store)(
HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_);
const size_t minor_ix = self->num_[key] & self->block_mask_;
const size_t offset = minor_ix + (key << self->block_bits_);
self->buckets_[offset] = (uint32_t)ix;
++self->num_[key];
}
static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatch* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashLongestMatch* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_);
}
/* Find a longest backward match of &data[cur_ix] up to the length of
max_length and stores the position cur_ix in the hash table.
REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache
values; if this method is invoked repeatedly with the same distance
cache values, it is enough to invoke FN(PrepareDistanceCache) once.
Does not look for matches longer than max_length.
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(
HashLongestMatch* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
uint16_t* BROTLI_RESTRICT num = self->num_;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
/* Don't accept a short copy from far away. */
score_t min_score = out->score;
score_t best_score = out->score;
size_t best_len = out->len;
size_t i;
out->len = 0;
out->len_code_delta = 0;
/* Try last distance first. */
for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) {
const size_t backward = (size_t)distance_cache[i];
size_t prev_ix = (size_t)(cur_ix - backward);
if (prev_ix >= cur_ix) {
continue;
}
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
continue;
}
prev_ix &= ring_buffer_mask;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
continue;
}
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 3 || (len == 2 && i < 2)) {
/* Comparing for >= 2 does not change the semantics, but just saves for
a few unnecessary binary logarithms in backward reference score,
since we are not interested in such short matches. */
score_t score = BackwardReferenceScoreUsingLastDistance(len);
if (best_score < score) {
if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
}
{
const uint32_t key =
FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_);
uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_];
const size_t down =
(num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u;
for (i = num[key]; i > down;) {
size_t prev_ix = bucket[--i & self->block_mask_];
const size_t backward = cur_ix - prev_ix;
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
break;
}
prev_ix &= ring_buffer_mask;
if (cur_ix_masked + best_len > ring_buffer_mask ||
prev_ix + best_len > ring_buffer_mask ||
data[cur_ix_masked + best_len] != data[prev_ix + best_len]) {
continue;
}
{
const size_t len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 4) {
/* Comparing for >= 3 does not change the semantics, but just saves
for a few unnecessary binary logarithms in backward reference
score, since we are not interested in such short matches. */
score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
best_score = score;
best_len = len;
out->len = best_len;
out->distance = backward;
out->score = best_score;
}
}
}
}
bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix;
++num[key];
}
if (min_score == out->score) {
SearchInStaticDictionary(dictionary,
self->common_, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_FALSE);
}
}
#undef HashLongestMatch
@@ -0,0 +1,266 @@
/* NOLINT(build/header_guard) */
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN,
USE_DICTIONARY
*/
#define HashLongestMatchQuickly HASHER()
#define BUCKET_SIZE (1 << BUCKET_BITS)
#define BUCKET_MASK (BUCKET_SIZE - 1)
#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS)
#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3)
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; }
/* HashBytes is the function that chooses the bucket to place
the address in. The HashLongestMatch and HashLongestMatchQuickly
classes have separate, different implementations of hashing. */
static uint32_t FN(HashBytes)(const uint8_t* data) {
const uint64_t h = ((BROTLI_UNALIGNED_LOAD64LE(data) << (64 - 8 * HASH_LEN)) *
kHashMul64);
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return (uint32_t)(h >> (64 - BUCKET_BITS));
}
/* A (forgetful) hash table to the data seen by the compressor, to
help create backward references to previous data.
This is a hash map of fixed size (BUCKET_SIZE). */
typedef struct HashLongestMatchQuickly {
/* Shortcuts. */
HasherCommon* common;
/* --- Dynamic size members --- */
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
} HashLongestMatchQuickly;
static void FN(Initialize)(
HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->common = common;
BROTLI_UNUSED(params);
self->buckets_ = (uint32_t*)common->extra;
}
static void FN(Prepare)(
HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
/* Partial preparation is 100 times slower (per socket). */
size_t partial_prepare_threshold = BUCKET_SIZE >> 5;
if (one_shot && input_size <= partial_prepare_threshold) {
size_t i;
for (i = 0; i < input_size; ++i) {
const uint32_t key = FN(HashBytes)(&data[i]);
if (BUCKET_SWEEP == 1) {
buckets[key] = 0;
} else {
uint32_t j;
for (j = 0; j < BUCKET_SWEEP; ++j) {
buckets[(key + (j << 3)) & BUCKET_MASK] = 0;
}
}
}
} else {
/* It is not strictly necessary to fill this buffer here, but
not filling will make the results of the compression stochastic
(but correct). This is because random data would cause the
system to find accidentally good backward references here and there. */
memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE);
}
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
return sizeof(uint32_t) * BUCKET_SIZE;
}
/* Look at 5 bytes at &data[ix & mask].
Compute a hash from these, and store the value somewhere within
[ix .. ix+3]. */
static BROTLI_INLINE void FN(Store)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
const uint32_t key = FN(HashBytes)(&data[ix & mask]);
if (BUCKET_SWEEP == 1) {
self->buckets_[key] = (uint32_t)ix;
} else {
/* Wiggle the value with the bucket sweep range. */
const uint32_t off = ix & BUCKET_SWEEP_MASK;
self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix;
}
}
static BROTLI_INLINE void FN(StoreRange)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i;
for (i = ix_start; i < ix_end; ++i) {
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
size_t num_bytes, size_t position,
const uint8_t* ringbuffer, size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) {
/* Prepare the hashes for three last bytes of the last write.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2);
FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1);
}
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(distance_cache);
}
/* Find a longest backward match of &data[cur_ix & ring_buffer_mask]
up to the length of max_length and stores the position cur_ix in the
hash table.
Does not look for matches longer than max_length.
Does not look for matches further away than max_backward.
Writes the best match into |out|.
|out|->score is updated only if a better match is found. */
static BROTLI_INLINE void FN(FindLongestMatch)(
HashLongestMatchQuickly* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data,
const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache,
const size_t cur_ix, const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
const size_t best_len_in = out->len;
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
int compare_char = data[cur_ix_masked + best_len_in];
size_t key = FN(HashBytes)(&data[cur_ix_masked]);
size_t key_out;
score_t min_score = out->score;
score_t best_score = out->score;
size_t best_len = best_len_in;
size_t cached_backward = (size_t)distance_cache[0];
size_t prev_ix = cur_ix - cached_backward;
out->len_code_delta = 0;
if (prev_ix < cur_ix) {
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char == data[prev_ix + best_len]) {
const size_t len = FindMatchLengthWithLimit(
&data[prev_ix], &data[cur_ix_masked], max_length);
if (len >= 4) {
const score_t score = BackwardReferenceScoreUsingLastDistance(len);
if (best_score < score) {
out->len = len;
out->distance = cached_backward;
out->score = score;
if (BUCKET_SWEEP == 1) {
buckets[key] = (uint32_t)cur_ix;
return;
} else {
best_len = len;
best_score = score;
compare_char = data[cur_ix_masked + len];
}
}
}
}
}
if (BUCKET_SWEEP == 1) {
size_t backward;
size_t len;
/* Only one to look for, don't bother to prepare for a loop. */
prev_ix = buckets[key];
buckets[key] = (uint32_t)cur_ix;
backward = cur_ix - prev_ix;
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char != data[prev_ix + best_len_in]) {
return;
}
if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) {
return;
}
len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 4) {
const score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
out->len = len;
out->distance = backward;
out->score = score;
return;
}
}
} else {
size_t keys[BUCKET_SWEEP];
size_t i;
for (i = 0; i < BUCKET_SWEEP; ++i) {
keys[i] = (key + (i << 3)) & BUCKET_MASK;
}
key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3];
for (i = 0; i < BUCKET_SWEEP; ++i) {
size_t len;
size_t backward;
prev_ix = buckets[keys[i]];
backward = cur_ix - prev_ix;
prev_ix &= (uint32_t)ring_buffer_mask;
if (compare_char != data[prev_ix + best_len]) {
continue;
}
if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) {
continue;
}
len = FindMatchLengthWithLimit(&data[prev_ix],
&data[cur_ix_masked],
max_length);
if (len >= 4) {
const score_t score = BackwardReferenceScore(len, backward);
if (best_score < score) {
best_len = len;
out->len = len;
compare_char = data[cur_ix_masked + len];
best_score = score;
out->score = score;
out->distance = backward;
}
}
}
}
if (USE_DICTIONARY && min_score == out->score) {
SearchInStaticDictionary(dictionary,
self->common, &data[cur_ix_masked], max_length, dictionary_distance,
max_distance, out, BROTLI_TRUE);
}
if (BUCKET_SWEEP != 1) {
buckets[key_out] = (uint32_t)cur_ix;
}
}
#undef BUCKET_SWEEP_MASK
#undef BUCKET_SWEEP
#undef BUCKET_MASK
#undef BUCKET_SIZE
#undef HashLongestMatchQuickly
@@ -0,0 +1,212 @@
/* NOLINT(build/header_guard) */
/* Copyright 2018 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, JUMP, NUMBUCKETS, MASK, CHUNKLEN */
/* NUMBUCKETS / (MASK + 1) = probability of storing and using hash code. */
/* JUMP = skip bytes for speedup */
/* Rolling hash for long distance long string matches. Stores one position
per bucket, bucket key is computed over a long region. */
#define HashRolling HASHER()
static const uint32_t FN(kRollingHashMul32) = 69069;
static const uint32_t FN(kInvalidPos) = 0xffffffff;
/* This hasher uses a longer forward length, but returning a higher value here
will hurt compression by the main hasher when combined with a composite
hasher. The hasher tests for forward itself instead. */
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; }
/* Computes a code from a single byte. A lookup table of 256 values could be
used, but simply adding 1 works about as good. */
static uint32_t FN(HashByte)(uint8_t byte) {
return (uint32_t)byte + 1u;
}
static uint32_t FN(HashRollingFunctionInitial)(uint32_t state, uint8_t add,
uint32_t factor) {
return (uint32_t)(factor * state + FN(HashByte)(add));
}
static uint32_t FN(HashRollingFunction)(uint32_t state, uint8_t add,
uint8_t rem, uint32_t factor,
uint32_t factor_remove) {
return (uint32_t)(factor * state +
FN(HashByte)(add) - factor_remove * FN(HashByte)(rem));
}
typedef struct HashRolling {
uint32_t state;
uint32_t* table;
size_t next_ix;
uint32_t chunk_len;
uint32_t factor;
uint32_t factor_remove;
} HashRolling;
static void FN(Initialize)(
HasherCommon* common, HashRolling* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
size_t i;
self->state = 0;
self->next_ix = 0;
self->factor = FN(kRollingHashMul32);
/* Compute the factor of the oldest byte to remove: factor**steps modulo
0xffffffff (the multiplications rely on 32-bit overflow) */
self->factor_remove = 1;
for (i = 0; i < CHUNKLEN; i += JUMP) {
self->factor_remove *= self->factor;
}
self->table = (uint32_t*)common->extra;
for (i = 0; i < NUMBUCKETS; i++) {
self->table[i] = FN(kInvalidPos);
}
BROTLI_UNUSED(params);
}
static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
size_t i;
/* Too small size, cannot use this hasher. */
if (input_size < CHUNKLEN) return;
self->state = 0;
for (i = 0; i < CHUNKLEN; i += JUMP) {
self->state = FN(HashRollingFunctionInitial)(
self->state, data[i], self->factor);
}
BROTLI_UNUSED(one_shot);
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
return NUMBUCKETS * sizeof(uint32_t);
BROTLI_UNUSED(params);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
}
static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(data);
BROTLI_UNUSED(mask);
BROTLI_UNUSED(ix);
}
static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(data);
BROTLI_UNUSED(mask);
BROTLI_UNUSED(ix_start);
BROTLI_UNUSED(ix_end);
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashRolling* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ring_buffer_mask) {
/* In this case we must re-initialize the hasher from scratch from the
current position. */
size_t position_masked;
size_t available = num_bytes;
if ((position & (JUMP - 1)) != 0) {
size_t diff = JUMP - (position & (JUMP - 1));
available = (diff > available) ? 0 : (available - diff);
position += diff;
}
position_masked = position & ring_buffer_mask;
/* wrapping around ringbuffer not handled. */
if (available > ring_buffer_mask - position_masked) {
available = ring_buffer_mask - position_masked;
}
FN(Prepare)(self, BROTLI_FALSE, available,
ringbuffer + (position & ring_buffer_mask));
self->next_ix = position;
BROTLI_UNUSED(num_bytes);
}
static BROTLI_INLINE void FN(PrepareDistanceCache)(
HashRolling* BROTLI_RESTRICT self,
int* BROTLI_RESTRICT distance_cache) {
BROTLI_UNUSED(self);
BROTLI_UNUSED(distance_cache);
}
static BROTLI_INLINE void FN(FindLongestMatch)(
HashRolling* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask,
const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix,
const size_t max_length, const size_t max_backward,
const size_t dictionary_distance, const size_t max_distance,
HasherSearchResult* BROTLI_RESTRICT out) {
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
size_t pos;
if ((cur_ix & (JUMP - 1)) != 0) return;
/* Not enough lookahead */
if (max_length < CHUNKLEN) return;
for (pos = self->next_ix; pos <= cur_ix; pos += JUMP) {
uint32_t code = self->state & MASK;
uint8_t rem = data[pos & ring_buffer_mask];
uint8_t add = data[(pos + CHUNKLEN) & ring_buffer_mask];
size_t found_ix = FN(kInvalidPos);
self->state = FN(HashRollingFunction)(
self->state, add, rem, self->factor, self->factor_remove);
if (code < NUMBUCKETS) {
found_ix = self->table[code];
self->table[code] = (uint32_t)pos;
if (pos == cur_ix && found_ix != FN(kInvalidPos)) {
/* The cast to 32-bit makes backward distances up to 4GB work even
if cur_ix is above 4GB, despite using 32-bit values in the table. */
size_t backward = (uint32_t)(cur_ix - found_ix);
if (backward <= max_backward) {
const size_t found_ix_masked = found_ix & ring_buffer_mask;
const size_t len = FindMatchLengthWithLimit(&data[found_ix_masked],
&data[cur_ix_masked],
max_length);
if (len >= 4 && len > out->len) {
score_t score = BackwardReferenceScore(len, backward);
if (score > out->score) {
out->len = len;
out->distance = backward;
out->score = score;
out->len_code_delta = 0;
}
}
}
}
}
}
self->next_ix = cur_ix + JUMP;
/* NOTE: this hasher does not search in the dictionary. It is used as
backup-hasher, the main hasher already searches in it. */
BROTLI_UNUSED(dictionary);
BROTLI_UNUSED(distance_cache);
BROTLI_UNUSED(dictionary_distance);
BROTLI_UNUSED(max_distance);
}
#undef HashRolling
@@ -0,0 +1,329 @@
/* NOLINT(build/header_guard) */
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN, BUCKET_BITS, MAX_TREE_COMP_LENGTH,
MAX_TREE_SEARCH_DEPTH */
/* A (forgetful) hash table where each hash bucket contains a binary tree of
sequences whose first 4 bytes share the same hash code.
Each sequence is MAX_TREE_COMP_LENGTH long and is identified by its starting
position in the input data. The binary tree is sorted by the lexicographic
order of the sequences, and it is also a max-heap with respect to the
starting positions. */
#define HashToBinaryTree HASHER()
#define BUCKET_SIZE (1 << BUCKET_BITS)
static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; }
static BROTLI_INLINE size_t FN(StoreLookahead)(void) {
return MAX_TREE_COMP_LENGTH;
}
static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) {
uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32;
/* The higher bits contain more mixture from the multiplication,
so we take our results from there. */
return h >> (32 - BUCKET_BITS);
}
typedef struct HashToBinaryTree {
/* The window size minus 1 */
size_t window_mask_;
/* Hash table that maps the 4-byte hashes of the sequence to the last
position where this hash was found, which is the root of the binary
tree of sequences that share this hash bucket. */
uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */
/* A position used to mark a non-existent sequence, i.e. a tree is empty if
its root is at invalid_pos_ and a node is a leaf if both its children
are at invalid_pos_. */
uint32_t invalid_pos_;
/* --- Dynamic size members --- */
/* The union of the binary trees of each hash bucket. The root of the tree
corresponding to a hash is a sequence starting at buckets_[hash] and
the left and right children of a sequence starting at pos are
forest_[2 * pos] and forest_[2 * pos + 1]. */
uint32_t* forest_; /* uint32_t[2 * num_nodes] */
} HashToBinaryTree;
static void FN(Initialize)(
HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self,
const BrotliEncoderParams* params) {
self->buckets_ = (uint32_t*)common->extra;
self->forest_ = &self->buckets_[BUCKET_SIZE];
self->window_mask_ = (1u << params->lgwin) - 1u;
self->invalid_pos_ = (uint32_t)(0 - self->window_mask_);
}
static void FN(Prepare)
(HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot,
size_t input_size, const uint8_t* BROTLI_RESTRICT data) {
uint32_t invalid_pos = self->invalid_pos_;
uint32_t i;
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
BROTLI_UNUSED(data);
BROTLI_UNUSED(one_shot);
BROTLI_UNUSED(input_size);
for (i = 0; i < BUCKET_SIZE; i++) {
buckets[i] = invalid_pos;
}
}
static BROTLI_INLINE size_t FN(HashMemAllocInBytes)(
const BrotliEncoderParams* params, BROTLI_BOOL one_shot,
size_t input_size) {
size_t num_nodes = (size_t)1 << params->lgwin;
if (one_shot && input_size < num_nodes) {
num_nodes = input_size;
}
return sizeof(uint32_t) * BUCKET_SIZE + 2 * sizeof(uint32_t) * num_nodes;
}
static BROTLI_INLINE size_t FN(LeftChildIndex)(
HashToBinaryTree* BROTLI_RESTRICT self,
const size_t pos) {
return 2 * (pos & self->window_mask_);
}
static BROTLI_INLINE size_t FN(RightChildIndex)(
HashToBinaryTree* BROTLI_RESTRICT self,
const size_t pos) {
return 2 * (pos & self->window_mask_) + 1;
}
/* Stores the hash of the next 4 bytes and in a single tree-traversal, the
hash bucket's binary tree is searched for matches and is re-rooted at the
current position.
If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the
current position is searched for matches, but the state of the hash table
is not changed, since we can not know the final sorting order of the
current (incomplete) sequence.
This function must be called with increasing cur_ix positions. */
static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)(
HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data,
const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length,
const size_t max_backward, size_t* const BROTLI_RESTRICT best_len,
BackwardMatch* BROTLI_RESTRICT matches) {
const size_t cur_ix_masked = cur_ix & ring_buffer_mask;
const size_t max_comp_len =
BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH);
const BROTLI_BOOL should_reroot_tree =
TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH);
const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]);
uint32_t* BROTLI_RESTRICT buckets = self->buckets_;
uint32_t* BROTLI_RESTRICT forest = self->forest_;
size_t prev_ix = buckets[key];
/* The forest index of the rightmost node of the left subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t node_left = FN(LeftChildIndex)(self, cur_ix);
/* The forest index of the leftmost node of the right subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t node_right = FN(RightChildIndex)(self, cur_ix);
/* The match length of the rightmost node of the left subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t best_len_left = 0;
/* The match length of the leftmost node of the right subtree of the new
root, updated as we traverse and re-root the tree of the hash bucket. */
size_t best_len_right = 0;
size_t depth_remaining;
if (should_reroot_tree) {
buckets[key] = (uint32_t)cur_ix;
}
for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) {
const size_t backward = cur_ix - prev_ix;
const size_t prev_ix_masked = prev_ix & ring_buffer_mask;
if (backward == 0 || backward > max_backward || depth_remaining == 0) {
if (should_reroot_tree) {
forest[node_left] = self->invalid_pos_;
forest[node_right] = self->invalid_pos_;
}
break;
}
{
const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right);
size_t len;
BROTLI_DCHECK(cur_len <= MAX_TREE_COMP_LENGTH);
len = cur_len +
FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len],
&data[prev_ix_masked + cur_len],
max_length - cur_len);
BROTLI_DCHECK(
0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len));
if (matches && len > *best_len) {
*best_len = len;
InitBackwardMatch(matches++, backward, len);
}
if (len >= max_comp_len) {
if (should_reroot_tree) {
forest[node_left] = forest[FN(LeftChildIndex)(self, prev_ix)];
forest[node_right] = forest[FN(RightChildIndex)(self, prev_ix)];
}
break;
}
if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) {
best_len_left = len;
if (should_reroot_tree) {
forest[node_left] = (uint32_t)prev_ix;
}
node_left = FN(RightChildIndex)(self, prev_ix);
prev_ix = forest[node_left];
} else {
best_len_right = len;
if (should_reroot_tree) {
forest[node_right] = (uint32_t)prev_ix;
}
node_right = FN(LeftChildIndex)(self, prev_ix);
prev_ix = forest[node_right];
}
}
}
return matches;
}
/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the
length of max_length and stores the position cur_ix in the hash table.
Sets *num_matches to the number of matches found, and stores the found
matches in matches[0] to matches[*num_matches - 1]. The matches will be
sorted by strictly increasing length and (non-strictly) increasing
distance. */
static BROTLI_INLINE size_t FN(FindAllMatches)(
HashToBinaryTree* BROTLI_RESTRICT self,
const BrotliEncoderDictionary* dictionary,
const uint8_t* BROTLI_RESTRICT 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 dictionary_distance, 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;
const size_t short_match_max_backward =
params->quality != HQ_ZOPFLIFICATION_QUALITY ? 16 : 64;
size_t stop = cur_ix - short_match_max_backward;
uint32_t dict_matches[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1];
size_t i;
if (cur_ix < short_match_max_backward) { stop = 0; }
for (i = cur_ix - 1; i > stop && best_len <= 2; --i) {
size_t prev_ix = i;
const size_t backward = cur_ix - prev_ix;
if (BROTLI_PREDICT_FALSE(backward > max_backward)) {
break;
}
prev_ix &= ring_buffer_mask;
if (data[cur_ix_masked] != data[prev_ix] ||
data[cur_ix_masked + 1] != data[prev_ix + 1]) {
continue;
}
{
const size_t len =
FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked],
max_length);
if (len > best_len) {
best_len = len;
InitBackwardMatch(matches++, backward, len);
}
}
}
if (best_len < max_length) {
matches = FN(StoreAndFindMatches)(self, data, cur_ix,
ring_buffer_mask, max_length, max_backward, &best_len, matches);
}
for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) {
dict_matches[i] = kInvalidMatch;
}
{
size_t minlen = BROTLI_MAX(size_t, 4, best_len + 1);
if (BrotliFindAllStaticDictionaryMatches(dictionary,
&data[cur_ix_masked], minlen, max_length, &dict_matches[0])) {
size_t maxlen = BROTLI_MIN(
size_t, BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN, max_length);
size_t l;
for (l = minlen; l <= maxlen; ++l) {
uint32_t dict_id = dict_matches[l];
if (dict_id < kInvalidMatch) {
size_t distance = dictionary_distance + (dict_id >> 5) + 1;
if (distance <= params->dist.max_distance) {
InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31);
}
}
}
}
}
return (size_t)(matches - orig_matches);
}
/* Stores the hash of the next 4 bytes and re-roots the binary tree at the
current sequence, without returning any matches.
REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */
static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data,
const size_t mask, const size_t ix) {
/* Maximum distance is window size - 16, see section 9.1. of the spec. */
const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1;
FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH,
max_backward, NULL, NULL);
}
static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self,
const uint8_t* BROTLI_RESTRICT data, const size_t mask,
const size_t ix_start, const size_t ix_end) {
size_t i = ix_start;
size_t j = ix_start;
if (ix_start + 63 <= ix_end) {
i = ix_end - 63;
}
if (ix_start + 512 <= i) {
for (; j < i; j += 8) {
FN(Store)(self, data, mask, j);
}
}
for (; i < ix_end; ++i) {
FN(Store)(self, data, mask, i);
}
}
static BROTLI_INLINE void FN(StitchToPreviousBlock)(
HashToBinaryTree* BROTLI_RESTRICT self,
size_t num_bytes, size_t position, const uint8_t* ringbuffer,
size_t ringbuffer_mask) {
if (num_bytes >= FN(HashTypeLength)() - 1 &&
position >= MAX_TREE_COMP_LENGTH) {
/* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher.
These could not be calculated before, since they require knowledge
of both the previous and the current block. */
const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1;
const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes);
size_t i;
for (i = i_start; i < i_end; ++i) {
/* Maximum distance is window size - 16, see section 9.1. of the spec.
Furthermore, we have to make sure that we don't look further back
from the start of the next block than the window size, otherwise we
could access already overwritten areas of the ring-buffer. */
const size_t max_backward =
self->window_mask_ - BROTLI_MAX(size_t,
BROTLI_WINDOW_GAP - 1,
position - i);
/* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the
end of the current block and that we have at least
MAX_TREE_COMP_LENGTH tail in the ring-buffer. */
FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask,
MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL);
}
}
}
#undef BUCKET_SIZE
#undef HashToBinaryTree
@@ -0,0 +1,63 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Models the histograms of literals, commands and distance codes. */
#ifndef BROTLI_ENC_HISTOGRAM_H_
#define BROTLI_ENC_HISTOGRAM_H_
#include <string.h> /* memset */
#include "../common/constants.h"
#include "../common/context.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./block_splitter.h"
#include "./command.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */
#define BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS 544
#define FN(X) X ## Literal
#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS
#define DataType uint8_t
#include "./histogram_inc.h" /* NOLINT(build/include) */
#undef DataType
#undef DATA_SIZE
#undef FN
#define FN(X) X ## Command
#define DataType uint16_t
#define DATA_SIZE BROTLI_NUM_COMMAND_SYMBOLS
#include "./histogram_inc.h" /* NOLINT(build/include) */
#undef DATA_SIZE
#undef FN
#define FN(X) X ## Distance
#define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS
#include "./histogram_inc.h" /* NOLINT(build/include) */
#undef DataType
#undef DATA_SIZE
#undef FN
BROTLI_INTERNAL void BrotliBuildHistogramsWithContext(
const Command* cmds, const size_t num_commands,
const BlockSplit* literal_split, const BlockSplit* insert_and_copy_split,
const BlockSplit* dist_split, const uint8_t* ringbuffer, size_t pos,
size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
const ContextType* context_modes, HistogramLiteral* literal_histograms,
HistogramCommand* insert_and_copy_histograms,
HistogramDistance* copy_dist_histograms);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_HISTOGRAM_H_ */
@@ -0,0 +1,51 @@
/* NOLINT(build/header_guard) */
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: Histogram, DATA_SIZE, DataType */
/* A simple container for histograms of data in blocks. */
typedef struct FN(Histogram) {
uint32_t data_[DATA_SIZE];
size_t total_count_;
double bit_cost_;
} FN(Histogram);
static BROTLI_INLINE void FN(HistogramClear)(FN(Histogram)* self) {
memset(self->data_, 0, sizeof(self->data_));
self->total_count_ = 0;
self->bit_cost_ = HUGE_VAL;
}
static BROTLI_INLINE void FN(ClearHistograms)(
FN(Histogram)* array, size_t length) {
size_t i;
for (i = 0; i < length; ++i) FN(HistogramClear)(array + i);
}
static BROTLI_INLINE void FN(HistogramAdd)(FN(Histogram)* self, size_t val) {
++self->data_[val];
++self->total_count_;
}
static BROTLI_INLINE void FN(HistogramAddVector)(FN(Histogram)* self,
const DataType* p, size_t n) {
self->total_count_ += n;
n += 1;
while (--n) ++self->data_[*p++];
}
static BROTLI_INLINE void FN(HistogramAddHistogram)(FN(Histogram)* self,
const FN(Histogram)* v) {
size_t i;
self->total_count_ += v->total_count_;
for (i = 0; i < DATA_SIZE; ++i) {
self->data_[i] += v->data_[i];
}
}
static BROTLI_INLINE size_t FN(HistogramDataSize)(void) { return DATA_SIZE; }
@@ -0,0 +1,30 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Literal cost model to allow backward reference replacement to be efficient.
*/
#ifndef BROTLI_ENC_LITERAL_COST_H_
#define BROTLI_ENC_LITERAL_COST_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Estimates how many bits the literals in the interval [pos, pos + len) in the
ring-buffer (data, mask) will take entropy coded and writes these estimates
to the cost[0..len) array. */
BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals(
size_t pos, size_t len, size_t mask, const uint8_t* data, float* cost);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_LITERAL_COST_H_ */
@@ -0,0 +1,114 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Macros for memory management. */
#ifndef BROTLI_ENC_MEMORY_H_
#define BROTLI_ENC_MEMORY_H_
#include <string.h> /* memcpy */
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#if !defined(BROTLI_ENCODER_CLEANUP_ON_OOM) && \
!defined(BROTLI_ENCODER_EXIT_ON_OOM)
#define BROTLI_ENCODER_EXIT_ON_OOM
#endif
typedef struct MemoryManager {
brotli_alloc_func alloc_func;
brotli_free_func free_func;
void* opaque;
#if !defined(BROTLI_ENCODER_EXIT_ON_OOM)
BROTLI_BOOL is_oom;
size_t perm_allocated;
size_t new_allocated;
size_t new_freed;
void* pointers[256];
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
} MemoryManager;
BROTLI_INTERNAL void BrotliInitMemoryManager(
MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func,
void* opaque);
BROTLI_INTERNAL void* BrotliAllocate(MemoryManager* m, size_t n);
#define BROTLI_ALLOC(M, T, N) \
((N) > 0 ? ((T*)BrotliAllocate((M), (N) * sizeof(T))) : NULL)
BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p);
#define BROTLI_FREE(M, P) { \
BrotliFree((M), (P)); \
P = NULL; \
}
#if defined(BROTLI_ENCODER_EXIT_ON_OOM)
#define BROTLI_IS_OOM(M) (!!0)
#else /* BROTLI_ENCODER_EXIT_ON_OOM */
#define BROTLI_IS_OOM(M) (!!(M)->is_oom)
#endif /* BROTLI_ENCODER_EXIT_ON_OOM */
/*
BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting.
The only purpose of it is to explain static analyzers the state of things.
NB: use ONLY together with BROTLI_IS_OOM
AND ONLY for allocations in the current scope.
*/
#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM)
#define BROTLI_IS_NULL(A) ((A) == nullptr)
#else /* defined(__clang_analyzer__) */
#define BROTLI_IS_NULL(A) (!!0)
#endif /* defined(__clang_analyzer__) */
BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m);
/*
Dynamically grows array capacity to at least the requested size
M: MemoryManager
T: data type
A: array
C: capacity
R: requested size
*/
#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \
if (C < (R)) { \
size_t _new_size = (C == 0) ? (R) : C; \
T* new_array; \
while (_new_size < (R)) _new_size *= 2; \
new_array = BROTLI_ALLOC((M), T, _new_size); \
if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \
memcpy(new_array, A, C * sizeof(T)); \
BROTLI_FREE((M), A); \
A = new_array; \
C = _new_size; \
} \
}
/*
Appends value and dynamically grows array capacity when needed
M: MemoryManager
T: data type
A: array
C: array capacity
S: array size
V: value to append
*/
#define BROTLI_ENSURE_CAPACITY_APPEND(M, T, A, C, S, V) { \
(S)++; \
BROTLI_ENSURE_CAPACITY(M, T, A, C, S); \
A[(S) - 1] = (V); \
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_MEMORY_H_ */
@@ -0,0 +1,105 @@
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Algorithms for distributing the literals and commands of a metablock between
block types and contexts. */
#ifndef BROTLI_ENC_METABLOCK_H_
#define BROTLI_ENC_METABLOCK_H_
#include "../common/context.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./block_splitter.h"
#include "./command.h"
#include "./histogram.h"
#include "./memory.h"
#include "./quality.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
typedef struct MetaBlockSplit {
BlockSplit literal_split;
BlockSplit command_split;
BlockSplit distance_split;
uint32_t* literal_context_map;
size_t literal_context_map_size;
uint32_t* distance_context_map;
size_t distance_context_map_size;
HistogramLiteral* literal_histograms;
size_t literal_histograms_size;
HistogramCommand* command_histograms;
size_t command_histograms_size;
HistogramDistance* distance_histograms;
size_t distance_histograms_size;
} MetaBlockSplit;
static BROTLI_INLINE void InitMetaBlockSplit(MetaBlockSplit* mb) {
BrotliInitBlockSplit(&mb->literal_split);
BrotliInitBlockSplit(&mb->command_split);
BrotliInitBlockSplit(&mb->distance_split);
mb->literal_context_map = 0;
mb->literal_context_map_size = 0;
mb->distance_context_map = 0;
mb->distance_context_map_size = 0;
mb->literal_histograms = 0;
mb->literal_histograms_size = 0;
mb->command_histograms = 0;
mb->command_histograms_size = 0;
mb->distance_histograms = 0;
mb->distance_histograms_size = 0;
}
static BROTLI_INLINE void DestroyMetaBlockSplit(
MemoryManager* m, MetaBlockSplit* mb) {
BrotliDestroyBlockSplit(m, &mb->literal_split);
BrotliDestroyBlockSplit(m, &mb->command_split);
BrotliDestroyBlockSplit(m, &mb->distance_split);
BROTLI_FREE(m, mb->literal_context_map);
BROTLI_FREE(m, mb->distance_context_map);
BROTLI_FREE(m, mb->literal_histograms);
BROTLI_FREE(m, mb->command_histograms);
BROTLI_FREE(m, mb->distance_histograms);
}
/* Uses the slow shortest-path block splitter and does context clustering.
The distance parameters are dynamically selected based on the commands
which get recomputed under the new distance parameters. The new distance
parameters are stored into *params. */
BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m,
const uint8_t* ringbuffer,
const size_t pos,
const size_t mask,
BrotliEncoderParams* params,
uint8_t prev_byte,
uint8_t prev_byte2,
Command* cmds,
size_t num_commands,
ContextType literal_context_mode,
MetaBlockSplit* mb);
/* Uses a fast greedy block splitter that tries to merge current block with the
last or the second last block and uses a static context clustering which
is the same for all block types. */
BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy(
MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask,
uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut,
size_t num_contexts, const uint32_t* static_context_map,
const Command* commands, size_t n_commands, MetaBlockSplit* mb);
BROTLI_INTERNAL void BrotliOptimizeHistograms(uint32_t num_distance_codes,
MetaBlockSplit* mb);
BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliEncoderParams* params,
uint32_t npostfix, uint32_t ndirect);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_METABLOCK_H_ */
@@ -0,0 +1,183 @@
/* NOLINT(build/header_guard) */
/* Copyright 2015 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* template parameters: FN */
#define HistogramType FN(Histogram)
/* Greedy block splitter for one block category (literal, command or distance).
*/
typedef struct FN(BlockSplitter) {
/* Alphabet size of particular block category. */
size_t alphabet_size_;
/* We collect at least this many symbols for each block. */
size_t min_block_size_;
/* We merge histograms A and B if
entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
where A is the current histogram and B is the histogram of the last or the
second last block type. */
double split_threshold_;
size_t num_blocks_;
BlockSplit* split_; /* not owned */
HistogramType* histograms_; /* not owned */
size_t* histograms_size_; /* not owned */
/* The number of symbols that we want to collect before deciding on whether
or not to merge the block with a previous one or emit a new block. */
size_t target_block_size_;
/* The number of symbols in the current histogram. */
size_t block_size_;
/* Offset of the current histogram. */
size_t curr_histogram_ix_;
/* Offset of the histograms of the previous two block types. */
size_t last_histogram_ix_[2];
/* Entropy of the previous two block types. */
double last_entropy_[2];
/* The number of times we merged the current block with the last one. */
size_t merge_last_count_;
} FN(BlockSplitter);
static void FN(InitBlockSplitter)(
MemoryManager* m, FN(BlockSplitter)* self, size_t alphabet_size,
size_t min_block_size, double split_threshold, size_t num_symbols,
BlockSplit* split, HistogramType** histograms, size_t* histograms_size) {
size_t max_num_blocks = num_symbols / min_block_size + 1;
/* We have to allocate one more histogram than the maximum number of block
types for the current histogram when the meta-block is too big. */
size_t max_num_types =
BROTLI_MIN(size_t, max_num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 1);
self->alphabet_size_ = alphabet_size;
self->min_block_size_ = min_block_size;
self->split_threshold_ = split_threshold;
self->num_blocks_ = 0;
self->split_ = split;
self->histograms_size_ = histograms_size;
self->target_block_size_ = min_block_size;
self->block_size_ = 0;
self->curr_histogram_ix_ = 0;
self->merge_last_count_ = 0;
BROTLI_ENSURE_CAPACITY(m, uint8_t,
split->types, split->types_alloc_size, max_num_blocks);
BROTLI_ENSURE_CAPACITY(m, uint32_t,
split->lengths, split->lengths_alloc_size, max_num_blocks);
if (BROTLI_IS_OOM(m)) return;
self->split_->num_blocks = max_num_blocks;
BROTLI_DCHECK(*histograms == 0);
*histograms_size = max_num_types;
*histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size);
self->histograms_ = *histograms;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
/* Clear only current histogram. */
FN(HistogramClear)(&self->histograms_[0]);
self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
}
/* Does either of three things:
(1) emits the current block with a new block type;
(2) emits the current block with the type of the second last block;
(3) merges the current block with the last block. */
static void FN(BlockSplitterFinishBlock)(
FN(BlockSplitter)* self, BROTLI_BOOL is_final) {
BlockSplit* split = self->split_;
double* last_entropy = self->last_entropy_;
HistogramType* histograms = self->histograms_;
self->block_size_ =
BROTLI_MAX(size_t, self->block_size_, self->min_block_size_);
if (self->num_blocks_ == 0) {
/* Create first block. */
split->lengths[0] = (uint32_t)self->block_size_;
split->types[0] = 0;
last_entropy[0] =
BitsEntropy(histograms[0].data_, self->alphabet_size_);
last_entropy[1] = last_entropy[0];
++self->num_blocks_;
++split->num_types;
++self->curr_histogram_ix_;
if (self->curr_histogram_ix_ < *self->histograms_size_)
FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
self->block_size_ = 0;
} else if (self->block_size_ > 0) {
double entropy = BitsEntropy(histograms[self->curr_histogram_ix_].data_,
self->alphabet_size_);
HistogramType combined_histo[2];
double combined_entropy[2];
double diff[2];
size_t j;
for (j = 0; j < 2; ++j) {
size_t last_histogram_ix = self->last_histogram_ix_[j];
combined_histo[j] = histograms[self->curr_histogram_ix_];
FN(HistogramAddHistogram)(&combined_histo[j],
&histograms[last_histogram_ix]);
combined_entropy[j] = BitsEntropy(
&combined_histo[j].data_[0], self->alphabet_size_);
diff[j] = combined_entropy[j] - entropy - last_entropy[j];
}
if (split->num_types < BROTLI_MAX_NUMBER_OF_BLOCK_TYPES &&
diff[0] > self->split_threshold_ &&
diff[1] > self->split_threshold_) {
/* Create new block. */
split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
split->types[self->num_blocks_] = (uint8_t)split->num_types;
self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
self->last_histogram_ix_[0] = (uint8_t)split->num_types;
last_entropy[1] = last_entropy[0];
last_entropy[0] = entropy;
++self->num_blocks_;
++split->num_types;
++self->curr_histogram_ix_;
if (self->curr_histogram_ix_ < *self->histograms_size_)
FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
self->block_size_ = 0;
self->merge_last_count_ = 0;
self->target_block_size_ = self->min_block_size_;
} else if (diff[1] < diff[0] - 20.0) {
/* Combine this block with second last block. */
split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
histograms[self->last_histogram_ix_[0]] = combined_histo[1];
last_entropy[1] = last_entropy[0];
last_entropy[0] = combined_entropy[1];
++self->num_blocks_;
self->block_size_ = 0;
FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
self->merge_last_count_ = 0;
self->target_block_size_ = self->min_block_size_;
} else {
/* Combine this block with last block. */
split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
histograms[self->last_histogram_ix_[0]] = combined_histo[0];
last_entropy[0] = combined_entropy[0];
if (split->num_types == 1) {
last_entropy[1] = last_entropy[0];
}
self->block_size_ = 0;
FN(HistogramClear)(&histograms[self->curr_histogram_ix_]);
if (++self->merge_last_count_ > 1) {
self->target_block_size_ += self->min_block_size_;
}
}
}
if (is_final) {
*self->histograms_size_ = split->num_types;
split->num_blocks = self->num_blocks_;
}
}
/* Adds the next symbol to the current histogram. When the current histogram
reaches the target size, decides on merging the block. */
static void FN(BlockSplitterAddSymbol)(FN(BlockSplitter)* self, size_t symbol) {
FN(HistogramAdd)(&self->histograms_[self->curr_histogram_ix_], symbol);
++self->block_size_;
if (self->block_size_ == self->target_block_size_) {
FN(BlockSplitterFinishBlock)(self, /* is_final = */ BROTLI_FALSE);
}
}
#undef HistogramType
@@ -0,0 +1,46 @@
/* Copyright 2017 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Parameters for the Brotli encoder with chosen quality levels. */
#ifndef BROTLI_ENC_PARAMS_H_
#define BROTLI_ENC_PARAMS_H_
#include <brotli/encode.h>
#include "./encoder_dict.h"
typedef struct BrotliHasherParams {
int type;
int bucket_bits;
int block_bits;
int hash_len;
int num_last_distances_to_check;
} BrotliHasherParams;
typedef struct BrotliDistanceParams {
uint32_t distance_postfix_bits;
uint32_t num_direct_distance_codes;
uint32_t alphabet_size_max;
uint32_t alphabet_size_limit;
size_t max_distance;
} BrotliDistanceParams;
/* Encoding parameters */
typedef struct BrotliEncoderParams {
BrotliEncoderMode mode;
int quality;
int lgwin;
int lgblock;
size_t stream_offset;
size_t size_hint;
BROTLI_BOOL disable_literal_context_modeling;
BROTLI_BOOL large_window;
BrotliHasherParams hasher;
BrotliDistanceParams dist;
BrotliEncoderDictionary dictionary;
} BrotliEncoderParams;
#endif /* BROTLI_ENC_PARAMS_H_ */
@@ -0,0 +1,53 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Functions for encoding of integers into prefix codes the amount of extra
bits, and the actual values of the extra bits. */
#ifndef BROTLI_ENC_PREFIX_H_
#define BROTLI_ENC_PREFIX_H_
#include "../common/constants.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./fast_log.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* Here distance_code is an intermediate code, i.e. one of the special codes or
the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */
static BROTLI_INLINE void PrefixEncodeCopyDistance(size_t distance_code,
size_t num_direct_codes,
size_t postfix_bits,
uint16_t* code,
uint32_t* extra_bits) {
if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes) {
*code = (uint16_t)distance_code;
*extra_bits = 0;
return;
} else {
size_t dist = ((size_t)1 << (postfix_bits + 2u)) +
(distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES - num_direct_codes);
size_t bucket = Log2FloorNonZero(dist) - 1;
size_t postfix_mask = (1u << postfix_bits) - 1;
size_t postfix = dist & postfix_mask;
size_t prefix = (dist >> bucket) & 1;
size_t offset = (2 + prefix) << bucket;
size_t nbits = bucket - postfix_bits;
*code = (uint16_t)((nbits << 10) |
(BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes +
((2 * (nbits - 1) + prefix) << postfix_bits) + postfix));
*extra_bits = (uint32_t)((dist - offset) >> postfix_bits);
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_PREFIX_H_ */
@@ -0,0 +1,165 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Constants and formulas that affect speed-ratio trade-offs and thus define
quality levels. */
#ifndef BROTLI_ENC_QUALITY_H_
#define BROTLI_ENC_QUALITY_H_
#include "../common/platform.h"
#include <brotli/encode.h>
#include "./params.h"
#define FAST_ONE_PASS_COMPRESSION_QUALITY 0
#define FAST_TWO_PASS_COMPRESSION_QUALITY 1
#define ZOPFLIFICATION_QUALITY 10
#define HQ_ZOPFLIFICATION_QUALITY 11
#define MAX_QUALITY_FOR_STATIC_ENTROPY_CODES 2
#define MIN_QUALITY_FOR_BLOCK_SPLIT 4
#define MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS 4
#define MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS 4
#define MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH 5
#define MIN_QUALITY_FOR_CONTEXT_MODELING 5
#define MIN_QUALITY_FOR_HQ_CONTEXT_MODELING 7
#define MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING 10
/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting,
so we buffer at most this much literals and commands. */
#define MAX_NUM_DELAYED_SYMBOLS 0x2FFF
/* Returns hash-table size for quality levels 0 and 1. */
static BROTLI_INLINE size_t MaxHashTableSize(int quality) {
return quality == FAST_ONE_PASS_COMPRESSION_QUALITY ? 1 << 15 : 1 << 17;
}
/* The maximum length for which the zopflification uses distinct distances. */
#define MAX_ZOPFLI_LEN_QUALITY_10 150
#define MAX_ZOPFLI_LEN_QUALITY_11 325
/* Do not thoroughly search when a long copy is found. */
#define BROTLI_LONG_COPY_QUICK_STEP 16384
static BROTLI_INLINE size_t MaxZopfliLen(const BrotliEncoderParams* params) {
return params->quality <= 10 ?
MAX_ZOPFLI_LEN_QUALITY_10 :
MAX_ZOPFLI_LEN_QUALITY_11;
}
/* Number of best candidates to evaluate to expand Zopfli chain. */
static BROTLI_INLINE size_t MaxZopfliCandidates(
const BrotliEncoderParams* params) {
return params->quality <= 10 ? 1 : 5;
}
static BROTLI_INLINE void SanitizeParams(BrotliEncoderParams* params) {
params->quality = BROTLI_MIN(int, BROTLI_MAX_QUALITY,
BROTLI_MAX(int, BROTLI_MIN_QUALITY, params->quality));
if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) {
params->large_window = BROTLI_FALSE;
}
if (params->lgwin < BROTLI_MIN_WINDOW_BITS) {
params->lgwin = BROTLI_MIN_WINDOW_BITS;
} else {
int max_lgwin = params->large_window ? BROTLI_LARGE_MAX_WINDOW_BITS :
BROTLI_MAX_WINDOW_BITS;
if (params->lgwin > max_lgwin) params->lgwin = max_lgwin;
}
}
/* Returns optimized lg_block value. */
static BROTLI_INLINE int ComputeLgBlock(const BrotliEncoderParams* params) {
int lgblock = params->lgblock;
if (params->quality == FAST_ONE_PASS_COMPRESSION_QUALITY ||
params->quality == FAST_TWO_PASS_COMPRESSION_QUALITY) {
lgblock = params->lgwin;
} else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) {
lgblock = 14;
} else if (lgblock == 0) {
lgblock = 16;
if (params->quality >= 9 && params->lgwin > lgblock) {
lgblock = BROTLI_MIN(int, 18, params->lgwin);
}
} else {
lgblock = BROTLI_MIN(int, BROTLI_MAX_INPUT_BLOCK_BITS,
BROTLI_MAX(int, BROTLI_MIN_INPUT_BLOCK_BITS, lgblock));
}
return lgblock;
}
/* Returns log2 of the size of main ring buffer area.
Allocate at least lgwin + 1 bits for the ring buffer so that the newly
added block fits there completely and we still get lgwin bits and at least
read_block_size_bits + 1 bits because the copy tail length needs to be
smaller than ring-buffer size. */
static BROTLI_INLINE int ComputeRbBits(const BrotliEncoderParams* params) {
return 1 + BROTLI_MAX(int, params->lgwin, params->lgblock);
}
static BROTLI_INLINE size_t MaxMetablockSize(
const BrotliEncoderParams* params) {
int bits =
BROTLI_MIN(int, ComputeRbBits(params), BROTLI_MAX_INPUT_BLOCK_BITS);
return (size_t)1 << bits;
}
/* When searching for backward references and have not seen matches for a long
time, we can skip some match lookups. Unsuccessful match lookups are very
expensive and this kind of a heuristic speeds up compression quite a lot.
At first 8 byte strides are taken and every second byte is put to hasher.
After 4x more literals stride by 16 bytes, every put 4-th byte to hasher.
Applied only to qualities 2 to 9. */
static BROTLI_INLINE size_t LiteralSpreeLengthForSparseSearch(
const BrotliEncoderParams* params) {
return params->quality < 9 ? 64 : 512;
}
static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params,
BrotliHasherParams* hparams) {
if (params->quality > 9) {
hparams->type = 10;
} else if (params->quality == 4 && params->size_hint >= (1 << 20)) {
hparams->type = 54;
} else if (params->quality < 5) {
hparams->type = params->quality;
} else if (params->lgwin <= 16) {
hparams->type = params->quality < 7 ? 40 : params->quality < 9 ? 41 : 42;
} else if (params->size_hint >= (1 << 20) && params->lgwin >= 19) {
hparams->type = 6;
hparams->block_bits = params->quality - 1;
hparams->bucket_bits = 15;
hparams->hash_len = 5;
hparams->num_last_distances_to_check =
params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
} else {
hparams->type = 5;
hparams->block_bits = params->quality - 1;
hparams->bucket_bits = params->quality < 7 ? 14 : 15;
hparams->num_last_distances_to_check =
params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16;
}
if (params->lgwin > 24) {
/* Different hashers for large window brotli: not for qualities <= 2,
these are too fast for large window. Not for qualities >= 10: their
hasher already works well with large window. So the changes are:
H3 --> H35: for quality 3.
H54 --> H55: for quality 4 with size hint > 1MB
H6 --> H65: for qualities 5, 6, 7, 8, 9. */
if (hparams->type == 3) {
hparams->type = 35;
}
if (hparams->type == 54) {
hparams->type = 55;
}
if (hparams->type == 6) {
hparams->type = 65;
}
}
}
#endif /* BROTLI_ENC_QUALITY_H_ */
@@ -0,0 +1,167 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Sliding window over the input data. */
#ifndef BROTLI_ENC_RINGBUFFER_H_
#define BROTLI_ENC_RINGBUFFER_H_
#include <string.h> /* memcpy */
#include "../common/platform.h"
#include <brotli/types.h>
#include "./memory.h"
#include "./quality.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of
data in a circular manner: writing a byte writes it to:
`position() % (1 << window_bits)'.
For convenience, the RingBuffer array contains another copy of the
first `1 << tail_bits' bytes:
buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits),
and another copy of the last two bytes:
buffer_[-1] == buffer_[(1 << window_bits) - 1] and
buffer_[-2] == buffer_[(1 << window_bits) - 2]. */
typedef struct RingBuffer {
/* Size of the ring-buffer is (1 << window_bits) + tail_size_. */
const uint32_t size_;
const uint32_t mask_;
const uint32_t tail_size_;
const uint32_t total_size_;
uint32_t cur_size_;
/* Position to write in the ring buffer. */
uint32_t pos_;
/* The actual ring buffer containing the copy of the last two bytes, the data,
and the copy of the beginning as a tail. */
uint8_t* data_;
/* The start of the ring-buffer. */
uint8_t* buffer_;
} RingBuffer;
static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) {
rb->cur_size_ = 0;
rb->pos_ = 0;
rb->data_ = 0;
rb->buffer_ = 0;
}
static BROTLI_INLINE void RingBufferSetup(
const BrotliEncoderParams* params, RingBuffer* rb) {
int window_bits = ComputeRbBits(params);
int tail_bits = params->lgblock;
*(uint32_t*)&rb->size_ = 1u << window_bits;
*(uint32_t*)&rb->mask_ = (1u << window_bits) - 1;
*(uint32_t*)&rb->tail_size_ = 1u << tail_bits;
*(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_;
}
static BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) {
BROTLI_FREE(m, rb->data_);
}
/* Allocates or re-allocates data_ to the given length + plus some slack
region before and after. Fills the slack regions with zeros. */
static BROTLI_INLINE void RingBufferInitBuffer(
MemoryManager* m, const uint32_t buflen, RingBuffer* rb) {
static const size_t kSlackForEightByteHashingEverywhere = 7;
uint8_t* new_data = BROTLI_ALLOC(
m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere);
size_t i;
if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return;
if (rb->data_) {
memcpy(new_data, rb->data_,
2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere);
BROTLI_FREE(m, rb->data_);
}
rb->data_ = new_data;
rb->cur_size_ = buflen;
rb->buffer_ = rb->data_ + 2;
rb->buffer_[-2] = rb->buffer_[-1] = 0;
for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) {
rb->buffer_[rb->cur_size_ + i] = 0;
}
}
static BROTLI_INLINE void RingBufferWriteTail(
const uint8_t* bytes, size_t n, RingBuffer* rb) {
const size_t masked_pos = rb->pos_ & rb->mask_;
if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) {
/* Just fill the tail buffer with the beginning data. */
const size_t p = rb->size_ + masked_pos;
memcpy(&rb->buffer_[p], bytes,
BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos));
}
}
/* Push bytes into the ring buffer. */
static BROTLI_INLINE void RingBufferWrite(
MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) {
if (rb->pos_ == 0 && n < rb->tail_size_) {
/* Special case for the first write: to process the first block, we don't
need to allocate the whole ring-buffer and we don't need the tail
either. However, we do this memory usage optimization only if the
first write is less than the tail size, which is also the input block
size, otherwise it is likely that other blocks will follow and we
will need to reallocate to the full size anyway. */
rb->pos_ = (uint32_t)n;
RingBufferInitBuffer(m, rb->pos_, rb);
if (BROTLI_IS_OOM(m)) return;
memcpy(rb->buffer_, bytes, n);
return;
}
if (rb->cur_size_ < rb->total_size_) {
/* Lazily allocate the full buffer. */
RingBufferInitBuffer(m, rb->total_size_, rb);
if (BROTLI_IS_OOM(m)) return;
/* Initialize the last two bytes to zero, so that we don't have to worry
later when we copy the last two bytes to the first two positions. */
rb->buffer_[rb->size_ - 2] = 0;
rb->buffer_[rb->size_ - 1] = 0;
/* Initialize tail; might be touched by "best_len++" optimization when
ring buffer is "full". */
rb->buffer_[rb->size_] = 241;
}
{
const size_t masked_pos = rb->pos_ & rb->mask_;
/* The length of the writes is limited so that we do not need to worry
about a write */
RingBufferWriteTail(bytes, n, rb);
if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) {
/* A single write fits. */
memcpy(&rb->buffer_[masked_pos], bytes, n);
} else {
/* Split into two writes.
Copy into the end of the buffer, including the tail buffer. */
memcpy(&rb->buffer_[masked_pos], bytes,
BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos));
/* Copy into the beginning of the buffer */
memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos),
n - (rb->size_ - masked_pos));
}
}
{
BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0;
uint32_t rb_pos_mask = (1u << 31) - 1;
rb->buffer_[-2] = rb->buffer_[rb->size_ - 2];
rb->buffer_[-1] = rb->buffer_[rb->size_ - 1];
rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask);
if (not_first_lap) {
/* Wrap, but preserve not-a-first-lap feature. */
rb->pos_ |= 1u << 31;
}
}
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_RINGBUFFER_H_ */
@@ -0,0 +1,40 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Class to model the static dictionary. */
#ifndef BROTLI_ENC_STATIC_DICT_H_
#define BROTLI_ENC_STATIC_DICT_H_
#include "../common/dictionary.h"
#include "../common/platform.h"
#include <brotli/types.h>
#include "./encoder_dict.h"
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
#define BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN 37
static const uint32_t kInvalidMatch = 0xFFFFFFF;
/* Matches data against static dictionary words, and for each length l,
for which a match is found, updates matches[l] to be the minimum possible
(distance << 5) + len_code.
Returns 1 if matches have been found, otherwise 0.
Prerequisites:
matches array is at least BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1 long
all elements are initialized to kInvalidMatch */
BROTLI_INTERNAL BROTLI_BOOL BrotliFindAllStaticDictionaryMatches(
const BrotliEncoderDictionary* dictionary,
const uint8_t* data, size_t min_length, size_t max_length,
uint32_t* matches);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_STATIC_DICT_H_ */
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,32 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Heuristics for deciding about the UTF8-ness of strings. */
#ifndef BROTLI_ENC_UTF8_UTIL_H_
#define BROTLI_ENC_UTF8_UTIL_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
static const double kMinUTF8Ratio = 0.75;
/* Returns 1 if at least min_fraction of the bytes between pos and
pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise
returns 0. */
BROTLI_INTERNAL BROTLI_BOOL BrotliIsMostlyUTF8(
const uint8_t* data, const size_t pos, const size_t mask,
const size_t length, const double min_fraction);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_UTF8_UTIL_H_ */
@@ -0,0 +1,87 @@
/* Copyright 2010 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Write bits into a byte array. */
#ifndef BROTLI_ENC_WRITE_BITS_H_
#define BROTLI_ENC_WRITE_BITS_H_
#include "../common/platform.h"
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/* This function writes bits into bytes in increasing addresses, and within
a byte least-significant-bit first.
The function can write up to 56 bits in one go with WriteBits
Example: let's assume that 3 bits (Rs below) have been written already:
BYTE-0 BYTE+1 BYTE+2
0000 0RRR 0000 0000 0000 0000
Now, we could write 5 or less bits in MSB by just shifting by 3
and OR'ing to BYTE-0.
For n bits, we take the last 5 bits, OR that with high bits in BYTE-0,
and locate the rest in BYTE+1, BYTE+2, etc. */
static BROTLI_INLINE void BrotliWriteBits(size_t n_bits,
uint64_t bits,
size_t* BROTLI_RESTRICT pos,
uint8_t* BROTLI_RESTRICT array) {
BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits,
(uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF),
(int)*pos));
BROTLI_DCHECK((bits >> n_bits) == 0);
BROTLI_DCHECK(n_bits <= 56);
#if defined(BROTLI_LITTLE_ENDIAN)
/* This branch of the code can write up to 56 bits at a time,
7 bits are lost by being perhaps already in *p and at least
1 bit is needed to initialize the bit-stream ahead (i.e. if 7
bits are in *p and we write 57 bits, then the next write will
access a byte that was never initialized). */
{
uint8_t* p = &array[*pos >> 3];
uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */
v |= bits << (*pos & 7);
BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */
*pos += n_bits;
}
#else
/* implicit & 0xFF is assumed for uint8_t arithmetics */
{
uint8_t* array_pos = &array[*pos >> 3];
const size_t bits_reserved_in_first_byte = (*pos & 7);
size_t bits_left_to_write;
bits <<= bits_reserved_in_first_byte;
*array_pos++ |= (uint8_t)bits;
for (bits_left_to_write = n_bits + bits_reserved_in_first_byte;
bits_left_to_write >= 9;
bits_left_to_write -= 8) {
bits >>= 8;
*array_pos++ = (uint8_t)bits;
}
*array_pos = 0;
*pos += n_bits;
}
#endif
}
static BROTLI_INLINE void BrotliWriteBitsPrepareStorage(
size_t pos, uint8_t* array) {
BROTLI_LOG(("WriteBitsPrepareStorage %10d\n", (int)pos));
BROTLI_DCHECK((pos & 7) == 0);
array[pos >> 3] = 0;
}
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_WRITE_BITS_H_ */
@@ -0,0 +1,346 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @file
* API for Brotli decompression.
*/
#ifndef BROTLI_DEC_DECODE_H_
#define BROTLI_DEC_DECODE_H_
#include "il2cpp-config.h"
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/**
* Opaque structure that holds decoder state.
*
* Allocated and initialized with ::BrotliDecoderCreateInstance.
* Cleaned up and deallocated with ::BrotliDecoderDestroyInstance.
*/
typedef struct BrotliDecoderStateStruct BrotliDecoderState;
/**
* Result type for ::BrotliDecoderDecompress and
* ::BrotliDecoderDecompressStream functions.
*/
typedef enum {
/** Decoding error, e.g. corrupted 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;
/**
* Template that evaluates items of ::BrotliDecoderErrorCode.
*
* Example: @code {.cpp}
* // Log Brotli error code.
* switch (brotliDecoderErrorCode) {
* #define CASE_(PREFIX, NAME, CODE) \
* case BROTLI_DECODER ## PREFIX ## NAME: \
* LOG(INFO) << "error code:" << #NAME; \
* break;
* #define NEWLINE_
* BROTLI_DECODER_ERROR_CODES_LIST(CASE_, NEWLINE_)
* #undef CASE_
* #undef NEWLINE_
* default: LOG(FATAL) << "unknown brotli error code";
* }
* @endcode
*/
#define BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \
BROTLI_ERROR_CODE(_, NO_ERROR, 0) SEPARATOR \
/* Same as BrotliDecoderResult values */ \
BROTLI_ERROR_CODE(_, SUCCESS, 1) SEPARATOR \
BROTLI_ERROR_CODE(_, NEEDS_MORE_INPUT, 2) SEPARATOR \
BROTLI_ERROR_CODE(_, NEEDS_MORE_OUTPUT, 3) SEPARATOR \
\
/* Errors caused by invalid input */ \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_NIBBLE, -1) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, RESERVED, -2) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_META_NIBBLE, -3) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, CL_SPACE, -6) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, HUFFMAN_SPACE, -7) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, CONTEXT_MAP_REPEAT, -8) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_1, -9) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_2, -10) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, TRANSFORM, -11) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, DICTIONARY, -12) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \
\
/* -17..-18 codes are reserved */ \
\
BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \
\
/* Memory allocation problems */ \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MODES, -21) SEPARATOR \
/* Literal, insert and distance trees together */ \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, TREE_GROUPS, -22) SEPARATOR \
/* -23..-24 codes are reserved for distinct tree groups */ \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MAP, -25) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_1, -26) SEPARATOR \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_2, -27) SEPARATOR \
/* -28..-29 codes are reserved for dynamic ring-buffer allocation */ \
BROTLI_ERROR_CODE(_ERROR_ALLOC_, BLOCK_TYPE_TREES, -30) SEPARATOR \
\
/* "Impossible" states */ \
BROTLI_ERROR_CODE(_ERROR_, UNREACHABLE, -31)
/**
* Error code for detailed logging / production debugging.
*
* See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE.
*/
typedef enum {
#define BROTLI_COMMA_ ,
#define BROTLI_ERROR_CODE_ENUM_ITEM_(PREFIX, NAME, CODE) \
BROTLI_DECODER ## PREFIX ## NAME = CODE
BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_ENUM_ITEM_, BROTLI_COMMA_)
} BrotliDecoderErrorCode;
#undef BROTLI_ERROR_CODE_ENUM_ITEM_
#undef BROTLI_COMMA_
/**
* The value of the last error code, negative integer.
*
* All other error code values are in the range from ::BROTLI_LAST_ERROR_CODE
* to @c -1. There are also 4 other possible non-error codes @c 0 .. @c 3 in
* ::BrotliDecoderErrorCode enumeration.
*/
#define BROTLI_LAST_ERROR_CODE BROTLI_DECODER_ERROR_UNREACHABLE
/** Options to be used with ::BrotliDecoderSetParameter. */
typedef enum BrotliDecoderParameter {
/**
* Disable "canny" ring buffer allocation strategy.
*
* Ring buffer is allocated according to window size, despite the real size of
* the content.
*/
BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0,
/**
* Flag that determines if "Large Window Brotli" is used.
*/
BROTLI_DECODER_PARAM_LARGE_WINDOW = 1
} BrotliDecoderParameter;
/**
* Sets the specified parameter to the given decoder instance.
*
* @param state decoder instance
* @param param parameter to set
* @param value new parameter value
* @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid
* @returns ::BROTLI_TRUE if value is accepted
*/
BROTLI_DEC_API BROTLI_BOOL BrotliDecoderSetParameter(
BrotliDecoderState* state, BrotliDecoderParameter param, uint32_t value);
/**
* Creates an instance of ::BrotliDecoderState and initializes it.
*
* The instance can be used once for decoding and should then be destroyed with
* ::BrotliDecoderDestroyInstance, it cannot be reused for a new decoding
* session.
*
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
* case they are both zero, default memory allocators are used. @p opaque is
* passed to @p alloc_func and @p free_func when they are called. @p free_func
* has to return without doing anything when asked to free a NULL pointer.
*
* @param alloc_func custom memory allocation function
* @param free_func custom memory free function
* @param opaque custom memory manager handle
* @returns @c 0 if instance can not be allocated or initialized
* @returns pointer to initialized ::BrotliDecoderState otherwise
*/
IL2CPP_EXPORT BROTLI_DEC_API BrotliDecoderState* STDCALL BrotliDecoderCreateInstance(
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
/**
* Deinitializes and frees ::BrotliDecoderState instance.
*
* @param state decoder instance to be cleaned up and deallocated
*/
IL2CPP_EXPORT BROTLI_DEC_API void STDCALL BrotliDecoderDestroyInstance(BrotliDecoderState* state);
/**
* Performs one-shot memory-to-memory decompression.
*
* Decompresses the data in @p encoded_buffer into @p decoded_buffer, and sets
* @p *decoded_size to the decompressed length.
*
* @param encoded_size size of @p encoded_buffer
* @param encoded_buffer compressed data buffer with at least @p encoded_size
* addressable bytes
* @param[in, out] decoded_size @b in: size of @p decoded_buffer; \n
* @b out: length of decompressed data written to
* @p decoded_buffer
* @param decoded_buffer decompressed data destination buffer
* @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory
* allocation failed, or @p decoded_buffer is not large enough;
* @returns ::BROTLI_DECODER_RESULT_SUCCESS otherwise
*/
IL2CPP_EXPORT BROTLI_DEC_API BrotliDecoderResult STDCALL BrotliDecoderDecompress(
size_t encoded_size,
const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)],
size_t* decoded_size,
uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]);
/**
* Decompresses the input stream to the output stream.
*
* The values @p *available_in and @p *available_out must specify the number of
* bytes addressable at @p *next_in and @p *next_out respectively.
* When @p *available_out is @c 0, @p next_out is allowed to be @c NULL.
*
* After each call, @p *available_in will be decremented by the amount of input
* bytes consumed, and the @p *next_in pointer will be incremented by that
* amount. Similarly, @p *available_out will be decremented by the amount of
* output bytes written, and the @p *next_out pointer will be incremented by
* that amount.
*
* @p total_out, if it is not a null-pointer, will be set to the number
* of bytes decompressed since the last @p state initialization.
*
* @note Input is never overconsumed, so @p next_in and @p available_in could be
* passed to the next consumer after decoding is complete.
*
* @param state decoder instance
* @param[in, out] available_in @b in: amount of available input; \n
* @b out: amount of unused input
* @param[in, out] next_in pointer to the next compressed byte
* @param[in, out] available_out @b in: length of output buffer; \n
* @b out: remaining size of output buffer
* @param[in, out] next_out output buffer cursor;
* can be @c NULL if @p available_out is @c 0
* @param[out] total_out number of bytes decompressed so far; can be @c NULL
* @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory
* allocation failed, arguments were invalid, etc.;
* use ::BrotliDecoderGetErrorCode to get detailed error code
* @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT decoding is blocked until
* more input data is provided
* @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT decoding is blocked until
* more output space is provided
* @returns ::BROTLI_DECODER_RESULT_SUCCESS decoding is finished, no more
* input might be consumed and no more output will be produced
*/
IL2CPP_EXPORT BROTLI_DEC_API BrotliDecoderResult STDCALL BrotliDecoderDecompressStream(
BrotliDecoderState* state, size_t* available_in, const uint8_t** next_in,
size_t* available_out, uint8_t** next_out, size_t* total_out);
/**
* Checks if decoder has more output.
*
* @param state decoder instance
* @returns ::BROTLI_TRUE, if decoder has some unconsumed output
* @returns ::BROTLI_FALSE otherwise
*/
BROTLI_DEC_API BROTLI_BOOL BrotliDecoderHasMoreOutput(
const BrotliDecoderState* state);
/**
* Acquires pointer to internal output buffer.
*
* This method is used to make language bindings easier and more efficient:
* -# push data to ::BrotliDecoderDecompressStream,
* until ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT is reported
* -# use ::BrotliDecoderTakeOutput to peek bytes and copy to language-specific
* entity
*
* Also this could be useful if there is an output stream that is able to
* consume all the provided data (e.g. when data is saved to file system).
*
* @attention After every call to ::BrotliDecoderTakeOutput @p *size bytes of
* output are considered consumed for all consecutive calls to the
* instance methods; returned pointer becomes invalidated as well.
*
* @note Decoder output is not guaranteed to be contiguous. This means that
* after the size-unrestricted call to ::BrotliDecoderTakeOutput,
* immediate next call to ::BrotliDecoderTakeOutput may return more data.
*
* @param state decoder instance
* @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if
* any amount could be handled; \n
* @b out: amount of data pointed by returned pointer and
* considered consumed; \n
* out value is never greater than in value, unless it is @c 0
* @returns pointer to output data
*/
BROTLI_DEC_API const uint8_t* BrotliDecoderTakeOutput(
BrotliDecoderState* state, size_t* size);
/**
* Checks if instance has already consumed input.
*
* Instance that returns ::BROTLI_FALSE is considered "fresh" and could be
* reused.
*
* @param state decoder instance
* @returns ::BROTLI_TRUE if decoder has already used some input bytes
* @returns ::BROTLI_FALSE otherwise
*/
BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* state);
/**
* Checks if decoder instance reached the final state.
*
* @param state decoder instance
* @returns ::BROTLI_TRUE if decoder is in a state where it reached the end of
* the input and produced all of the output
* @returns ::BROTLI_FALSE otherwise
*/
IL2CPP_EXPORT BROTLI_DEC_API BROTLI_BOOL STDCALL BrotliDecoderIsFinished(
const BrotliDecoderState* state);
/**
* Acquires a detailed error code.
*
* Should be used only after ::BrotliDecoderDecompressStream returns
* ::BROTLI_DECODER_RESULT_ERROR.
*
* See also ::BrotliDecoderErrorString
*
* @param state decoder instance
* @returns last saved error code
*/
BROTLI_DEC_API BrotliDecoderErrorCode BrotliDecoderGetErrorCode(
const BrotliDecoderState* state);
/**
* Converts error code to a c-string.
*/
BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c);
/**
* Gets a decoder library version.
*
* Look at BROTLI_VERSION for more information.
*/
BROTLI_DEC_API uint32_t BrotliDecoderVersion(void);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_DEC_DECODE_H_ */
@@ -0,0 +1,450 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @file
* API for Brotli compression.
*/
#ifndef BROTLI_ENC_ENCODE_H_
#define BROTLI_ENC_ENCODE_H_
#include "il2cpp-config.h"
#include <brotli/port.h>
#include <brotli/types.h>
#if defined(__cplusplus) || defined(c_plusplus)
extern "C" {
#endif
/** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */
#define BROTLI_MIN_WINDOW_BITS 10
/**
* Maximal value for ::BROTLI_PARAM_LGWIN parameter.
*
* @note equal to @c BROTLI_MAX_DISTANCE_BITS constant.
*/
#define BROTLI_MAX_WINDOW_BITS 24
/**
* Maximal value for ::BROTLI_PARAM_LGWIN parameter
* in "Large Window Brotli" (32-bit).
*/
#define BROTLI_LARGE_MAX_WINDOW_BITS 30
/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */
#define BROTLI_MIN_INPUT_BLOCK_BITS 16
/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */
#define BROTLI_MAX_INPUT_BLOCK_BITS 24
/** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */
#define BROTLI_MIN_QUALITY 0
/** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */
#define BROTLI_MAX_QUALITY 11
/** Options for ::BROTLI_PARAM_MODE parameter. */
typedef enum BrotliEncoderMode {
/**
* Default compression mode.
*
* In this mode compressor does not know anything in advance about the
* properties of the input.
*/
BROTLI_MODE_GENERIC = 0,
/** Compression mode for UTF-8 formatted text input. */
BROTLI_MODE_TEXT = 1,
/** Compression mode used in WOFF 2.0. */
BROTLI_MODE_FONT = 2
} BrotliEncoderMode;
/** Default value for ::BROTLI_PARAM_QUALITY parameter. */
#define BROTLI_DEFAULT_QUALITY 11
/** Default value for ::BROTLI_PARAM_LGWIN parameter. */
#define BROTLI_DEFAULT_WINDOW 22
/** Default value for ::BROTLI_PARAM_MODE parameter. */
#define BROTLI_DEFAULT_MODE BROTLI_MODE_GENERIC
/** Operations that can be performed by streaming encoder. */
typedef enum BrotliEncoderOperation {
/**
* Process input.
*
* Encoder may postpone producing output, until it has processed enough input.
*/
BROTLI_OPERATION_PROCESS = 0,
/**
* Produce output for all processed input.
*
* Actual flush is performed when input stream is depleted and there is enough
* space in output stream. This means that client should repeat
* ::BROTLI_OPERATION_FLUSH operation until @p available_in becomes @c 0, and
* ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired
* via ::BrotliEncoderTakeOutput, then operation should be repeated after
* output buffer is drained.
*
* @warning Until flush is complete, client @b SHOULD @b NOT swap,
* reduce or extend input stream.
*
* When flush is complete, output data will be sufficient for decoder to
* reproduce all the given input.
*/
BROTLI_OPERATION_FLUSH = 1,
/**
* Finalize the stream.
*
* Actual finalization is performed when input stream is depleted and there is
* enough space in output stream. This means that client should repeat
* ::BROTLI_OPERATION_FINISH operation until @p available_in becomes @c 0, and
* ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired
* via ::BrotliEncoderTakeOutput, then operation should be repeated after
* output buffer is drained.
*
* @warning Until finalization is complete, client @b SHOULD @b NOT swap,
* reduce or extend input stream.
*
* Helper function ::BrotliEncoderIsFinished checks if stream is finalized and
* output fully dumped.
*
* Adding more input data to finalized stream is impossible.
*/
BROTLI_OPERATION_FINISH = 2,
/**
* Emit metadata block to stream.
*
* Metadata is opaque to Brotli: neither encoder, nor decoder processes this
* data or relies on it. It may be used to pass some extra information from
* encoder client to decoder client without interfering with main data stream.
*
* @note Encoder may emit empty metadata blocks internally, to pad encoded
* stream to byte boundary.
*
* @warning Until emitting metadata is complete client @b SHOULD @b NOT swap,
* reduce or extend input stream.
*
* @warning The whole content of input buffer is considered to be the content
* of metadata block. Do @b NOT @e append metadata to input stream,
* before it is depleted with other operations.
*
* Stream is soft-flushed before metadata block is emitted. Metadata block
* @b MUST be no longer than than 16MiB.
*/
BROTLI_OPERATION_EMIT_METADATA = 3
} BrotliEncoderOperation;
/** Options to be used with ::BrotliEncoderSetParameter. */
typedef enum BrotliEncoderParameter {
/**
* Tune encoder for specific input.
*
* ::BrotliEncoderMode enumerates all available values.
*/
BROTLI_PARAM_MODE = 0,
/**
* The main compression speed-density lever.
*
* The higher the quality, the slower the compression. Range is
* from ::BROTLI_MIN_QUALITY to ::BROTLI_MAX_QUALITY.
*/
BROTLI_PARAM_QUALITY = 1,
/**
* Recommended sliding LZ77 window size.
*
* Encoder may reduce this value, e.g. if input is much smaller than
* window size.
*
* Window size is `(1 << value) - 16`.
*
* Range is from ::BROTLI_MIN_WINDOW_BITS to ::BROTLI_MAX_WINDOW_BITS.
*/
BROTLI_PARAM_LGWIN = 2,
/**
* Recommended input block size.
*
* Encoder may reduce this value, e.g. if input is much smaller than input
* block size.
*
* Range is from ::BROTLI_MIN_INPUT_BLOCK_BITS to
* ::BROTLI_MAX_INPUT_BLOCK_BITS.
*
* @note Bigger input block size allows better compression, but consumes more
* memory. \n The rough formula of memory used for temporary input
* storage is `3 << lgBlock`.
*/
BROTLI_PARAM_LGBLOCK = 3,
/**
* Flag that affects usage of "literal context modeling" format feature.
*
* This flag is a "decoding-speed vs compression ratio" trade-off.
*/
BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING = 4,
/**
* Estimated total input size for all ::BrotliEncoderCompressStream calls.
*
* The default value is 0, which means that the total input size is unknown.
*/
BROTLI_PARAM_SIZE_HINT = 5,
/**
* Flag that determines if "Large Window Brotli" is used.
*/
BROTLI_PARAM_LARGE_WINDOW = 6,
/**
* Recommended number of postfix bits (NPOSTFIX).
*
* Encoder may change this value.
*
* Range is from 0 to ::BROTLI_MAX_NPOSTFIX.
*/
BROTLI_PARAM_NPOSTFIX = 7,
/**
* Recommended number of direct distance codes (NDIRECT).
*
* Encoder may change this value.
*
* Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX).
*/
BROTLI_PARAM_NDIRECT = 8,
/**
* Number of bytes of input stream already processed by a different instance.
*
* @note It is important to configure all the encoder instances with same
* parameters (except this one) in order to allow all the encoded parts
* obey the same restrictions implied by header.
*
* If offset is not 0, then stream header is omitted.
* In any case output start is byte aligned, so for proper streams stitching
* "predecessor" stream must be flushed.
*
* Range is not artificially limited, but all the values greater or equal to
* maximal window size have the same effect. Values greater than 2**30 are not
* allowed.
*/
BROTLI_PARAM_STREAM_OFFSET = 9
} BrotliEncoderParameter;
/**
* Opaque structure that holds encoder state.
*
* Allocated and initialized with ::BrotliEncoderCreateInstance.
* Cleaned up and deallocated with ::BrotliEncoderDestroyInstance.
*/
typedef struct BrotliEncoderStateStruct BrotliEncoderState;
/**
* Sets the specified parameter to the given encoder instance.
*
* @param state encoder instance
* @param param parameter to set
* @param value new parameter value
* @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid
* @returns ::BROTLI_FALSE if value of parameter can not be changed at current
* encoder state (e.g. when encoding is started, window size might be
* already encoded and therefore it is impossible to change it)
* @returns ::BROTLI_TRUE if value is accepted
* @warning invalid values might be accepted in case they would not break
* encoding process.
*/
IL2CPP_EXPORT BROTLI_ENC_API BROTLI_BOOL STDCALL BrotliEncoderSetParameter(
BrotliEncoderState* state, BrotliEncoderParameter param, uint32_t value);
/**
* Creates an instance of ::BrotliEncoderState and initializes it.
*
* @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the
* case they are both zero, default memory allocators are used. @p opaque is
* passed to @p alloc_func and @p free_func when they are called. @p free_func
* has to return without doing anything when asked to free a NULL pointer.
*
* @param alloc_func custom memory allocation function
* @param free_func custom memory free function
* @param opaque custom memory manager handle
* @returns @c 0 if instance can not be allocated or initialized
* @returns pointer to initialized ::BrotliEncoderState otherwise
*/
IL2CPP_EXPORT BROTLI_ENC_API BrotliEncoderState* STDCALL BrotliEncoderCreateInstance(
brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque);
/**
* Deinitializes and frees ::BrotliEncoderState instance.
*
* @param state decoder instance to be cleaned up and deallocated
*/
IL2CPP_EXPORT BROTLI_ENC_API void STDCALL BrotliEncoderDestroyInstance(BrotliEncoderState* state);
/**
* Calculates the output size bound for the given @p input_size.
*
* @warning Result is only valid if quality is at least @c 2 and, in
* case ::BrotliEncoderCompressStream was used, no flushes
* (::BROTLI_OPERATION_FLUSH) were performed.
*
* @param input_size size of projected input
* @returns @c 0 if result does not fit @c size_t
*/
BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size);
/**
* Performs one-shot memory-to-memory compression.
*
* Compresses the data in @p input_buffer into @p encoded_buffer, and sets
* @p *encoded_size to the compressed length.
*
* @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero
* value, then output is guaranteed to be no longer than that.
*
* @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting
* stream might be incompatible with RFC 7932; to decode such streams,
* decoder should be configured with
* ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1
*
* @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY
* @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW
* @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE
* @param input_size size of @p input_buffer
* @param input_buffer input data buffer with at least @p input_size
* addressable bytes
* @param[in, out] encoded_size @b in: size of @p encoded_buffer; \n
* @b out: length of compressed data written to
* @p encoded_buffer, or @c 0 if compression fails
* @param encoded_buffer compressed data destination buffer
* @returns ::BROTLI_FALSE in case of compression error
* @returns ::BROTLI_FALSE if output buffer is too small
* @returns ::BROTLI_TRUE otherwise
*/
IL2CPP_EXPORT BROTLI_ENC_API BROTLI_BOOL STDCALL BrotliEncoderCompress(
int quality, int lgwin, BrotliEncoderMode mode, size_t input_size,
const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)],
size_t* encoded_size,
uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]);
/**
* Compresses input stream to output stream.
*
* The values @p *available_in and @p *available_out must specify the number of
* bytes addressable at @p *next_in and @p *next_out respectively.
* When @p *available_out is @c 0, @p next_out is allowed to be @c NULL.
*
* After each call, @p *available_in will be decremented by the amount of input
* bytes consumed, and the @p *next_in pointer will be incremented by that
* amount. Similarly, @p *available_out will be decremented by the amount of
* output bytes written, and the @p *next_out pointer will be incremented by
* that amount.
*
* @p total_out, if it is not a null-pointer, will be set to the number
* of bytes compressed since the last @p state initialization.
*
*
*
* Internally workflow consists of 3 tasks:
* -# (optionally) copy input data to internal buffer
* -# actually compress data and (optionally) store it to internal buffer
* -# (optionally) copy compressed bytes from internal buffer to output stream
*
* Whenever all 3 tasks can't move forward anymore, or error occurs, this
* method returns the control flow to caller.
*
* @p op is used to perform flush, finish the stream, or inject metadata block.
* See ::BrotliEncoderOperation for more information.
*
* Flushing the stream means forcing encoding of all input passed to encoder and
* completing the current output block, so it could be fully decoded by stream
* decoder. To perform flush set @p op to ::BROTLI_OPERATION_FLUSH.
* Under some circumstances (e.g. lack of output stream capacity) this operation
* would require several calls to ::BrotliEncoderCompressStream. The method must
* be called again until both input stream is depleted and encoder has no more
* output (see ::BrotliEncoderHasMoreOutput) after the method is called.
*
* Finishing the stream means encoding of all input passed to encoder and
* adding specific "final" marks, so stream decoder could determine that stream
* is complete. To perform finish set @p op to ::BROTLI_OPERATION_FINISH.
* Under some circumstances (e.g. lack of output stream capacity) this operation
* would require several calls to ::BrotliEncoderCompressStream. The method must
* be called again until both input stream is depleted and encoder has no more
* output (see ::BrotliEncoderHasMoreOutput) after the method is called.
*
* @warning When flushing and finishing, @p op should not change until operation
* is complete; input stream should not be swapped, reduced or
* extended as well.
*
* @param state encoder instance
* @param op requested operation
* @param[in, out] available_in @b in: amount of available input; \n
* @b out: amount of unused input
* @param[in, out] next_in pointer to the next input byte
* @param[in, out] available_out @b in: length of output buffer; \n
* @b out: remaining size of output buffer
* @param[in, out] next_out compressed output buffer cursor;
* can be @c NULL if @p available_out is @c 0
* @param[out] total_out number of bytes produced so far; can be @c NULL
* @returns ::BROTLI_FALSE if there was an error
* @returns ::BROTLI_TRUE otherwise
*/
IL2CPP_EXPORT BROTLI_ENC_API BROTLI_BOOL STDCALL BrotliEncoderCompressStream(
BrotliEncoderState* state, BrotliEncoderOperation op, size_t* available_in,
const uint8_t** next_in, size_t* available_out, uint8_t** next_out,
size_t* total_out);
/**
* Checks if encoder instance reached the final state.
*
* @param state encoder instance
* @returns ::BROTLI_TRUE if encoder is in a state where it reached the end of
* the input and produced all of the output
* @returns ::BROTLI_FALSE otherwise
*/
BROTLI_ENC_API BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* state);
/**
* Checks if encoder has more output.
*
* @param state encoder instance
* @returns ::BROTLI_TRUE, if encoder has some unconsumed output
* @returns ::BROTLI_FALSE otherwise
*/
IL2CPP_EXPORT BROTLI_ENC_API BROTLI_BOOL STDCALL BrotliEncoderHasMoreOutput(
BrotliEncoderState* state);
/**
* Acquires pointer to internal output buffer.
*
* This method is used to make language bindings easier and more efficient:
* -# push data to ::BrotliEncoderCompressStream,
* until ::BrotliEncoderHasMoreOutput returns BROTL_TRUE
* -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific
* entity
*
* Also this could be useful if there is an output stream that is able to
* consume all the provided data (e.g. when data is saved to file system).
*
* @attention After every call to ::BrotliEncoderTakeOutput @p *size bytes of
* output are considered consumed for all consecutive calls to the
* instance methods; returned pointer becomes invalidated as well.
*
* @note Encoder output is not guaranteed to be contiguous. This means that
* after the size-unrestricted call to ::BrotliEncoderTakeOutput,
* immediate next call to ::BrotliEncoderTakeOutput may return more data.
*
* @param state encoder instance
* @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if
* any amount could be handled; \n
* @b out: amount of data pointed by returned pointer and
* considered consumed; \n
* out value is never greater than in value, unless it is @c 0
* @returns pointer to output data
*/
BROTLI_ENC_API const uint8_t* BrotliEncoderTakeOutput(
BrotliEncoderState* state, size_t* size);
/**
* Gets an encoder library version.
*
* Look at BROTLI_VERSION for more information.
*/
BROTLI_ENC_API uint32_t BrotliEncoderVersion(void);
#if defined(__cplusplus) || defined(c_plusplus)
} /* extern "C" */
#endif
#endif /* BROTLI_ENC_ENCODE_H_ */
@@ -0,0 +1,288 @@
/* Copyright 2016 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/* Macros for compiler / platform specific API declarations. */
#ifndef BROTLI_COMMON_PORT_H_
#define BROTLI_COMMON_PORT_H_
/* The following macros were borrowed from https://github.com/nemequ/hedley
* with permission of original author - Evan Nemerson <evan@nemerson.com> */
/* >>> >>> >>> hedley macros */
#define BROTLI_MAKE_VERSION(major, minor, revision) \
(((major) * 1000000) + ((minor) * 1000) + (revision))
#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__)
#define BROTLI_GNUC_VERSION \
BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
#elif defined(__GNUC__)
#define BROTLI_GNUC_VERSION BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, 0)
#endif
#if defined(BROTLI_GNUC_VERSION)
#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) \
(BROTLI_GNUC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000)
#define BROTLI_MSVC_VERSION \
BROTLI_MAKE_VERSION((_MSC_FULL_VER / 10000000), \
(_MSC_FULL_VER % 10000000) / 100000, \
(_MSC_FULL_VER % 100000) / 100)
#elif defined(_MSC_FULL_VER)
#define BROTLI_MSVC_VERSION \
BROTLI_MAKE_VERSION((_MSC_FULL_VER / 1000000), \
(_MSC_FULL_VER % 1000000) / 10000, \
(_MSC_FULL_VER % 10000) / 10)
#elif defined(_MSC_VER)
#define BROTLI_MSVC_VERSION \
BROTLI_MAKE_VERSION(_MSC_VER / 100, _MSC_VER % 100, 0)
#endif
#if !defined(_MSC_VER)
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) (0)
#elif defined(_MSC_VER) && (_MSC_VER >= 1400)
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
(_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch)))
#elif defined(_MSC_VER) && (_MSC_VER >= 1200)
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
(_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch)))
#else
#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \
(_MSC_VER >= ((major * 100) + (minor)))
#endif
#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE)
#define BROTLI_INTEL_VERSION \
BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, \
__INTEL_COMPILER % 100, \
__INTEL_COMPILER_UPDATE)
#elif defined(__INTEL_COMPILER)
#define BROTLI_INTEL_VERSION \
BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0)
#endif
#if defined(BROTLI_INTEL_VERSION)
#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) \
(BROTLI_INTEL_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__PGI) && \
defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__)
#define BROTLI_PGI_VERSION \
BROTLI_MAKE_VERSION(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__)
#endif
#if defined(BROTLI_PGI_VERSION)
#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) \
(BROTLI_PGI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000)
#define BROTLI_SUNPRO_VERSION \
BROTLI_MAKE_VERSION( \
(((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \
(((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \
(__SUNPRO_C & 0xf) * 10)
#elif defined(__SUNPRO_C)
#define BROTLI_SUNPRO_VERSION \
BROTLI_MAKE_VERSION((__SUNPRO_C >> 8) & 0xf, \
(__SUNPRO_C >> 4) & 0xf, \
(__SUNPRO_C) & 0xf)
#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000)
#define BROTLI_SUNPRO_VERSION \
BROTLI_MAKE_VERSION( \
(((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \
(((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \
(__SUNPRO_CC & 0xf) * 10)
#elif defined(__SUNPRO_CC)
#define BROTLI_SUNPRO_VERSION \
BROTLI_MAKE_VERSION((__SUNPRO_CC >> 8) & 0xf, \
(__SUNPRO_CC >> 4) & 0xf, \
(__SUNPRO_CC) & 0xf)
#endif
#if defined(BROTLI_SUNPRO_VERSION)
#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) \
(BROTLI_SUNPRO_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION)
#define BROTLI_ARM_VERSION \
BROTLI_MAKE_VERSION((__ARMCOMPILER_VERSION / 1000000), \
(__ARMCOMPILER_VERSION % 1000000) / 10000, \
(__ARMCOMPILER_VERSION % 10000) / 100)
#elif defined(__CC_ARM) && defined(__ARMCC_VERSION)
#define BROTLI_ARM_VERSION \
BROTLI_MAKE_VERSION((__ARMCC_VERSION / 1000000), \
(__ARMCC_VERSION % 1000000) / 10000, \
(__ARMCC_VERSION % 10000) / 100)
#endif
#if defined(BROTLI_ARM_VERSION)
#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) \
(BROTLI_ARM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__ibmxl__)
#define BROTLI_IBM_VERSION \
BROTLI_MAKE_VERSION(__ibmxl_version__, \
__ibmxl_release__, \
__ibmxl_modification__)
#elif defined(__xlC__) && defined(__xlC_ver__)
#define BROTLI_IBM_VERSION \
BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff)
#elif defined(__xlC__)
#define BROTLI_IBM_VERSION BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, 0)
#endif
#if defined(BROTLI_IBM_VERSION)
#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) \
(BROTLI_IBM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__TI_COMPILER_VERSION__)
#define BROTLI_TI_VERSION \
BROTLI_MAKE_VERSION((__TI_COMPILER_VERSION__ / 1000000), \
(__TI_COMPILER_VERSION__ % 1000000) / 1000, \
(__TI_COMPILER_VERSION__ % 1000))
#endif
#if defined(BROTLI_TI_VERSION)
#define BROTLI_TI_VERSION_CHECK(major, minor, patch) \
(BROTLI_TI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_TI_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__IAR_SYSTEMS_ICC__)
#if __VER__ > 1000
#define BROTLI_IAR_VERSION \
BROTLI_MAKE_VERSION((__VER__ / 1000000), \
(__VER__ / 1000) % 1000, \
(__VER__ % 1000))
#else
#define BROTLI_IAR_VERSION BROTLI_MAKE_VERSION(VER / 100, __VER__ % 100, 0)
#endif
#endif
#if defined(BROTLI_IAR_VERSION)
#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) \
(BROTLI_IAR_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__TINYC__)
#define BROTLI_TINYC_VERSION \
BROTLI_MAKE_VERSION(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100)
#endif
#if defined(BROTLI_TINYC_VERSION)
#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) \
(BROTLI_TINYC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch))
#else
#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) (0)
#endif
#if defined(__has_attribute)
#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
__has_attribute(attribute)
#else
#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \
BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
#endif
#if defined(__has_builtin)
#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
__has_builtin(builtin)
#else
#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \
BROTLI_GNUC_VERSION_CHECK(major, minor, patch)
#endif
#if defined(__has_feature)
#define BROTLI_HAS_FEATURE(feature) __has_feature(feature)
#else
#define BROTLI_HAS_FEATURE(feature) (0)
#endif
#if defined(ADDRESS_SANITIZER) || BROTLI_HAS_FEATURE(address_sanitizer) || \
defined(THREAD_SANITIZER) || BROTLI_HAS_FEATURE(thread_sanitizer) || \
defined(MEMORY_SANITIZER) || BROTLI_HAS_FEATURE(memory_sanitizer)
#define BROTLI_SANITIZED 1
#else
#define BROTLI_SANITIZED 0
#endif
#if defined(_WIN32) || defined(__CYGWIN__)
#define BROTLI_PUBLIC
#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \
BROTLI_TI_VERSION_CHECK(8, 0, 0) || \
BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \
BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \
BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \
BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \
(BROTLI_TI_VERSION_CHECK(7, 3, 0) && \
defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__))
#define BROTLI_PUBLIC __attribute__ ((visibility ("default")))
#else
#define BROTLI_PUBLIC
#endif
#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \
!defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \
!defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__)
#define BROTLI_ARRAY_PARAM(name) (name)
#else
#define BROTLI_ARRAY_PARAM(name)
#endif
/* <<< <<< <<< end of hedley macros. */
#if defined(BROTLI_SHARED_COMPILATION)
#if defined(_WIN32)
#if defined(BROTLICOMMON_SHARED_COMPILATION)
#define BROTLI_COMMON_API __declspec(dllexport)
#else
#define BROTLI_COMMON_API __declspec(dllimport)
#endif /* BROTLICOMMON_SHARED_COMPILATION */
#if defined(BROTLIDEC_SHARED_COMPILATION)
#define BROTLI_DEC_API __declspec(dllexport)
#else
#define BROTLI_DEC_API __declspec(dllimport)
#endif /* BROTLIDEC_SHARED_COMPILATION */
#if defined(BROTLIENC_SHARED_COMPILATION)
#define BROTLI_ENC_API __declspec(dllexport)
#else
#define BROTLI_ENC_API __declspec(dllimport)
#endif /* BROTLIENC_SHARED_COMPILATION */
#else /* _WIN32 */
#define BROTLI_COMMON_API BROTLI_PUBLIC
#define BROTLI_DEC_API BROTLI_PUBLIC
#define BROTLI_ENC_API BROTLI_PUBLIC
#endif /* _WIN32 */
#else /* BROTLI_SHARED_COMPILATION */
#define BROTLI_COMMON_API
#define BROTLI_DEC_API
#define BROTLI_ENC_API
#endif
#endif /* BROTLI_COMMON_PORT_H_ */
@@ -0,0 +1,83 @@
/* Copyright 2013 Google Inc. All Rights Reserved.
Distributed under MIT license.
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
*/
/**
* @file
* Common types used in decoder and encoder API.
*/
#ifndef BROTLI_COMMON_TYPES_H_
#define BROTLI_COMMON_TYPES_H_
#include <stddef.h> /* for size_t */
#if defined(_MSC_VER) && (_MSC_VER < 1600)
typedef __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
typedef __int64 int64_t;
#else
#include <stdint.h>
#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */
/**
* A portable @c bool replacement.
*
* ::BROTLI_BOOL is a "documentation" type: actually it is @c int, but in API it
* denotes a type, whose only values are ::BROTLI_TRUE and ::BROTLI_FALSE.
*
* ::BROTLI_BOOL values passed to Brotli should either be ::BROTLI_TRUE or
* ::BROTLI_FALSE, or be a result of ::TO_BROTLI_BOOL macros.
*
* ::BROTLI_BOOL values returned by Brotli should not be tested for equality
* with @c true, @c false, ::BROTLI_TRUE, ::BROTLI_FALSE, but rather should be
* evaluated, for example: @code{.cpp}
* if (SomeBrotliFunction(encoder, BROTLI_TRUE) &&
* !OtherBrotliFunction(decoder, BROTLI_FALSE)) {
* bool x = !!YetAnotherBrotliFunction(encoder, TO_BROLTI_BOOL(2 * 2 == 4));
* DoSomething(x);
* }
* @endcode
*/
#define BROTLI_BOOL int
/** Portable @c true replacement. */
#define BROTLI_TRUE 1
/** Portable @c false replacement. */
#define BROTLI_FALSE 0
/** @c bool to ::BROTLI_BOOL conversion macros. */
#define TO_BROTLI_BOOL(X) (!!(X) ? BROTLI_TRUE : BROTLI_FALSE)
#define BROTLI_MAKE_UINT64_T(high, low) ((((uint64_t)(high)) << 32) | low)
#define BROTLI_UINT32_MAX (~((uint32_t)0))
#define BROTLI_SIZE_MAX (~((size_t)0))
/**
* Allocating function pointer type.
*
* @param opaque custom memory manager handle provided by client
* @param size requested memory region size; can not be @c 0
* @returns @c 0 in the case of failure
* @returns a valid pointer to a memory region of at least @p size bytes
* long otherwise
*/
typedef void* (*brotli_alloc_func)(void* opaque, size_t size);
/**
* Deallocating function pointer type.
*
* This function @b SHOULD do nothing if @p address is @c 0.
*
* @param opaque custom memory manager handle provided by client
* @param address memory region pointer returned by ::brotli_alloc_func, or @c 0
*/
typedef void (*brotli_free_func)(void* opaque, void* address);
#endif /* BROTLI_COMMON_TYPES_H_ */
@@ -0,0 +1,24 @@
#pragma once
/**
* File status returned by Stat or FStat.
*/
struct FileStatus
{
int32_t Flags; // flags for testing if some members are present (see FileStatusFlags)
int32_t Mode; // file mode (see S_I* constants above for bit values)
uint32_t Uid; // user ID of owner
uint32_t Gid; // group ID of owner
int64_t Size; // total size, in bytes
int64_t ATime; // time of last access
int64_t ATimeNsec; // nanosecond part
int64_t MTime; // time of last modification
int64_t MTimeNsec; // nanosecond part
int64_t CTime; // time of last status change
int64_t CTimeNsec; // nanosecond part
int64_t BirthTime; // time the file was created
int64_t BirthTimeNsec; // nanosecond part
int64_t Dev; // ID of the device containing the file
int64_t Ino; // inode number of the file
uint32_t UserFlags; // user defined flags
};
@@ -0,0 +1,53 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_TARGET_LINUX
#include "os/Linux/pal_linux.h"
#elif IL2CPP_TARGET_DARWIN
#include "os/OSX/pal_darwin.h"
#elif IL2CPP_TARGET_ANDROID
#include "os/Android/pal_android.h"
#elif IL2CPP_TARGET_JAVASCRIPT
#include "os/Emscripten/pal_emscripten.h"
#elif IL2CPP_TARGET_SWITCH
#include "pal/pal_switch.h"
#elif IL2CPP_TARGET_PS4 || IL2CPP_TARGET_PS5
#include "pal/pal_playstation.h"
#endif
/*
These defines below just remap some posix function names. By default they fallback to the standard posix name but
some platforms might need to define this symbols to something different in their "pal_[platform name]" header above.
This is normally due to the platform not including the posix function as standard (e.g. Switch, Playstation).
*/
#ifndef stat_
#define stat_ stat
#endif
#ifndef fstat_
#define fstat_ fstat
#endif
#ifndef lstat_
#define lstat_ lstat
#endif
#ifndef utimes_
#define utimes_ utimes
#endif
#ifndef chmod_
#define chmod_ chmod
#endif
#ifndef link_
#define link_ link
#endif
#ifndef symlink_
#define symlink_ symlink
#endif
#ifndef readlink_
#define readlink_ readlink
#endif
#ifndef geteuid_
#define geteuid_ geteuid
#endif
#ifndef getegid_
#define getegid_ getegid
#endif
@@ -0,0 +1,27 @@
#pragma once
#include "utils/NonCopyable.h"
#include <stdint.h>
namespace il2cpp
{
namespace os
{
class FastMutex;
class ConditionVariableImpl;
class ConditionVariable : public il2cpp::utils::NonCopyable
{
public:
ConditionVariable();
~ConditionVariable();
int Wait(FastMutex* lock);
int TimedWait(FastMutex* lock, uint32_t timeout_ms);
void Broadcast();
void Signal();
private:
ConditionVariableImpl* m_ConditionVariable;
};
}
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
#include <string>
#include <stdint.h>
namespace il2cpp
{
namespace os
{
namespace Console
{
// Isatty is in File class
int32_t InternalKeyAvailable(int32_t ms_timeout);
bool SetBreak(bool wantBreak);
bool SetEcho(bool wantEcho);
bool TtySetup(const std::string& keypadXmit, const std::string& teardown, uint8_t* control_characters, int32_t** size);
const char* NewLine();
}
}
}
@@ -0,0 +1,21 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_SUPPORTS_CONSOLE_EXTENSION
#include <string>
#include <stdint.h>
namespace il2cpp
{
namespace os
{
namespace ConsoleExtension
{
void Write(const char* buffer);
}
}
}
#endif
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
namespace il2cpp
{
namespace os
{
class CpuInfo
{
public:
static void* Create();
/*
* This function returns the cpu usage in percentage,
* normalized on the number of cores.
*
* Warning : the percentage returned can be > 100%. This
* might happens on systems like Android which, for
* battery and performance reasons, shut down cores and
* lie about the number of active cores.
*/
static int32_t Usage(void* previous);
};
}
}
@@ -0,0 +1,15 @@
#pragma once
namespace il2cpp
{
namespace os
{
class CrashHelpers
{
public:
NORETURN static void Crash();
private:
NORETURN static void CrashImpl();
};
}
}
@@ -0,0 +1,23 @@
#pragma once
namespace il2cpp
{
namespace os
{
class Cryptography
{
public:
/* Returns a handle the cryptography provider to use in other calls on this API. */
static void* GetCryptographyProvider();
/* Open the cryptogrpahy provider. */
static bool OpenCryptographyProvider();
/* Indicate that the cyrptography provider is no longer in use. */
static void ReleaseCryptographyProvider(void* provider);
/* Use the provider to fill the buffer with cryptographically random bytes. */
static bool FillBufferWithRandomBytes(void* provider, intptr_t length, unsigned char* data);
};
}
}
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include "il2cpp-config.h"
#include "utils/StringView.h"
namespace il2cpp
{
namespace os
{
class Debug
{
public:
static bool IsDebuggerPresent();
static void WriteString(const utils::StringView<Il2CppNativeChar>& message);
};
}
}
@@ -0,0 +1,54 @@
#pragma once
#include <stdint.h>
#include <string>
#include <set>
#include "il2cpp-string-types.h"
#include "os/ErrorCodes.h"
#include "utils/StringView.h"
#undef FindFirstFile
#undef FindNextFile
namespace il2cpp
{
namespace os
{
// I feel dirty putting it here, but our abstraction here is really
// leaky already with FindHandle struct containing directoryPath and pattern
// If we ever refactor FindHandle to be less leaky, move this too.
enum FindHandleFlags
{
kNoFindHandleFlags = 0,
kUseBrokeredFileSystem = 1,
};
class Directory
{
public:
static std::string GetCurrent(int* error);
static bool SetCurrent(const std::string& path, int* error);
static bool Create(const std::string& path, int *error);
static bool Remove(const std::string& path, int *error);
static std::set<std::string> GetFileSystemEntries(const std::string& path, const std::string& pathWithPattern, int32_t attrs, int32_t mask, int* error);
struct FindHandle
{
void* osHandle;
FindHandleFlags handleFlags;
Il2CppNativeString directoryPath;
Il2CppNativeString pattern;
FindHandle(const utils::StringView<Il2CppNativeChar>& searchPathWithPattern);
~FindHandle();
inline void SetOSHandle(void* osHandle) { this->osHandle = osHandle; }
int32_t CloseOSHandle();
};
static os::ErrorCode FindFirstFile(FindHandle* findHandle, const utils::StringView<Il2CppNativeChar>& searchPathWithPattern, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
static os::ErrorCode FindNextFile(FindHandle* findHandle, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
static int32_t CloseOSFindHandleDirectly(intptr_t osHandle);
};
}
}
@@ -0,0 +1,21 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_TARGET_JAVASCRIPT
#define IL2CPP_USES_POSIX_CLASS_LIBRARY_PAL 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_LCHFLAGS 1
#define IL2CPP_HAVE_FUTIMENS 1
#define IL2CPP_HAVE_SYS_UN 1
#define stat_ stat
#define fstat_ fstat
#define lstat_ lstat
#include <dirent.h>
#endif // IL2CPP_TARGET_JAVASCRIPT
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include <string>
namespace il2cpp
{
namespace os
{
namespace Encoding
{
std::string GetCharSet();
}
}
}
@@ -0,0 +1,36 @@
#pragma once
#include "il2cpp-config.h"
#include "utils/Expected.h"
#include <string>
#include <stdint.h>
#include <vector>
#undef SetEnvironmentVariable // Get rid of windows.h #define.
#undef GetEnvironmentVariable // Get rid of windows.h #define.
struct Il2CppArray;
namespace il2cpp
{
namespace os
{
class Environment
{
public:
static std::string GetMachineName();
static int32_t GetProcessorCount();
static std::string GetOsVersionString();
static std::string GetOsUserName();
static std::string GetEnvironmentVariable(const std::string& name);
static void SetEnvironmentVariable(const std::string& name, const std::string& value);
static std::vector<std::string> GetEnvironmentVariableNames();
static std::string GetHomeDirectory();
static std::vector<std::string> GetLogicalDrives();
static void Exit(int result);
static NORETURN void Abort();
static utils::Expected<std::string> GetWindowsFolderPath(int32_t folder);
static utils::Expected<bool> Is64BitOs();
};
}
}
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "os/ErrorCodes.h"
namespace il2cpp
{
namespace os
{
class Error
{
public:
static ErrorCode GetLastError();
static void SetLastError(ErrorCode code);
};
}
}
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
#pragma once
#include "os/ErrorCodes.h"
#include "os/Handle.h"
#include "os/WaitStatus.h"
#include "utils/NonCopyable.h"
namespace il2cpp
{
namespace os
{
class EventImpl;
class Event : public il2cpp::utils::NonCopyable
{
public:
Event(bool manualReset = false, bool signaled = false);
~Event();
ErrorCode Set();
ErrorCode Reset();
WaitStatus Wait(bool interruptible = false);
WaitStatus Wait(uint32_t ms, bool interruptible = false);
void* GetOSHandle();
private:
EventImpl* m_Event;
};
class EventHandle : public Handle
{
public:
EventHandle(Event* event)
: m_Event(event) {}
virtual ~EventHandle() { delete m_Event; }
virtual bool Wait() { m_Event->Wait(true); return true; }
virtual bool Wait(uint32_t ms) { return m_Event->Wait(ms, true) != kWaitStatusTimeout; }
virtual WaitStatus Wait(bool interruptible) { return m_Event->Wait(interruptible); }
virtual WaitStatus Wait(uint32_t ms, bool interruptible) { return m_Event->Wait(ms, interruptible); }
virtual void Signal() { m_Event->Set(); }
virtual void* GetOSHandle() { return m_Event->GetOSHandle(); }
Event& Get() { return *m_Event; }
private:
Event* m_Event;
};
}
}
@@ -0,0 +1,62 @@
#pragma once
#include "utils/NonCopyable.h"
namespace il2cpp
{
namespace os
{
class FastReaderReaderWriterLockImpl;
// Use this class if the work done in the shared lock is "fast" - on the order of taking a lock
class FastReaderReaderWriterLock
{
public:
FastReaderReaderWriterLock();
~FastReaderReaderWriterLock();
void LockExclusive();
void LockShared();
void ReleaseExclusive();
void ReleaseShared();
FastReaderReaderWriterLockImpl* GetImpl();
private:
FastReaderReaderWriterLockImpl* m_Impl;
};
struct FastReaderReaderWriterAutoSharedLock : public il2cpp::utils::NonCopyable
{
FastReaderReaderWriterAutoSharedLock(FastReaderReaderWriterLock* lock)
: m_Lock(lock)
{
m_Lock->LockShared();
}
~FastReaderReaderWriterAutoSharedLock()
{
m_Lock->ReleaseShared();
}
private:
FastReaderReaderWriterLock* m_Lock;
};
struct FastReaderReaderWriterAutoExclusiveLock : public il2cpp::utils::NonCopyable
{
FastReaderReaderWriterAutoExclusiveLock(FastReaderReaderWriterLock* lock)
: m_Lock(lock)
{
m_Lock->LockExclusive();
}
~FastReaderReaderWriterAutoExclusiveLock()
{
m_Lock->ReleaseExclusive();
}
private:
FastReaderReaderWriterLock* m_Lock;
};
}
}
@@ -0,0 +1,13 @@
#pragma once
#include "os/ReaderWriterLockImpl.h"
namespace il2cpp
{
namespace os
{
class FastReaderReaderWriterLockImpl : public ReaderWriterLockImpl
{
};
}
}
+76
View File
@@ -0,0 +1,76 @@
#pragma once
#include "il2cpp-config.h"
#include <stdint.h>
#include <string>
#include "os/ErrorCodes.h"
#include "os/c-api/OSGlobalEnums.h"
#include "utils/Expected.h"
#undef CopyFile
#undef DeleteFile
#undef MoveFile
#undef ReplaceFile
#undef GetFileAttributes
#undef SetFileAttributes
#undef CreatePipe
namespace il2cpp
{
namespace os
{
// File enums and structs
struct FileHandle;
struct FileStat
{
std::string name;
int32_t attributes;
int64_t length;
int64_t creation_time;
int64_t last_access_time;
int64_t last_write_time;
};
class LIBIL2CPP_CODEGEN_API File
{
public:
static utils::Expected<bool> Isatty(FileHandle* fileHandle);
static FileHandle* GetStdInput();
static FileHandle* GetStdOutput();
static FileHandle* GetStdError();
static utils::Expected<bool> CreatePipe(FileHandle** read_handle, FileHandle** write_handle);
static utils::Expected<bool> CreatePipe(FileHandle** read_handle, FileHandle** write_handle, int* error);
static FileType GetFileType(FileHandle* handle);
static UnityPalFileAttributes GetFileAttributes(const std::string& path, int* error);
static bool SetFileAttributes(const std::string& path, UnityPalFileAttributes attributes, int* error);
static bool GetFileStat(const std::string& path, FileStat * stat, int* error);
static bool CopyFile(const std::string& src, const std::string& dest, bool overwrite, int* error);
static bool MoveFile(const std::string& src, const std::string& dest, int* error);
static bool DeleteFile(const std::string& path, int *error);
static bool ReplaceFile(const std::string& sourceFileName, const std::string& destinationFileName, const std::string& destinationBackupFileName, bool ignoreMetadataErrors, int* error);
static FileHandle* Open(const std::string& path, int openMode, int accessMode, int shareMode, int options, int *error);
static bool Close(FileHandle* handle, int *error);
static bool SetFileTime(FileHandle* handle, int64_t creation_time, int64_t last_access_time, int64_t last_write_time, int* error);
static int64_t GetLength(FileHandle* handle, int *error);
static bool SetLength(FileHandle* handle, int64_t length, int *error);
static int64_t Seek(FileHandle* handle, int64_t offset, int origin, int *error);
static int Read(FileHandle* handle, char *dest, int count, int *error);
static int32_t Write(FileHandle* handle, const char* buffer, int count, int *error);
static bool Flush(FileHandle* handle, int* error);
static void Lock(FileHandle* handle, int64_t position, int64_t length, int* error);
static void Unlock(FileHandle* handle, int64_t position, int64_t length, int* error);
static utils::Expected<bool> IsExecutable(const std::string& path);
static bool Truncate(FileHandle* handle, int *error);
static bool Cancel(FileHandle* handle);
static utils::Expected<bool> DuplicateHandle(FileHandle* source_process_handle, FileHandle* source_handle, FileHandle* target_process_handle,
FileHandle** target_handle, int access, int inherit, int options, int* error);
static bool IsHandleOpenFileHandle(intptr_t lookup);
};
}
}
@@ -0,0 +1,12 @@
#pragma once
namespace il2cpp
{
namespace os
{
namespace FileSystemWatcher
{
int IsSupported();
}
}
}
@@ -0,0 +1,110 @@
#pragma once
#if IL2CPP_USE_GENERIC_SOCKET_IMPL
#include <string>
#include <vector>
#include <stdint.h>
#include "os/Socket.h"
#include "os/ErrorCodes.h"
#include "os/WaitStatus.h"
#include "utils/NonCopyable.h"
namespace il2cpp
{
namespace os
{
class SocketImpl : public il2cpp::utils::NonCopyable
{
public:
typedef int32_t SocketDescriptor;
SocketImpl(ThreadStatusCallback thread_status_callback);
~SocketImpl();
inline SocketDescriptor GetDescriptor()
{
return -1;
}
ErrorCode GetLastError() const;
WaitStatus Create(SocketDescriptor fd, int32_t family, int32_t type, int32_t protocol);
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
WaitStatus Close();
bool IsClosed()
{
return true;
}
WaitStatus SetBlocking(bool blocking);
WaitStatus Listen(int32_t blacklog);
WaitStatus Bind(const char *path);
WaitStatus Bind(const char *address, uint16_t port);
WaitStatus Bind(uint32_t address, uint16_t port);
WaitStatus Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
WaitStatus Connect(const char *path);
WaitStatus Connect(uint32_t address, uint16_t port);
WaitStatus Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
WaitStatus Disconnect(bool reuse);
WaitStatus Shutdown(int32_t how);
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
WaitStatus RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
WaitStatus Accept(os::Socket **socket);
WaitStatus Available(int32_t *amount);
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
#if IL2CPP_SUPPORT_IPV6
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
#endif
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus Poll(PollRequest& request, int32_t timeout, int32_t *result, int32_t *error);
static WaitStatus GetHostName(std::string &name);
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
static void Startup();
static void Cleanup();
};
}
}
#endif
+29
View File
@@ -0,0 +1,29 @@
#pragma once
#include <stdint.h>
#include <vector>
#include "utils/NonCopyable.h"
#include "os/WaitStatus.h"
namespace il2cpp
{
namespace os
{
class Handle : public il2cpp::utils::NonCopyable
{
public:
virtual ~Handle() {}
virtual bool Wait() = 0;
virtual bool Wait(uint32_t ms) = 0;
virtual WaitStatus Wait(bool interruptible) = 0;
virtual WaitStatus Wait(uint32_t ms, bool interruptible) = 0;
virtual void Signal() = 0;
virtual void* GetOSHandle() = 0;
static int32_t WaitAny(const std::vector<Handle*>& handles, int32_t ms);
static bool WaitAll(std::vector<Handle*>& handles, int32_t ms);
private:
static const int m_waitIntervalMs = 10;
};
}
}
+20
View File
@@ -0,0 +1,20 @@
#pragma once
namespace il2cpp
{
namespace os
{
namespace Image
{
void Initialize();
void* GetImageBase();
#if IL2CPP_ENABLE_NATIVE_INSTRUCTION_POINTER_EMISSION
char* GetImageUUID();
char* GetImageName();
#endif
bool IsInManagedSection(void*ip);
bool ManagedSectionExists();
void SetManagedSectionStartAndEnd(void* start, void* end);
}
}
}
@@ -0,0 +1,11 @@
#pragma once
namespace il2cpp
{
namespace os
{
void Initialize();
void Uninitialize();
}
}
@@ -0,0 +1,13 @@
#pragma once
namespace il2cpp
{
namespace os
{
class LastError
{
public:
static uint32_t GetLastError();
};
} /* namespace os */
} /* namespace il2cpp*/
@@ -0,0 +1,59 @@
#pragma once
#include "il2cpp-config.h"
#include "il2cpp-pinvoke-support.h"
#include "utils/StringView.h"
#include <string>
#include "Baselib.h"
#include "Cpp/Baselib_DynamicLibrary.h"
#if !RUNTIME_TINY
#include "Cpp/ReentrantLock.h"
#include <vector>
#include <string>
#endif
namespace il2cpp
{
namespace os
{
struct HardcodedPInvokeDependencyFunction
{
const char* functionName;
Il2CppMethodPointer functionPointer;
size_t functionNameLen;
};
struct HardcodedPInvokeDependencyLibrary
{
const Il2CppNativeChar* libraryName;
size_t functionCount;
const HardcodedPInvokeDependencyFunction* functions;
};
#define HARDCODED_DEPENDENCY_LIBRARY(libraryName, libraryFunctions) { libraryName, sizeof(libraryFunctions) / sizeof(HardcodedPInvokeDependencyFunction), libraryFunctions }
#define HARDCODED_DEPENDENCY_FUNCTION(function) { #function, reinterpret_cast<Il2CppMethodPointer>(function), IL2CPP_ARRAY_SIZE(#function)-1 }
class LibraryLoader
{
public:
static Il2CppMethodPointer GetHardcodedPInvokeDependencyFunctionPointer(const il2cpp::utils::StringView<Il2CppNativeChar>& nativeDynamicLibrary, const il2cpp::utils::StringView<char>& entryPoint, Il2CppCharSet charSet);
static Baselib_DynamicLibrary_Handle LoadDynamicLibrary(const utils::StringView<Il2CppNativeChar> nativeDynamicLibrary, std::string& detailedError);
static Il2CppMethodPointer GetFunctionPointer(Baselib_DynamicLibrary_Handle handle, const PInvokeArguments& pinvokeArgs, std::string& detailedError);
static Il2CppMethodPointer GetFunctionPointer(Baselib_DynamicLibrary_Handle handle, const char* functionName, std::string& detailedError);
static void CleanupLoadedLibraries();
static bool CloseLoadedLibrary(Baselib_DynamicLibrary_Handle handle);
static void SetFindPluginCallback(Il2CppSetFindPlugInCallback method);
static Baselib_DynamicLibrary_Handle TryOpeningLibrary(const Il2CppNativeChar* libraryName, std::string& detailedError);
private:
static Baselib_DynamicLibrary_Handle ProbeForLibrary(const Il2CppNativeChar* libraryName, const size_t libraryNameLength, std::string& detailedError);
// needsClosing defaults to true, only set it to false when needed
static Baselib_DynamicLibrary_Handle OpenProgramHandle(Baselib_ErrorState& errorState, bool& needsClosing);
static const HardcodedPInvokeDependencyLibrary* HardcodedPInvokeDependencies;
static const size_t HardcodedPInvokeDependenciesCount;
static bool EntryNameMatches(const il2cpp::utils::StringView<char>& hardcodedEntryPoint, const il2cpp::utils::StringView<char>& entryPoint);
};
} /* namespace os */
} /* namespace il2cpp*/
@@ -0,0 +1,28 @@
#pragma once
#include "il2cpp-config.h"
#if IL2CPP_TARGET_LINUX
#define IL2CPP_USES_POSIX_CLASS_LIBRARY_PAL 1
#define IL2CPP_HAVE_GNU_STRERROR_R 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_STAT_FLAGS 1
#define IL2CPP_HAVE_LCHFLAGS 1
#define IL2CPP_HAVE_FUTIMENS 1
#define IL2CPP_HAVE_REWINDDIR 1
#define IL2CPP_HAVE_STAT_TIM 1
#include <sys/sendfile.h>
#include <limits.h>
#define IL2CPP_HAVE_SENDFILE_4 1
#define IL2CPP_HAVE_SYS_UN 1
#define stat_ stat
#define fstat_ fstat
#define lstat_ lstat
#include <dirent.h>
#endif // IL2CPP_TARGET_LINUX
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <stdint.h>
#include <string>
namespace il2cpp
{
namespace os
{
class Locale
{
public:
static void Initialize();
static void UnInitialize();
static std::string GetLocale();
#if IL2CPP_SUPPORT_LOCALE_INDEPENDENT_PARSING
static double DoubleParseLocaleIndependentImpl(char *ptr, char** endptr);
#endif
#if IL2CPP_TARGET_WINRT
static il2cpp_hresult_t InitializeUserPreferredCultureInfoInAppX(CultureInfoChangedCallback onCultureInfoChangedInAppX);
static il2cpp_hresult_t SetUserPreferredCultureInfoInAppX(const Il2CppChar* name);
static void UnInitializeWinRT();
#endif
};
} /* namespace os */
} /* namespace il2cpp */
@@ -0,0 +1,16 @@
#pragma once
namespace il2cpp
{
namespace os
{
namespace lumin
{
namespace automation
{
void Bootstrap();
void WaitForAppThread();
}
}
}
}
@@ -0,0 +1,15 @@
#pragma once
#include <string>
namespace il2cpp
{
namespace os
{
namespace lumin
{
std::string PathForErrorLog();
std::string PathForOutputLog();
}
}
}
@@ -0,0 +1,16 @@
#pragma once
#include <string>
namespace il2cpp
{
namespace os
{
namespace lumin
{
extern std::string GetPackageName();
extern std::string GetPackageTempPath();
extern void LifecycleInit();
}
}
}
@@ -0,0 +1,18 @@
#pragma once
namespace il2cpp
{
namespace os
{
class MarshalAlloc
{
public:
static void* Allocate(size_t size);
static void* ReAlloc(void* ptr, size_t size);
static void Free(void* ptr);
static void* AllocateHGlobal(size_t size);
static void* ReAllocHGlobal(void* ptr, size_t size);
static void FreeHGlobal(void* ptr);
};
} /* namespace os */
} /* namespace il2cpp*/
@@ -0,0 +1,15 @@
#pragma once
namespace il2cpp
{
namespace os
{
class MarshalStringAlloc
{
public:
static il2cpp_hresult_t AllocateBStringLength(const Il2CppChar* text, int32_t length, Il2CppChar** bstr);
static il2cpp_hresult_t GetBStringLength(const Il2CppChar* bstr, int32_t* length);
static il2cpp_hresult_t FreeBString(Il2CppChar* bstr);
};
} /* namespace os */
} /* namespace il2cpp*/
+14
View File
@@ -0,0 +1,14 @@
#pragma once
namespace il2cpp
{
namespace os
{
namespace Memory
{
void* AlignedAlloc(size_t size, size_t alignment);
void* AlignedReAlloc(void* memory, size_t newSize, size_t alignment);
void AlignedFree(void* memory);
}
}
}
@@ -0,0 +1,65 @@
#pragma once
#include <string>
#include "File.h"
#include <map>
#include "os/Mutex.h"
namespace il2cpp
{
namespace os
{
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
enum MemoryMappedFileAccess
{
MMAP_FILE_ACCESS_READ_WRITE = 0,
MMAP_FILE_ACCESS_READ = 1,
MMAP_FILE_ACCESS_WRITE = 2,
MMAP_FILE_ACCESS_COPY_ON_WRITE = 3,
MMAP_FILE_ACCESS_READ_EXECUTE = 4,
MMAP_FILE_ACCESS_READ_WRITE_EXECUTE = 5,
};
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
enum MemoryMappedFileError
{
NO_MEMORY_MAPPED_FILE_ERROR = 0,
BAD_CAPACITY_FOR_FILE_BACKED,
CAPACITY_SMALLER_THAN_FILE_SIZE,
FILE_NOT_FOUND,
FILE_ALREADY_EXISTS,
PATH_TOO_LONG,
COULD_NOT_OPEN,
CAPACITY_MUST_BE_POSITIVE,
INVALID_FILE_MODE,
COULD_NOT_MAP_MEMORY,
ACCESS_DENIED,
CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE
};
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
enum MemoryMappedFileMode
{
FILE_MODE_CREATE_NEW = 1,
FILE_MODE_CREATE = 2,
FILE_MODE_OPEN = 3,
FILE_MODE_OPEN_OR_CREATE = 4,
FILE_MODE_TRUNCATE = 5,
FILE_MODE_APPEND = 6,
};
class MemoryMappedFile
{
public:
typedef void* MemoryMappedFileHandle;
static FileHandle* Create(FileHandle* file, const char* mapName, int32_t mode, int64_t *capacity, MemoryMappedFileAccess access, int32_t options, MemoryMappedFileError* error);
static MemoryMappedFileHandle View(FileHandle* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, int64_t* actualOffset, MemoryMappedFileError* error);
static void Flush(MemoryMappedFileHandle memoryMappedFileData, int64_t length);
static bool UnmapView(MemoryMappedFileHandle memoryMappedFileData, int64_t length);
static bool Close(FileHandle* file);
static void ConfigureHandleInheritability(FileHandle* file, bool inheritability);
static bool OwnsDuplicatedFileHandle(FileHandle* file);
};
}
}
+32
View File
@@ -0,0 +1,32 @@
#pragma once
#include "il2cpp-config.h"
#include <stdint.h>
#include <string>
#include "os/ErrorCodes.h"
namespace il2cpp
{
namespace os
{
struct ErrorDesc
{
ErrorCode code;
const char *message;
};
extern ErrorDesc common_messages[];
#ifndef IL2CPP_DISABLE_FULL_MESSAGES
extern ErrorDesc messages[];
#endif
class Messages
{
public:
static std::string FromCode(ErrorCode code);
};
}
}
+118
View File
@@ -0,0 +1,118 @@
#pragma once
#include "os/ErrorCodes.h"
#include "os/Handle.h"
#include "os/WaitStatus.h"
#include "utils/NonCopyable.h"
#include "Baselib.h"
#include "Cpp/ReentrantLock.h"
namespace il2cpp
{
namespace os
{
class MutexImpl;
class FastMutexImpl;
class Mutex : public il2cpp::utils::NonCopyable
{
public:
Mutex(bool initiallyOwned = false);
~Mutex();
void Lock(bool interruptible = false);
bool TryLock(uint32_t milliseconds = 0, bool interruptible = false);
void Unlock();
void* GetOSHandle();
private:
MutexImpl* m_Mutex;
};
struct AutoLock : public il2cpp::utils::NonCopyable
{
AutoLock(Mutex* mutex) : m_Mutex(mutex) { m_Mutex->Lock(); }
~AutoLock() { m_Mutex->Unlock(); }
private:
Mutex* m_Mutex;
};
class MutexHandle : public Handle
{
public:
MutexHandle(Mutex* mutex) : m_Mutex(mutex) {}
virtual ~MutexHandle() { delete m_Mutex; }
virtual bool Wait() { m_Mutex->Lock(true); return true; }
virtual bool Wait(uint32_t ms) { return m_Mutex->TryLock(ms, true); }
virtual WaitStatus Wait(bool interruptible) { m_Mutex->Lock(interruptible); return kWaitStatusSuccess; }
virtual WaitStatus Wait(uint32_t ms, bool interruptible) { return m_Mutex->TryLock(ms, interruptible) ? kWaitStatusSuccess : kWaitStatusFailure; }
virtual void Signal() { m_Mutex->Unlock(); }
virtual void* GetOSHandle() { return m_Mutex->GetOSHandle(); }
Mutex* Get() { return m_Mutex; }
private:
Mutex* m_Mutex;
};
/// Lightweight mutex that has no support for interruption or timed waits. Meant for
/// internal use only.
class FastMutex
{
public:
FastMutex();
~FastMutex();
void Lock();
void Unlock();
FastMutexImpl* GetImpl();
private:
FastMutexImpl* m_Impl;
};
struct FastAutoLock : public il2cpp::utils::NonCopyable
{
FastAutoLock(baselib::ReentrantLock* mutex)
: m_Mutex(mutex)
{
m_Mutex->Acquire();
}
~FastAutoLock()
{
m_Mutex->Release();
}
#if IL2CPP_DEBUG
bool IsLock(baselib::ReentrantLock* mutex) const
{
return mutex == m_Mutex;
}
#endif
private:
baselib::ReentrantLock* m_Mutex;
};
struct FastAutoUnlock : public il2cpp::utils::NonCopyable
{
FastAutoUnlock(baselib::ReentrantLock* mutex)
: m_Mutex(mutex)
{
m_Mutex->Release();
}
~FastAutoUnlock()
{
m_Mutex->Acquire();
}
private:
baselib::ReentrantLock* m_Mutex;
};
}
}
@@ -0,0 +1,23 @@
#pragma once
#include <stdint.h>
#include "os/Process.h"
#include "utils/Expected.h"
#include <vector>
#include <string>
namespace il2cpp
{
namespace os
{
class NativeMethods
{
public:
static bool CloseProcess(ProcessHandle* handle);
static utils::Expected<bool> GetExitCodeProcess(ProcessHandle* handle, int32_t* exitCode);
static int32_t GetCurrentProcessId();
static utils::Expected<ProcessHandle*> GetCurrentProcess();
};
}
}

Some files were not shown because too many files have changed in this diff Show More