| /* |
| LZ4 Encoder - Part of LZ4 compression algorithm |
| Copyright (C) 2011-2013, Yann Collet. |
| BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the following disclaimer |
| in the documentation and/or other materials provided with the |
| distribution. |
| |
| THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| You can contact the author at : |
| - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html |
| - LZ4 source repository : http://code.google.com/p/lz4/ |
| */ |
| |
| /* lz4_encoder.h must be included into lz4.c |
| The objective of this file is to create a single LZ4 compression function source |
| which will be instanciated multiple times with minor variations |
| depending on a set of #define. |
| */ |
| |
| |
| |
| //**************************** |
| // Check required defines |
| //**************************** |
| |
| #ifndef FUNCTION_NAME |
| # error "FUNTION_NAME is not defined" |
| #endif |
| |
| |
| //**************************** |
| // Local definitions |
| //**************************** |
| |
| #ifdef COMPRESS_64K |
| # define HASHLOG (MEMORY_USAGE-1) |
| # define CURRENT_H_TYPE U16 |
| # define CURRENTBASE(base) const BYTE* const base = ip |
| #else |
| # define HASHLOG (MEMORY_USAGE-2) |
| # define CURRENT_H_TYPE HTYPE |
| # define CURRENTBASE(base) INITBASE(base) |
| #endif |
| |
| #define HASHTABLE_NBCELLS (1U<<HASHLOG) |
| #define LZ4_HASH(i) (((i) * 2654435761U) >> ((MINMATCH*8)-HASHLOG)) |
| #define LZ4_HASHVALUE(p) LZ4_HASH(A32(p)) |
| |
| |
| |
| //**************************** |
| // Function code |
| //**************************** |
| |
| int FUNCTION_NAME( |
| #ifdef USE_HEAPMEMORY |
| void* ctx, |
| #endif |
| const char* source, |
| char* dest, |
| int inputSize |
| #ifdef LIMITED_OUTPUT |
| ,int maxOutputSize |
| #endif |
| ) |
| { |
| #ifdef USE_HEAPMEMORY |
| CURRENT_H_TYPE* HashTable = (CURRENT_H_TYPE*)ctx; |
| #else |
| CURRENT_H_TYPE HashTable[HASHTABLE_NBCELLS] = {0}; |
| #endif |
| |
| const BYTE* ip = (BYTE*) source; |
| CURRENTBASE(base); |
| const BYTE* anchor = ip; |
| const BYTE* const iend = ip + inputSize; |
| const BYTE* const mflimit = iend - MFLIMIT; |
| #define matchlimit (iend - LASTLITERALS) |
| |
| BYTE* op = (BYTE*) dest; |
| #ifdef LIMITED_OUTPUT |
| BYTE* const oend = op + maxOutputSize; |
| #endif |
| |
| int length; |
| const int skipStrength = SKIPSTRENGTH; |
| U32 forwardH; |
| |
| |
| // Init |
| if (inputSize<MINLENGTH) goto _last_literals; |
| #ifdef COMPRESS_64K |
| if (inputSize>=LZ4_64KLIMIT) return 0; // Size too large (not within 64K limit) |
| #endif |
| #ifdef USE_HEAPMEMORY |
| memset((void*)HashTable, 0, HASHTABLESIZE); |
| #endif |
| |
| // First Byte |
| HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base); |
| ip++; forwardH = LZ4_HASHVALUE(ip); |
| |
| // Main Loop |
| for ( ; ; ) |
| { |
| int findMatchAttempts = (1U << skipStrength) + 3; |
| const BYTE* forwardIp = ip; |
| const BYTE* ref; |
| BYTE* token; |
| |
| // Find a match |
| do { |
| U32 h = forwardH; |
| int step = findMatchAttempts++ >> skipStrength; |
| ip = forwardIp; |
| forwardIp = ip + step; |
| |
| if unlikely(forwardIp > mflimit) { goto _last_literals; } |
| |
| forwardH = LZ4_HASHVALUE(forwardIp); |
| ref = base + HashTable[h]; |
| HashTable[h] = (CURRENT_H_TYPE)(ip - base); |
| |
| } while ((ref < ip - MAX_DISTANCE) || (A32(ref) != A32(ip))); |
| |
| // Catch up |
| while ((ip>anchor) && (ref>(BYTE*)source) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; } |
| |
| // Encode Literal length |
| length = (int)(ip - anchor); |
| token = op++; |
| #ifdef LIMITED_OUTPUT |
| if unlikely(op + length + (2 + 1 + LASTLITERALS) + (length>>8) > oend) return 0; // Check output limit |
| #endif |
| if (length>=(int)RUN_MASK) |
| { |
| int len = length-RUN_MASK; |
| *token=(RUN_MASK<<ML_BITS); |
| for(; len >= 255 ; len-=255) *op++ = 255; |
| *op++ = (BYTE)len; |
| } |
| else *token = (BYTE)(length<<ML_BITS); |
| |
| // Copy Literals |
| LZ4_BLINDCOPY(anchor, op, length); |
| |
| _next_match: |
| // Encode Offset |
| LZ4_WRITE_LITTLEENDIAN_16(op,(U16)(ip-ref)); |
| |
| // Start Counting |
| ip+=MINMATCH; ref+=MINMATCH; // MinMatch already verified |
| anchor = ip; |
| while likely(ip<matchlimit-(STEPSIZE-1)) |
| { |
| size_t diff = AARCH(ref) ^ AARCH(ip); |
| if (!diff) { ip+=STEPSIZE; ref+=STEPSIZE; continue; } |
| ip += LZ4_NbCommonBytes(diff); |
| goto _endCount; |
| } |
| if (LZ4_ARCH64) if ((ip<(matchlimit-3)) && (A32(ref) == A32(ip))) { ip+=4; ref+=4; } |
| if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; } |
| if ((ip<matchlimit) && (*ref == *ip)) ip++; |
| _endCount: |
| |
| // Encode MatchLength |
| length = (int)(ip - anchor); |
| #ifdef LIMITED_OUTPUT |
| if unlikely(op + (1 + LASTLITERALS) + (length>>8) > oend) return 0; // Check output limit |
| #endif |
| if (length>=(int)ML_MASK) |
| { |
| *token += ML_MASK; |
| length -= ML_MASK; |
| for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; } |
| if (length >= 255) { length-=255; *op++ = 255; } |
| *op++ = (BYTE)length; |
| } |
| else *token += (BYTE)(length); |
| |
| // Test end of chunk |
| if (ip > mflimit) { anchor = ip; break; } |
| |
| // Fill table |
| HashTable[LZ4_HASHVALUE(ip-2)] = (CURRENT_H_TYPE)(ip - 2 - base); |
| |
| // Test next position |
| ref = base + HashTable[LZ4_HASHVALUE(ip)]; |
| HashTable[LZ4_HASHVALUE(ip)] = (CURRENT_H_TYPE)(ip - base); |
| if ((ref >= ip - MAX_DISTANCE) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; } |
| |
| // Prepare next loop |
| anchor = ip++; |
| forwardH = LZ4_HASHVALUE(ip); |
| } |
| |
| _last_literals: |
| // Encode Last Literals |
| { |
| int lastRun = (int)(iend - anchor); |
| #ifdef LIMITED_OUTPUT |
| if (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) return 0; // Check output limit |
| #endif |
| if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun >= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; } |
| else *op++ = (BYTE)(lastRun<<ML_BITS); |
| memcpy(op, anchor, iend - anchor); |
| op += iend-anchor; |
| } |
| |
| // End |
| return (int) (((char*)op)-dest); |
| } |
| |
| |
| |
| //**************************** |
| // Clean defines |
| //**************************** |
| |
| // Required defines |
| #undef FUNCTION_NAME |
| |
| // Locally Generated |
| #undef HASHLOG |
| #undef HASHTABLE_NBCELLS |
| #undef LZ4_HASH |
| #undef LZ4_HASHVALUE |
| #undef CURRENT_H_TYPE |
| #undef CURRENTBASE |
| |
| // Optional defines |
| #ifdef LIMITED_OUTPUT |
| #undef LIMITED_OUTPUT |
| #endif |
| |
| #ifdef USE_HEAPMEMORY |
| #undef USE_HEAPMEMORY |
| #endif |