ref: 7d02e382d314d5bdde7978ccb7a64ea9201d03db
dir: /lzcompress.c/
#include <assert.h> #include <stdlib.h> #include <string.h> #include "ficl.h" static int ficlLzCompareWindow(const unsigned char *window, const unsigned char *buffer, int *offset, unsigned char *next, int windowSize, int bufferSize) { const unsigned char *windowEnd; const unsigned char *bufferEnd; int longest; unsigned char bufferFirst; const unsigned char *windowTrace; longest = 0; bufferFirst = buffer[0]; *next = bufferFirst; /* ** we can't match more than bufferSize-1 characters... ** we need to reserve the last character for the "next", ** and this also prevents us from returning FICL_LZ_BUFFER_LENGTH ** as the length (which won't work, max we can store is FICL_LZ_BUFFER_LENGTH - 1) */ bufferSize--; windowEnd = window + windowSize; bufferEnd = buffer + bufferSize; for (windowTrace = window; windowTrace < windowEnd; windowTrace++) { const unsigned char *bufferTrace; const unsigned char *windowTrace2; int length; if (*windowTrace != bufferFirst) continue; bufferTrace = buffer; for (windowTrace2 = windowTrace; (windowTrace2 < windowEnd) && (bufferTrace < bufferEnd) && (*windowTrace2 == *bufferTrace); windowTrace2++, bufferTrace++) { } length = windowTrace2 - windowTrace; if ((length > longest) && (length >= FICL_LZ_MINIMUM_USEFUL_MATCH)) { *offset = windowTrace - window; longest = length; *next = *bufferTrace; } } return longest; } void ficlLzEncodeHeaderField(unsigned char *data, unsigned int input, int *byteOffset) { int i; if (input <= 252) data[(*byteOffset)++] = (unsigned char)input; else { unsigned char id; int length; int inputPosition; int bitsOffset; if (input <= 65536) { id = 253; length = 2; } else { id = 254; length = 4; } input = ficlNetworkUnsigned32(input); inputPosition = (sizeof(uint32_t) * 8) - (length * 8); bitsOffset; data[(*byteOffset)++] = (unsigned char)id; bitsOffset = *byteOffset * 8; (*byteOffset) += length; for (i = 0; i < (length * 8); i++) ficlBitSet(data, bitsOffset++, ficlBitGet((unsigned char *)&input, inputPosition++)); } } int ficlLzCompress(const char *uncompressed, size_t uncompressedSize, unsigned char **compressed_p, size_t *compressedSize_p) { unsigned char *compressed; const unsigned char *window; const unsigned char *buffer; int outputPosition; int remaining; int windowSize; int headerLength; unsigned char headerBuffer[10]; int compressedSize; int totalSize; *compressed_p = NULL; compressed = (unsigned char *)calloc(((uncompressedSize * 5) / 4) + 10, 1); if (compressed == NULL) return -1; window = buffer = (const unsigned char*)uncompressed; outputPosition = 0; remaining = uncompressedSize; windowSize = 0; while (remaining > 0) { int bufferSize = FICL_MIN(remaining, FICL_LZ_BUFFER_SIZE); int useWindowSize = FICL_MIN(remaining, windowSize); int offset = 0; int i; unsigned long token; int tokenLength; unsigned char next; int length = ficlLzCompareWindow(window, buffer, &offset, &next, useWindowSize, bufferSize); if (length > 1) { /* phrase token */ assert((length - FICL_LZ_MINIMUM_USEFUL_MATCH) < (1 << FICL_LZ_LENGTH_BITS)); token = (1 << (FICL_LZ_PHRASE_BITS - 1)) | (offset << (FICL_LZ_PHRASE_BITS - FICL_LZ_TYPE_BITS - FICL_LZ_OFFSET_BITS)) | ((length - FICL_LZ_MINIMUM_USEFUL_MATCH) << (FICL_LZ_PHRASE_BITS - FICL_LZ_TYPE_BITS - FICL_LZ_OFFSET_BITS - FICL_LZ_LENGTH_BITS)) | next; tokenLength = FICL_LZ_PHRASE_BITS; } else { token = next; tokenLength = FICL_LZ_SYMBOL_BITS; } token = ficlNetworkUnsigned32(token); for (i = 0; i < tokenLength; i++) { int inputPosition = (sizeof(uint32_t) * 8) - tokenLength + i; ficlBitSet(compressed, outputPosition, ficlBitGet((unsigned char *)&token, inputPosition)); outputPosition++; } length++; buffer += length; if (windowSize == FICL_LZ_WINDOW_SIZE) window += length; else { if ((windowSize + length) < FICL_LZ_WINDOW_SIZE) windowSize += length; else { window += (windowSize + length) - FICL_LZ_WINDOW_SIZE; windowSize = FICL_LZ_WINDOW_SIZE; } } remaining -= length; } headerLength = 0; memset(&headerBuffer, 0, sizeof(headerBuffer)); ficlLzEncodeHeaderField(headerBuffer, outputPosition, &headerLength); ficlLzEncodeHeaderField(headerBuffer, uncompressedSize, &headerLength); /* plug in header */ compressedSize = (((outputPosition - 1) / 8) + 1); totalSize = compressedSize + headerLength; compressed = (unsigned char *)realloc(compressed, totalSize); memmove(compressed + headerLength, compressed, compressedSize); memcpy(compressed, headerBuffer, headerLength); *compressed_p = compressed; *compressedSize_p = totalSize; return 0; }