efl
1538 строк · 64.9 Кб
1/*
2LZ4 HC - High Compression Mode of LZ4
3Copyright (C) 2011-2017, Yann Collet.
4
5BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
6
7Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10
11* Redistributions of source code must retain the above copyright
12notice, this list of conditions and the following disclaimer.
13* Redistributions in binary form must reproduce the above
14copyright notice, this list of conditions and the following disclaimer
15in the documentation and/or other materials provided with the
16distribution.
17
18THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30You can contact the author at :
31- LZ4 source repository : https://github.com/lz4/lz4
32- LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
33*/
34/* note : lz4hc is not an independent module, it requires lz4.h/lz4.c for proper compilation */
35
36
37/* *************************************
38* Tuning Parameter
39***************************************/
40
41/*! HEAPMODE :
42* Select how default compression function will allocate workplace memory,
43* in stack (0:fastest), or in heap (1:requires malloc()).
44* Since workplace is rather large, heap mode is recommended.
45*/
46#ifndef LZ4HC_HEAPMODE47# define LZ4HC_HEAPMODE 148#endif49
50
51/*=== Dependency ===*/
52#define LZ4_HC_STATIC_LINKING_ONLY53#include "lz4hc.h"54
55
56/*=== Common LZ4 definitions ===*/
57#if defined(__GNUC__)58# pragma GCC diagnostic ignored "-Wunused-function"59#endif60#if defined (__clang__)61# pragma clang diagnostic ignored "-Wunused-function"62#endif63
64/*=== Enums ===*/
65typedef enum { noDictCtx, usingDictCtxHc } dictCtx_directive;66
67
68#define LZ4_COMMONDEFS_ONLY69#ifndef LZ4_SRC_INCLUDED70#include "lz4.c" /* LZ4_count, constants, mem */71#endif72
73/*=== Constants ===*/
74#define OPTIMAL_ML (int)((ML_MASK-1)+MINMATCH)75#define LZ4_OPT_NUM (1<<12)76
77
78/*=== Macros ===*/
79#define MIN(a,b) ( (a) < (b) ? (a) : (b) )80#define MAX(a,b) ( (a) > (b) ? (a) : (b) )81#define HASH_FUNCTION(i) (((i) * 2654435761U) >> ((MINMATCH*8)-LZ4HC_HASH_LOG))82#define DELTANEXTMAXD(p) chainTable[(p) & LZ4HC_MAXD_MASK] /* flexible, LZ4HC_MAXD dependent */83#define DELTANEXTU16(table, pos) table[(U16)(pos)] /* faster */84/* Make fields passed to, and updated by LZ4HC_encodeSequence explicit */
85#define UPDATABLE(ip, op, anchor) &ip, &op, &anchor86
87static U32 LZ4HC_hashPtr(const void* ptr) { return HASH_FUNCTION(LZ4_read32(ptr)); }88
89
90/**************************************
91* HC Compression
92**************************************/
93static void LZ4HC_clearTables (LZ4HC_CCtx_internal* hc4)94{
95MEM_INIT((void*)hc4->hashTable, 0, sizeof(hc4->hashTable));96MEM_INIT(hc4->chainTable, 0xFF, sizeof(hc4->chainTable));97}
98
99static void LZ4HC_init_internal (LZ4HC_CCtx_internal* hc4, const BYTE* start)100{
101uptrval startingOffset = (uptrval)(hc4->end - hc4->base);102if (startingOffset > 1 GB) {103LZ4HC_clearTables(hc4);104startingOffset = 0;105}106startingOffset += 64 KB;107hc4->nextToUpdate = (U32) startingOffset;108hc4->base = start - startingOffset;109hc4->end = start;110hc4->dictBase = start - startingOffset;111hc4->dictLimit = (U32) startingOffset;112hc4->lowLimit = (U32) startingOffset;113}
114
115
116/* Update chains up to ip (excluded) */
117LZ4_FORCE_INLINE void LZ4HC_Insert (LZ4HC_CCtx_internal* hc4, const BYTE* ip)118{
119U16* const chainTable = hc4->chainTable;120U32* const hashTable = hc4->hashTable;121const BYTE* const base = hc4->base;122U32 const target = (U32)(ip - base);123U32 idx = hc4->nextToUpdate;124
125while (idx < target) {126U32 const h = LZ4HC_hashPtr(base+idx);127size_t delta = idx - hashTable[h];128if (delta>LZ4_DISTANCE_MAX) delta = LZ4_DISTANCE_MAX;129DELTANEXTU16(chainTable, idx) = (U16)delta;130hashTable[h] = idx;131idx++;132}133
134hc4->nextToUpdate = target;135}
136
137/** LZ4HC_countBack() :
138* @return : negative value, nb of common bytes before ip/match */
139LZ4_FORCE_INLINE
140int LZ4HC_countBack(const BYTE* const ip, const BYTE* const match,141const BYTE* const iMin, const BYTE* const mMin)142{
143int back = 0;144int const min = (int)MAX(iMin - ip, mMin - match);145assert(min <= 0);146assert(ip >= iMin); assert((size_t)(ip-iMin) < (1U<<31));147assert(match >= mMin); assert((size_t)(match - mMin) < (1U<<31));148while ( (back > min)149&& (ip[back-1] == match[back-1]) )150back--;151return back;152}
153
154#if defined(_MSC_VER)155# define LZ4HC_rotl32(x,r) _rotl(x,r)156#else157# define LZ4HC_rotl32(x,r) ((x << r) | (x >> (32 - r)))158#endif159
160
161static U32 LZ4HC_rotatePattern(size_t const rotate, U32 const pattern)162{
163size_t const bitsToRotate = (rotate & (sizeof(pattern) - 1)) << 3;164if (bitsToRotate == 0)165return pattern;166return LZ4HC_rotl32(pattern, (int)bitsToRotate);167}
168
169/* LZ4HC_countPattern() :
170* pattern32 must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!) */
171static unsigned172LZ4HC_countPattern(const BYTE* ip, const BYTE* const iEnd, U32 const pattern32)173{
174const BYTE* const iStart = ip;175reg_t const pattern = (sizeof(pattern)==8) ? (reg_t)pattern32 + (((reg_t)pattern32) << 32) : pattern32;176
177while (likely(ip < iEnd-(sizeof(pattern)-1))) {178reg_t const diff = LZ4_read_ARCH(ip) ^ pattern;179if (!diff) { ip+=sizeof(pattern); continue; }180ip += LZ4_NbCommonBytes(diff);181return (unsigned)(ip - iStart);182}183
184if (LZ4_isLittleEndian()) {185reg_t patternByte = pattern;186while ((ip<iEnd) && (*ip == (BYTE)patternByte)) {187ip++; patternByte >>= 8;188}189} else { /* big endian */190U32 bitOffset = (sizeof(pattern)*8) - 8;191while (ip < iEnd) {192BYTE const byte = (BYTE)(pattern >> bitOffset);193if (*ip != byte) break;194ip ++; bitOffset -= 8;195}196}197
198return (unsigned)(ip - iStart);199}
200
201/* LZ4HC_reverseCountPattern() :
202* pattern must be a sample of repetitive pattern of length 1, 2 or 4 (but not 3!)
203* read using natural platform endianess */
204static unsigned205LZ4HC_reverseCountPattern(const BYTE* ip, const BYTE* const iLow, U32 pattern)206{
207const BYTE* const iStart = ip;208
209while (likely(ip >= iLow+4)) {210if (LZ4_read32(ip-4) != pattern) break;211ip -= 4;212}213{ const BYTE* bytePtr = (const BYTE*)(&pattern) + 3; /* works for any endianess */214while (likely(ip>iLow)) {215if (ip[-1] != *bytePtr) break;216ip--; bytePtr--;217} }218return (unsigned)(iStart - ip);219}
220
221/* LZ4HC_protectDictEnd() :
222* Checks if the match is in the last 3 bytes of the dictionary, so reading the
223* 4 byte MINMATCH would overflow.
224* @returns true if the match index is okay.
225*/
226static int LZ4HC_protectDictEnd(U32 const dictLimit, U32 const matchIndex)227{
228return ((U32)((dictLimit - 1) - matchIndex) >= 3);229}
230
231typedef enum { rep_untested, rep_not, rep_confirmed } repeat_state_e;232typedef enum { favorCompressionRatio=0, favorDecompressionSpeed } HCfavor_e;233
234LZ4_FORCE_INLINE int235LZ4HC_InsertAndGetWiderMatch (236LZ4HC_CCtx_internal* hc4,237const BYTE* const ip,238const BYTE* const iLowLimit,239const BYTE* const iHighLimit,240int longest,241const BYTE** matchpos,242const BYTE** startpos,243const int maxNbAttempts,244const int patternAnalysis,245const int chainSwap,246const dictCtx_directive dict,247const HCfavor_e favorDecSpeed)248{
249U16* const chainTable = hc4->chainTable;250U32* const HashTable = hc4->hashTable;251const LZ4HC_CCtx_internal * const dictCtx = hc4->dictCtx;252const BYTE* const base = hc4->base;253const U32 dictLimit = hc4->dictLimit;254const BYTE* const lowPrefixPtr = base + dictLimit;255const U32 ipIndex = (U32)(ip - base);256const U32 lowestMatchIndex = (hc4->lowLimit + (LZ4_DISTANCE_MAX + 1) > ipIndex) ? hc4->lowLimit : ipIndex - LZ4_DISTANCE_MAX;257const BYTE* const dictBase = hc4->dictBase;258int const lookBackLength = (int)(ip-iLowLimit);259int nbAttempts = maxNbAttempts;260U32 matchChainPos = 0;261U32 const pattern = LZ4_read32(ip);262U32 matchIndex;263repeat_state_e repeat = rep_untested;264size_t srcPatternLength = 0;265
266DEBUGLOG(7, "LZ4HC_InsertAndGetWiderMatch");267/* First Match */268LZ4HC_Insert(hc4, ip);269matchIndex = HashTable[LZ4HC_hashPtr(ip)];270DEBUGLOG(7, "First match at index %u / %u (lowestMatchIndex)",271matchIndex, lowestMatchIndex);272
273while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) {274int matchLength=0;275nbAttempts--;276assert(matchIndex < ipIndex);277if (favorDecSpeed && (ipIndex - matchIndex < 8)) {278/* do nothing */279} else if (matchIndex >= dictLimit) { /* within current Prefix */280const BYTE* const matchPtr = base + matchIndex;281assert(matchPtr >= lowPrefixPtr);282assert(matchPtr < ip);283assert(longest >= 1);284if (LZ4_read16(iLowLimit + longest - 1) == LZ4_read16(matchPtr - lookBackLength + longest - 1)) {285if (LZ4_read32(matchPtr) == pattern) {286int const back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, lowPrefixPtr) : 0;287matchLength = MINMATCH + (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, iHighLimit);288matchLength -= back;289if (matchLength > longest) {290longest = matchLength;291*matchpos = matchPtr + back;292*startpos = ip + back;293} } }294} else { /* lowestMatchIndex <= matchIndex < dictLimit */295const BYTE* const matchPtr = dictBase + matchIndex;296if (LZ4_read32(matchPtr) == pattern) {297const BYTE* const dictStart = dictBase + hc4->lowLimit;298int back = 0;299const BYTE* vLimit = ip + (dictLimit - matchIndex);300if (vLimit > iHighLimit) vLimit = iHighLimit;301matchLength = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;302if ((ip+matchLength == vLimit) && (vLimit < iHighLimit))303matchLength += LZ4_count(ip+matchLength, lowPrefixPtr, iHighLimit);304back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictStart) : 0;305matchLength -= back;306if (matchLength > longest) {307longest = matchLength;308*matchpos = base + matchIndex + back; /* virtual pos, relative to ip, to retrieve offset */309*startpos = ip + back;310} } }311
312if (chainSwap && matchLength==longest) { /* better match => select a better chain */313assert(lookBackLength==0); /* search forward only */314if (matchIndex + (U32)longest <= ipIndex) {315int const kTrigger = 4;316U32 distanceToNextMatch = 1;317int const end = longest - MINMATCH + 1;318int step = 1;319int accel = 1 << kTrigger;320int pos;321for (pos = 0; pos < end; pos += step) {322U32 const candidateDist = DELTANEXTU16(chainTable, matchIndex + (U32)pos);323step = (accel++ >> kTrigger);324if (candidateDist > distanceToNextMatch) {325distanceToNextMatch = candidateDist;326matchChainPos = (U32)pos;327accel = 1 << kTrigger;328}329}330if (distanceToNextMatch > 1) {331if (distanceToNextMatch > matchIndex) break; /* avoid overflow */332matchIndex -= distanceToNextMatch;333continue;334} } }335
336{ U32 const distNextMatch = DELTANEXTU16(chainTable, matchIndex);337if (patternAnalysis && distNextMatch==1 && matchChainPos==0) {338U32 const matchCandidateIdx = matchIndex-1;339/* may be a repeated pattern */340if (repeat == rep_untested) {341if ( ((pattern & 0xFFFF) == (pattern >> 16))342& ((pattern & 0xFF) == (pattern >> 24)) ) {343repeat = rep_confirmed;344srcPatternLength = LZ4HC_countPattern(ip+sizeof(pattern), iHighLimit, pattern) + sizeof(pattern);345} else {346repeat = rep_not;347} }348if ( (repeat == rep_confirmed) && (matchCandidateIdx >= lowestMatchIndex)349&& LZ4HC_protectDictEnd(dictLimit, matchCandidateIdx) ) {350const int extDict = matchCandidateIdx < dictLimit;351const BYTE* const matchPtr = (extDict ? dictBase : base) + matchCandidateIdx;352if (LZ4_read32(matchPtr) == pattern) { /* good candidate */353const BYTE* const dictStart = dictBase + hc4->lowLimit;354const BYTE* const iLimit = extDict ? dictBase + dictLimit : iHighLimit;355size_t forwardPatternLength = LZ4HC_countPattern(matchPtr+sizeof(pattern), iLimit, pattern) + sizeof(pattern);356if (extDict && matchPtr + forwardPatternLength == iLimit) {357U32 const rotatedPattern = LZ4HC_rotatePattern(forwardPatternLength, pattern);358forwardPatternLength += LZ4HC_countPattern(lowPrefixPtr, iHighLimit, rotatedPattern);359}360{ const BYTE* const lowestMatchPtr = extDict ? dictStart : lowPrefixPtr;361size_t backLength = LZ4HC_reverseCountPattern(matchPtr, lowestMatchPtr, pattern);362size_t currentSegmentLength;363if (!extDict && matchPtr - backLength == lowPrefixPtr && hc4->lowLimit < dictLimit) {364U32 const rotatedPattern = LZ4HC_rotatePattern((U32)(-(int)backLength), pattern);365backLength += LZ4HC_reverseCountPattern(dictBase + dictLimit, dictStart, rotatedPattern);366}367/* Limit backLength not go further than lowestMatchIndex */368backLength = matchCandidateIdx - MAX(matchCandidateIdx - (U32)backLength, lowestMatchIndex);369assert(matchCandidateIdx - backLength >= lowestMatchIndex);370currentSegmentLength = backLength + forwardPatternLength;371/* Adjust to end of pattern if the source pattern fits, otherwise the beginning of the pattern */372if ( (currentSegmentLength >= srcPatternLength) /* current pattern segment large enough to contain full srcPatternLength */373&& (forwardPatternLength <= srcPatternLength) ) { /* haven't reached this position yet */374U32 const newMatchIndex = matchCandidateIdx + (U32)forwardPatternLength - (U32)srcPatternLength; /* best position, full pattern, might be followed by more match */375if (LZ4HC_protectDictEnd(dictLimit, newMatchIndex))376matchIndex = newMatchIndex;377else {378/* Can only happen if started in the prefix */379assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);380matchIndex = dictLimit;381}382} else {383U32 const newMatchIndex = matchCandidateIdx - (U32)backLength; /* farthest position in current segment, will find a match of length currentSegmentLength + maybe some back */384if (!LZ4HC_protectDictEnd(dictLimit, newMatchIndex)) {385assert(newMatchIndex >= dictLimit - 3 && newMatchIndex < dictLimit && !extDict);386matchIndex = dictLimit;387} else {388matchIndex = newMatchIndex;389if (lookBackLength==0) { /* no back possible */390size_t const maxML = MIN(currentSegmentLength, srcPatternLength);391if ((size_t)longest < maxML) {392assert(base + matchIndex != ip);393if ((size_t)(ip - base) - matchIndex > LZ4_DISTANCE_MAX) break;394assert(maxML < 2 GB);395longest = (int)maxML;396*matchpos = base + matchIndex; /* virtual pos, relative to ip, to retrieve offset */397*startpos = ip;398}399{ U32 const distToNextPattern = DELTANEXTU16(chainTable, matchIndex);400if (distToNextPattern > matchIndex) break; /* avoid overflow */401matchIndex -= distToNextPattern;402} } } } }403continue;404} }405} } /* PA optimization */406
407/* follow current chain */408matchIndex -= DELTANEXTU16(chainTable, matchIndex + matchChainPos);409
410} /* while ((matchIndex>=lowestMatchIndex) && (nbAttempts)) */411
412if ( dict == usingDictCtxHc413&& nbAttempts414&& ipIndex - lowestMatchIndex < LZ4_DISTANCE_MAX) {415size_t const dictEndOffset = (size_t)(dictCtx->end - dictCtx->base);416U32 dictMatchIndex = dictCtx->hashTable[LZ4HC_hashPtr(ip)];417assert(dictEndOffset <= 1 GB);418matchIndex = dictMatchIndex + lowestMatchIndex - (U32)dictEndOffset;419while (ipIndex - matchIndex <= LZ4_DISTANCE_MAX && nbAttempts--) {420const BYTE* const matchPtr = dictCtx->base + dictMatchIndex;421
422if (LZ4_read32(matchPtr) == pattern) {423int mlt;424int back = 0;425const BYTE* vLimit = ip + (dictEndOffset - dictMatchIndex);426if (vLimit > iHighLimit) vLimit = iHighLimit;427mlt = (int)LZ4_count(ip+MINMATCH, matchPtr+MINMATCH, vLimit) + MINMATCH;428back = lookBackLength ? LZ4HC_countBack(ip, matchPtr, iLowLimit, dictCtx->base + dictCtx->dictLimit) : 0;429mlt -= back;430if (mlt > longest) {431longest = mlt;432*matchpos = base + matchIndex + back;433*startpos = ip + back;434} }435
436{ U32 const nextOffset = DELTANEXTU16(dictCtx->chainTable, dictMatchIndex);437dictMatchIndex -= nextOffset;438matchIndex -= nextOffset;439} } }440
441return longest;442}
443
444LZ4_FORCE_INLINE
445int LZ4HC_InsertAndFindBestMatch(LZ4HC_CCtx_internal* const hc4, /* Index table will be updated */446const BYTE* const ip, const BYTE* const iLimit,447const BYTE** matchpos,448const int maxNbAttempts,449const int patternAnalysis,450const dictCtx_directive dict)451{
452const BYTE* uselessPtr = ip;453/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),454* but this won't be the case here, as we define iLowLimit==ip,
455* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
456return LZ4HC_InsertAndGetWiderMatch(hc4, ip, ip, iLimit, MINMATCH-1, matchpos, &uselessPtr, maxNbAttempts, patternAnalysis, 0 /*chainSwap*/, dict, favorCompressionRatio);457}
458
459/* LZ4HC_encodeSequence() :
460* @return : 0 if ok,
461* 1 if buffer issue detected */
462LZ4_FORCE_INLINE int LZ4HC_encodeSequence (463const BYTE** ip,464BYTE** op,465const BYTE** anchor,466int matchLength,467const BYTE* const match,468limitedOutput_directive limit,469BYTE* oend)470{
471size_t length;472BYTE* const token = (*op)++;473
474#if defined(LZ4_DEBUG) && (LZ4_DEBUG >= 6)475static const BYTE* start = NULL;476static U32 totalCost = 0;477U32 const pos = (start==NULL) ? 0 : (U32)(*anchor - start);478U32 const ll = (U32)(*ip - *anchor);479U32 const llAdd = (ll>=15) ? ((ll-15) / 255) + 1 : 0;480U32 const mlAdd = (matchLength>=19) ? ((matchLength-19) / 255) + 1 : 0;481U32 const cost = 1 + llAdd + ll + 2 + mlAdd;482if (start==NULL) start = *anchor; /* only works for single segment */483/* g_debuglog_enable = (pos >= 2228) & (pos <= 2262); */484DEBUGLOG(6, "pos:%7u -- literals:%3u, match:%4i, offset:%5u, cost:%3u + %u",485pos,486(U32)(*ip - *anchor), matchLength, (U32)(*ip-match),487cost, totalCost);488totalCost += cost;489#endif490
491/* Encode Literal length */492length = (size_t)(*ip - *anchor);493if ((limit) && ((*op + (length / 255) + length + (2 + 1 + LASTLITERALS)) > oend)) return 1; /* Check output limit */494if (length >= RUN_MASK) {495size_t len = length - RUN_MASK;496*token = (RUN_MASK << ML_BITS);497for(; len >= 255 ; len -= 255) *(*op)++ = 255;498*(*op)++ = (BYTE)len;499} else {500*token = (BYTE)(length << ML_BITS);501}502
503/* Copy Literals */504LZ4_wildCopy8(*op, *anchor, (*op) + length);505*op += length;506
507/* Encode Offset */508assert( (*ip - match) <= LZ4_DISTANCE_MAX ); /* note : consider providing offset as a value, rather than as a pointer difference */509LZ4_writeLE16(*op, (U16)(*ip-match)); *op += 2;510
511/* Encode MatchLength */512assert(matchLength >= MINMATCH);513length = (size_t)matchLength - MINMATCH;514if ((limit) && (*op + (length / 255) + (1 + LASTLITERALS) > oend)) return 1; /* Check output limit */515if (length >= ML_MASK) {516*token += ML_MASK;517length -= ML_MASK;518for(; length >= 510 ; length -= 510) { *(*op)++ = 255; *(*op)++ = 255; }519if (length >= 255) { length -= 255; *(*op)++ = 255; }520*(*op)++ = (BYTE)length;521} else {522*token += (BYTE)(length);523}524
525/* Prepare next loop */526*ip += matchLength;527*anchor = *ip;528
529return 0;530}
531
532LZ4_FORCE_INLINE int LZ4HC_compress_hashChain (533LZ4HC_CCtx_internal* const ctx,534const char* const source,535char* const dest,536int* srcSizePtr,537int const maxOutputSize,538unsigned maxNbAttempts,539const limitedOutput_directive limit,540const dictCtx_directive dict541)542{
543const int inputSize = *srcSizePtr;544const int patternAnalysis = (maxNbAttempts > 128); /* levels 9+ */545
546const BYTE* ip = (const BYTE*) source;547const BYTE* anchor = ip;548const BYTE* const iend = ip + inputSize;549const BYTE* const mflimit = iend - MFLIMIT;550const BYTE* const matchlimit = (iend - LASTLITERALS);551
552BYTE* optr = (BYTE*) dest;553BYTE* op = (BYTE*) dest;554BYTE* oend = op + maxOutputSize;555
556int ml0, ml, ml2, ml3;557const BYTE* start0;558const BYTE* ref0;559const BYTE* ref = NULL;560const BYTE* start2 = NULL;561const BYTE* ref2 = NULL;562const BYTE* start3 = NULL;563const BYTE* ref3 = NULL;564
565/* init */566*srcSizePtr = 0;567if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */568if (inputSize < LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */569
570/* Main Loop */571while (ip <= mflimit) {572ml = LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, &ref, maxNbAttempts, patternAnalysis, dict);573if (ml<MINMATCH) { ip++; continue; }574
575/* saved, in case we would skip too much */576start0 = ip; ref0 = ref; ml0 = ml;577
578_Search2:579if (ip+ml <= mflimit) {580ml2 = LZ4HC_InsertAndGetWiderMatch(ctx,581ip + ml - 2, ip + 0, matchlimit, ml, &ref2, &start2,582maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);583} else {584ml2 = ml;585}586
587if (ml2 == ml) { /* No better match => encode ML1 */588optr = op;589if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;590continue;591}592
593if (start0 < ip) { /* first match was skipped at least once */594if (start2 < ip + ml0) { /* squeezing ML1 between ML0(original ML1) and ML2 */595ip = start0; ref = ref0; ml = ml0; /* restore initial ML1 */596} }597
598/* Here, start0==ip */599if ((start2 - ip) < 3) { /* First Match too small : removed */600ml = ml2;601ip = start2;602ref =ref2;603goto _Search2;604}605
606_Search3:607/* At this stage, we have :608* ml2 > ml1, and
609* ip1+3 <= ip2 (usually < ip1+ml1) */
610if ((start2 - ip) < OPTIMAL_ML) {611int correction;612int new_ml = ml;613if (new_ml > OPTIMAL_ML) new_ml = OPTIMAL_ML;614if (ip+new_ml > start2 + ml2 - MINMATCH) new_ml = (int)(start2 - ip) + ml2 - MINMATCH;615correction = new_ml - (int)(start2 - ip);616if (correction > 0) {617start2 += correction;618ref2 += correction;619ml2 -= correction;620}621}622/* Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) */623
624if (start2 + ml2 <= mflimit) {625ml3 = LZ4HC_InsertAndGetWiderMatch(ctx,626start2 + ml2 - 3, start2, matchlimit, ml2, &ref3, &start3,627maxNbAttempts, patternAnalysis, 0, dict, favorCompressionRatio);628} else {629ml3 = ml2;630}631
632if (ml3 == ml2) { /* No better match => encode ML1 and ML2 */633/* ip & ref are known; Now for ml */634if (start2 < ip+ml) ml = (int)(start2 - ip);635/* Now, encode 2 sequences */636optr = op;637if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;638ip = start2;639optr = op;640if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml2, ref2, limit, oend)) goto _dest_overflow;641continue;642}643
644if (start3 < ip+ml+3) { /* Not enough space for match 2 : remove it */645if (start3 >= (ip+ml)) { /* can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 */646if (start2 < ip+ml) {647int correction = (int)(ip+ml - start2);648start2 += correction;649ref2 += correction;650ml2 -= correction;651if (ml2 < MINMATCH) {652start2 = start3;653ref2 = ref3;654ml2 = ml3;655}656}657
658optr = op;659if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;660ip = start3;661ref = ref3;662ml = ml3;663
664start0 = start2;665ref0 = ref2;666ml0 = ml2;667goto _Search2;668}669
670start2 = start3;671ref2 = ref3;672ml2 = ml3;673goto _Search3;674}675
676/*677* OK, now we have 3 ascending matches;
678* let's write the first one ML1.
679* ip & ref are known; Now decide ml.
680*/
681if (start2 < ip+ml) {682if ((start2 - ip) < OPTIMAL_ML) {683int correction;684if (ml > OPTIMAL_ML) ml = OPTIMAL_ML;685if (ip + ml > start2 + ml2 - MINMATCH) ml = (int)(start2 - ip) + ml2 - MINMATCH;686correction = ml - (int)(start2 - ip);687if (correction > 0) {688start2 += correction;689ref2 += correction;690ml2 -= correction;691}692} else {693ml = (int)(start2 - ip);694}695}696optr = op;697if (LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ref, limit, oend)) goto _dest_overflow;698
699/* ML2 becomes ML1 */700ip = start2; ref = ref2; ml = ml2;701
702/* ML3 becomes ML2 */703start2 = start3; ref2 = ref3; ml2 = ml3;704
705/* let's find a new ML3 */706goto _Search3;707}708
709_last_literals:710/* Encode Last Literals */711{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */712size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;713size_t const totalSize = 1 + litLength + lastRunSize;714if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */715if (limit && (op + totalSize > oend)) {716if (limit == limitedOutput) return 0; /* Check output limit */717/* adapt lastRunSize to fill 'dest' */718lastRunSize = (size_t)(oend - op) - 1;719litLength = (lastRunSize + 255 - RUN_MASK) / 255;720lastRunSize -= litLength;721}722ip = anchor + lastRunSize;723
724if (lastRunSize >= RUN_MASK) {725size_t accumulator = lastRunSize - RUN_MASK;726*op++ = (RUN_MASK << ML_BITS);727for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;728*op++ = (BYTE) accumulator;729} else {730*op++ = (BYTE)(lastRunSize << ML_BITS);731}732memcpy(op, anchor, lastRunSize);733op += lastRunSize;734}735
736/* End */737*srcSizePtr = (int) (((const char*)ip) - source);738return (int) (((char*)op)-dest);739
740_dest_overflow:741if (limit == fillOutput) {742op = optr; /* restore correct out pointer */743goto _last_literals;744}745return 0;746}
747
748
749static int LZ4HC_compress_optimal( LZ4HC_CCtx_internal* ctx,750const char* const source, char* dst,751int* srcSizePtr, int dstCapacity,752int const nbSearches, size_t sufficient_len,753const limitedOutput_directive limit, int const fullUpdate,754const dictCtx_directive dict,755HCfavor_e favorDecSpeed);756
757
758LZ4_FORCE_INLINE int LZ4HC_compress_generic_internal (759LZ4HC_CCtx_internal* const ctx,760const char* const src,761char* const dst,762int* const srcSizePtr,763int const dstCapacity,764int cLevel,765const limitedOutput_directive limit,766const dictCtx_directive dict767)768{
769typedef enum { lz4hc, lz4opt } lz4hc_strat_e;770typedef struct {771lz4hc_strat_e strat;772U32 nbSearches;773U32 targetLength;774} cParams_t;775static const cParams_t clTable[LZ4HC_CLEVEL_MAX+1] = {776{ lz4hc, 2, 16 }, /* 0, unused */777{ lz4hc, 2, 16 }, /* 1, unused */778{ lz4hc, 2, 16 }, /* 2, unused */779{ lz4hc, 4, 16 }, /* 3 */780{ lz4hc, 8, 16 }, /* 4 */781{ lz4hc, 16, 16 }, /* 5 */782{ lz4hc, 32, 16 }, /* 6 */783{ lz4hc, 64, 16 }, /* 7 */784{ lz4hc, 128, 16 }, /* 8 */785{ lz4hc, 256, 16 }, /* 9 */786{ lz4opt, 96, 64 }, /*10==LZ4HC_CLEVEL_OPT_MIN*/787{ lz4opt, 512,128 }, /*11 */788{ lz4opt,16384,LZ4_OPT_NUM }, /* 12==LZ4HC_CLEVEL_MAX */789};790
791DEBUGLOG(4, "LZ4HC_compress_generic(ctx=%p, src=%p, srcSize=%d)", ctx, src, *srcSizePtr);792
793if (limit == fillOutput && dstCapacity < 1) return 0; /* Impossible to store anything */794if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size (too large or negative) */795
796ctx->end += *srcSizePtr;797if (cLevel < 1) cLevel = LZ4HC_CLEVEL_DEFAULT; /* note : convention is different from lz4frame, maybe something to review */798cLevel = MIN(LZ4HC_CLEVEL_MAX, cLevel);799{ cParams_t const cParam = clTable[cLevel];800HCfavor_e const favor = ctx->favorDecSpeed ? favorDecompressionSpeed : favorCompressionRatio;801int result;802
803if (cParam.strat == lz4hc) {804result = LZ4HC_compress_hashChain(ctx,805src, dst, srcSizePtr, dstCapacity,806cParam.nbSearches, limit, dict);807} else {808assert(cParam.strat == lz4opt);809result = LZ4HC_compress_optimal(ctx,810src, dst, srcSizePtr, dstCapacity,811(int)cParam.nbSearches, cParam.targetLength, limit,812cLevel == LZ4HC_CLEVEL_MAX, /* ultra mode */813dict, favor);814}815if (result <= 0) ctx->dirty = 1;816return result;817}818}
819
820static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock);821
822static int823LZ4HC_compress_generic_noDictCtx (824LZ4HC_CCtx_internal* const ctx,825const char* const src,826char* const dst,827int* const srcSizePtr,828int const dstCapacity,829int cLevel,830limitedOutput_directive limit
831)832{
833assert(ctx->dictCtx == NULL);834return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, noDictCtx);835}
836
837static int838LZ4HC_compress_generic_dictCtx (839LZ4HC_CCtx_internal* const ctx,840const char* const src,841char* const dst,842int* const srcSizePtr,843int const dstCapacity,844int cLevel,845limitedOutput_directive limit
846)847{
848const size_t position = (size_t)(ctx->end - ctx->base) - ctx->lowLimit;849assert(ctx->dictCtx != NULL);850if (position >= 64 KB) {851ctx->dictCtx = NULL;852return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);853} else if (position == 0 && *srcSizePtr > 4 KB) {854memcpy(ctx, ctx->dictCtx, sizeof(LZ4HC_CCtx_internal));855LZ4HC_setExternalDict(ctx, (const BYTE *)src);856ctx->compressionLevel = (short)cLevel;857return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);858} else {859return LZ4HC_compress_generic_internal(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit, usingDictCtxHc);860}861}
862
863static int864LZ4HC_compress_generic (865LZ4HC_CCtx_internal* const ctx,866const char* const src,867char* const dst,868int* const srcSizePtr,869int const dstCapacity,870int cLevel,871limitedOutput_directive limit
872)873{
874if (ctx->dictCtx == NULL) {875return LZ4HC_compress_generic_noDictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);876} else {877return LZ4HC_compress_generic_dictCtx(ctx, src, dst, srcSizePtr, dstCapacity, cLevel, limit);878}879}
880
881
882int LZ4_sizeofStateHC(void) { return (int)sizeof(LZ4_streamHC_t); }883
884#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :885* it reports an aligment of 8-bytes,
886* while actually aligning LZ4_streamHC_t on 4 bytes. */
887static size_t LZ4_streamHC_t_alignment(void)888{
889struct { char c; LZ4_streamHC_t t; } t_a;890return sizeof(t_a) - sizeof(t_a.t);891}
892#endif893
894/* state is presumed correctly initialized,
895* in which case its size and alignment have already been validate */
896int LZ4_compress_HC_extStateHC_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)897{
898LZ4HC_CCtx_internal* const ctx = &((LZ4_streamHC_t*)state)->internal_donotuse;899#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :900* it reports an aligment of 8-bytes,
901* while actually aligning LZ4_streamHC_t on 4 bytes. */
902assert(((size_t)state & (LZ4_streamHC_t_alignment() - 1)) == 0); /* check alignment */903#endif904if (((size_t)(state)&(sizeof(void*)-1)) != 0) return 0; /* Error : state is not aligned for pointers (32 or 64 bits) */905LZ4_resetStreamHC_fast((LZ4_streamHC_t*)state, compressionLevel);906LZ4HC_init_internal (ctx, (const BYTE*)src);907if (dstCapacity < LZ4_compressBound(srcSize))908return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, limitedOutput);909else910return LZ4HC_compress_generic (ctx, src, dst, &srcSize, dstCapacity, compressionLevel, notLimited);911}
912
913int LZ4_compress_HC_extStateHC (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)914{
915LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));916if (ctx==NULL) return 0; /* init failure */917return LZ4_compress_HC_extStateHC_fastReset(state, src, dst, srcSize, dstCapacity, compressionLevel);918}
919
920int LZ4_compress_HC(const char* src, char* dst, int srcSize, int dstCapacity, int compressionLevel)921{
922#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1923LZ4_streamHC_t* const statePtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));924#else925LZ4_streamHC_t state;926LZ4_streamHC_t* const statePtr = &state;927#endif928int const cSize = LZ4_compress_HC_extStateHC(statePtr, src, dst, srcSize, dstCapacity, compressionLevel);929#if defined(LZ4HC_HEAPMODE) && LZ4HC_HEAPMODE==1930FREEMEM(statePtr);931#endif932return cSize;933}
934
935/* state is presumed sized correctly (>= sizeof(LZ4_streamHC_t)) */
936int LZ4_compress_HC_destSize(void* state, const char* source, char* dest, int* sourceSizePtr, int targetDestSize, int cLevel)937{
938LZ4_streamHC_t* const ctx = LZ4_initStreamHC(state, sizeof(*ctx));939if (ctx==NULL) return 0; /* init failure */940LZ4HC_init_internal(&ctx->internal_donotuse, (const BYTE*) source);941LZ4_setCompressionLevel(ctx, cLevel);942return LZ4HC_compress_generic(&ctx->internal_donotuse, source, dest, sourceSizePtr, targetDestSize, cLevel, fillOutput);943}
944
945
946
947/**************************************
948* Streaming Functions
949**************************************/
950/* allocation */
951LZ4_streamHC_t* LZ4_createStreamHC(void)952{
953LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)ALLOC(sizeof(LZ4_streamHC_t));954if (LZ4_streamHCPtr==NULL) return NULL;955LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr)); /* full initialization, malloc'ed buffer can be full of garbage */956return LZ4_streamHCPtr;957}
958
959int LZ4_freeStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr)960{
961DEBUGLOG(4, "LZ4_freeStreamHC(%p)", LZ4_streamHCPtr);962if (!LZ4_streamHCPtr) return 0; /* support free on NULL */963FREEMEM(LZ4_streamHCPtr);964return 0;965}
966
967
968LZ4_streamHC_t* LZ4_initStreamHC (void* buffer, size_t size)969{
970LZ4_streamHC_t* const LZ4_streamHCPtr = (LZ4_streamHC_t*)buffer;971if (buffer == NULL) return NULL;972if (size < sizeof(LZ4_streamHC_t)) return NULL;973#ifndef _MSC_VER /* for some reason, Visual fails the aligment test on 32-bit x86 :974* it reports an aligment of 8-bytes,
975* while actually aligning LZ4_streamHC_t on 4 bytes. */
976if (((size_t)buffer) & (LZ4_streamHC_t_alignment() - 1)) return NULL; /* alignment check */977#endif978/* if compilation fails here, LZ4_STREAMHCSIZE must be increased */979LZ4_STATIC_ASSERT(sizeof(LZ4HC_CCtx_internal) <= LZ4_STREAMHCSIZE);980DEBUGLOG(4, "LZ4_initStreamHC(%p, %u)", LZ4_streamHCPtr, (unsigned)size);981/* end-base will trigger a clearTable on starting compression */982LZ4_streamHCPtr->internal_donotuse.end = (const BYTE *)(ptrdiff_t)-1;983LZ4_streamHCPtr->internal_donotuse.base = NULL;984LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;985LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = 0;986LZ4_streamHCPtr->internal_donotuse.dirty = 0;987LZ4_setCompressionLevel(LZ4_streamHCPtr, LZ4HC_CLEVEL_DEFAULT);988return LZ4_streamHCPtr;989}
990
991/* just a stub */
992void LZ4_resetStreamHC (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)993{
994LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));995LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);996}
997
998void LZ4_resetStreamHC_fast (LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)999{
1000DEBUGLOG(4, "LZ4_resetStreamHC_fast(%p, %d)", LZ4_streamHCPtr, compressionLevel);1001if (LZ4_streamHCPtr->internal_donotuse.dirty) {1002LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));1003} else {1004/* preserve end - base : can trigger clearTable's threshold */1005LZ4_streamHCPtr->internal_donotuse.end -= (uptrval)LZ4_streamHCPtr->internal_donotuse.base;1006LZ4_streamHCPtr->internal_donotuse.base = NULL;1007LZ4_streamHCPtr->internal_donotuse.dictCtx = NULL;1008}1009LZ4_setCompressionLevel(LZ4_streamHCPtr, compressionLevel);1010}
1011
1012void LZ4_setCompressionLevel(LZ4_streamHC_t* LZ4_streamHCPtr, int compressionLevel)1013{
1014DEBUGLOG(5, "LZ4_setCompressionLevel(%p, %d)", LZ4_streamHCPtr, compressionLevel);1015if (compressionLevel < 1) compressionLevel = LZ4HC_CLEVEL_DEFAULT;1016if (compressionLevel > LZ4HC_CLEVEL_MAX) compressionLevel = LZ4HC_CLEVEL_MAX;1017LZ4_streamHCPtr->internal_donotuse.compressionLevel = (short)compressionLevel;1018}
1019
1020void LZ4_favorDecompressionSpeed(LZ4_streamHC_t* LZ4_streamHCPtr, int favor)1021{
1022LZ4_streamHCPtr->internal_donotuse.favorDecSpeed = (favor!=0);1023}
1024
1025/* LZ4_loadDictHC() :
1026* LZ4_streamHCPtr is presumed properly initialized */
1027int LZ4_loadDictHC (LZ4_streamHC_t* LZ4_streamHCPtr,1028const char* dictionary, int dictSize)1029{
1030LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;1031DEBUGLOG(4, "LZ4_loadDictHC(ctx:%p, dict:%p, dictSize:%d)", LZ4_streamHCPtr, dictionary, dictSize);1032assert(LZ4_streamHCPtr != NULL);1033if (dictSize > 64 KB) {1034dictionary += (size_t)dictSize - 64 KB;1035dictSize = 64 KB;1036}1037/* need a full initialization, there are bad side-effects when using resetFast() */1038{ int const cLevel = ctxPtr->compressionLevel;1039LZ4_initStreamHC(LZ4_streamHCPtr, sizeof(*LZ4_streamHCPtr));1040LZ4_setCompressionLevel(LZ4_streamHCPtr, cLevel);1041}1042LZ4HC_init_internal (ctxPtr, (const BYTE*)dictionary);1043ctxPtr->end = (const BYTE*)dictionary + dictSize;1044if (dictSize >= 4) LZ4HC_Insert (ctxPtr, ctxPtr->end-3);1045return dictSize;1046}
1047
1048void LZ4_attach_HC_dictionary(LZ4_streamHC_t *working_stream, const LZ4_streamHC_t *dictionary_stream) {1049working_stream->internal_donotuse.dictCtx = dictionary_stream != NULL ? &(dictionary_stream->internal_donotuse) : NULL;1050}
1051
1052/* compression */
1053
1054static void LZ4HC_setExternalDict(LZ4HC_CCtx_internal* ctxPtr, const BYTE* newBlock)1055{
1056DEBUGLOG(4, "LZ4HC_setExternalDict(%p, %p)", ctxPtr, newBlock);1057if (ctxPtr->end >= ctxPtr->base + ctxPtr->dictLimit + 4)1058LZ4HC_Insert (ctxPtr, ctxPtr->end-3); /* Referencing remaining dictionary content */1059
1060/* Only one memory segment for extDict, so any previous extDict is lost at this stage */1061ctxPtr->lowLimit = ctxPtr->dictLimit;1062ctxPtr->dictLimit = (U32)(ctxPtr->end - ctxPtr->base);1063ctxPtr->dictBase = ctxPtr->base;1064ctxPtr->base = newBlock - ctxPtr->dictLimit;1065ctxPtr->end = newBlock;1066ctxPtr->nextToUpdate = ctxPtr->dictLimit; /* match referencing will resume from there */1067
1068/* cannot reference an extDict and a dictCtx at the same time */1069ctxPtr->dictCtx = NULL;1070}
1071
1072static int LZ4_compressHC_continue_generic (LZ4_streamHC_t* LZ4_streamHCPtr,1073const char* src, char* dst,1074int* srcSizePtr, int dstCapacity,1075limitedOutput_directive limit)1076{
1077LZ4HC_CCtx_internal* const ctxPtr = &LZ4_streamHCPtr->internal_donotuse;1078DEBUGLOG(4, "LZ4_compressHC_continue_generic(ctx=%p, src=%p, srcSize=%d)",1079LZ4_streamHCPtr, src, *srcSizePtr);1080assert(ctxPtr != NULL);1081/* auto-init if forgotten */1082if (ctxPtr->base == NULL) LZ4HC_init_internal (ctxPtr, (const BYTE*) src);1083
1084/* Check overflow */1085if ((size_t)(ctxPtr->end - ctxPtr->base) > 2 GB) {1086size_t dictSize = (size_t)(ctxPtr->end - ctxPtr->base) - ctxPtr->dictLimit;1087if (dictSize > 64 KB) dictSize = 64 KB;1088LZ4_loadDictHC(LZ4_streamHCPtr, (const char*)(ctxPtr->end) - dictSize, (int)dictSize);1089}1090
1091/* Check if blocks follow each other */1092if ((const BYTE*)src != ctxPtr->end)1093LZ4HC_setExternalDict(ctxPtr, (const BYTE*)src);1094
1095/* Check overlapping input/dictionary space */1096{ const BYTE* sourceEnd = (const BYTE*) src + *srcSizePtr;1097const BYTE* const dictBegin = ctxPtr->dictBase + ctxPtr->lowLimit;1098const BYTE* const dictEnd = ctxPtr->dictBase + ctxPtr->dictLimit;1099if ((sourceEnd > dictBegin) && ((const BYTE*)src < dictEnd)) {1100if (sourceEnd > dictEnd) sourceEnd = dictEnd;1101ctxPtr->lowLimit = (U32)(sourceEnd - ctxPtr->dictBase);1102if (ctxPtr->dictLimit - ctxPtr->lowLimit < 4) ctxPtr->lowLimit = ctxPtr->dictLimit;1103}1104}1105
1106return LZ4HC_compress_generic (ctxPtr, src, dst, srcSizePtr, dstCapacity, ctxPtr->compressionLevel, limit);1107}
1108
1109int LZ4_compress_HC_continue (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int srcSize, int dstCapacity)1110{
1111if (dstCapacity < LZ4_compressBound(srcSize))1112return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, limitedOutput);1113else1114return LZ4_compressHC_continue_generic (LZ4_streamHCPtr, src, dst, &srcSize, dstCapacity, notLimited);1115}
1116
1117int LZ4_compress_HC_continue_destSize (LZ4_streamHC_t* LZ4_streamHCPtr, const char* src, char* dst, int* srcSizePtr, int targetDestSize)1118{
1119return LZ4_compressHC_continue_generic(LZ4_streamHCPtr, src, dst, srcSizePtr, targetDestSize, fillOutput);1120}
1121
1122
1123
1124/* dictionary saving */
1125
1126int LZ4_saveDictHC (LZ4_streamHC_t* LZ4_streamHCPtr, char* safeBuffer, int dictSize)1127{
1128LZ4HC_CCtx_internal* const streamPtr = &LZ4_streamHCPtr->internal_donotuse;1129int const prefixSize = (int)(streamPtr->end - (streamPtr->base + streamPtr->dictLimit));1130DEBUGLOG(4, "LZ4_saveDictHC(%p, %p, %d)", LZ4_streamHCPtr, safeBuffer, dictSize);1131if (dictSize > 64 KB) dictSize = 64 KB;1132if (dictSize < 4) dictSize = 0;1133if (dictSize > prefixSize) dictSize = prefixSize;1134memmove(safeBuffer, streamPtr->end - dictSize, dictSize);1135{ U32 const endIndex = (U32)(streamPtr->end - streamPtr->base);1136streamPtr->end = (const BYTE*)safeBuffer + dictSize;1137streamPtr->base = streamPtr->end - endIndex;1138streamPtr->dictLimit = endIndex - (U32)dictSize;1139streamPtr->lowLimit = endIndex - (U32)dictSize;1140if (streamPtr->nextToUpdate < streamPtr->dictLimit) streamPtr->nextToUpdate = streamPtr->dictLimit;1141}1142return dictSize;1143}
1144
1145
1146/***************************************************
1147* Deprecated Functions
1148***************************************************/
1149
1150/* These functions currently generate deprecation warnings */
1151
1152/* Wrappers for deprecated compression functions */
1153int LZ4_compressHC(const char* src, char* dst, int srcSize) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), 0); }1154int LZ4_compressHC_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, 0); }1155int LZ4_compressHC2(const char* src, char* dst, int srcSize, int cLevel) { return LZ4_compress_HC (src, dst, srcSize, LZ4_compressBound(srcSize), cLevel); }1156int LZ4_compressHC2_limitedOutput(const char* src, char* dst, int srcSize, int maxDstSize, int cLevel) { return LZ4_compress_HC(src, dst, srcSize, maxDstSize, cLevel); }1157int 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); }1158int 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); }1159int 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); }1160int 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); }1161int 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)); }1162int 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); }1163
1164
1165/* Deprecated streaming functions */
1166int LZ4_sizeofStreamStateHC(void) { return LZ4_STREAMHCSIZE; }1167
1168/* state is presumed correctly sized, aka >= sizeof(LZ4_streamHC_t)
1169* @return : 0 on success, !=0 if error */
1170int LZ4_resetStreamStateHC(void* state, char* inputBuffer)1171{
1172LZ4_streamHC_t* const hc4 = LZ4_initStreamHC(state, sizeof(*hc4));1173if (hc4 == NULL) return 1; /* init failed */1174LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);1175return 0;1176}
1177
1178void* LZ4_createHC (const char* inputBuffer)1179{
1180LZ4_streamHC_t* const hc4 = LZ4_createStreamHC();1181if (hc4 == NULL) return NULL; /* not enough memory */1182LZ4HC_init_internal (&hc4->internal_donotuse, (const BYTE*)inputBuffer);1183return hc4;1184}
1185
1186int LZ4_freeHC (void* LZ4HC_Data)1187{
1188if (!LZ4HC_Data) return 0; /* support free on NULL */1189FREEMEM(LZ4HC_Data);1190return 0;1191}
1192
1193int LZ4_compressHC2_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int cLevel)1194{
1195return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, 0, cLevel, notLimited);1196}
1197
1198int LZ4_compressHC2_limitedOutput_continue (void* LZ4HC_Data, const char* src, char* dst, int srcSize, int dstCapacity, int cLevel)1199{
1200return LZ4HC_compress_generic (&((LZ4_streamHC_t*)LZ4HC_Data)->internal_donotuse, src, dst, &srcSize, dstCapacity, cLevel, limitedOutput);1201}
1202
1203char* LZ4_slideInputBufferHC(void* LZ4HC_Data)1204{
1205LZ4_streamHC_t *ctx = (LZ4_streamHC_t*)LZ4HC_Data;1206const BYTE *bufferStart = ctx->internal_donotuse.base + ctx->internal_donotuse.lowLimit;1207LZ4_resetStreamHC_fast(ctx, ctx->internal_donotuse.compressionLevel);1208/* avoid const char * -> char * conversion warning :( */1209return (char *)(uptrval)bufferStart;1210}
1211
1212
1213/* ================================================
1214* LZ4 Optimal parser (levels [LZ4HC_CLEVEL_OPT_MIN - LZ4HC_CLEVEL_MAX])
1215* ===============================================*/
1216typedef struct {1217int price;1218int off;1219int mlen;1220int litlen;1221} LZ4HC_optimal_t;1222
1223/* price in bytes */
1224LZ4_FORCE_INLINE int LZ4HC_literalsPrice(int const litlen)1225{
1226int price = litlen;1227assert(litlen >= 0);1228if (litlen >= (int)RUN_MASK)1229price += 1 + ((litlen-(int)RUN_MASK) / 255);1230return price;1231}
1232
1233
1234/* requires mlen >= MINMATCH */
1235LZ4_FORCE_INLINE int LZ4HC_sequencePrice(int litlen, int mlen)1236{
1237int price = 1 + 2 ; /* token + 16-bit offset */1238assert(litlen >= 0);1239assert(mlen >= MINMATCH);1240
1241price += LZ4HC_literalsPrice(litlen);1242
1243if (mlen >= (int)(ML_MASK+MINMATCH))1244price += 1 + ((mlen-(int)(ML_MASK+MINMATCH)) / 255);1245
1246return price;1247}
1248
1249
1250typedef struct {1251int off;1252int len;1253} LZ4HC_match_t;1254
1255LZ4_FORCE_INLINE LZ4HC_match_t
1256LZ4HC_FindLongerMatch(LZ4HC_CCtx_internal* const ctx,1257const BYTE* ip, const BYTE* const iHighLimit,1258int minLen, int nbSearches,1259const dictCtx_directive dict,1260const HCfavor_e favorDecSpeed)1261{
1262LZ4HC_match_t match = { 0 , 0 };1263const BYTE* matchPtr = NULL;1264/* note : LZ4HC_InsertAndGetWiderMatch() is able to modify the starting position of a match (*startpos),1265* but this won't be the case here, as we define iLowLimit==ip,
1266* so LZ4HC_InsertAndGetWiderMatch() won't be allowed to search past ip */
1267int matchLength = LZ4HC_InsertAndGetWiderMatch(ctx, ip, ip, iHighLimit, minLen, &matchPtr, &ip, nbSearches, 1 /*patternAnalysis*/, 1 /*chainSwap*/, dict, favorDecSpeed);1268if (matchLength <= minLen) return match;1269if (favorDecSpeed) {1270if ((matchLength>18) & (matchLength<=36)) matchLength=18; /* favor shortcut */1271}1272match.len = matchLength;1273match.off = (int)(ip-matchPtr);1274return match;1275}
1276
1277
1278static int LZ4HC_compress_optimal ( LZ4HC_CCtx_internal* ctx,1279const char* const source,1280char* dst,1281int* srcSizePtr,1282int dstCapacity,1283int const nbSearches,1284size_t sufficient_len,1285const limitedOutput_directive limit,1286int const fullUpdate,1287const dictCtx_directive dict,1288const HCfavor_e favorDecSpeed)1289{
1290#define TRAILING_LITERALS 31291LZ4HC_optimal_t opt[LZ4_OPT_NUM + TRAILING_LITERALS]; /* ~64 KB, which is a bit large for stack... */1292
1293const BYTE* ip = (const BYTE*) source;1294const BYTE* anchor = ip;1295const BYTE* const iend = ip + *srcSizePtr;1296const BYTE* const mflimit = iend - MFLIMIT;1297const BYTE* const matchlimit = iend - LASTLITERALS;1298BYTE* op = (BYTE*) dst;1299BYTE* opSaved = (BYTE*) dst;1300BYTE* oend = op + dstCapacity;1301
1302/* init */1303DEBUGLOG(5, "LZ4HC_compress_optimal(dst=%p, dstCapa=%u)", dst, (unsigned)dstCapacity);1304*srcSizePtr = 0;1305if (limit == fillOutput) oend -= LASTLITERALS; /* Hack for support LZ4 format restriction */1306if (sufficient_len >= LZ4_OPT_NUM) sufficient_len = LZ4_OPT_NUM-1;1307
1308/* Main Loop */1309assert(ip - anchor < LZ4_MAX_INPUT_SIZE);1310while (ip <= mflimit) {1311int const llen = (int)(ip - anchor);1312int best_mlen, best_off;1313int cur, last_match_pos = 0;1314
1315LZ4HC_match_t const firstMatch = LZ4HC_FindLongerMatch(ctx, ip, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);1316if (firstMatch.len==0) { ip++; continue; }1317
1318if ((size_t)firstMatch.len > sufficient_len) {1319/* good enough solution : immediate encoding */1320int const firstML = firstMatch.len;1321const BYTE* const matchPos = ip - firstMatch.off;1322opSaved = op;1323if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), firstML, matchPos, limit, oend) ) /* updates ip, op and anchor */1324goto _dest_overflow;1325continue;1326}1327
1328/* set prices for first positions (literals) */1329{ int rPos;1330for (rPos = 0 ; rPos < MINMATCH ; rPos++) {1331int const cost = LZ4HC_literalsPrice(llen + rPos);1332opt[rPos].mlen = 1;1333opt[rPos].off = 0;1334opt[rPos].litlen = llen + rPos;1335opt[rPos].price = cost;1336DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",1337rPos, cost, opt[rPos].litlen);1338} }1339/* set prices using initial match */1340{ int mlen = MINMATCH;1341int const matchML = firstMatch.len; /* necessarily < sufficient_len < LZ4_OPT_NUM */1342int const offset = firstMatch.off;1343assert(matchML < LZ4_OPT_NUM);1344for ( ; mlen <= matchML ; mlen++) {1345int const cost = LZ4HC_sequencePrice(llen, mlen);1346opt[mlen].mlen = mlen;1347opt[mlen].off = offset;1348opt[mlen].litlen = llen;1349opt[mlen].price = cost;1350DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i) -- initial setup",1351mlen, cost, mlen);1352} }1353last_match_pos = firstMatch.len;1354{ int addLit;1355for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {1356opt[last_match_pos+addLit].mlen = 1; /* literal */1357opt[last_match_pos+addLit].off = 0;1358opt[last_match_pos+addLit].litlen = addLit;1359opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);1360DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i) -- initial setup",1361last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);1362} }1363
1364/* check further positions */1365for (cur = 1; cur < last_match_pos; cur++) {1366const BYTE* const curPtr = ip + cur;1367LZ4HC_match_t newMatch;1368
1369if (curPtr > mflimit) break;1370DEBUGLOG(7, "rPos:%u[%u] vs [%u]%u",1371cur, opt[cur].price, opt[cur+1].price, cur+1);1372if (fullUpdate) {1373/* not useful to search here if next position has same (or lower) cost */1374if ( (opt[cur+1].price <= opt[cur].price)1375/* in some cases, next position has same cost, but cost rises sharply after, so a small match would still be beneficial */1376&& (opt[cur+MINMATCH].price < opt[cur].price + 3/*min seq price*/) )1377continue;1378} else {1379/* not useful to search here if next position has same (or lower) cost */1380if (opt[cur+1].price <= opt[cur].price) continue;1381}1382
1383DEBUGLOG(7, "search at rPos:%u", cur);1384if (fullUpdate)1385newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, MINMATCH-1, nbSearches, dict, favorDecSpeed);1386else1387/* only test matches of minimum length; slightly faster, but misses a few bytes */1388newMatch = LZ4HC_FindLongerMatch(ctx, curPtr, matchlimit, last_match_pos - cur, nbSearches, dict, favorDecSpeed);1389if (!newMatch.len) continue;1390
1391if ( ((size_t)newMatch.len > sufficient_len)1392|| (newMatch.len + cur >= LZ4_OPT_NUM) ) {1393/* immediate encoding */1394best_mlen = newMatch.len;1395best_off = newMatch.off;1396last_match_pos = cur + 1;1397goto encode;1398}1399
1400/* before match : set price with literals at beginning */1401{ int const baseLitlen = opt[cur].litlen;1402int litlen;1403for (litlen = 1; litlen < MINMATCH; litlen++) {1404int const price = opt[cur].price - LZ4HC_literalsPrice(baseLitlen) + LZ4HC_literalsPrice(baseLitlen+litlen);1405int const pos = cur + litlen;1406if (price < opt[pos].price) {1407opt[pos].mlen = 1; /* literal */1408opt[pos].off = 0;1409opt[pos].litlen = baseLitlen+litlen;1410opt[pos].price = price;1411DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)",1412pos, price, opt[pos].litlen);1413} } }1414
1415/* set prices using match at position = cur */1416{ int const matchML = newMatch.len;1417int ml = MINMATCH;1418
1419assert(cur + newMatch.len < LZ4_OPT_NUM);1420for ( ; ml <= matchML ; ml++) {1421int const pos = cur + ml;1422int const offset = newMatch.off;1423int price;1424int ll;1425DEBUGLOG(7, "testing price rPos %i (last_match_pos=%i)",1426pos, last_match_pos);1427if (opt[cur].mlen == 1) {1428ll = opt[cur].litlen;1429price = ((cur > ll) ? opt[cur - ll].price : 0)1430+ LZ4HC_sequencePrice(ll, ml);1431} else {1432ll = 0;1433price = opt[cur].price + LZ4HC_sequencePrice(0, ml);1434}1435
1436assert((U32)favorDecSpeed <= 1);1437if (pos > last_match_pos+TRAILING_LITERALS1438|| price <= opt[pos].price - (int)favorDecSpeed) {1439DEBUGLOG(7, "rPos:%3i => price:%3i (matchlen=%i)",1440pos, price, ml);1441assert(pos < LZ4_OPT_NUM);1442if ( (ml == matchML) /* last pos of last match */1443&& (last_match_pos < pos) )1444last_match_pos = pos;1445opt[pos].mlen = ml;1446opt[pos].off = offset;1447opt[pos].litlen = ll;1448opt[pos].price = price;1449} } }1450/* complete following positions with literals */1451{ int addLit;1452for (addLit = 1; addLit <= TRAILING_LITERALS; addLit ++) {1453opt[last_match_pos+addLit].mlen = 1; /* literal */1454opt[last_match_pos+addLit].off = 0;1455opt[last_match_pos+addLit].litlen = addLit;1456opt[last_match_pos+addLit].price = opt[last_match_pos].price + LZ4HC_literalsPrice(addLit);1457DEBUGLOG(7, "rPos:%3i => price:%3i (litlen=%i)", last_match_pos+addLit, opt[last_match_pos+addLit].price, addLit);1458} }1459} /* for (cur = 1; cur <= last_match_pos; cur++) */1460
1461assert(last_match_pos < LZ4_OPT_NUM + TRAILING_LITERALS);1462best_mlen = opt[last_match_pos].mlen;1463best_off = opt[last_match_pos].off;1464cur = last_match_pos - best_mlen;1465
1466encode: /* cur, last_match_pos, best_mlen, best_off must be set */1467assert(cur < LZ4_OPT_NUM);1468assert(last_match_pos >= 1); /* == 1 when only one candidate */1469DEBUGLOG(6, "reverse traversal, looking for shortest path (last_match_pos=%i)", last_match_pos);1470{ int candidate_pos = cur;1471int selected_matchLength = best_mlen;1472int selected_offset = best_off;1473while (1) { /* from end to beginning */1474int const next_matchLength = opt[candidate_pos].mlen; /* can be 1, means literal */1475int const next_offset = opt[candidate_pos].off;1476DEBUGLOG(7, "pos %i: sequence length %i", candidate_pos, selected_matchLength);1477opt[candidate_pos].mlen = selected_matchLength;1478opt[candidate_pos].off = selected_offset;1479selected_matchLength = next_matchLength;1480selected_offset = next_offset;1481if (next_matchLength > candidate_pos) break; /* last match elected, first match to encode */1482assert(next_matchLength > 0); /* can be 1, means literal */1483candidate_pos -= next_matchLength;1484} }1485
1486/* encode all recorded sequences in order */1487{ int rPos = 0; /* relative position (to ip) */1488while (rPos < last_match_pos) {1489int const ml = opt[rPos].mlen;1490int const offset = opt[rPos].off;1491if (ml == 1) { ip++; rPos++; continue; } /* literal; note: can end up with several literals, in which case, skip them */1492rPos += ml;1493assert(ml >= MINMATCH);1494assert((offset >= 1) && (offset <= LZ4_DISTANCE_MAX));1495opSaved = op;1496if ( LZ4HC_encodeSequence(UPDATABLE(ip, op, anchor), ml, ip - offset, limit, oend) ) /* updates ip, op and anchor */1497goto _dest_overflow;1498} }1499} /* while (ip <= mflimit) */1500
1501_last_literals:1502/* Encode Last Literals */1503{ size_t lastRunSize = (size_t)(iend - anchor); /* literals */1504size_t litLength = (lastRunSize + 255 - RUN_MASK) / 255;1505size_t const totalSize = 1 + litLength + lastRunSize;1506if (limit == fillOutput) oend += LASTLITERALS; /* restore correct value */1507if (limit && (op + totalSize > oend)) {1508if (limit == limitedOutput) return 0; /* Check output limit */1509/* adapt lastRunSize to fill 'dst' */1510lastRunSize = (size_t)(oend - op) - 1;1511litLength = (lastRunSize + 255 - RUN_MASK) / 255;1512lastRunSize -= litLength;1513}1514ip = anchor + lastRunSize;1515
1516if (lastRunSize >= RUN_MASK) {1517size_t accumulator = lastRunSize - RUN_MASK;1518*op++ = (RUN_MASK << ML_BITS);1519for(; accumulator >= 255 ; accumulator -= 255) *op++ = 255;1520*op++ = (BYTE) accumulator;1521} else {1522*op++ = (BYTE)(lastRunSize << ML_BITS);1523}1524memcpy(op, anchor, lastRunSize);1525op += lastRunSize;1526}1527
1528/* End */1529*srcSizePtr = (int) (((const char*)ip) - source);1530return (int) ((char*)op-dst);1531
1532_dest_overflow:1533if (limit == fillOutput) {1534op = opSaved; /* restore correct out pointer */1535goto _last_literals;1536}1537return 0;1538}1539