From 298e7dcb241eb05a06096788c25bccc653a6cba1 Mon Sep 17 00:00:00 2001 From: steve-chamberlin Date: Mon, 9 May 2016 16:18:00 -0700 Subject: [PATCH] Added block mode compression option --- compression.c | 59 +++++++++++++++------ fc8.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++---- fc8.h | 7 ++- 3 files changed, 182 insertions(+), 27 deletions(-) diff --git a/compression.c b/compression.c index 53fa1f6..9ff9d66 100644 --- a/compression.c +++ b/compression.c @@ -1,6 +1,25 @@ /* -* FC8 compression by Steve Chamberlin -* Derived from liblzg by Marcus Geelnard +* FC8 compression by Steve Chamberlin, 2016 +* Some concepts and code derived from liblzg by Marcus Geelnard, 2010 +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would +* be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not +* be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. */ #include @@ -61,12 +80,20 @@ const uint16_t _FC8_LENGTH_QUANT_LUT[257] = { 256 /* 256 */ }; -uint32_t GetDecodedSize(const uint8_t *in) +uint32_t GetUInt32(const uint8_t *in) { - return ((uint32_t)in[FC8_DECODED_SIZE_OFFSET]) << 24 | - ((uint32_t)in[FC8_DECODED_SIZE_OFFSET+1]) << 16 | - ((uint32_t)in[FC8_DECODED_SIZE_OFFSET+2]) << 8 | - ((uint32_t)in[FC8_DECODED_SIZE_OFFSET+3]); + return ((uint32_t)in[0]) << 24 | + ((uint32_t)in[1]) << 16 | + ((uint32_t)in[2]) << 8 | + ((uint32_t)in[3]); +} + +void SetUInt32(uint8_t *in, uint32_t val) +{ + in[0] = val >> 24; + in[1] = val >> 16; + in[2] = val >> 8; + in[3] = val; } typedef struct { @@ -338,6 +365,12 @@ uint32_t Encode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsi } } + if (literalRunLength) + { + // terminate the final literal run, if any + *pRunLengthByte = literalRunLength-1; + } + // insert EOF *dst++ = 0x40; @@ -352,11 +385,7 @@ uint32_t Encode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsi out[2] = '8'; out[3] = '_'; - /* Decoded buffer size */ - out[4] = insize >> 24; - out[5] = insize >> 16; - out[6] = insize >> 8; - out[7] = insize; + SetUInt32(out + FC8_DECODED_SIZE_OFFSET, insize); /* Return size of compressed buffer */ return compressedSize; @@ -380,7 +409,7 @@ fail: uint32_t Decode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize) { - uint8_t *src, *inEnd, *dst, *outEnd, symbol, symbolType; + uint8_t *src, *dst, symbol, symbolType; uint32_t i, length, offset; /* Does the input buffer at least contain the header? */ @@ -392,14 +421,12 @@ uint32_t Decode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsi return 0; /* Get & check output buffer size */ - if (outsize < GetDecodedSize(in)) + if (outsize < GetUInt32(&in[FC8_DECODED_SIZE_OFFSET])) return 0; /* Initialize the byte streams */ src = (unsigned char *)in; - inEnd = ((unsigned char *)in) + insize; dst = out; - outEnd = out + outsize; /* Skip header information */ src += FC8_HEADER_SIZE; diff --git a/fc8.c b/fc8.c index 4e0f9ff..6155c67 100644 --- a/fc8.c +++ b/fc8.c @@ -1,6 +1,25 @@ /* -* FC8 compression by Steve Chamberlin -* Derived from liblzg by Marcus Geelnard +* FC8 compression by Steve Chamberlin, 2016 +* Some concepts and code derived from liblzg by Marcus Geelnard, 2010 +* +* This software is provided 'as-is', without any express or implied +* warranty. In no event will the authors be held liable for any damages +* arising from the use of this software. +* +* Permission is granted to anyone to use this software for any purpose, +* including commercial applications, and to alter it and redistribute it +* freely, subject to the following restrictions: +* +* 1. The origin of this software must not be misrepresented; you must not +* claim that you wrote the original software. If you use this software +* in a product, an acknowledgment in the product documentation would +* be appreciated but is not required. +* +* 2. Altered source versions must be plainly marked as such, and must not +* be misrepresented as being the original software. +* +* 3. This notice may not be removed or altered from any source +* distribution. */ #include @@ -18,6 +37,7 @@ void ShowUsage(char *prgName) { fprintf(stderr, "Usage: %s [options] infile [outfile]\n", prgName); fprintf(stderr, "Options:\n"); + fprintf(stderr, " -b:NNN compress the input as multiple independent blocks of size NNN bytes\n"); fprintf(stderr, " -d decompress\n"); fprintf(stderr, "\nIf no output file is given, stdout is used for output.\n"); } @@ -31,6 +51,8 @@ int main(int argc, char **argv) uint8_t *inBuf, *outBuf; size_t fileSize; uint8_t decompress = 0; + uint32_t blockSize = 0; + uint32_t i, numBlocks = 0; int arg; // Default arguments @@ -42,6 +64,12 @@ int main(int argc, char **argv) { if (strcmp("-d", argv[arg]) == 0) decompress = 1; + else if (strncmp("-b", argv[arg], 2) == 0) + { + if (argv[arg][2] != ':') + ShowUsage(argv[0]); + blockSize = atoi(&argv[arg][3]); + } else if (!inName) inName = argv[arg]; else if (!outName) @@ -58,6 +86,11 @@ int main(int argc, char **argv) return 0; } + if (decompress && blockSize != 0) + { + fprintf(stderr, "Block size will be read from the input data, -b option ignored\n"); + } + // Read input file inBuf = (unsigned char*) 0; inFile = fopen(inName, "rb"); @@ -95,28 +128,118 @@ int main(int argc, char **argv) if (decompress) { - maxOutSize = GetDecodedSize(inBuf); + // determine blockSize and numBlocks + if (inBuf[0] != 'F' || inBuf[1] != 'C' || inBuf[2] != '8' || (inBuf[3] != '_' && inBuf[3] != 'b')) + { + fprintf(stderr, "Input is not an FC8 compressed file.\n"); + return 0; + } + + maxOutSize = GetUInt32(&inBuf[FC8_DECODED_SIZE_OFFSET]); + + if (inBuf[3] == 'b') + { + blockSize = GetUInt32(&inBuf[FC8_BLOCK_SIZE_OFFSET]); + numBlocks = (maxOutSize + blockSize - 1) / blockSize; + fprintf(stderr, "Decompressing block format with %d byte blocks\n", blockSize); + } + else + { + blockSize = maxOutSize; + numBlocks = 1; + } } else { - // Guess maximum size of compressed data in worst case + // Estimate the maximum size of compressed data in worst case maxOutSize = inSize * 2; + + if (blockSize != 0) + { + numBlocks = (inSize + blockSize - 1) / blockSize; + } + else + { + blockSize = inSize; + numBlocks = 1; + } } // Allocate memory for the output data outBuf = (unsigned char*) malloc(maxOutSize); if (outBuf) { - // Compress/Decompress - if (decompress) - outSize = Decode(inBuf, inSize, outBuf, maxOutSize); - else - outSize = Encode(inBuf, inSize, outBuf, maxOutSize); + // If compressing block format, add the block header + if (!decompress && blockSize != inSize) + { + // Set header data + outBuf[0] = 'F'; + outBuf[1] = 'C'; + outBuf[2] = '8'; + outBuf[3] = 'b'; + // Uncompressed file size + SetUInt32(outBuf + FC8_DECODED_SIZE_OFFSET, inSize); + + // block size + SetUInt32(outBuf + FC8_BLOCK_SIZE_OFFSET, blockSize); + + // skip block header + outSize += FC8_BLOCK_HEADER_SIZE; + + // skip block offsets + outSize += numBlocks * sizeof(uint32_t); + } + + // process all the blocks + for (i=0; i