Added block mode compression option
This commit is contained in:
parent
54864236e9
commit
298e7dcb24
|
@ -1,6 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* FC8 compression by Steve Chamberlin
|
* FC8 compression by Steve Chamberlin, 2016
|
||||||
* Derived from liblzg by Marcus Geelnard
|
* 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 <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -61,12 +80,20 @@ const uint16_t _FC8_LENGTH_QUANT_LUT[257] = {
|
||||||
256 /* 256 */
|
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 |
|
return ((uint32_t)in[0]) << 24 |
|
||||||
((uint32_t)in[FC8_DECODED_SIZE_OFFSET+1]) << 16 |
|
((uint32_t)in[1]) << 16 |
|
||||||
((uint32_t)in[FC8_DECODED_SIZE_OFFSET+2]) << 8 |
|
((uint32_t)in[2]) << 8 |
|
||||||
((uint32_t)in[FC8_DECODED_SIZE_OFFSET+3]);
|
((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 {
|
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
|
// insert EOF
|
||||||
*dst++ = 0x40;
|
*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[2] = '8';
|
||||||
out[3] = '_';
|
out[3] = '_';
|
||||||
|
|
||||||
/* Decoded buffer size */
|
SetUInt32(out + FC8_DECODED_SIZE_OFFSET, insize);
|
||||||
out[4] = insize >> 24;
|
|
||||||
out[5] = insize >> 16;
|
|
||||||
out[6] = insize >> 8;
|
|
||||||
out[7] = insize;
|
|
||||||
|
|
||||||
/* Return size of compressed buffer */
|
/* Return size of compressed buffer */
|
||||||
return compressedSize;
|
return compressedSize;
|
||||||
|
@ -380,7 +409,7 @@ fail:
|
||||||
|
|
||||||
uint32_t Decode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize)
|
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;
|
uint32_t i, length, offset;
|
||||||
|
|
||||||
/* Does the input buffer at least contain the header? */
|
/* 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;
|
return 0;
|
||||||
|
|
||||||
/* Get & check output buffer size */
|
/* Get & check output buffer size */
|
||||||
if (outsize < GetDecodedSize(in))
|
if (outsize < GetUInt32(&in[FC8_DECODED_SIZE_OFFSET]))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
/* Initialize the byte streams */
|
/* Initialize the byte streams */
|
||||||
src = (unsigned char *)in;
|
src = (unsigned char *)in;
|
||||||
inEnd = ((unsigned char *)in) + insize;
|
|
||||||
dst = out;
|
dst = out;
|
||||||
outEnd = out + outsize;
|
|
||||||
|
|
||||||
/* Skip header information */
|
/* Skip header information */
|
||||||
src += FC8_HEADER_SIZE;
|
src += FC8_HEADER_SIZE;
|
||||||
|
|
143
fc8.c
143
fc8.c
|
@ -1,6 +1,25 @@
|
||||||
/*
|
/*
|
||||||
* FC8 compression by Steve Chamberlin
|
* FC8 compression by Steve Chamberlin, 2016
|
||||||
* Derived from liblzg by Marcus Geelnard
|
* 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 <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -18,6 +37,7 @@ void ShowUsage(char *prgName)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Usage: %s [options] infile [outfile]\n", prgName);
|
fprintf(stderr, "Usage: %s [options] infile [outfile]\n", prgName);
|
||||||
fprintf(stderr, "Options:\n");
|
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, " -d decompress\n");
|
||||||
fprintf(stderr, "\nIf no output file is given, stdout is used for output.\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;
|
uint8_t *inBuf, *outBuf;
|
||||||
size_t fileSize;
|
size_t fileSize;
|
||||||
uint8_t decompress = 0;
|
uint8_t decompress = 0;
|
||||||
|
uint32_t blockSize = 0;
|
||||||
|
uint32_t i, numBlocks = 0;
|
||||||
int arg;
|
int arg;
|
||||||
|
|
||||||
// Default arguments
|
// Default arguments
|
||||||
|
@ -42,6 +64,12 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
if (strcmp("-d", argv[arg]) == 0)
|
if (strcmp("-d", argv[arg]) == 0)
|
||||||
decompress = 1;
|
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)
|
else if (!inName)
|
||||||
inName = argv[arg];
|
inName = argv[arg];
|
||||||
else if (!outName)
|
else if (!outName)
|
||||||
|
@ -58,6 +86,11 @@ int main(int argc, char **argv)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (decompress && blockSize != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Block size will be read from the input data, -b option ignored\n");
|
||||||
|
}
|
||||||
|
|
||||||
// Read input file
|
// Read input file
|
||||||
inBuf = (unsigned char*) 0;
|
inBuf = (unsigned char*) 0;
|
||||||
inFile = fopen(inName, "rb");
|
inFile = fopen(inName, "rb");
|
||||||
|
@ -95,28 +128,118 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
if (decompress)
|
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
|
else
|
||||||
{
|
{
|
||||||
// Guess maximum size of compressed data in worst case
|
// Estimate the maximum size of compressed data in worst case
|
||||||
maxOutSize = inSize * 2;
|
maxOutSize = inSize * 2;
|
||||||
|
|
||||||
|
if (blockSize != 0)
|
||||||
|
{
|
||||||
|
numBlocks = (inSize + blockSize - 1) / blockSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
blockSize = inSize;
|
||||||
|
numBlocks = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allocate memory for the output data
|
// Allocate memory for the output data
|
||||||
outBuf = (unsigned char*) malloc(maxOutSize);
|
outBuf = (unsigned char*) malloc(maxOutSize);
|
||||||
if (outBuf)
|
if (outBuf)
|
||||||
{
|
{
|
||||||
// Compress/Decompress
|
// If compressing block format, add the block header
|
||||||
if (decompress)
|
if (!decompress && blockSize != inSize)
|
||||||
outSize = Decode(inBuf, inSize, outBuf, maxOutSize);
|
{
|
||||||
else
|
// Set header data
|
||||||
outSize = Encode(inBuf, inSize, outBuf, maxOutSize);
|
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<numBlocks; i++)
|
||||||
|
{
|
||||||
|
if (decompress)
|
||||||
|
{
|
||||||
|
uint32_t blockOffset = 0, processedBlockSize;
|
||||||
|
|
||||||
|
// decompressing block format?
|
||||||
|
if (blockSize != maxOutSize)
|
||||||
|
blockOffset = GetUInt32(&inBuf[FC8_BLOCK_HEADER_SIZE + sizeof(uint32_t) * i]);
|
||||||
|
|
||||||
|
processedBlockSize = Decode(inBuf + blockOffset, FC8_HEADER_SIZE, outBuf + blockSize * i, maxOutSize - blockSize * i);
|
||||||
|
|
||||||
|
// error?
|
||||||
|
if (processedBlockSize != blockSize)
|
||||||
|
{
|
||||||
|
outSize = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
outSize += processedBlockSize;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t processedBlockSize = Encode(inBuf + blockSize * i, blockSize, outBuf + outSize, maxOutSize - outSize);
|
||||||
|
|
||||||
|
// error?
|
||||||
|
if (!processedBlockSize)
|
||||||
|
{
|
||||||
|
outSize = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// compressing block format?
|
||||||
|
if (blockSize != inSize)
|
||||||
|
{
|
||||||
|
// update the block offset in the block header
|
||||||
|
SetUInt32(&outBuf[FC8_BLOCK_HEADER_SIZE + sizeof(uint32_t) * i], outSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
outSize += processedBlockSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// save result
|
||||||
if (outSize)
|
if (outSize)
|
||||||
{
|
{
|
||||||
if (decompress)
|
if (decompress)
|
||||||
fprintf(stderr, "Decompressed file is %d byte\n", outSize);
|
fprintf(stderr, "Decompressed file is %d bytes\n", outSize);
|
||||||
else
|
else
|
||||||
fprintf(stderr, "Result: %d bytes (%d%% of the original)\n", outSize, (100 * outSize) / inSize);
|
fprintf(stderr, "Result: %d bytes (%d%% of the original)\n", outSize, (100 * outSize) / inSize);
|
||||||
|
|
||||||
|
|
7
fc8.h
7
fc8.h
|
@ -9,10 +9,15 @@
|
||||||
#define FC8_HEADER_SIZE 8
|
#define FC8_HEADER_SIZE 8
|
||||||
#define FC8_DECODED_SIZE_OFFSET 4
|
#define FC8_DECODED_SIZE_OFFSET 4
|
||||||
|
|
||||||
|
// for FC8b block format header
|
||||||
|
#define FC8_BLOCK_HEADER_SIZE 12
|
||||||
|
#define FC8_BLOCK_SIZE_OFFSET 8
|
||||||
|
|
||||||
uint32_t Encode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize);
|
uint32_t Encode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize);
|
||||||
|
|
||||||
uint32_t Decode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize);
|
uint32_t Decode(const uint8_t *in, uint32_t insize, uint8_t *out, uint32_t outsize);
|
||||||
|
|
||||||
uint32_t GetDecodedSize(const uint8_t *in);
|
uint32_t GetUInt32(const uint8_t *in);
|
||||||
|
void SetUInt32(uint8_t *in, uint32_t val);
|
||||||
|
|
||||||
#endif // _FC8_H_
|
#endif // _FC8_H_
|
||||||
|
|
Loading…
Reference in New Issue