[add] first
This commit is contained in:
@@ -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
|
||||
@@ -0,0 +1,5 @@
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#if IL2CPP_DEBUG
|
||||
void il2cpp_assert(const char* assertion, const char* file, unsigned int line);
|
||||
#endif
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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, ¶ms->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,
|
||||
¶ms->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++, ¶ms->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_ */
|
||||
+54
@@ -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, ¶ms->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
|
||||
+266
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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
|
||||
{
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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*/
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user