127b27ec6Sopenharmony_ci/* 227b27ec6Sopenharmony_ci LZ4 HC - High Compression Mode of LZ4 327b27ec6Sopenharmony_ci Copyright (C) 2011-2020, Yann Collet. 427b27ec6Sopenharmony_ci 527b27ec6Sopenharmony_ci BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) 627b27ec6Sopenharmony_ci 727b27ec6Sopenharmony_ci Redistribution and use in source and binary forms, with or without 827b27ec6Sopenharmony_ci modification, are permitted provided that the following conditions are 927b27ec6Sopenharmony_ci met: 1027b27ec6Sopenharmony_ci 1127b27ec6Sopenharmony_ci * Redistributions of source code must retain the above copyright 1227b27ec6Sopenharmony_ci notice, this list of conditions and the following disclaimer. 1327b27ec6Sopenharmony_ci * Redistributions in binary form must reproduce the above 1427b27ec6Sopenharmony_ci copyright notice, this list of conditions and the following disclaimer 1527b27ec6Sopenharmony_ci in the documentation and/or other materials provided with the 1627b27ec6Sopenharmony_ci distribution. 1727b27ec6Sopenharmony_ci 1827b27ec6Sopenharmony_ci THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 1927b27ec6Sopenharmony_ci "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2027b27ec6Sopenharmony_ci LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2127b27ec6Sopenharmony_ci A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2227b27ec6Sopenharmony_ci OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2327b27ec6Sopenharmony_ci SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2427b27ec6Sopenharmony_ci LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2527b27ec6Sopenharmony_ci DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2627b27ec6Sopenharmony_ci THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2727b27ec6Sopenharmony_ci (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2827b27ec6Sopenharmony_ci OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2927b27ec6Sopenharmony_ci 3027b27ec6Sopenharmony_ci You can contact the author at : 3127b27ec6Sopenharmony_ci - LZ4 source repository : https://github.com/lz4/lz4 3227b27ec6Sopenharmony_ci - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c 3327b27ec6Sopenharmony_ci*/ 3427b27ec6Sopenharmony_ci/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */ 3527b27ec6Sopenharmony_ci 3627b27ec6Sopenharmony_ci 3727b27ec6Sopenharmony_ci/* ************************************* 3827b27ec6Sopenharmony_ci* Tuning Parameter 3927b27ec6Sopenharmony_ci***************************************/ 4027b27ec6Sopenharmony_ci 4127b27ec6Sopenharmony_ci/*! HEAPMODE : 4227b27ec6Sopenharmony_ci * Select how default compression function will allocate workplace memory, 4327b27ec6Sopenharmony_ci * in stack (0:fastest), or in heap (1:requires malloc()). 4427b27ec6Sopenharmony_ci * Since workplace is rather large, heap mode is recommended. 4527b27ec6Sopenharmony_ci**/ 4627b27ec6Sopenharmony_ci#ifndef LZ4HC_HEAPMODE 4727b27ec6Sopenharmony_ci# define LZ4HC_HEAPMODE 1 4827b27ec6Sopenharmony_ci#endif 4927b27ec6Sopenharmony_ci 5027b27ec6Sopenharmony_ci 5127b27ec6Sopenharmony_ci/*=== Dependency ===*/ 5227b27ec6Sopenharmony_ci#define LZ4_HC_STATIC_LINKING_ONLY 5327b27ec6Sopenharmony_ci#include "lz4hc.h" 5427b27ec6Sopenharmony_ci 5527b27ec6Sopenharmony_ci 5627b27ec6Sopenharmony_ci/*=== Common definitions ===*/ 5727b27ec6Sopenharmony_ci#if defined(__GNUC__) 5827b27ec6Sopenharmony_ci# pragma GCC diagnostic ignored "-Wunused-function" 5927b27ec6Sopenharmony_ci#endif 6027b27ec6Sopenharmony_ci#if defined (__clang__) 6127b27ec6Sopenharmony_ci# pragma clang diagnostic ignored "-Wunused-function" 6227b27ec6Sopenharmony_ci#endif 6327b27ec6Sopenharmony_ci 6427b27ec6Sopenharmony_ci#define LZ4_COMMONDEFS_ONLY 6527b27ec6Sopenharmony_ci#ifndef LZ4_SRC_INCLUDED 6627b27ec6Sopenharmony_ci#include "lz4.c" /* LZ4_count, constants, mem */ 6727b27ec6Sopenharmony_ci#endif 6827b27ec6Sopenharmony_ci 6927b27ec6Sopenharmony_ci 7027b27ec6Sopenharmony_ci/*=== Enums ===*/ 7127b27ec6Sopenharmony_citypedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive; 7227b27ec6Sopenharmony_ci 7327b27ec6Sopenharmony_ci 7427b27ec6Sopenharmony_ci/*=== Constants ===*/ 7527b27ec6Sopenharmony_ci#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH) 7627b27ec6Sopenharmony_ci#define LZ4_OPT_NUM (1<<12) 7727b27ec6Sopenharmony_ci 7827b27ec6Sopenharmony_ci 7927b27ec6Sopenharmony_ci/*=== Macros ===*/ 8027b27ec6Sopenharmony_ci#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) 8127b27ec6Sopenharmony_ci#define MAX(a,b) ( (a) > (b) ? (a) : (b) ) 8227b27ec6Sopenharmony_ci#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG)) 8327b27ec6Sopenharmony_ci#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */ 8427b27ec6Sopenharmony_ci#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */ 8527b27ec6Sopenharmony_ci/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */ 8627b27ec6Sopenharmony_ci#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor 8727b27ec6Sopenharmony_ci 8827b27ec6Sopenharmony_cistatic U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); } 8927b27ec6Sopenharmony_ci 9027b27ec6Sopenharmony_ci 9127b27ec6Sopenharmony_ci/************************************** 9227b27ec6Sopenharmony_ci* HC Compression 9327b27ec6Sopenharmony_ci**************************************/ 9427b27ec6Sopenharmony_cistatic void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4) 9527b27ec6Sopenharmony_ci{ 9627b27ec6Sopenharmony_ci MEM_INIT(hc4->hashTable, 0, sizeof(hc4->hashTable)); 9727b27ec6Sopenharmony_ci MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable)); 9827b27ec6Sopenharmony_ci} 9927b27ec6Sopenharmony_ci 10027b27ec6Sopenharmony_cistatic void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start) 10127b27ec6Sopenharmony_ci{ 10227b27ec6Sopenharmony_ci size_t const bufferSize = (size_t)(hc4->end - hc4->prefixStart); 10327b27ec6Sopenharmony_ci size_t newStartingOffset = bufferSize + hc4->dictLimit; 10427b27ec6Sopenharmony_ci assert(newStartingOffset >= bufferSize); /* check overflow */ 10527b27ec6Sopenharmony_ci if (newStartingOffset > 1 GB) { 10627b27ec6Sopenharmony_ci LZ4HC_clearTables(hc4); 10727b27ec6Sopenharmony_ci newStartingOffset = 0; 10827b27ec6Sopenharmony_ci } 10927b27ec6Sopenharmony_ci newStartingOffset += 64 KB; 11027b27ec6Sopenharmony_ci hc4->nextToUpdate = (U32)newStartingOffset; 11127b27ec6Sopenharmony_ci hc4->prefixStart = start; 11227b27ec6Sopenharmony_ci hc4->end = start; 11327b27ec6Sopenharmony_ci hc4->dictStart = start; 11427b27ec6Sopenharmony_ci hc4->dictLimit = (U32)newStartingOffset; 11527b27ec6Sopenharmony_ci hc4->lowLimit = (U32)newStartingOffset; 11627b27ec6Sopenharmony_ci} 11727b27ec6Sopenharmony_ci 11827b27ec6Sopenharmony_ci 11927b27ec6Sopenharmony_ci/* Update chains up to ip (excluded) */ 12027b27ec6Sopenharmony_ciLZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip) 12127b27ec6Sopenharmony_ci{ 12227b27ec6Sopenharmony_ci U16* const chainTable = hc4->chainTable; 12327b27ec6Sopenharmony_ci U32* const hashTable = hc4->hashTable; 12427b27ec6Sopenharmony_ci const BYTE* const prefixPtr = hc4->prefixStart; 12527b27ec6Sopenharmony_ci U32 const prefixIdx = hc4->dictLimit; 12627b27ec6Sopenharmony_ci U32 const target = (U32)(ip - prefixPtr) + prefixIdx; 12727b27ec6Sopenharmony_ci U32 idx = hc4->nextToUpdate; 12827b27ec6Sopenharmony_ci assert(ip >= prefixPtr); 12927b27ec6Sopenharmony_ci assert(target >= prefixIdx); 13027b27ec6Sopenharmony_ci 13127b27ec6Sopenharmony_ci while (idx < target) { 13227b27ec6Sopenharmony_ci U32 const h = LZ4HC_hashPtr(prefixPtr+idx-prefixIdx); 13327b27ec6Sopenharmony_ci size_t delta = idx - hashTable[h]; 13427b27ec6Sopenharmony_ci if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX; 13527b27ec6Sopenharmony_ci DELTANEXTU16(chainTable, idx) = (U16)delta; 13627b27ec6Sopenharmony_ci hashTable[h] = idx; 13727b27ec6Sopenharmony_ci idx++; 13827b27ec6Sopenharmony_ci } 13927b27ec6Sopenharmony_ci 14027b27ec6Sopenharmony_ci hc4->nextToUpdate = target; 14127b27ec6Sopenharmony_ci} 14227b27ec6Sopenharmony_ci 14327b27ec6Sopenharmony_ci/** LZ4HC_countBack() : 14427b27ec6Sopenharmony_ci * @return : negative value, nb of common bytes before ip/match */ 14527b27ec6Sopenharmony_ciLZ4_FORCE_INLINE 14627b27ec6Sopenharmony_ciint LZ4HC_countBack(const BYTE* const ip, const BYTE* const match, 14727b27ec6Sopenharmony_ci const BYTE* const iMin, const BYTE* const mMin) 14827b27ec6Sopenharmony_ci{ 14927b27ec6Sopenharmony_ci int back = 0; 15027b27ec6Sopenharmony_ci int const min = (int)MAX(iMin - ip, mMin - match); 15127b27ec6Sopenharmony_ci assert(min <= 0); 15227b27ec6Sopenharmony_ci assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31)); 15327b27ec6Sopenharmony_ci assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31)); 15427b27ec6Sopenharmony_ci while ( (back > min) 15527b27ec6Sopenharmony_ci && (ip[back-1] == match[back-1]) ) 15627b27ec6Sopenharmony_ci back--; 15727b27ec6Sopenharmony_ci return back; 15827b27ec6Sopenharmony_ci} 15927b27ec6Sopenharmony_ci 16027b27ec6Sopenharmony_ci#if defined(_MSC_VER) 16127b27ec6Sopenharmony_ci# define LZ4HC_rotl32(x,r) _rotl(x,r) 16227b27ec6Sopenharmony_ci#else 16327b27ec6Sopenharmony_ci# define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r))) 16427b27ec6Sopenharmony_ci#endif 16527b27ec6Sopenharmony_ci 16627b27ec6Sopenharmony_ci 16727b27ec6Sopenharmony_cistatic U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern) 16827b27ec6Sopenharmony_ci{ 16927b27ec6Sopenharmony_ci size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3; 17027b27ec6Sopenharmony_ci if (bitsToRotate == 0) return pattern; 17127b27ec6Sopenharmony_ci return LZ4HC_rotl32(pattern, (int)bitsToRotate); 17227b27ec6Sopenharmony_ci} 17327b27ec6Sopenharmony_ci 17427b27ec6Sopenharmony_ci/* LZ4HC_countPattern() : 17527b27ec6Sopenharmony_ci * pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */ 17627b27ec6Sopenharmony_cistatic unsigned 17727b27ec6Sopenharmony_ciLZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32) 17827b27ec6Sopenharmony_ci{ 17927b27ec6Sopenharmony_ci const BYTE* const iStart = ip; 18027b27ec6Sopenharmony_ci reg_t const pattern = (sizeof(pattern)==8) ? 18127b27ec6Sopenharmony_ci (reg_t)pattern32 + (((reg_t)pattern32) << (sizeof(pattern)*4)) : pattern32; 18227b27ec6Sopenharmony_ci 18327b27ec6Sopenharmony_ci while (likely(ip < iEnd-(sizeof(pattern)-1))) { 18427b27ec6Sopenharmony_ci reg_t const diff = LZ4_read_ARCH(ip) ^ pattern; 18527b27ec6Sopenharmony_ci if (!diff) { ip+=sizeof(pattern); continue; } 18627b27ec6Sopenharmony_ci ip += LZ4_NbCommonBytes(diff); 18727b27ec6Sopenharmony_ci return (unsigned)(ip - iStart); 18827b27ec6Sopenharmony_ci } 18927b27ec6Sopenharmony_ci 19027b27ec6Sopenharmony_ci if (LZ4_isLittleEndian()) { 19127b27ec6Sopenharmony_ci reg_t patternByte = pattern; 19227b27ec6Sopenharmony_ci while ((ip<iEnd) && (*ip == (BYTE)patternByte)) { 19327b27ec6Sopenharmony_ci ip++; patternByte >>= 8; 19427b27ec6Sopenharmony_ci } 19527b27ec6Sopenharmony_ci } else { /* big endian */ 19627b27ec6Sopenharmony_ci U32 bitOffset = (sizeof(pattern)*8) - 8; 19727b27ec6Sopenharmony_ci while (ip < iEnd) { 19827b27ec6Sopenharmony_ci BYTE const byte = (BYTE)(pattern >> bitOffset); 19927b27ec6Sopenharmony_ci if (*ip != byte) break; 20027b27ec6Sopenharmony_ci ip ++; bitOffset -= 8; 20127b27ec6Sopenharmony_ci } } 20227b27ec6Sopenharmony_ci 20327b27ec6Sopenharmony_ci return (unsigned)(ip - iStart); 20427b27ec6Sopenharmony_ci} 20527b27ec6Sopenharmony_ci 20627b27ec6Sopenharmony_ci/* LZ4HC_reverseCountPattern() : 20727b27ec6Sopenharmony_ci * pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) 20827b27ec6Sopenharmony_ci * read using natural platform endianness */ 20927b27ec6Sopenharmony_cistatic unsigned 21027b27ec6Sopenharmony_ciLZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern) 21127b27ec6Sopenharmony_ci{ 21227b27ec6Sopenharmony_ci const BYTE* const iStart = ip; 21327b27ec6Sopenharmony_ci 21427b27ec6Sopenharmony_ci while (likely(ip >= iLow+4)) { 21527b27ec6Sopenharmony_ci if (LZ4_read32(ip-4) != pattern) break; 21627b27ec6Sopenharmony_ci ip -= 4; 21727b27ec6Sopenharmony_ci } 21827b27ec6Sopenharmony_ci { const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianness */ 21927b27ec6Sopenharmony_ci while (likely(ip>iLow)) { 22027b27ec6Sopenharmony_ci if (ip[-1] != *bytePtr) break; 22127b27ec6Sopenharmony_ci ip--; bytePtr--; 22227b27ec6Sopenharmony_ci } } 22327b27ec6Sopenharmony_ci return (unsigned)(iStart - ip); 22427b27ec6Sopenharmony_ci} 22527b27ec6Sopenharmony_ci 22627b27ec6Sopenharmony_ci/* LZ4HC_protectDictEnd() : 22727b27ec6Sopenharmony_ci * Checks if the match is in the last 3 bytes of the dictionary, so reading the 22827b27ec6Sopenharmony_ci * 4 byte MINMATCH would overflow. 22927b27ec6Sopenharmony_ci * @returns true if the match index is okay. 23027b27ec6Sopenharmony_ci */ 23127b27ec6Sopenharmony_cistatic int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex) 23227b27ec6Sopenharmony_ci{ 23327b27ec6Sopenharmony_ci return ((U32)((dictLimit - 1) - matchIndex) >= 3); 23427b27ec6Sopenharmony_ci} 23527b27ec6Sopenharmony_ci 23627b27ec6Sopenharmony_citypedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e; 23727b27ec6Sopenharmony_citypedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e; 23827b27ec6Sopenharmony_ci 23927b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int 24027b27ec6Sopenharmony_ciLZ4HC_InsertAndGetWiderMatch ( 24127b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const hc4, 24227b27ec6Sopenharmony_ci const BYTE* const ip, 24327b27ec6Sopenharmony_ci const BYTE* const iLowLimit, const BYTE* const iHighLimit, 24427b27ec6Sopenharmony_ci int longest, 24527b27ec6Sopenharmony_ci const BYTE** matchpos, 24627b27ec6Sopenharmony_ci const BYTE** startpos, 24727b27ec6Sopenharmony_ci const int maxNbAttempts, 24827b27ec6Sopenharmony_ci const int patternAnalysis, const int chainSwap, 24927b27ec6Sopenharmony_ci const dictCtx_directive dict, 25027b27ec6Sopenharmony_ci const HCfavor_e favorDecSpeed) 25127b27ec6Sopenharmony_ci{ 25227b27ec6Sopenharmony_ci U16* const chainTable = hc4->chainTable; 25327b27ec6Sopenharmony_ci U32* const HashTable = hc4->hashTable; 25427b27ec6Sopenharmony_ci const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx; 25527b27ec6Sopenharmony_ci const BYTE* const prefixPtr = hc4->prefixStart; 25627b27ec6Sopenharmony_ci const U32 prefixIdx = hc4->dictLimit; 25727b27ec6Sopenharmony_ci const U32 ipIndex = (U32)(ip - prefixPtr) + prefixIdx; 25827b27ec6Sopenharmony_ci const int withinStartDistance = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex); 25927b27ec6Sopenharmony_ci const U32 lowestMatchIndex = (withinStartDistance) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX; 26027b27ec6Sopenharmony_ci const BYTE* const dictStart = hc4->dictStart; 26127b27ec6Sopenharmony_ci const U32 dictIdx = hc4->lowLimit; 26227b27ec6Sopenharmony_ci const BYTE* const dictEnd = dictStart + prefixIdx - dictIdx; 26327b27ec6Sopenharmony_ci int const lookBackLength = (int)(ip-iLowLimit); 26427b27ec6Sopenharmony_ci int nbAttempts = maxNbAttempts; 26527b27ec6Sopenharmony_ci U32 matchChainPos = 0; 26627b27ec6Sopenharmony_ci U32 const pattern = LZ4_read32(ip); 26727b27ec6Sopenharmony_ci U32 matchIndex; 26827b27ec6Sopenharmony_ci repeat_state_e repeat = rep_untested; 26927b27ec6Sopenharmony_ci size_t srcPatternLength = 0; 27027b27ec6Sopenharmony_ci 27127b27ec6Sopenharmony_ci DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch"); 27227b27ec6Sopenharmony_ci /* First Match */ 27327b27ec6Sopenharmony_ci LZ4HC_Insert(hc4, ip); 27427b27ec6Sopenharmony_ci matchIndex = HashTable[LZ4HC_hashPtr(ip)]; 27527b27ec6Sopenharmony_ci DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)", 27627b27ec6Sopenharmony_ci matchIndex, lowestMatchIndex); 27727b27ec6Sopenharmony_ci 27827b27ec6Sopenharmony_ci while ((matchIndex>=lowestMatchIndex) && (nbAttempts>0)) { 27927b27ec6Sopenharmony_ci int matchLength=0; 28027b27ec6Sopenharmony_ci nbAttempts--; 28127b27ec6Sopenharmony_ci assert(matchIndex < ipIndex); 28227b27ec6Sopenharmony_ci if (favorDecSpeed && (ipIndex - matchIndex < 8)) { 28327b27ec6Sopenharmony_ci /* do nothing */ 28427b27ec6Sopenharmony_ci } else if (matchIndex >= prefixIdx) { /* within current Prefix */ 28527b27ec6Sopenharmony_ci const BYTE* const matchPtr = prefixPtr + matchIndex - prefixIdx; 28627b27ec6Sopenharmony_ci assert(matchPtr < ip); 28727b27ec6Sopenharmony_ci assert(longest >= 1); 28827b27ec6Sopenharmony_ci if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) { 28927b27ec6Sopenharmony_ci if (LZ4_read32(matchPtr) == pattern) { 29027b27ec6Sopenharmony_ci int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, prefixPtr) : 0; 29127b27ec6Sopenharmony_ci matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit); 29227b27ec6Sopenharmony_ci matchLength -= back; 29327b27ec6Sopenharmony_ci if (matchLength > longest) { 29427b27ec6Sopenharmony_ci longest = matchLength; 29527b27ec6Sopenharmony_ci *matchpos = matchPtr + back; 29627b27ec6Sopenharmony_ci *startpos = ip + back; 29727b27ec6Sopenharmony_ci } } } 29827b27ec6Sopenharmony_ci } else { /* lowestMatchIndex <= matchIndex < dictLimit */ 29927b27ec6Sopenharmony_ci const BYTE* const matchPtr = dictStart + (matchIndex - dictIdx); 30027b27ec6Sopenharmony_ci assert(matchIndex >= dictIdx); 30127b27ec6Sopenharmony_ci if ( likely(matchIndex <= prefixIdx - 4) 30227b27ec6Sopenharmony_ci && (LZ4_read32(matchPtr) == pattern) ) { 30327b27ec6Sopenharmony_ci int back = 0; 30427b27ec6Sopenharmony_ci const BYTE* vLimit = ip + (prefixIdx - matchIndex); 30527b27ec6Sopenharmony_ci if (vLimit > iHighLimit) vLimit = iHighLimit; 30627b27ec6Sopenharmony_ci matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; 30727b27ec6Sopenharmony_ci if ((ip+matchLength == vLimit) && (vLimit < iHighLimit)) 30827b27ec6Sopenharmony_ci matchLength += LZ4_count(ip+matchLength, prefixPtr, iHighLimit); 30927b27ec6Sopenharmony_ci back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0; 31027b27ec6Sopenharmony_ci matchLength -= back; 31127b27ec6Sopenharmony_ci if (matchLength > longest) { 31227b27ec6Sopenharmony_ci longest = matchLength; 31327b27ec6Sopenharmony_ci *matchpos = prefixPtr - prefixIdx + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */ 31427b27ec6Sopenharmony_ci *startpos = ip + back; 31527b27ec6Sopenharmony_ci } } } 31627b27ec6Sopenharmony_ci 31727b27ec6Sopenharmony_ci if (chainSwap && matchLength==longest) { /* better match => select a better chain */ 31827b27ec6Sopenharmony_ci assert(lookBackLength==0); /* search forward only */ 31927b27ec6Sopenharmony_ci if (matchIndex + (U32)longest <= ipIndex) { 32027b27ec6Sopenharmony_ci int const kTrigger = 4; 32127b27ec6Sopenharmony_ci U32 distanceToNextMatch = 1; 32227b27ec6Sopenharmony_ci int const end = longest - MINMATCH + 1; 32327b27ec6Sopenharmony_ci int step = 1; 32427b27ec6Sopenharmony_ci int accel = 1 << kTrigger; 32527b27ec6Sopenharmony_ci int pos; 32627b27ec6Sopenharmony_ci for (pos = 0; pos < end; pos += step) { 32727b27ec6Sopenharmony_ci U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos); 32827b27ec6Sopenharmony_ci step = (accel++ >> kTrigger); 32927b27ec6Sopenharmony_ci if (candidateDist > distanceToNextMatch) { 33027b27ec6Sopenharmony_ci distanceToNextMatch = candidateDist; 33127b27ec6Sopenharmony_ci matchChainPos = (U32)pos; 33227b27ec6Sopenharmony_ci accel = 1 << kTrigger; 33327b27ec6Sopenharmony_ci } } 33427b27ec6Sopenharmony_ci if (distanceToNextMatch > 1) { 33527b27ec6Sopenharmony_ci if (distanceToNextMatch > matchIndex) break; /* avoid overflow */ 33627b27ec6Sopenharmony_ci matchIndex -= distanceToNextMatch; 33727b27ec6Sopenharmony_ci continue; 33827b27ec6Sopenharmony_ci } } } 33927b27ec6Sopenharmony_ci 34027b27ec6Sopenharmony_ci { U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex); 34127b27ec6Sopenharmony_ci if (patternAnalysis && distNextMatch==1 && matchChainPos==0) { 34227b27ec6Sopenharmony_ci U32 const matchCandidateIdx = matchIndex-1; 34327b27ec6Sopenharmony_ci /* may be a repeated pattern */ 34427b27ec6Sopenharmony_ci if (repeat == rep_untested) { 34527b27ec6Sopenharmony_ci if ( ((pattern & 0xFFFF) == (pattern >> 16)) 34627b27ec6Sopenharmony_ci & ((pattern & 0xFF) == (pattern >> 24)) ) { 34727b27ec6Sopenharmony_ci repeat = rep_confirmed; 34827b27ec6Sopenharmony_ci srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern); 34927b27ec6Sopenharmony_ci } else { 35027b27ec6Sopenharmony_ci repeat = rep_not; 35127b27ec6Sopenharmony_ci } } 35227b27ec6Sopenharmony_ci if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex) 35327b27ec6Sopenharmony_ci && LZ4HC_protectDictEnd(prefixIdx, matchCandidateIdx) ) { 35427b27ec6Sopenharmony_ci const int extDict = matchCandidateIdx < prefixIdx; 35527b27ec6Sopenharmony_ci const BYTE* const matchPtr = (extDict ? dictStart - dictIdx : prefixPtr - prefixIdx) + matchCandidateIdx; 35627b27ec6Sopenharmony_ci if (LZ4_read32(matchPtr) == pattern) { /* good candidate */ 35727b27ec6Sopenharmony_ci const BYTE* const iLimit = extDict ? dictEnd : iHighLimit; 35827b27ec6Sopenharmony_ci size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern); 35927b27ec6Sopenharmony_ci if (extDict && matchPtr + forwardPatternLength == iLimit) { 36027b27ec6Sopenharmony_ci U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern); 36127b27ec6Sopenharmony_ci forwardPatternLength += LZ4HC_countPattern(prefixPtr, iHighLimit, rotatedPattern); 36227b27ec6Sopenharmony_ci } 36327b27ec6Sopenharmony_ci { const BYTE* const lowestMatchPtr = extDict ? dictStart : prefixPtr; 36427b27ec6Sopenharmony_ci size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern); 36527b27ec6Sopenharmony_ci size_t currentSegmentLength; 36627b27ec6Sopenharmony_ci if (!extDict 36727b27ec6Sopenharmony_ci && matchPtr - backLength == prefixPtr 36827b27ec6Sopenharmony_ci && dictIdx < prefixIdx) { 36927b27ec6Sopenharmony_ci U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern); 37027b27ec6Sopenharmony_ci backLength += LZ4HC_reverseCountPattern(dictEnd, dictStart, rotatedPattern); 37127b27ec6Sopenharmony_ci } 37227b27ec6Sopenharmony_ci /* Limit backLength not go further than lowestMatchIndex */ 37327b27ec6Sopenharmony_ci backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex); 37427b27ec6Sopenharmony_ci assert(matchCandidateIdx - backLength >= lowestMatchIndex); 37527b27ec6Sopenharmony_ci currentSegmentLength = backLength + forwardPatternLength; 37627b27ec6Sopenharmony_ci /* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */ 37727b27ec6Sopenharmony_ci if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */ 37827b27ec6Sopenharmony_ci && (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */ 37927b27ec6Sopenharmony_ci U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */ 38027b27ec6Sopenharmony_ci if (LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) 38127b27ec6Sopenharmony_ci matchIndex = newMatchIndex; 38227b27ec6Sopenharmony_ci else { 38327b27ec6Sopenharmony_ci /* Can only happen if started in the prefix */ 38427b27ec6Sopenharmony_ci assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); 38527b27ec6Sopenharmony_ci matchIndex = prefixIdx; 38627b27ec6Sopenharmony_ci } 38727b27ec6Sopenharmony_ci } else { 38827b27ec6Sopenharmony_ci U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */ 38927b27ec6Sopenharmony_ci if (!LZ4HC_protectDictEnd(prefixIdx, newMatchIndex)) { 39027b27ec6Sopenharmony_ci assert(newMatchIndex >= prefixIdx - 3 && newMatchIndex < prefixIdx && !extDict); 39127b27ec6Sopenharmony_ci matchIndex = prefixIdx; 39227b27ec6Sopenharmony_ci } else { 39327b27ec6Sopenharmony_ci matchIndex = newMatchIndex; 39427b27ec6Sopenharmony_ci if (lookBackLength==0) { /* no back possible */ 39527b27ec6Sopenharmony_ci size_t const maxML = MIN(currentSegmentLength, srcPatternLength); 39627b27ec6Sopenharmony_ci if ((size_t)longest < maxML) { 39727b27ec6Sopenharmony_ci assert(prefixPtr - prefixIdx + matchIndex != ip); 39827b27ec6Sopenharmony_ci if ((size_t)(ip - prefixPtr) + prefixIdx - matchIndex > LZ4_DISTANCE_MAX) break; 39927b27ec6Sopenharmony_ci assert(maxML < 2 GB); 40027b27ec6Sopenharmony_ci longest = (int)maxML; 40127b27ec6Sopenharmony_ci *matchpos = prefixPtr - prefixIdx + matchIndex; /* virtual pos, relative to ip, to retrieve offset */ 40227b27ec6Sopenharmony_ci *startpos = ip; 40327b27ec6Sopenharmony_ci } 40427b27ec6Sopenharmony_ci { U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex); 40527b27ec6Sopenharmony_ci if (distToNextPattern > matchIndex) break; /* avoid overflow */ 40627b27ec6Sopenharmony_ci matchIndex -= distToNextPattern; 40727b27ec6Sopenharmony_ci } } } } } 40827b27ec6Sopenharmony_ci continue; 40927b27ec6Sopenharmony_ci } } 41027b27ec6Sopenharmony_ci } } /* PA optimization */ 41127b27ec6Sopenharmony_ci 41227b27ec6Sopenharmony_ci /* follow current chain */ 41327b27ec6Sopenharmony_ci matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos); 41427b27ec6Sopenharmony_ci 41527b27ec6Sopenharmony_ci } /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */ 41627b27ec6Sopenharmony_ci 41727b27ec6Sopenharmony_ci if ( dict == usingDictCtxHc 41827b27ec6Sopenharmony_ci && nbAttempts > 0 41927b27ec6Sopenharmony_ci && ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) { 42027b27ec6Sopenharmony_ci size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->prefixStart) + dictCtx->dictLimit; 42127b27ec6Sopenharmony_ci U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)]; 42227b27ec6Sopenharmony_ci assert(dictEndOffset <= 1 GB); 42327b27ec6Sopenharmony_ci matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset; 42427b27ec6Sopenharmony_ci while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) { 42527b27ec6Sopenharmony_ci const BYTE* const matchPtr = dictCtx->prefixStart - dictCtx->dictLimit + dictMatchIndex; 42627b27ec6Sopenharmony_ci 42727b27ec6Sopenharmony_ci if (LZ4_read32(matchPtr) == pattern) { 42827b27ec6Sopenharmony_ci int mlt; 42927b27ec6Sopenharmony_ci int back = 0; 43027b27ec6Sopenharmony_ci const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex); 43127b27ec6Sopenharmony_ci if (vLimit > iHighLimit) vLimit = iHighLimit; 43227b27ec6Sopenharmony_ci mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH; 43327b27ec6Sopenharmony_ci back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->prefixStart) : 0; 43427b27ec6Sopenharmony_ci mlt -= back; 43527b27ec6Sopenharmony_ci if (mlt > longest) { 43627b27ec6Sopenharmony_ci longest = mlt; 43727b27ec6Sopenharmony_ci *matchpos = prefixPtr - prefixIdx + matchIndex + back; 43827b27ec6Sopenharmony_ci *startpos = ip + back; 43927b27ec6Sopenharmony_ci } } 44027b27ec6Sopenharmony_ci 44127b27ec6Sopenharmony_ci { U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex); 44227b27ec6Sopenharmony_ci dictMatchIndex -= nextOffset; 44327b27ec6Sopenharmony_ci matchIndex -= nextOffset; 44427b27ec6Sopenharmony_ci } } } 44527b27ec6Sopenharmony_ci 44627b27ec6Sopenharmony_ci return longest; 44727b27ec6Sopenharmony_ci} 44827b27ec6Sopenharmony_ci 44927b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int 45027b27ec6Sopenharmony_ciLZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */ 45127b27ec6Sopenharmony_ci const BYTE* const ip, const BYTE* const iLimit, 45227b27ec6Sopenharmony_ci const BYTE** matchpos, 45327b27ec6Sopenharmony_ci const int maxNbAttempts, 45427b27ec6Sopenharmony_ci const int patternAnalysis, 45527b27ec6Sopenharmony_ci const dictCtx_directive dict) 45627b27ec6Sopenharmony_ci{ 45727b27ec6Sopenharmony_ci const BYTE* uselessPtr = ip; 45827b27ec6Sopenharmony_ci /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), 45927b27ec6Sopenharmony_ci * but this won't be the case here, as we define iLowLimit==ip, 46027b27ec6Sopenharmony_ci * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */ 46127b27ec6Sopenharmony_ci return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio); 46227b27ec6Sopenharmony_ci} 46327b27ec6Sopenharmony_ci 46427b27ec6Sopenharmony_ci/* LZ4HC_encodeSequence() : 46527b27ec6Sopenharmony_ci * @return : 0 if ok, 46627b27ec6Sopenharmony_ci * 1 if buffer issue detected */ 46727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_encodeSequence ( 46827b27ec6Sopenharmony_ci const BYTE** _ip, 46927b27ec6Sopenharmony_ci BYTE** _op, 47027b27ec6Sopenharmony_ci const BYTE** _anchor, 47127b27ec6Sopenharmony_ci int matchLength, 47227b27ec6Sopenharmony_ci const BYTE* const match, 47327b27ec6Sopenharmony_ci limitedOutput_directive limit, 47427b27ec6Sopenharmony_ci BYTE* oend) 47527b27ec6Sopenharmony_ci{ 47627b27ec6Sopenharmony_ci#define ip (*_ip) 47727b27ec6Sopenharmony_ci#define op (*_op) 47827b27ec6Sopenharmony_ci#define anchor (*_anchor) 47927b27ec6Sopenharmony_ci 48027b27ec6Sopenharmony_ci size_t length; 48127b27ec6Sopenharmony_ci BYTE* const token = op++; 48227b27ec6Sopenharmony_ci 48327b27ec6Sopenharmony_ci#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6) 48427b27ec6Sopenharmony_ci static const BYTE* start = NULL; 48527b27ec6Sopenharmony_ci static U32 totalCost = 0; 48627b27ec6Sopenharmony_ci U32 const pos = (start==NULL) ? 0 : (U32)(anchor - start); 48727b27ec6Sopenharmony_ci U32 const ll = (U32)(ip - anchor); 48827b27ec6Sopenharmony_ci U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0; 48927b27ec6Sopenharmony_ci U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0; 49027b27ec6Sopenharmony_ci U32 const cost = 1 + llAdd + ll + 2 + mlAdd; 49127b27ec6Sopenharmony_ci if (start==NULL) start = anchor; /* only works for single segment */ 49227b27ec6Sopenharmony_ci /* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */ 49327b27ec6Sopenharmony_ci DEBUGLOG(6, "pos:%7u -- literals:%4u, match:%4i, offset:%5u, cost:%4u + %5u", 49427b27ec6Sopenharmony_ci pos, 49527b27ec6Sopenharmony_ci (U32)(ip - anchor), matchLength, (U32)(ip-match), 49627b27ec6Sopenharmony_ci cost, totalCost); 49727b27ec6Sopenharmony_ci totalCost += cost; 49827b27ec6Sopenharmony_ci#endif 49927b27ec6Sopenharmony_ci 50027b27ec6Sopenharmony_ci /* Encode Literal length */ 50127b27ec6Sopenharmony_ci length = (size_t)(ip - anchor); 50227b27ec6Sopenharmony_ci LZ4_STATIC_ASSERT(notLimited == 0); 50327b27ec6Sopenharmony_ci /* Check output limit */ 50427b27ec6Sopenharmony_ci if (limit && ((op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) { 50527b27ec6Sopenharmony_ci DEBUGLOG(6, "Not enough room to write %i literals (%i bytes remaining)", 50627b27ec6Sopenharmony_ci (int)length, (int)(oend - op)); 50727b27ec6Sopenharmony_ci return 1; 50827b27ec6Sopenharmony_ci } 50927b27ec6Sopenharmony_ci if (length >= RUN_MASK) { 51027b27ec6Sopenharmony_ci size_t len = length - RUN_MASK; 51127b27ec6Sopenharmony_ci *token = (RUN_MASK << ML_BITS); 51227b27ec6Sopenharmony_ci for(; len >= 255 ; len -= 255) *op++ = 255; 51327b27ec6Sopenharmony_ci *op++ = (BYTE)len; 51427b27ec6Sopenharmony_ci } else { 51527b27ec6Sopenharmony_ci *token = (BYTE)(length << ML_BITS); 51627b27ec6Sopenharmony_ci } 51727b27ec6Sopenharmony_ci 51827b27ec6Sopenharmony_ci /* Copy Literals */ 51927b27ec6Sopenharmony_ci LZ4_wildCopy8(op, anchor, op + length); 52027b27ec6Sopenharmony_ci op += length; 52127b27ec6Sopenharmony_ci 52227b27ec6Sopenharmony_ci /* Encode Offset */ 52327b27ec6Sopenharmony_ci assert( (ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */ 52427b27ec6Sopenharmony_ci LZ4_writeLE16(op, (U16)(ip - match)); op += 2; 52527b27ec6Sopenharmony_ci 52627b27ec6Sopenharmony_ci /* Encode MatchLength */ 52727b27ec6Sopenharmony_ci assert(matchLength >= MINMATCH); 52827b27ec6Sopenharmony_ci length = (size_t)matchLength - MINMATCH; 52927b27ec6Sopenharmony_ci if (limit && (op + (length / 255) + (1 + LASTLITERALS) > oend)) { 53027b27ec6Sopenharmony_ci DEBUGLOG(6, "Not enough room to write match length"); 53127b27ec6Sopenharmony_ci return 1; /* Check output limit */ 53227b27ec6Sopenharmony_ci } 53327b27ec6Sopenharmony_ci if (length >= ML_MASK) { 53427b27ec6Sopenharmony_ci *token += ML_MASK; 53527b27ec6Sopenharmony_ci length -= ML_MASK; 53627b27ec6Sopenharmony_ci for(; length >= 510 ; length -= 510) { *op++ = 255; *op++ = 255; } 53727b27ec6Sopenharmony_ci if (length >= 255) { length -= 255; *op++ = 255; } 53827b27ec6Sopenharmony_ci *op++ = (BYTE)length; 53927b27ec6Sopenharmony_ci } else { 54027b27ec6Sopenharmony_ci *token += (BYTE)(length); 54127b27ec6Sopenharmony_ci } 54227b27ec6Sopenharmony_ci 54327b27ec6Sopenharmony_ci /* Prepare next loop */ 54427b27ec6Sopenharmony_ci ip += matchLength; 54527b27ec6Sopenharmony_ci anchor = ip; 54627b27ec6Sopenharmony_ci 54727b27ec6Sopenharmony_ci return 0; 54827b27ec6Sopenharmony_ci} 54927b27ec6Sopenharmony_ci#undef ip 55027b27ec6Sopenharmony_ci#undef op 55127b27ec6Sopenharmony_ci#undef anchor 55227b27ec6Sopenharmony_ci 55327b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_compress_hashChain ( 55427b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx, 55527b27ec6Sopenharmony_ci const char* const source, 55627b27ec6Sopenharmony_ci char* const dest, 55727b27ec6Sopenharmony_ci int* srcSizePtr, 55827b27ec6Sopenharmony_ci int const maxOutputSize, 55927b27ec6Sopenharmony_ci int maxNbAttempts, 56027b27ec6Sopenharmony_ci const limitedOutput_directive limit, 56127b27ec6Sopenharmony_ci const dictCtx_directive dict 56227b27ec6Sopenharmony_ci ) 56327b27ec6Sopenharmony_ci{ 56427b27ec6Sopenharmony_ci const int inputSize = *srcSizePtr; 56527b27ec6Sopenharmony_ci const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */ 56627b27ec6Sopenharmony_ci 56727b27ec6Sopenharmony_ci const BYTE* ip = (const BYTE*) source; 56827b27ec6Sopenharmony_ci const BYTE* anchor = ip; 56927b27ec6Sopenharmony_ci const BYTE* const iend = ip + inputSize; 57027b27ec6Sopenharmony_ci const BYTE* const mflimit = iend - MFLIMIT; 57127b27ec6Sopenharmony_ci const BYTE* const matchlimit = (iend - LASTLITERALS); 57227b27ec6Sopenharmony_ci 57327b27ec6Sopenharmony_ci BYTE* optr = (BYTE*) dest; 57427b27ec6Sopenharmony_ci BYTE* op = (BYTE*) dest; 57527b27ec6Sopenharmony_ci BYTE* oend = op + maxOutputSize; 57627b27ec6Sopenharmony_ci 57727b27ec6Sopenharmony_ci int ml0, ml, ml2, ml3; 57827b27ec6Sopenharmony_ci const BYTE* start0; 57927b27ec6Sopenharmony_ci const BYTE* ref0; 58027b27ec6Sopenharmony_ci const BYTE* ref = NULL; 58127b27ec6Sopenharmony_ci const BYTE* start2 = NULL; 58227b27ec6Sopenharmony_ci const BYTE* ref2 = NULL; 58327b27ec6Sopenharmony_ci const BYTE* start3 = NULL; 58427b27ec6Sopenharmony_ci const BYTE* ref3 = NULL; 58527b27ec6Sopenharmony_ci 58627b27ec6Sopenharmony_ci /* init */ 58727b27ec6Sopenharmony_ci *srcSizePtr = 0; 58827b27ec6Sopenharmony_ci if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ 58927b27ec6Sopenharmony_ci if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */ 59027b27ec6Sopenharmony_ci 59127b27ec6Sopenharmony_ci /* Main Loop */ 59227b27ec6Sopenharmony_ci while (ip <= mflimit) { 59327b27ec6Sopenharmony_ci ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict); 59427b27ec6Sopenharmony_ci if (ml<MINMATCH) { ip++; continue; } 59527b27ec6Sopenharmony_ci 59627b27ec6Sopenharmony_ci /* saved, in case we would skip too much */ 59727b27ec6Sopenharmony_ci start0 = ip; ref0 = ref; ml0 = ml; 59827b27ec6Sopenharmony_ci 59927b27ec6Sopenharmony_ci_Search2: 60027b27ec6Sopenharmony_ci if (ip+ml <= mflimit) { 60127b27ec6Sopenharmony_ci ml2 = LZ4HC_InsertAndGetWiderMatch(ctx, 60227b27ec6Sopenharmony_ci ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2, 60327b27ec6Sopenharmony_ci maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio); 60427b27ec6Sopenharmony_ci } else { 60527b27ec6Sopenharmony_ci ml2 = ml; 60627b27ec6Sopenharmony_ci } 60727b27ec6Sopenharmony_ci 60827b27ec6Sopenharmony_ci if (ml2 == ml) { /* No better match => encode ML1 */ 60927b27ec6Sopenharmony_ci optr = op; 61027b27ec6Sopenharmony_ci if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; 61127b27ec6Sopenharmony_ci continue; 61227b27ec6Sopenharmony_ci } 61327b27ec6Sopenharmony_ci 61427b27ec6Sopenharmony_ci if (start0 < ip) { /* first match was skipped at least once */ 61527b27ec6Sopenharmony_ci if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */ 61627b27ec6Sopenharmony_ci ip = start0; ref = ref0; ml = ml0; /* restore initial ML1 */ 61727b27ec6Sopenharmony_ci } } 61827b27ec6Sopenharmony_ci 61927b27ec6Sopenharmony_ci /* Here, start0==ip */ 62027b27ec6Sopenharmony_ci if ((start2 - ip) < 3) { /* First Match too small : removed */ 62127b27ec6Sopenharmony_ci ml = ml2; 62227b27ec6Sopenharmony_ci ip = start2; 62327b27ec6Sopenharmony_ci ref =ref2; 62427b27ec6Sopenharmony_ci goto _Search2; 62527b27ec6Sopenharmony_ci } 62627b27ec6Sopenharmony_ci 62727b27ec6Sopenharmony_ci_Search3: 62827b27ec6Sopenharmony_ci /* At this stage, we have : 62927b27ec6Sopenharmony_ci * ml2 > ml1, and 63027b27ec6Sopenharmony_ci * ip1+3 <= ip2 (usually < ip1+ml1) */ 63127b27ec6Sopenharmony_ci if ((start2 - ip) < OPTIMAL_ML) { 63227b27ec6Sopenharmony_ci int correction; 63327b27ec6Sopenharmony_ci int new_ml = ml; 63427b27ec6Sopenharmony_ci if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML; 63527b27ec6Sopenharmony_ci if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH; 63627b27ec6Sopenharmony_ci correction = new_ml - (int)(start2 - ip); 63727b27ec6Sopenharmony_ci if (correction > 0) { 63827b27ec6Sopenharmony_ci start2 += correction; 63927b27ec6Sopenharmony_ci ref2 += correction; 64027b27ec6Sopenharmony_ci ml2 -= correction; 64127b27ec6Sopenharmony_ci } 64227b27ec6Sopenharmony_ci } 64327b27ec6Sopenharmony_ci /* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */ 64427b27ec6Sopenharmony_ci 64527b27ec6Sopenharmony_ci if (start2 + ml2 <= mflimit) { 64627b27ec6Sopenharmony_ci ml3 = LZ4HC_InsertAndGetWiderMatch(ctx, 64727b27ec6Sopenharmony_ci start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3, 64827b27ec6Sopenharmony_ci maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio); 64927b27ec6Sopenharmony_ci } else { 65027b27ec6Sopenharmony_ci ml3 = ml2; 65127b27ec6Sopenharmony_ci } 65227b27ec6Sopenharmony_ci 65327b27ec6Sopenharmony_ci if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */ 65427b27ec6Sopenharmony_ci /* ip & ref are known; Now for ml */ 65527b27ec6Sopenharmony_ci if (start2 < ip+ml) ml = (int)(start2 - ip); 65627b27ec6Sopenharmony_ci /* Now, encode 2 sequences */ 65727b27ec6Sopenharmony_ci optr = op; 65827b27ec6Sopenharmony_ci if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; 65927b27ec6Sopenharmony_ci ip = start2; 66027b27ec6Sopenharmony_ci optr = op; 66127b27ec6Sopenharmony_ci if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) { 66227b27ec6Sopenharmony_ci ml = ml2; 66327b27ec6Sopenharmony_ci ref = ref2; 66427b27ec6Sopenharmony_ci goto _dest_overflow; 66527b27ec6Sopenharmony_ci } 66627b27ec6Sopenharmony_ci continue; 66727b27ec6Sopenharmony_ci } 66827b27ec6Sopenharmony_ci 66927b27ec6Sopenharmony_ci if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */ 67027b27ec6Sopenharmony_ci if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */ 67127b27ec6Sopenharmony_ci if (start2 < ip+ml) { 67227b27ec6Sopenharmony_ci int correction = (int)(ip+ml - start2); 67327b27ec6Sopenharmony_ci start2 += correction; 67427b27ec6Sopenharmony_ci ref2 += correction; 67527b27ec6Sopenharmony_ci ml2 -= correction; 67627b27ec6Sopenharmony_ci if (ml2 < MINMATCH) { 67727b27ec6Sopenharmony_ci start2 = start3; 67827b27ec6Sopenharmony_ci ref2 = ref3; 67927b27ec6Sopenharmony_ci ml2 = ml3; 68027b27ec6Sopenharmony_ci } 68127b27ec6Sopenharmony_ci } 68227b27ec6Sopenharmony_ci 68327b27ec6Sopenharmony_ci optr = op; 68427b27ec6Sopenharmony_ci if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; 68527b27ec6Sopenharmony_ci ip = start3; 68627b27ec6Sopenharmony_ci ref = ref3; 68727b27ec6Sopenharmony_ci ml = ml3; 68827b27ec6Sopenharmony_ci 68927b27ec6Sopenharmony_ci start0 = start2; 69027b27ec6Sopenharmony_ci ref0 = ref2; 69127b27ec6Sopenharmony_ci ml0 = ml2; 69227b27ec6Sopenharmony_ci goto _Search2; 69327b27ec6Sopenharmony_ci } 69427b27ec6Sopenharmony_ci 69527b27ec6Sopenharmony_ci start2 = start3; 69627b27ec6Sopenharmony_ci ref2 = ref3; 69727b27ec6Sopenharmony_ci ml2 = ml3; 69827b27ec6Sopenharmony_ci goto _Search3; 69927b27ec6Sopenharmony_ci } 70027b27ec6Sopenharmony_ci 70127b27ec6Sopenharmony_ci /* 70227b27ec6Sopenharmony_ci * OK, now we have 3 ascending matches; 70327b27ec6Sopenharmony_ci * let's write the first one ML1. 70427b27ec6Sopenharmony_ci * ip & ref are known; Now decide ml. 70527b27ec6Sopenharmony_ci */ 70627b27ec6Sopenharmony_ci if (start2 < ip+ml) { 70727b27ec6Sopenharmony_ci if ((start2 - ip) < OPTIMAL_ML) { 70827b27ec6Sopenharmony_ci int correction; 70927b27ec6Sopenharmony_ci if (ml > OPTIMAL_ML) ml = OPTIMAL_ML; 71027b27ec6Sopenharmony_ci if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH; 71127b27ec6Sopenharmony_ci correction = ml - (int)(start2 - ip); 71227b27ec6Sopenharmony_ci if (correction > 0) { 71327b27ec6Sopenharmony_ci start2 += correction; 71427b27ec6Sopenharmony_ci ref2 += correction; 71527b27ec6Sopenharmony_ci ml2 -= correction; 71627b27ec6Sopenharmony_ci } 71727b27ec6Sopenharmony_ci } else { 71827b27ec6Sopenharmony_ci ml = (int)(start2 - ip); 71927b27ec6Sopenharmony_ci } 72027b27ec6Sopenharmony_ci } 72127b27ec6Sopenharmony_ci optr = op; 72227b27ec6Sopenharmony_ci if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow; 72327b27ec6Sopenharmony_ci 72427b27ec6Sopenharmony_ci /* ML2 becomes ML1 */ 72527b27ec6Sopenharmony_ci ip = start2; ref = ref2; ml = ml2; 72627b27ec6Sopenharmony_ci 72727b27ec6Sopenharmony_ci /* ML3 becomes ML2 */ 72827b27ec6Sopenharmony_ci start2 = start3; ref2 = ref3; ml2 = ml3; 72927b27ec6Sopenharmony_ci 73027b27ec6Sopenharmony_ci /* let's find a new ML3 */ 73127b27ec6Sopenharmony_ci goto _Search3; 73227b27ec6Sopenharmony_ci } 73327b27ec6Sopenharmony_ci 73427b27ec6Sopenharmony_ci_last_literals: 73527b27ec6Sopenharmony_ci /* Encode Last Literals */ 73627b27ec6Sopenharmony_ci { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ 73727b27ec6Sopenharmony_ci size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; 73827b27ec6Sopenharmony_ci size_t const totalSize = 1 + llAdd + lastRunSize; 73927b27ec6Sopenharmony_ci if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ 74027b27ec6Sopenharmony_ci if (limit && (op + totalSize > oend)) { 74127b27ec6Sopenharmony_ci if (limit == limitedOutput) return 0; 74227b27ec6Sopenharmony_ci /* adapt lastRunSize to fill 'dest' */ 74327b27ec6Sopenharmony_ci lastRunSize = (size_t)(oend - op) - 1 /*token*/; 74427b27ec6Sopenharmony_ci llAdd = (lastRunSize + 256 - RUN_MASK) / 256; 74527b27ec6Sopenharmony_ci lastRunSize -= llAdd; 74627b27ec6Sopenharmony_ci } 74727b27ec6Sopenharmony_ci DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); 74827b27ec6Sopenharmony_ci ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ 74927b27ec6Sopenharmony_ci 75027b27ec6Sopenharmony_ci if (lastRunSize >= RUN_MASK) { 75127b27ec6Sopenharmony_ci size_t accumulator = lastRunSize - RUN_MASK; 75227b27ec6Sopenharmony_ci *op++ = (RUN_MASK << ML_BITS); 75327b27ec6Sopenharmony_ci for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; 75427b27ec6Sopenharmony_ci *op++ = (BYTE) accumulator; 75527b27ec6Sopenharmony_ci } else { 75627b27ec6Sopenharmony_ci *op++ = (BYTE)(lastRunSize << ML_BITS); 75727b27ec6Sopenharmony_ci } 75827b27ec6Sopenharmony_ci LZ4_memcpy(op, anchor, lastRunSize); 75927b27ec6Sopenharmony_ci op += lastRunSize; 76027b27ec6Sopenharmony_ci } 76127b27ec6Sopenharmony_ci 76227b27ec6Sopenharmony_ci /* End */ 76327b27ec6Sopenharmony_ci *srcSizePtr = (int) (((const char*)ip) - source); 76427b27ec6Sopenharmony_ci return (int) (((char*)op)-dest); 76527b27ec6Sopenharmony_ci 76627b27ec6Sopenharmony_ci_dest_overflow: 76727b27ec6Sopenharmony_ci if (limit == fillOutput) { 76827b27ec6Sopenharmony_ci /* Assumption : ip, anchor, ml and ref must be set correctly */ 76927b27ec6Sopenharmony_ci size_t const ll = (size_t)(ip - anchor); 77027b27ec6Sopenharmony_ci size_t const ll_addbytes = (ll + 240) / 255; 77127b27ec6Sopenharmony_ci size_t const ll_totalCost = 1 + ll_addbytes + ll; 77227b27ec6Sopenharmony_ci BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ 77327b27ec6Sopenharmony_ci DEBUGLOG(6, "Last sequence overflowing"); 77427b27ec6Sopenharmony_ci op = optr; /* restore correct out pointer */ 77527b27ec6Sopenharmony_ci if (op + ll_totalCost <= maxLitPos) { 77627b27ec6Sopenharmony_ci /* ll validated; now adjust match length */ 77727b27ec6Sopenharmony_ci size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); 77827b27ec6Sopenharmony_ci size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); 77927b27ec6Sopenharmony_ci assert(maxMlSize < INT_MAX); assert(ml >= 0); 78027b27ec6Sopenharmony_ci if ((size_t)ml > maxMlSize) ml = (int)maxMlSize; 78127b27ec6Sopenharmony_ci if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ml >= MFLIMIT) { 78227b27ec6Sopenharmony_ci LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, notLimited, oend); 78327b27ec6Sopenharmony_ci } } 78427b27ec6Sopenharmony_ci goto _last_literals; 78527b27ec6Sopenharmony_ci } 78627b27ec6Sopenharmony_ci /* compression failed */ 78727b27ec6Sopenharmony_ci return 0; 78827b27ec6Sopenharmony_ci} 78927b27ec6Sopenharmony_ci 79027b27ec6Sopenharmony_ci 79127b27ec6Sopenharmony_cistatic int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx, 79227b27ec6Sopenharmony_ci const char* const source, char* dst, 79327b27ec6Sopenharmony_ci int* srcSizePtr, int dstCapacity, 79427b27ec6Sopenharmony_ci int const nbSearches, size_t sufficient_len, 79527b27ec6Sopenharmony_ci const limitedOutput_directive limit, int const fullUpdate, 79627b27ec6Sopenharmony_ci const dictCtx_directive dict, 79727b27ec6Sopenharmony_ci const HCfavor_e favorDecSpeed); 79827b27ec6Sopenharmony_ci 79927b27ec6Sopenharmony_ci 80027b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_compress_generic_internal ( 80127b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx, 80227b27ec6Sopenharmony_ci const char* const src, 80327b27ec6Sopenharmony_ci char* const dst, 80427b27ec6Sopenharmony_ci int* const srcSizePtr, 80527b27ec6Sopenharmony_ci int const dstCapacity, 80627b27ec6Sopenharmony_ci int cLevel, 80727b27ec6Sopenharmony_ci const limitedOutput_directive limit, 80827b27ec6Sopenharmony_ci const dictCtx_directive dict 80927b27ec6Sopenharmony_ci ) 81027b27ec6Sopenharmony_ci{ 81127b27ec6Sopenharmony_ci typedef enum { lz4hc, lz4opt } lz4hc_strat_e; 81227b27ec6Sopenharmony_ci typedef struct { 81327b27ec6Sopenharmony_ci lz4hc_strat_e strat; 81427b27ec6Sopenharmony_ci int nbSearches; 81527b27ec6Sopenharmony_ci U32 targetLength; 81627b27ec6Sopenharmony_ci } cParams_t; 81727b27ec6Sopenharmony_ci static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = { 81827b27ec6Sopenharmony_ci { lz4hc, 2, 16 }, /* 0, unused */ 81927b27ec6Sopenharmony_ci { lz4hc, 2, 16 }, /* 1, unused */ 82027b27ec6Sopenharmony_ci { lz4hc, 2, 16 }, /* 2, unused */ 82127b27ec6Sopenharmony_ci { lz4hc, 4, 16 }, /* 3 */ 82227b27ec6Sopenharmony_ci { lz4hc, 8, 16 }, /* 4 */ 82327b27ec6Sopenharmony_ci { lz4hc, 16, 16 }, /* 5 */ 82427b27ec6Sopenharmony_ci { lz4hc, 32, 16 }, /* 6 */ 82527b27ec6Sopenharmony_ci { lz4hc, 64, 16 }, /* 7 */ 82627b27ec6Sopenharmony_ci { lz4hc, 128, 16 }, /* 8 */ 82727b27ec6Sopenharmony_ci { lz4hc, 256, 16 }, /* 9 */ 82827b27ec6Sopenharmony_ci { lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/ 82927b27ec6Sopenharmony_ci { lz4opt, 512,128 }, /*11 */ 83027b27ec6Sopenharmony_ci { lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */ 83127b27ec6Sopenharmony_ci }; 83227b27ec6Sopenharmony_ci 83327b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)", 83427b27ec6Sopenharmony_ci ctx, src, *srcSizePtr, limit); 83527b27ec6Sopenharmony_ci 83627b27ec6Sopenharmony_ci if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */ 83727b27ec6Sopenharmony_ci if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */ 83827b27ec6Sopenharmony_ci 83927b27ec6Sopenharmony_ci ctx->end += *srcSizePtr; 84027b27ec6Sopenharmony_ci if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */ 84127b27ec6Sopenharmony_ci cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel); 84227b27ec6Sopenharmony_ci { cParams_t const cParam = clTable[cLevel]; 84327b27ec6Sopenharmony_ci HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio; 84427b27ec6Sopenharmony_ci int result; 84527b27ec6Sopenharmony_ci 84627b27ec6Sopenharmony_ci if (cParam.strat == lz4hc) { 84727b27ec6Sopenharmony_ci result = LZ4HC_compress_hashChain(ctx, 84827b27ec6Sopenharmony_ci src, dst, srcSizePtr, dstCapacity, 84927b27ec6Sopenharmony_ci cParam.nbSearches, limit, dict); 85027b27ec6Sopenharmony_ci } else { 85127b27ec6Sopenharmony_ci assert(cParam.strat == lz4opt); 85227b27ec6Sopenharmony_ci result = LZ4HC_compress_optimal(ctx, 85327b27ec6Sopenharmony_ci src, dst, srcSizePtr, dstCapacity, 85427b27ec6Sopenharmony_ci cParam.nbSearches, cParam.targetLength, limit, 85527b27ec6Sopenharmony_ci cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */ 85627b27ec6Sopenharmony_ci dict, favor); 85727b27ec6Sopenharmony_ci } 85827b27ec6Sopenharmony_ci if (result <= 0) ctx->dirty = 1; 85927b27ec6Sopenharmony_ci return result; 86027b27ec6Sopenharmony_ci } 86127b27ec6Sopenharmony_ci} 86227b27ec6Sopenharmony_ci 86327b27ec6Sopenharmony_cistatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock); 86427b27ec6Sopenharmony_ci 86527b27ec6Sopenharmony_cistatic int 86627b27ec6Sopenharmony_ciLZ4HC_compress_generic_noDictCtx ( 86727b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx, 86827b27ec6Sopenharmony_ci const char* const src, 86927b27ec6Sopenharmony_ci char* const dst, 87027b27ec6Sopenharmony_ci int* const srcSizePtr, 87127b27ec6Sopenharmony_ci int const dstCapacity, 87227b27ec6Sopenharmony_ci int cLevel, 87327b27ec6Sopenharmony_ci limitedOutput_directive limit 87427b27ec6Sopenharmony_ci ) 87527b27ec6Sopenharmony_ci{ 87627b27ec6Sopenharmony_ci assert(ctx->dictCtx == NULL); 87727b27ec6Sopenharmony_ci return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx); 87827b27ec6Sopenharmony_ci} 87927b27ec6Sopenharmony_ci 88027b27ec6Sopenharmony_cistatic int 88127b27ec6Sopenharmony_ciLZ4HC_compress_generic_dictCtx ( 88227b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx, 88327b27ec6Sopenharmony_ci const char* const src, 88427b27ec6Sopenharmony_ci char* const dst, 88527b27ec6Sopenharmony_ci int* const srcSizePtr, 88627b27ec6Sopenharmony_ci int const dstCapacity, 88727b27ec6Sopenharmony_ci int cLevel, 88827b27ec6Sopenharmony_ci limitedOutput_directive limit 88927b27ec6Sopenharmony_ci ) 89027b27ec6Sopenharmony_ci{ 89127b27ec6Sopenharmony_ci const size_t position = (size_t)(ctx->end - ctx->prefixStart) + (ctx->dictLimit - ctx->lowLimit); 89227b27ec6Sopenharmony_ci assert(ctx->dictCtx != NULL); 89327b27ec6Sopenharmony_ci if (position >= 64 KB) { 89427b27ec6Sopenharmony_ci ctx->dictCtx = NULL; 89527b27ec6Sopenharmony_ci return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); 89627b27ec6Sopenharmony_ci } else if (position == 0 && *srcSizePtr > 4 KB) { 89727b27ec6Sopenharmony_ci LZ4_memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal)); 89827b27ec6Sopenharmony_ci LZ4HC_setExternalDict(ctx, (const BYTE *)src); 89927b27ec6Sopenharmony_ci ctx->compressionLevel = (short)cLevel; 90027b27ec6Sopenharmony_ci return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); 90127b27ec6Sopenharmony_ci } else { 90227b27ec6Sopenharmony_ci return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc); 90327b27ec6Sopenharmony_ci } 90427b27ec6Sopenharmony_ci} 90527b27ec6Sopenharmony_ci 90627b27ec6Sopenharmony_cistatic int 90727b27ec6Sopenharmony_ciLZ4HC_compress_generic ( 90827b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx, 90927b27ec6Sopenharmony_ci const char* const src, 91027b27ec6Sopenharmony_ci char* const dst, 91127b27ec6Sopenharmony_ci int* const srcSizePtr, 91227b27ec6Sopenharmony_ci int const dstCapacity, 91327b27ec6Sopenharmony_ci int cLevel, 91427b27ec6Sopenharmony_ci limitedOutput_directive limit 91527b27ec6Sopenharmony_ci ) 91627b27ec6Sopenharmony_ci{ 91727b27ec6Sopenharmony_ci if (ctx->dictCtx == NULL) { 91827b27ec6Sopenharmony_ci return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); 91927b27ec6Sopenharmony_ci } else { 92027b27ec6Sopenharmony_ci return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit); 92127b27ec6Sopenharmony_ci } 92227b27ec6Sopenharmony_ci} 92327b27ec6Sopenharmony_ci 92427b27ec6Sopenharmony_ci 92527b27ec6Sopenharmony_ciint LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); } 92627b27ec6Sopenharmony_ci 92727b27ec6Sopenharmony_cistatic size_t LZ4_streamHC_t_alignment(void) 92827b27ec6Sopenharmony_ci{ 92927b27ec6Sopenharmony_ci#if LZ4_ALIGN_TEST 93027b27ec6Sopenharmony_ci typedef struct { char c; LZ4_streamHC_t t; } t_a; 93127b27ec6Sopenharmony_ci return sizeof(t_a) - sizeof(LZ4_streamHC_t); 93227b27ec6Sopenharmony_ci#else 93327b27ec6Sopenharmony_ci return 1; /* effectively disabled */ 93427b27ec6Sopenharmony_ci#endif 93527b27ec6Sopenharmony_ci} 93627b27ec6Sopenharmony_ci 93727b27ec6Sopenharmony_ci/* state is presumed correctly initialized, 93827b27ec6Sopenharmony_ci * in which case its size and alignment have already been validate */ 93927b27ec6Sopenharmony_ciint LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) 94027b27ec6Sopenharmony_ci{ 94127b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse; 94227b27ec6Sopenharmony_ci if (!LZ4_isAligned(state, LZ4_streamHC_t_alignment())) return 0; 94327b27ec6Sopenharmony_ci LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel); 94427b27ec6Sopenharmony_ci LZ4HC_init_internal (ctx, (const BYTE*)src); 94527b27ec6Sopenharmony_ci if (dstCapacity < LZ4_compressBound(srcSize)) 94627b27ec6Sopenharmony_ci return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput); 94727b27ec6Sopenharmony_ci else 94827b27ec6Sopenharmony_ci return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited); 94927b27ec6Sopenharmony_ci} 95027b27ec6Sopenharmony_ci 95127b27ec6Sopenharmony_ciint LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) 95227b27ec6Sopenharmony_ci{ 95327b27ec6Sopenharmony_ci LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); 95427b27ec6Sopenharmony_ci if (ctx==NULL) return 0; /* init failure */ 95527b27ec6Sopenharmony_ci return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel); 95627b27ec6Sopenharmony_ci} 95727b27ec6Sopenharmony_ci 95827b27ec6Sopenharmony_ciint LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel) 95927b27ec6Sopenharmony_ci{ 96027b27ec6Sopenharmony_ci int cSize; 96127b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 96227b27ec6Sopenharmony_ci LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t)); 96327b27ec6Sopenharmony_ci if (statePtr==NULL) return 0; 96427b27ec6Sopenharmony_ci#else 96527b27ec6Sopenharmony_ci LZ4_streamHC_t state; 96627b27ec6Sopenharmony_ci LZ4_streamHC_t* const statePtr = &state; 96727b27ec6Sopenharmony_ci#endif 96827b27ec6Sopenharmony_ci cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel); 96927b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 97027b27ec6Sopenharmony_ci FREEMEM(statePtr); 97127b27ec6Sopenharmony_ci#endif 97227b27ec6Sopenharmony_ci return cSize; 97327b27ec6Sopenharmony_ci} 97427b27ec6Sopenharmony_ci 97527b27ec6Sopenharmony_ci/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */ 97627b27ec6Sopenharmony_ciint LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel) 97727b27ec6Sopenharmony_ci{ 97827b27ec6Sopenharmony_ci LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx)); 97927b27ec6Sopenharmony_ci if (ctx==NULL) return 0; /* init failure */ 98027b27ec6Sopenharmony_ci LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source); 98127b27ec6Sopenharmony_ci LZ4_setCompressionLevel(ctx, cLevel); 98227b27ec6Sopenharmony_ci return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput); 98327b27ec6Sopenharmony_ci} 98427b27ec6Sopenharmony_ci 98527b27ec6Sopenharmony_ci 98627b27ec6Sopenharmony_ci 98727b27ec6Sopenharmony_ci/************************************** 98827b27ec6Sopenharmony_ci* Streaming Functions 98927b27ec6Sopenharmony_ci**************************************/ 99027b27ec6Sopenharmony_ci/* allocation */ 99127b27ec6Sopenharmony_ci#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) 99227b27ec6Sopenharmony_ciLZ4_streamHC_t* LZ4_createStreamHC(void) 99327b27ec6Sopenharmony_ci{ 99427b27ec6Sopenharmony_ci LZ4_streamHC_t* const state = 99527b27ec6Sopenharmony_ci (LZ4_streamHC_t*)ALLOC_AND_ZERO(sizeof(LZ4_streamHC_t)); 99627b27ec6Sopenharmony_ci if (state == NULL) return NULL; 99727b27ec6Sopenharmony_ci LZ4_setCompressionLevel(state, LZ4HC_CLEVEL_DEFAULT); 99827b27ec6Sopenharmony_ci return state; 99927b27ec6Sopenharmony_ci} 100027b27ec6Sopenharmony_ci 100127b27ec6Sopenharmony_ciint LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr) 100227b27ec6Sopenharmony_ci{ 100327b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr); 100427b27ec6Sopenharmony_ci if (!LZ4_streamHCPtr) return 0; /* support free on NULL */ 100527b27ec6Sopenharmony_ci FREEMEM(LZ4_streamHCPtr); 100627b27ec6Sopenharmony_ci return 0; 100727b27ec6Sopenharmony_ci} 100827b27ec6Sopenharmony_ci#endif 100927b27ec6Sopenharmony_ci 101027b27ec6Sopenharmony_ci 101127b27ec6Sopenharmony_ciLZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size) 101227b27ec6Sopenharmony_ci{ 101327b27ec6Sopenharmony_ci LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer; 101427b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", buffer, (unsigned)size); 101527b27ec6Sopenharmony_ci /* check conditions */ 101627b27ec6Sopenharmony_ci if (buffer == NULL) return NULL; 101727b27ec6Sopenharmony_ci if (size < sizeof(LZ4_streamHC_t)) return NULL; 101827b27ec6Sopenharmony_ci if (!LZ4_isAligned(buffer, LZ4_streamHC_t_alignment())) return NULL; 101927b27ec6Sopenharmony_ci /* init */ 102027b27ec6Sopenharmony_ci { LZ4HC_CCtx_internal* const hcstate = &(LZ4_streamHCPtr->internal_donotuse); 102127b27ec6Sopenharmony_ci MEM_INIT(hcstate, 0, sizeof(*hcstate)); } 102227b27ec6Sopenharmony_ci LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT); 102327b27ec6Sopenharmony_ci return LZ4_streamHCPtr; 102427b27ec6Sopenharmony_ci} 102527b27ec6Sopenharmony_ci 102627b27ec6Sopenharmony_ci/* just a stub */ 102727b27ec6Sopenharmony_civoid LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) 102827b27ec6Sopenharmony_ci{ 102927b27ec6Sopenharmony_ci LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); 103027b27ec6Sopenharmony_ci LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); 103127b27ec6Sopenharmony_ci} 103227b27ec6Sopenharmony_ci 103327b27ec6Sopenharmony_civoid LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) 103427b27ec6Sopenharmony_ci{ 103527b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel); 103627b27ec6Sopenharmony_ci if (LZ4_streamHCPtr->internal_donotuse.dirty) { 103727b27ec6Sopenharmony_ci LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); 103827b27ec6Sopenharmony_ci } else { 103927b27ec6Sopenharmony_ci /* preserve end - prefixStart : can trigger clearTable's threshold */ 104027b27ec6Sopenharmony_ci if (LZ4_streamHCPtr->internal_donotuse.end != NULL) { 104127b27ec6Sopenharmony_ci LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.prefixStart; 104227b27ec6Sopenharmony_ci } else { 104327b27ec6Sopenharmony_ci assert(LZ4_streamHCPtr->internal_donotuse.prefixStart == NULL); 104427b27ec6Sopenharmony_ci } 104527b27ec6Sopenharmony_ci LZ4_streamHCPtr->internal_donotuse.prefixStart = NULL; 104627b27ec6Sopenharmony_ci LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL; 104727b27ec6Sopenharmony_ci } 104827b27ec6Sopenharmony_ci LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel); 104927b27ec6Sopenharmony_ci} 105027b27ec6Sopenharmony_ci 105127b27ec6Sopenharmony_civoid LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel) 105227b27ec6Sopenharmony_ci{ 105327b27ec6Sopenharmony_ci DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel); 105427b27ec6Sopenharmony_ci if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT; 105527b27ec6Sopenharmony_ci if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX; 105627b27ec6Sopenharmony_ci LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel; 105727b27ec6Sopenharmony_ci} 105827b27ec6Sopenharmony_ci 105927b27ec6Sopenharmony_civoid LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor) 106027b27ec6Sopenharmony_ci{ 106127b27ec6Sopenharmony_ci LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0); 106227b27ec6Sopenharmony_ci} 106327b27ec6Sopenharmony_ci 106427b27ec6Sopenharmony_ci/* LZ4_loadDictHC() : 106527b27ec6Sopenharmony_ci * LZ4_streamHCPtr is presumed properly initialized */ 106627b27ec6Sopenharmony_ciint LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, 106727b27ec6Sopenharmony_ci const char* dictionary, int dictSize) 106827b27ec6Sopenharmony_ci{ 106927b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; 107027b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize); 107127b27ec6Sopenharmony_ci assert(LZ4_streamHCPtr != NULL); 107227b27ec6Sopenharmony_ci if (dictSize > 64 KB) { 107327b27ec6Sopenharmony_ci dictionary += (size_t)dictSize - 64 KB; 107427b27ec6Sopenharmony_ci dictSize = 64 KB; 107527b27ec6Sopenharmony_ci } 107627b27ec6Sopenharmony_ci /* need a full initialization, there are bad side-effects when using resetFast() */ 107727b27ec6Sopenharmony_ci { int const cLevel = ctxPtr->compressionLevel; 107827b27ec6Sopenharmony_ci LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); 107927b27ec6Sopenharmony_ci LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel); 108027b27ec6Sopenharmony_ci } 108127b27ec6Sopenharmony_ci LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary); 108227b27ec6Sopenharmony_ci ctxPtr->end = (const BYTE*)dictionary + dictSize; 108327b27ec6Sopenharmony_ci if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3); 108427b27ec6Sopenharmony_ci return dictSize; 108527b27ec6Sopenharmony_ci} 108627b27ec6Sopenharmony_ci 108727b27ec6Sopenharmony_civoid LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) { 108827b27ec6Sopenharmony_ci working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL; 108927b27ec6Sopenharmony_ci} 109027b27ec6Sopenharmony_ci 109127b27ec6Sopenharmony_ci/* compression */ 109227b27ec6Sopenharmony_ci 109327b27ec6Sopenharmony_cistatic void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock) 109427b27ec6Sopenharmony_ci{ 109527b27ec6Sopenharmony_ci DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock); 109627b27ec6Sopenharmony_ci if (ctxPtr->end >= ctxPtr->prefixStart + 4) 109727b27ec6Sopenharmony_ci LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */ 109827b27ec6Sopenharmony_ci 109927b27ec6Sopenharmony_ci /* Only one memory segment for extDict, so any previous extDict is lost at this stage */ 110027b27ec6Sopenharmony_ci ctxPtr->lowLimit = ctxPtr->dictLimit; 110127b27ec6Sopenharmony_ci ctxPtr->dictStart = ctxPtr->prefixStart; 110227b27ec6Sopenharmony_ci ctxPtr->dictLimit += (U32)(ctxPtr->end - ctxPtr->prefixStart); 110327b27ec6Sopenharmony_ci ctxPtr->prefixStart = newBlock; 110427b27ec6Sopenharmony_ci ctxPtr->end = newBlock; 110527b27ec6Sopenharmony_ci ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */ 110627b27ec6Sopenharmony_ci 110727b27ec6Sopenharmony_ci /* cannot reference an extDict and a dictCtx at the same time */ 110827b27ec6Sopenharmony_ci ctxPtr->dictCtx = NULL; 110927b27ec6Sopenharmony_ci} 111027b27ec6Sopenharmony_ci 111127b27ec6Sopenharmony_cistatic int 111227b27ec6Sopenharmony_ciLZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr, 111327b27ec6Sopenharmony_ci const char* src, char* dst, 111427b27ec6Sopenharmony_ci int* srcSizePtr, int dstCapacity, 111527b27ec6Sopenharmony_ci limitedOutput_directive limit) 111627b27ec6Sopenharmony_ci{ 111727b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse; 111827b27ec6Sopenharmony_ci DEBUGLOG(5, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d, limit=%d)", 111927b27ec6Sopenharmony_ci LZ4_streamHCPtr, src, *srcSizePtr, limit); 112027b27ec6Sopenharmony_ci assert(ctxPtr != NULL); 112127b27ec6Sopenharmony_ci /* auto-init if forgotten */ 112227b27ec6Sopenharmony_ci if (ctxPtr->prefixStart == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src); 112327b27ec6Sopenharmony_ci 112427b27ec6Sopenharmony_ci /* Check overflow */ 112527b27ec6Sopenharmony_ci if ((size_t)(ctxPtr->end - ctxPtr->prefixStart) + ctxPtr->dictLimit > 2 GB) { 112627b27ec6Sopenharmony_ci size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->prefixStart); 112727b27ec6Sopenharmony_ci if (dictSize > 64 KB) dictSize = 64 KB; 112827b27ec6Sopenharmony_ci LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize); 112927b27ec6Sopenharmony_ci } 113027b27ec6Sopenharmony_ci 113127b27ec6Sopenharmony_ci /* Check if blocks follow each other */ 113227b27ec6Sopenharmony_ci if ((const BYTE*)src != ctxPtr->end) 113327b27ec6Sopenharmony_ci LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src); 113427b27ec6Sopenharmony_ci 113527b27ec6Sopenharmony_ci /* Check overlapping input/dictionary space */ 113627b27ec6Sopenharmony_ci { const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr; 113727b27ec6Sopenharmony_ci const BYTE* const dictBegin = ctxPtr->dictStart; 113827b27ec6Sopenharmony_ci const BYTE* const dictEnd = ctxPtr->dictStart + (ctxPtr->dictLimit - ctxPtr->lowLimit); 113927b27ec6Sopenharmony_ci if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) { 114027b27ec6Sopenharmony_ci if (sourceEnd > dictEnd) sourceEnd = dictEnd; 114127b27ec6Sopenharmony_ci ctxPtr->lowLimit += (U32)(sourceEnd - ctxPtr->dictStart); 114227b27ec6Sopenharmony_ci ctxPtr->dictStart += (U32)(sourceEnd - ctxPtr->dictStart); 114327b27ec6Sopenharmony_ci if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) { 114427b27ec6Sopenharmony_ci ctxPtr->lowLimit = ctxPtr->dictLimit; 114527b27ec6Sopenharmony_ci ctxPtr->dictStart = ctxPtr->prefixStart; 114627b27ec6Sopenharmony_ci } } } 114727b27ec6Sopenharmony_ci 114827b27ec6Sopenharmony_ci return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit); 114927b27ec6Sopenharmony_ci} 115027b27ec6Sopenharmony_ci 115127b27ec6Sopenharmony_ciint LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity) 115227b27ec6Sopenharmony_ci{ 115327b27ec6Sopenharmony_ci if (dstCapacity < LZ4_compressBound(srcSize)) 115427b27ec6Sopenharmony_ci return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput); 115527b27ec6Sopenharmony_ci else 115627b27ec6Sopenharmony_ci return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited); 115727b27ec6Sopenharmony_ci} 115827b27ec6Sopenharmony_ci 115927b27ec6Sopenharmony_ciint LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize) 116027b27ec6Sopenharmony_ci{ 116127b27ec6Sopenharmony_ci return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput); 116227b27ec6Sopenharmony_ci} 116327b27ec6Sopenharmony_ci 116427b27ec6Sopenharmony_ci 116527b27ec6Sopenharmony_ci 116627b27ec6Sopenharmony_ci/* LZ4_saveDictHC : 116727b27ec6Sopenharmony_ci * save history content 116827b27ec6Sopenharmony_ci * into a user-provided buffer 116927b27ec6Sopenharmony_ci * which is then used to continue compression 117027b27ec6Sopenharmony_ci */ 117127b27ec6Sopenharmony_ciint LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize) 117227b27ec6Sopenharmony_ci{ 117327b27ec6Sopenharmony_ci LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse; 117427b27ec6Sopenharmony_ci int const prefixSize = (int)(streamPtr->end - streamPtr->prefixStart); 117527b27ec6Sopenharmony_ci DEBUGLOG(5, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize); 117627b27ec6Sopenharmony_ci assert(prefixSize >= 0); 117727b27ec6Sopenharmony_ci if (dictSize > 64 KB) dictSize = 64 KB; 117827b27ec6Sopenharmony_ci if (dictSize < 4) dictSize = 0; 117927b27ec6Sopenharmony_ci if (dictSize > prefixSize) dictSize = prefixSize; 118027b27ec6Sopenharmony_ci if (safeBuffer == NULL) assert(dictSize == 0); 118127b27ec6Sopenharmony_ci if (dictSize > 0) 118227b27ec6Sopenharmony_ci LZ4_memmove(safeBuffer, streamPtr->end - dictSize, dictSize); 118327b27ec6Sopenharmony_ci { U32 const endIndex = (U32)(streamPtr->end - streamPtr->prefixStart) + streamPtr->dictLimit; 118427b27ec6Sopenharmony_ci streamPtr->end = (const BYTE*)safeBuffer + dictSize; 118527b27ec6Sopenharmony_ci streamPtr->prefixStart = streamPtr->end - dictSize; 118627b27ec6Sopenharmony_ci streamPtr->dictLimit = endIndex - (U32)dictSize; 118727b27ec6Sopenharmony_ci streamPtr->lowLimit = endIndex - (U32)dictSize; 118827b27ec6Sopenharmony_ci streamPtr->dictStart = streamPtr->prefixStart; 118927b27ec6Sopenharmony_ci if (streamPtr->nextToUpdate < streamPtr->dictLimit) 119027b27ec6Sopenharmony_ci streamPtr->nextToUpdate = streamPtr->dictLimit; 119127b27ec6Sopenharmony_ci } 119227b27ec6Sopenharmony_ci return dictSize; 119327b27ec6Sopenharmony_ci} 119427b27ec6Sopenharmony_ci 119527b27ec6Sopenharmony_ci 119627b27ec6Sopenharmony_ci/*************************************************** 119727b27ec6Sopenharmony_ci* Deprecated Functions 119827b27ec6Sopenharmony_ci***************************************************/ 119927b27ec6Sopenharmony_ci 120027b27ec6Sopenharmony_ci/* These functions currently generate deprecation warnings */ 120127b27ec6Sopenharmony_ci 120227b27ec6Sopenharmony_ci/* Wrappers for deprecated compression functions */ 120327b27ec6Sopenharmony_ciint LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); } 120427b27ec6Sopenharmony_ciint LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); } 120527b27ec6Sopenharmony_ciint LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } 120627b27ec6Sopenharmony_ciint LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); } 120727b27ec6Sopenharmony_ciint LZ4_compressHC_withStateHC (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, LZ4_compressBound(srcSize), 0); } 120827b27ec6Sopenharmony_ciint LZ4_compressHC_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_extStateHC (state, src, dst, srcSize, maxDstSize, 0); } 120927b27ec6Sopenharmony_ciint LZ4_compressHC2_withStateHC (void* state, const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); } 121027b27ec6Sopenharmony_ciint LZ4_compressHC2_limitedOutput_withStateHC (void* state, const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC_extStateHC(state, src, dst, srcSize, maxDstSize, cLevel); } 121127b27ec6Sopenharmony_ciint LZ4_compressHC_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, LZ4_compressBound(srcSize)); } 121227b27ec6Sopenharmony_ciint LZ4_compressHC_limitedOutput_continue (LZ4_streamHC_t* ctx, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC_continue (ctx, src, dst, srcSize, maxDstSize); } 121327b27ec6Sopenharmony_ci 121427b27ec6Sopenharmony_ci 121527b27ec6Sopenharmony_ci/* Deprecated streaming functions */ 121627b27ec6Sopenharmony_ciint LZ4_sizeofStreamStateHC(void) { return sizeof(LZ4_streamHC_t); } 121727b27ec6Sopenharmony_ci 121827b27ec6Sopenharmony_ci/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t) 121927b27ec6Sopenharmony_ci * @return : 0 on success, !=0 if error */ 122027b27ec6Sopenharmony_ciint LZ4_resetStreamStateHC(void* state, char* inputBuffer) 122127b27ec6Sopenharmony_ci{ 122227b27ec6Sopenharmony_ci LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4)); 122327b27ec6Sopenharmony_ci if (hc4 == NULL) return 1; /* init failed */ 122427b27ec6Sopenharmony_ci LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); 122527b27ec6Sopenharmony_ci return 0; 122627b27ec6Sopenharmony_ci} 122727b27ec6Sopenharmony_ci 122827b27ec6Sopenharmony_ci#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) 122927b27ec6Sopenharmony_civoid* LZ4_createHC (const char* inputBuffer) 123027b27ec6Sopenharmony_ci{ 123127b27ec6Sopenharmony_ci LZ4_streamHC_t* const hc4 = LZ4_createStreamHC(); 123227b27ec6Sopenharmony_ci if (hc4 == NULL) return NULL; /* not enough memory */ 123327b27ec6Sopenharmony_ci LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer); 123427b27ec6Sopenharmony_ci return hc4; 123527b27ec6Sopenharmony_ci} 123627b27ec6Sopenharmony_ci 123727b27ec6Sopenharmony_ciint LZ4_freeHC (void* LZ4HC_Data) 123827b27ec6Sopenharmony_ci{ 123927b27ec6Sopenharmony_ci if (!LZ4HC_Data) return 0; /* support free on NULL */ 124027b27ec6Sopenharmony_ci FREEMEM(LZ4HC_Data); 124127b27ec6Sopenharmony_ci return 0; 124227b27ec6Sopenharmony_ci} 124327b27ec6Sopenharmony_ci#endif 124427b27ec6Sopenharmony_ci 124527b27ec6Sopenharmony_ciint LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel) 124627b27ec6Sopenharmony_ci{ 124727b27ec6Sopenharmony_ci return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited); 124827b27ec6Sopenharmony_ci} 124927b27ec6Sopenharmony_ci 125027b27ec6Sopenharmony_ciint LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel) 125127b27ec6Sopenharmony_ci{ 125227b27ec6Sopenharmony_ci return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput); 125327b27ec6Sopenharmony_ci} 125427b27ec6Sopenharmony_ci 125527b27ec6Sopenharmony_cichar* LZ4_slideInputBufferHC(void* LZ4HC_Data) 125627b27ec6Sopenharmony_ci{ 125727b27ec6Sopenharmony_ci LZ4_streamHC_t* const ctx = (LZ4_streamHC_t*)LZ4HC_Data; 125827b27ec6Sopenharmony_ci const BYTE* bufferStart = ctx->internal_donotuse.prefixStart - ctx->internal_donotuse.dictLimit + ctx->internal_donotuse.lowLimit; 125927b27ec6Sopenharmony_ci LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel); 126027b27ec6Sopenharmony_ci /* avoid const char * -> char * conversion warning :( */ 126127b27ec6Sopenharmony_ci return (char*)(uptrval)bufferStart; 126227b27ec6Sopenharmony_ci} 126327b27ec6Sopenharmony_ci 126427b27ec6Sopenharmony_ci 126527b27ec6Sopenharmony_ci/* ================================================ 126627b27ec6Sopenharmony_ci * LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX]) 126727b27ec6Sopenharmony_ci * ===============================================*/ 126827b27ec6Sopenharmony_citypedef struct { 126927b27ec6Sopenharmony_ci int price; 127027b27ec6Sopenharmony_ci int off; 127127b27ec6Sopenharmony_ci int mlen; 127227b27ec6Sopenharmony_ci int litlen; 127327b27ec6Sopenharmony_ci} LZ4HC_optimal_t; 127427b27ec6Sopenharmony_ci 127527b27ec6Sopenharmony_ci/* price in bytes */ 127627b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen) 127727b27ec6Sopenharmony_ci{ 127827b27ec6Sopenharmony_ci int price = litlen; 127927b27ec6Sopenharmony_ci assert(litlen >= 0); 128027b27ec6Sopenharmony_ci if (litlen >= (int)RUN_MASK) 128127b27ec6Sopenharmony_ci price += 1 + ((litlen-(int)RUN_MASK) / 255); 128227b27ec6Sopenharmony_ci return price; 128327b27ec6Sopenharmony_ci} 128427b27ec6Sopenharmony_ci 128527b27ec6Sopenharmony_ci 128627b27ec6Sopenharmony_ci/* requires mlen >= MINMATCH */ 128727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen) 128827b27ec6Sopenharmony_ci{ 128927b27ec6Sopenharmony_ci int price = 1 + 2 ; /* token + 16-bit offset */ 129027b27ec6Sopenharmony_ci assert(litlen >= 0); 129127b27ec6Sopenharmony_ci assert(mlen >= MINMATCH); 129227b27ec6Sopenharmony_ci 129327b27ec6Sopenharmony_ci price += LZ4HC_literalsPrice(litlen); 129427b27ec6Sopenharmony_ci 129527b27ec6Sopenharmony_ci if (mlen >= (int)(ML_MASK+MINMATCH)) 129627b27ec6Sopenharmony_ci price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255); 129727b27ec6Sopenharmony_ci 129827b27ec6Sopenharmony_ci return price; 129927b27ec6Sopenharmony_ci} 130027b27ec6Sopenharmony_ci 130127b27ec6Sopenharmony_ci 130227b27ec6Sopenharmony_citypedef struct { 130327b27ec6Sopenharmony_ci int off; 130427b27ec6Sopenharmony_ci int len; 130527b27ec6Sopenharmony_ci} LZ4HC_match_t; 130627b27ec6Sopenharmony_ci 130727b27ec6Sopenharmony_ciLZ4_FORCE_INLINE LZ4HC_match_t 130827b27ec6Sopenharmony_ciLZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx, 130927b27ec6Sopenharmony_ci const BYTE* ip, const BYTE* const iHighLimit, 131027b27ec6Sopenharmony_ci int minLen, int nbSearches, 131127b27ec6Sopenharmony_ci const dictCtx_directive dict, 131227b27ec6Sopenharmony_ci const HCfavor_e favorDecSpeed) 131327b27ec6Sopenharmony_ci{ 131427b27ec6Sopenharmony_ci LZ4HC_match_t match = { 0 , 0 }; 131527b27ec6Sopenharmony_ci const BYTE* matchPtr = NULL; 131627b27ec6Sopenharmony_ci /* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos), 131727b27ec6Sopenharmony_ci * but this won't be the case here, as we define iLowLimit==ip, 131827b27ec6Sopenharmony_ci * so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */ 131927b27ec6Sopenharmony_ci int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed); 132027b27ec6Sopenharmony_ci if (matchLength <= minLen) return match; 132127b27ec6Sopenharmony_ci if (favorDecSpeed) { 132227b27ec6Sopenharmony_ci if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */ 132327b27ec6Sopenharmony_ci } 132427b27ec6Sopenharmony_ci match.len = matchLength; 132527b27ec6Sopenharmony_ci match.off = (int)(ip-matchPtr); 132627b27ec6Sopenharmony_ci return match; 132727b27ec6Sopenharmony_ci} 132827b27ec6Sopenharmony_ci 132927b27ec6Sopenharmony_ci 133027b27ec6Sopenharmony_cistatic int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx, 133127b27ec6Sopenharmony_ci const char* const source, 133227b27ec6Sopenharmony_ci char* dst, 133327b27ec6Sopenharmony_ci int* srcSizePtr, 133427b27ec6Sopenharmony_ci int dstCapacity, 133527b27ec6Sopenharmony_ci int const nbSearches, 133627b27ec6Sopenharmony_ci size_t sufficient_len, 133727b27ec6Sopenharmony_ci const limitedOutput_directive limit, 133827b27ec6Sopenharmony_ci int const fullUpdate, 133927b27ec6Sopenharmony_ci const dictCtx_directive dict, 134027b27ec6Sopenharmony_ci const HCfavor_e favorDecSpeed) 134127b27ec6Sopenharmony_ci{ 134227b27ec6Sopenharmony_ci int retval = 0; 134327b27ec6Sopenharmony_ci#define TRAILING_LITERALS 3 134427b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 134527b27ec6Sopenharmony_ci LZ4HC_optimal_t* const opt = (LZ4HC_optimal_t*)ALLOC(sizeof(LZ4HC_optimal_t) * (LZ4_OPT_NUM + TRAILING_LITERALS)); 134627b27ec6Sopenharmony_ci#else 134727b27ec6Sopenharmony_ci LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */ 134827b27ec6Sopenharmony_ci#endif 134927b27ec6Sopenharmony_ci 135027b27ec6Sopenharmony_ci const BYTE* ip = (const BYTE*) source; 135127b27ec6Sopenharmony_ci const BYTE* anchor = ip; 135227b27ec6Sopenharmony_ci const BYTE* const iend = ip + *srcSizePtr; 135327b27ec6Sopenharmony_ci const BYTE* const mflimit = iend - MFLIMIT; 135427b27ec6Sopenharmony_ci const BYTE* const matchlimit = iend - LASTLITERALS; 135527b27ec6Sopenharmony_ci BYTE* op = (BYTE*) dst; 135627b27ec6Sopenharmony_ci BYTE* opSaved = (BYTE*) dst; 135727b27ec6Sopenharmony_ci BYTE* oend = op + dstCapacity; 135827b27ec6Sopenharmony_ci int ovml = MINMATCH; /* overflow - last sequence */ 135927b27ec6Sopenharmony_ci const BYTE* ovref = NULL; 136027b27ec6Sopenharmony_ci 136127b27ec6Sopenharmony_ci /* init */ 136227b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 136327b27ec6Sopenharmony_ci if (opt == NULL) goto _return_label; 136427b27ec6Sopenharmony_ci#endif 136527b27ec6Sopenharmony_ci DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity); 136627b27ec6Sopenharmony_ci *srcSizePtr = 0; 136727b27ec6Sopenharmony_ci if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */ 136827b27ec6Sopenharmony_ci if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1; 136927b27ec6Sopenharmony_ci 137027b27ec6Sopenharmony_ci /* Main Loop */ 137127b27ec6Sopenharmony_ci while (ip <= mflimit) { 137227b27ec6Sopenharmony_ci int const llen = (int)(ip - anchor); 137327b27ec6Sopenharmony_ci int best_mlen, best_off; 137427b27ec6Sopenharmony_ci int cur, last_match_pos = 0; 137527b27ec6Sopenharmony_ci 137627b27ec6Sopenharmony_ci LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed); 137727b27ec6Sopenharmony_ci if (firstMatch.len==0) { ip++; continue; } 137827b27ec6Sopenharmony_ci 137927b27ec6Sopenharmony_ci if ((size_t)firstMatch.len > sufficient_len) { 138027b27ec6Sopenharmony_ci /* good enough solution : immediate encoding */ 138127b27ec6Sopenharmony_ci int const firstML = firstMatch.len; 138227b27ec6Sopenharmony_ci const BYTE* const matchPos = ip - firstMatch.off; 138327b27ec6Sopenharmony_ci opSaved = op; 138427b27ec6Sopenharmony_ci if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) { /* updates ip, op and anchor */ 138527b27ec6Sopenharmony_ci ovml = firstML; 138627b27ec6Sopenharmony_ci ovref = matchPos; 138727b27ec6Sopenharmony_ci goto _dest_overflow; 138827b27ec6Sopenharmony_ci } 138927b27ec6Sopenharmony_ci continue; 139027b27ec6Sopenharmony_ci } 139127b27ec6Sopenharmony_ci 139227b27ec6Sopenharmony_ci /* set prices for first positions (literals) */ 139327b27ec6Sopenharmony_ci { int rPos; 139427b27ec6Sopenharmony_ci for (rPos = 0 ; rPos < MINMATCH ; rPos++) { 139527b27ec6Sopenharmony_ci int const cost = LZ4HC_literalsPrice(llen + rPos); 139627b27ec6Sopenharmony_ci opt[rPos].mlen = 1; 139727b27ec6Sopenharmony_ci opt[rPos].off = 0; 139827b27ec6Sopenharmony_ci opt[rPos].litlen = llen + rPos; 139927b27ec6Sopenharmony_ci opt[rPos].price = cost; 140027b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", 140127b27ec6Sopenharmony_ci rPos, cost, opt[rPos].litlen); 140227b27ec6Sopenharmony_ci } } 140327b27ec6Sopenharmony_ci /* set prices using initial match */ 140427b27ec6Sopenharmony_ci { int mlen = MINMATCH; 140527b27ec6Sopenharmony_ci int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */ 140627b27ec6Sopenharmony_ci int const offset = firstMatch.off; 140727b27ec6Sopenharmony_ci assert(matchML < LZ4_OPT_NUM); 140827b27ec6Sopenharmony_ci for ( ; mlen <= matchML ; mlen++) { 140927b27ec6Sopenharmony_ci int const cost = LZ4HC_sequencePrice(llen, mlen); 141027b27ec6Sopenharmony_ci opt[mlen].mlen = mlen; 141127b27ec6Sopenharmony_ci opt[mlen].off = offset; 141227b27ec6Sopenharmony_ci opt[mlen].litlen = llen; 141327b27ec6Sopenharmony_ci opt[mlen].price = cost; 141427b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup", 141527b27ec6Sopenharmony_ci mlen, cost, mlen); 141627b27ec6Sopenharmony_ci } } 141727b27ec6Sopenharmony_ci last_match_pos = firstMatch.len; 141827b27ec6Sopenharmony_ci { int addLit; 141927b27ec6Sopenharmony_ci for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { 142027b27ec6Sopenharmony_ci opt[last_match_pos+addLit].mlen = 1; /* literal */ 142127b27ec6Sopenharmony_ci opt[last_match_pos+addLit].off = 0; 142227b27ec6Sopenharmony_ci opt[last_match_pos+addLit].litlen = addLit; 142327b27ec6Sopenharmony_ci opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); 142427b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup", 142527b27ec6Sopenharmony_ci last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); 142627b27ec6Sopenharmony_ci } } 142727b27ec6Sopenharmony_ci 142827b27ec6Sopenharmony_ci /* check further positions */ 142927b27ec6Sopenharmony_ci for (cur = 1; cur < last_match_pos; cur++) { 143027b27ec6Sopenharmony_ci const BYTE* const curPtr = ip + cur; 143127b27ec6Sopenharmony_ci LZ4HC_match_t newMatch; 143227b27ec6Sopenharmony_ci 143327b27ec6Sopenharmony_ci if (curPtr > mflimit) break; 143427b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u", 143527b27ec6Sopenharmony_ci cur, opt[cur].price, opt[cur+1].price, cur+1); 143627b27ec6Sopenharmony_ci if (fullUpdate) { 143727b27ec6Sopenharmony_ci /* not useful to search here if next position has same (or lower) cost */ 143827b27ec6Sopenharmony_ci if ( (opt[cur+1].price <= opt[cur].price) 143927b27ec6Sopenharmony_ci /* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */ 144027b27ec6Sopenharmony_ci && (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) ) 144127b27ec6Sopenharmony_ci continue; 144227b27ec6Sopenharmony_ci } else { 144327b27ec6Sopenharmony_ci /* not useful to search here if next position has same (or lower) cost */ 144427b27ec6Sopenharmony_ci if (opt[cur+1].price <= opt[cur].price) continue; 144527b27ec6Sopenharmony_ci } 144627b27ec6Sopenharmony_ci 144727b27ec6Sopenharmony_ci DEBUGLOG(7, "search at rPos:%u", cur); 144827b27ec6Sopenharmony_ci if (fullUpdate) 144927b27ec6Sopenharmony_ci newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed); 145027b27ec6Sopenharmony_ci else 145127b27ec6Sopenharmony_ci /* only test matches of minimum length; slightly faster, but misses a few bytes */ 145227b27ec6Sopenharmony_ci newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed); 145327b27ec6Sopenharmony_ci if (!newMatch.len) continue; 145427b27ec6Sopenharmony_ci 145527b27ec6Sopenharmony_ci if ( ((size_t)newMatch.len > sufficient_len) 145627b27ec6Sopenharmony_ci || (newMatch.len + cur >= LZ4_OPT_NUM) ) { 145727b27ec6Sopenharmony_ci /* immediate encoding */ 145827b27ec6Sopenharmony_ci best_mlen = newMatch.len; 145927b27ec6Sopenharmony_ci best_off = newMatch.off; 146027b27ec6Sopenharmony_ci last_match_pos = cur + 1; 146127b27ec6Sopenharmony_ci goto encode; 146227b27ec6Sopenharmony_ci } 146327b27ec6Sopenharmony_ci 146427b27ec6Sopenharmony_ci /* before match : set price with literals at beginning */ 146527b27ec6Sopenharmony_ci { int const baseLitlen = opt[cur].litlen; 146627b27ec6Sopenharmony_ci int litlen; 146727b27ec6Sopenharmony_ci for (litlen = 1; litlen < MINMATCH; litlen++) { 146827b27ec6Sopenharmony_ci int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen); 146927b27ec6Sopenharmony_ci int const pos = cur + litlen; 147027b27ec6Sopenharmony_ci if (price < opt[pos].price) { 147127b27ec6Sopenharmony_ci opt[pos].mlen = 1; /* literal */ 147227b27ec6Sopenharmony_ci opt[pos].off = 0; 147327b27ec6Sopenharmony_ci opt[pos].litlen = baseLitlen+litlen; 147427b27ec6Sopenharmony_ci opt[pos].price = price; 147527b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", 147627b27ec6Sopenharmony_ci pos, price, opt[pos].litlen); 147727b27ec6Sopenharmony_ci } } } 147827b27ec6Sopenharmony_ci 147927b27ec6Sopenharmony_ci /* set prices using match at position = cur */ 148027b27ec6Sopenharmony_ci { int const matchML = newMatch.len; 148127b27ec6Sopenharmony_ci int ml = MINMATCH; 148227b27ec6Sopenharmony_ci 148327b27ec6Sopenharmony_ci assert(cur + newMatch.len < LZ4_OPT_NUM); 148427b27ec6Sopenharmony_ci for ( ; ml <= matchML ; ml++) { 148527b27ec6Sopenharmony_ci int const pos = cur + ml; 148627b27ec6Sopenharmony_ci int const offset = newMatch.off; 148727b27ec6Sopenharmony_ci int price; 148827b27ec6Sopenharmony_ci int ll; 148927b27ec6Sopenharmony_ci DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)", 149027b27ec6Sopenharmony_ci pos, last_match_pos); 149127b27ec6Sopenharmony_ci if (opt[cur].mlen == 1) { 149227b27ec6Sopenharmony_ci ll = opt[cur].litlen; 149327b27ec6Sopenharmony_ci price = ((cur > ll) ? opt[cur - ll].price : 0) 149427b27ec6Sopenharmony_ci + LZ4HC_sequencePrice(ll, ml); 149527b27ec6Sopenharmony_ci } else { 149627b27ec6Sopenharmony_ci ll = 0; 149727b27ec6Sopenharmony_ci price = opt[cur].price + LZ4HC_sequencePrice(0, ml); 149827b27ec6Sopenharmony_ci } 149927b27ec6Sopenharmony_ci 150027b27ec6Sopenharmony_ci assert((U32)favorDecSpeed <= 1); 150127b27ec6Sopenharmony_ci if (pos > last_match_pos+TRAILING_LITERALS 150227b27ec6Sopenharmony_ci || price <= opt[pos].price - (int)favorDecSpeed) { 150327b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)", 150427b27ec6Sopenharmony_ci pos, price, ml); 150527b27ec6Sopenharmony_ci assert(pos < LZ4_OPT_NUM); 150627b27ec6Sopenharmony_ci if ( (ml == matchML) /* last pos of last match */ 150727b27ec6Sopenharmony_ci && (last_match_pos < pos) ) 150827b27ec6Sopenharmony_ci last_match_pos = pos; 150927b27ec6Sopenharmony_ci opt[pos].mlen = ml; 151027b27ec6Sopenharmony_ci opt[pos].off = offset; 151127b27ec6Sopenharmony_ci opt[pos].litlen = ll; 151227b27ec6Sopenharmony_ci opt[pos].price = price; 151327b27ec6Sopenharmony_ci } } } 151427b27ec6Sopenharmony_ci /* complete following positions with literals */ 151527b27ec6Sopenharmony_ci { int addLit; 151627b27ec6Sopenharmony_ci for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) { 151727b27ec6Sopenharmony_ci opt[last_match_pos+addLit].mlen = 1; /* literal */ 151827b27ec6Sopenharmony_ci opt[last_match_pos+addLit].off = 0; 151927b27ec6Sopenharmony_ci opt[last_match_pos+addLit].litlen = addLit; 152027b27ec6Sopenharmony_ci opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit); 152127b27ec6Sopenharmony_ci DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit); 152227b27ec6Sopenharmony_ci } } 152327b27ec6Sopenharmony_ci } /* for (cur = 1; cur <= last_match_pos; cur++) */ 152427b27ec6Sopenharmony_ci 152527b27ec6Sopenharmony_ci assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS); 152627b27ec6Sopenharmony_ci best_mlen = opt[last_match_pos].mlen; 152727b27ec6Sopenharmony_ci best_off = opt[last_match_pos].off; 152827b27ec6Sopenharmony_ci cur = last_match_pos - best_mlen; 152927b27ec6Sopenharmony_ci 153027b27ec6Sopenharmony_ciencode: /* cur, last_match_pos, best_mlen, best_off must be set */ 153127b27ec6Sopenharmony_ci assert(cur < LZ4_OPT_NUM); 153227b27ec6Sopenharmony_ci assert(last_match_pos >= 1); /* == 1 when only one candidate */ 153327b27ec6Sopenharmony_ci DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos); 153427b27ec6Sopenharmony_ci { int candidate_pos = cur; 153527b27ec6Sopenharmony_ci int selected_matchLength = best_mlen; 153627b27ec6Sopenharmony_ci int selected_offset = best_off; 153727b27ec6Sopenharmony_ci while (1) { /* from end to beginning */ 153827b27ec6Sopenharmony_ci int const next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */ 153927b27ec6Sopenharmony_ci int const next_offset = opt[candidate_pos].off; 154027b27ec6Sopenharmony_ci DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength); 154127b27ec6Sopenharmony_ci opt[candidate_pos].mlen = selected_matchLength; 154227b27ec6Sopenharmony_ci opt[candidate_pos].off = selected_offset; 154327b27ec6Sopenharmony_ci selected_matchLength = next_matchLength; 154427b27ec6Sopenharmony_ci selected_offset = next_offset; 154527b27ec6Sopenharmony_ci if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */ 154627b27ec6Sopenharmony_ci assert(next_matchLength > 0); /* can be 1, means literal */ 154727b27ec6Sopenharmony_ci candidate_pos -= next_matchLength; 154827b27ec6Sopenharmony_ci } } 154927b27ec6Sopenharmony_ci 155027b27ec6Sopenharmony_ci /* encode all recorded sequences in order */ 155127b27ec6Sopenharmony_ci { int rPos = 0; /* relative position (to ip) */ 155227b27ec6Sopenharmony_ci while (rPos < last_match_pos) { 155327b27ec6Sopenharmony_ci int const ml = opt[rPos].mlen; 155427b27ec6Sopenharmony_ci int const offset = opt[rPos].off; 155527b27ec6Sopenharmony_ci if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */ 155627b27ec6Sopenharmony_ci rPos += ml; 155727b27ec6Sopenharmony_ci assert(ml >= MINMATCH); 155827b27ec6Sopenharmony_ci assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX)); 155927b27ec6Sopenharmony_ci opSaved = op; 156027b27ec6Sopenharmony_ci if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) { /* updates ip, op and anchor */ 156127b27ec6Sopenharmony_ci ovml = ml; 156227b27ec6Sopenharmony_ci ovref = ip - offset; 156327b27ec6Sopenharmony_ci goto _dest_overflow; 156427b27ec6Sopenharmony_ci } } } 156527b27ec6Sopenharmony_ci } /* while (ip <= mflimit) */ 156627b27ec6Sopenharmony_ci 156727b27ec6Sopenharmony_ci_last_literals: 156827b27ec6Sopenharmony_ci /* Encode Last Literals */ 156927b27ec6Sopenharmony_ci { size_t lastRunSize = (size_t)(iend - anchor); /* literals */ 157027b27ec6Sopenharmony_ci size_t llAdd = (lastRunSize + 255 - RUN_MASK) / 255; 157127b27ec6Sopenharmony_ci size_t const totalSize = 1 + llAdd + lastRunSize; 157227b27ec6Sopenharmony_ci if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */ 157327b27ec6Sopenharmony_ci if (limit && (op + totalSize > oend)) { 157427b27ec6Sopenharmony_ci if (limit == limitedOutput) { /* Check output limit */ 157527b27ec6Sopenharmony_ci retval = 0; 157627b27ec6Sopenharmony_ci goto _return_label; 157727b27ec6Sopenharmony_ci } 157827b27ec6Sopenharmony_ci /* adapt lastRunSize to fill 'dst' */ 157927b27ec6Sopenharmony_ci lastRunSize = (size_t)(oend - op) - 1 /*token*/; 158027b27ec6Sopenharmony_ci llAdd = (lastRunSize + 256 - RUN_MASK) / 256; 158127b27ec6Sopenharmony_ci lastRunSize -= llAdd; 158227b27ec6Sopenharmony_ci } 158327b27ec6Sopenharmony_ci DEBUGLOG(6, "Final literal run : %i literals", (int)lastRunSize); 158427b27ec6Sopenharmony_ci ip = anchor + lastRunSize; /* can be != iend if limit==fillOutput */ 158527b27ec6Sopenharmony_ci 158627b27ec6Sopenharmony_ci if (lastRunSize >= RUN_MASK) { 158727b27ec6Sopenharmony_ci size_t accumulator = lastRunSize - RUN_MASK; 158827b27ec6Sopenharmony_ci *op++ = (RUN_MASK << ML_BITS); 158927b27ec6Sopenharmony_ci for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255; 159027b27ec6Sopenharmony_ci *op++ = (BYTE) accumulator; 159127b27ec6Sopenharmony_ci } else { 159227b27ec6Sopenharmony_ci *op++ = (BYTE)(lastRunSize << ML_BITS); 159327b27ec6Sopenharmony_ci } 159427b27ec6Sopenharmony_ci LZ4_memcpy(op, anchor, lastRunSize); 159527b27ec6Sopenharmony_ci op += lastRunSize; 159627b27ec6Sopenharmony_ci } 159727b27ec6Sopenharmony_ci 159827b27ec6Sopenharmony_ci /* End */ 159927b27ec6Sopenharmony_ci *srcSizePtr = (int) (((const char*)ip) - source); 160027b27ec6Sopenharmony_ci retval = (int) ((char*)op-dst); 160127b27ec6Sopenharmony_ci goto _return_label; 160227b27ec6Sopenharmony_ci 160327b27ec6Sopenharmony_ci_dest_overflow: 160427b27ec6Sopenharmony_ciif (limit == fillOutput) { 160527b27ec6Sopenharmony_ci /* Assumption : ip, anchor, ovml and ovref must be set correctly */ 160627b27ec6Sopenharmony_ci size_t const ll = (size_t)(ip - anchor); 160727b27ec6Sopenharmony_ci size_t const ll_addbytes = (ll + 240) / 255; 160827b27ec6Sopenharmony_ci size_t const ll_totalCost = 1 + ll_addbytes + ll; 160927b27ec6Sopenharmony_ci BYTE* const maxLitPos = oend - 3; /* 2 for offset, 1 for token */ 161027b27ec6Sopenharmony_ci DEBUGLOG(6, "Last sequence overflowing (only %i bytes remaining)", (int)(oend-1-opSaved)); 161127b27ec6Sopenharmony_ci op = opSaved; /* restore correct out pointer */ 161227b27ec6Sopenharmony_ci if (op + ll_totalCost <= maxLitPos) { 161327b27ec6Sopenharmony_ci /* ll validated; now adjust match length */ 161427b27ec6Sopenharmony_ci size_t const bytesLeftForMl = (size_t)(maxLitPos - (op+ll_totalCost)); 161527b27ec6Sopenharmony_ci size_t const maxMlSize = MINMATCH + (ML_MASK-1) + (bytesLeftForMl * 255); 161627b27ec6Sopenharmony_ci assert(maxMlSize < INT_MAX); assert(ovml >= 0); 161727b27ec6Sopenharmony_ci if ((size_t)ovml > maxMlSize) ovml = (int)maxMlSize; 161827b27ec6Sopenharmony_ci if ((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1 + ovml >= MFLIMIT) { 161927b27ec6Sopenharmony_ci DEBUGLOG(6, "Space to end : %i + ml (%i)", (int)((oend + LASTLITERALS) - (op + ll_totalCost + 2) - 1), ovml); 162027b27ec6Sopenharmony_ci DEBUGLOG(6, "Before : ip = %p, anchor = %p", ip, anchor); 162127b27ec6Sopenharmony_ci LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ovml, ovref, notLimited, oend); 162227b27ec6Sopenharmony_ci DEBUGLOG(6, "After : ip = %p, anchor = %p", ip, anchor); 162327b27ec6Sopenharmony_ci } } 162427b27ec6Sopenharmony_ci goto _last_literals; 162527b27ec6Sopenharmony_ci} 162627b27ec6Sopenharmony_ci_return_label: 162727b27ec6Sopenharmony_ci#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1 162827b27ec6Sopenharmony_ci FREEMEM(opt); 162927b27ec6Sopenharmony_ci#endif 163027b27ec6Sopenharmony_ci return retval; 163127b27ec6Sopenharmony_ci} 1632