2017-07-24 19:40:59 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
|
|
|
|
#include "ldm.h"
|
|
|
|
|
2017-07-27 22:37:37 +00:00
|
|
|
/**
|
|
|
|
* This function reads the header at the beginning of src and writes
|
|
|
|
* the compressed and decompressed size to compressedSize and
|
|
|
|
* decompressedSize.
|
|
|
|
*
|
|
|
|
* The header consists of 16 bytes: 8 bytes each in little-endian format
|
|
|
|
* of the compressed size and the decompressed size.
|
|
|
|
*/
|
2017-07-24 19:40:59 +00:00
|
|
|
void LDM_readHeader(const void *src, U64 *compressedSize,
|
|
|
|
U64 *decompressedSize) {
|
|
|
|
const BYTE *ip = (const BYTE *)src;
|
|
|
|
*compressedSize = MEM_readLE64(ip);
|
2017-07-27 22:37:37 +00:00
|
|
|
*decompressedSize = MEM_readLE64(ip + 8);
|
2017-07-24 19:40:59 +00:00
|
|
|
}
|
|
|
|
|
2017-07-27 22:37:37 +00:00
|
|
|
/**
|
|
|
|
* Writes the 16-byte header (8-bytes each of the compressedSize and
|
|
|
|
* decompressedSize in little-endian format) to memPtr.
|
|
|
|
*/
|
2017-07-24 19:40:59 +00:00
|
|
|
void LDM_writeHeader(void *memPtr, U64 compressedSize,
|
|
|
|
U64 decompressedSize) {
|
2017-07-27 22:37:37 +00:00
|
|
|
MEM_writeLE64(memPtr, compressedSize);
|
|
|
|
MEM_writeLE64((BYTE *)memPtr + 8, decompressedSize);
|
2017-07-24 19:40:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct LDM_DCtx {
|
|
|
|
size_t compressedSize;
|
|
|
|
size_t maxDecompressedSize;
|
|
|
|
|
|
|
|
const BYTE *ibase; /* Base of input */
|
|
|
|
const BYTE *ip; /* Current input position */
|
|
|
|
const BYTE *iend; /* End of source */
|
|
|
|
|
|
|
|
const BYTE *obase; /* Base of output */
|
|
|
|
BYTE *op; /* Current output position */
|
|
|
|
const BYTE *oend; /* End of output */
|
|
|
|
};
|
|
|
|
|
|
|
|
void LDM_initializeDCtx(LDM_DCtx *dctx,
|
|
|
|
const void *src, size_t compressedSize,
|
|
|
|
void *dst, size_t maxDecompressedSize) {
|
|
|
|
dctx->compressedSize = compressedSize;
|
|
|
|
dctx->maxDecompressedSize = maxDecompressedSize;
|
|
|
|
|
|
|
|
dctx->ibase = src;
|
|
|
|
dctx->ip = (const BYTE *)src;
|
|
|
|
dctx->iend = dctx->ip + dctx->compressedSize;
|
|
|
|
dctx->op = dst;
|
|
|
|
dctx->oend = dctx->op + dctx->maxDecompressedSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t LDM_decompress(const void *src, size_t compressedSize,
|
|
|
|
void *dst, size_t maxDecompressedSize) {
|
|
|
|
|
|
|
|
LDM_DCtx dctx;
|
|
|
|
LDM_initializeDCtx(&dctx, src, compressedSize, dst, maxDecompressedSize);
|
|
|
|
|
|
|
|
while (dctx.ip < dctx.iend) {
|
|
|
|
BYTE *cpy;
|
|
|
|
const BYTE *match;
|
|
|
|
size_t length, offset;
|
|
|
|
|
|
|
|
/* Get the literal length. */
|
|
|
|
const unsigned token = *(dctx.ip)++;
|
|
|
|
if ((length = (token >> ML_BITS)) == RUN_MASK) {
|
|
|
|
unsigned s;
|
|
|
|
do {
|
|
|
|
s = *(dctx.ip)++;
|
|
|
|
length += s;
|
|
|
|
} while (s == 255);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy the literals. */
|
|
|
|
cpy = dctx.op + length;
|
|
|
|
memcpy(dctx.op, dctx.ip, length);
|
|
|
|
dctx.ip += length;
|
|
|
|
dctx.op = cpy;
|
|
|
|
|
2017-07-26 01:13:27 +00:00
|
|
|
//TODO: dynamic offset size?
|
|
|
|
/* Encode the offset. */
|
2017-07-24 19:40:59 +00:00
|
|
|
offset = MEM_read32(dctx.ip);
|
|
|
|
dctx.ip += LDM_OFFSET_SIZE;
|
|
|
|
match = dctx.op - offset;
|
|
|
|
|
|
|
|
/* Get the match length. */
|
|
|
|
length = token & ML_MASK;
|
|
|
|
if (length == ML_MASK) {
|
|
|
|
unsigned s;
|
|
|
|
do {
|
|
|
|
s = *(dctx.ip)++;
|
|
|
|
length += s;
|
|
|
|
} while (s == 255);
|
|
|
|
}
|
|
|
|
length += LDM_MIN_MATCH_LENGTH;
|
|
|
|
|
|
|
|
/* Copy match. */
|
|
|
|
cpy = dctx.op + length;
|
|
|
|
|
2017-07-26 01:13:27 +00:00
|
|
|
// TODO: this can be made more efficient.
|
2017-07-24 19:40:59 +00:00
|
|
|
while (match < cpy - offset && dctx.op < dctx.oend) {
|
|
|
|
*(dctx.op)++ = *match++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return dctx.op - (BYTE *)dst;
|
|
|
|
}
|