/* 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. */ #include "backward_references.h" #include "../common/constants.h" #include "../common/context.h" #include "../common/platform.h" #include "command.h" #include "compound_dictionary.h" #include "encoder_dict.h" #include "hash.h" #include "params.h" #include "quality.h" /* IWYU pragma: keep for inc */ BROTLI_INTERNAL const BROTLI_MODEL("small") uint8_t kIsBase64[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, /* 43 '+', 47 '/' (45 '-' is 0) */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, /* 48-57 '0'-'9' (61 '=' is 0) */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 65-79 'A'-'O' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 80-90 'P'-'Z' */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 97-111 'a'-'o' */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 112-122 'p'-'z' */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; static const size_t kBase64TriggerLen = 8; static BROTLI_INLINE BROTLI_BOOL IsBase64Char(uint8_t c) { return TO_BROTLI_BOOL(kIsBase64[c]); } static BROTLI_INLINE BROTLI_BOOL MatchTrigger(const uint8_t* ringbuffer, size_t mask, size_t pos) { const char* trigger = ";base64,"; size_t i; for (i = 0; i < kBase64TriggerLen; ++i) { if (ringbuffer[(pos + i) & mask] != trigger[i]) return BROTLI_FALSE; } return BROTLI_TRUE; } static size_t FindNextBase64Trigger(const uint8_t* ringbuffer, size_t mask, size_t pos, size_t end) { while (pos + kBase64TriggerLen <= end) { size_t ringbuffer_size = mask + 1; size_t pos_index = pos & mask; size_t contiguous_len = ringbuffer_size - pos_index; size_t max_scan_len = end - pos; size_t scan_len = BROTLI_MIN(size_t, contiguous_len, max_scan_len); const uint8_t* p = (const uint8_t*)memchr(&ringbuffer[pos_index], ';', scan_len); if (p != NULL) { size_t offset = (size_t)(p - &ringbuffer[pos_index]); if (pos + offset + kBase64TriggerLen <= end) { if (MatchTrigger(ringbuffer, mask, pos + offset)) { return pos + offset; } } else { return end; } pos += offset + 1; } else { pos += scan_len; } } return end; } #if defined(__cplusplus) || defined(c_plusplus) extern "C" { #endif static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance, size_t max_distance, const int* dist_cache) { if (distance <= max_distance) { size_t distance_plus_3 = distance + 3; size_t offset0 = distance_plus_3 - (size_t)dist_cache[0]; size_t offset1 = distance_plus_3 - (size_t)dist_cache[1]; if (distance == (size_t)dist_cache[0]) { return 0; } else if (distance == (size_t)dist_cache[1]) { return 1; } else if (offset0 < 7) { return (0x9750468 >> (4 * offset0)) & 0xF; } else if (offset1 < 7) { return (0xFDB1ACE >> (4 * offset1)) & 0xF; } else if (distance == (size_t)dist_cache[2]) { return 2; } else if (distance == (size_t)dist_cache[3]) { return 3; } } return distance + BROTLI_NUM_DISTANCE_SHORT_CODES - 1; } #define EXPAND_CAT(a, b) CAT(a, b) #define CAT(a, b) a ## b #define FN(X) EXPAND_CAT(X, HASHER()) #define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER())) #define PREFIX() N #define ENABLE_COMPOUND_DICTIONARY 0 #define HASHER() H2 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H3 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H4 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H5 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H6 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H40 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H41 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H42 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H54 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H35 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H55 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H65 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #if defined(BROTLI_MAX_SIMD_QUALITY) #define HASHER() H58 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H59 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc_opt.h" #undef HASHER #define HASHER() H68 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #endif #undef ENABLE_COMPOUND_DICTIONARY #undef PREFIX #define PREFIX() D #define ENABLE_COMPOUND_DICTIONARY 1 #define HASHER() H3 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H4 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H5 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H6 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H40 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H41 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H42 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H55 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H65 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #if defined(BROTLI_MAX_SIMD_QUALITY) #define HASHER() H58 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #define HASHER() H59 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc_opt.h" #undef HASHER #define HASHER() H68 /* NOLINTNEXTLINE(build/include) */ #include "backward_references_inc.h" #undef HASHER #endif #undef ENABLE_COMPOUND_DICTIONARY #undef PREFIX #undef EXPORT_FN #undef FN #undef CAT #undef EXPAND_CAT 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 (params->dictionary.compound.num_chunks != 0) { switch (params->hasher.type) { #define CASE_(N) \ case N: \ CreateBackwardReferencesDH ## N(num_bytes, \ position, ringbuffer, ringbuffer_mask, \ literal_context_lut, params, hasher, dist_cache, \ last_insert_len, commands, num_commands, num_literals); \ return; CASE_(3) CASE_(4) CASE_(5) CASE_(6) #if defined(BROTLI_MAX_SIMD_QUALITY) CASE_(58) CASE_(59) CASE_(68) #endif CASE_(40) CASE_(41) CASE_(42) CASE_(55) CASE_(65) #undef CASE_ default: BROTLI_DCHECK(BROTLI_FALSE); break; } } switch (params->hasher.type) { #define CASE_(N) \ case N: \ CreateBackwardReferencesNH ## N(num_bytes, \ position, ringbuffer, ringbuffer_mask, \ literal_context_lut, params, hasher, dist_cache, \ last_insert_len, commands, num_commands, num_literals); \ return; FOR_GENERIC_HASHERS(CASE_) #undef CASE_ default: BROTLI_DCHECK(BROTLI_FALSE); break; } } #if defined(__cplusplus) || defined(c_plusplus) } /* extern "C" */ #endif