Add decompression routines

This commit is contained in:
Michael Theall 2017-11-12 13:38:06 -06:00 committed by fincs
parent caacf37594
commit 1165b4cb8b
4 changed files with 1040 additions and 0 deletions

View File

@ -31,6 +31,7 @@ SOURCES := source \
source/services \
source/services/soc \
source/applets \
source/util/decompress \
source/util/rbtree \
source/util/utf \
source/system

View File

@ -22,6 +22,7 @@ extern "C" {
#include <3ds/gfx.h>
#include <3ds/console.h>
#include <3ds/env.h>
#include <3ds/util/decompress.h>
#include <3ds/util/utf.h>
#include <3ds/allocator/linear.h>

View File

@ -0,0 +1,203 @@
/**
* @file decompress.h
* @brief Decompression functions.
*/
#pragma once
#include <stdbool.h>
#include <sys/types.h>
/** @brief I/O vector */
typedef struct
{
void *data; ///< I/O buffer
size_t size; ///< Buffer size
} decompressIOVec;
/** @brief Data callback */
typedef ssize_t (*decompressCallback)(void *userdata, void *buffer,
size_t size);
#ifdef __cplusplus
extern "C"
{
#endif
/** @brief Decompression callback for file descriptors
* @param[in] userdata Address of file descriptor
* @param[in] buffer Buffer to write into
* @param[in] size Size to read from file descriptor
* @returns Number of bytes read
*/
ssize_t decompressCallback_FD(void *userdata, void *buffer, size_t size);
/** @brief Decompression callback for stdio FILE*
* @param[in] userdata FILE*
* @param[in] buffer Buffer to write into
* @param[in] size Size to read from file descriptor
* @returns Number of bytes read
*/
ssize_t decompressCallback_Stdio(void *userdata, void *buffer, size_t size);
/** @brief Decompress data
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] callback Data callback (see note)
* @param[in] userdata User data passed to callback (see note)
* @param[in] insize Size of userdata (see note)
* @returns Whether succeeded
*
* @note If callback is null, userdata is a pointer to memory to read from,
* and insize is the size of that data. If callback is not null,
* userdata is passed to callback to fetch more data, and insize is
* unused.
*/
bool decompressV(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t insize);
/** @brief Decompress data
* @param[in] output Output buffer
* @param[in] size Output size limit
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
static inline bool
decompress(void *output, size_t size, decompressCallback callback,
void *userdata, size_t insize)
{
decompressIOVec iov;
iov.data = output;
iov.size = size;
return decompressV(&iov, 1, callback, userdata, insize);
}
/** @brief Decompress LZSS/LZ10
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
bool decompressV_LZSS(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata,
size_t insize);
/** @brief Decompress LZSS/LZ10
* @param[in] output Output buffer
* @param[in] size Output size limit
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
static inline bool
decompress_LZSS(void *output, size_t size, decompressCallback callback,
void *userdata, size_t insize)
{
decompressIOVec iov;
iov.data = output;
iov.size = size;
return decompressV_LZSS(&iov, 1, callback, userdata, insize);
}
/** @brief Decompress LZ11
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
bool decompressV_LZ11(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata,
size_t insize);
/** @brief Decompress LZ11
* @param[in] output Output buffer
* @param[in] size Output size limit
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
static inline bool
decompress_LZ11(void *output, size_t size, decompressCallback callback,
void *userdata, size_t insize)
{
decompressIOVec iov;
iov.data = output;
iov.size = size;
return decompressV_LZ11(&iov, 1, callback, userdata, insize);
}
/** @brief Decompress Huffman
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
bool decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata,
size_t insize);
/** @brief Decompress Huffman
* @param[in] output Output buffer
* @param[in] size Output size limit
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
static inline bool
decompress_Huff(void *output, size_t size, decompressCallback callback,
void *userdata, size_t insize)
{
decompressIOVec iov;
iov.data = output;
iov.size = size;
return decompressV_Huff(&iov, 1, callback, userdata, insize);
}
/** @brief Decompress run-length encoding
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
bool decompressV_RLE(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata,
size_t insize);
/** @brief Decompress run-length encoding
* @param[in] output Output buffer
* @param[in] size Output size limit
* @param[in] callback Data callback (see decompressV())
* @param[in] userdata User data passed to callback (see decompressV())
* @param[in] insize Size of userdata (see decompressV())
* @returns Whether succeeded
*/
static inline bool
decompress_RLE(void *output, size_t size, decompressCallback callback,
void *userdata, size_t insize)
{
decompressIOVec iov;
iov.data = output;
iov.size = size;
return decompressV_RLE(&iov, 1, callback, userdata, insize);
}
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,835 @@
/** @file decompress.c
* @brief Decompression routines
*/
#include <3ds/util/decompress.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define BUFFERSIZE 4096
/** @brief Buffer */
typedef struct buffer_t
{
uint8_t *data; ///< Pointer to buffer
size_t limit; ///< Max buffer size
size_t size; ///< Current buffer size
size_t pos; ///< Buffer position
} buffer_t;
/*! I/O vector iterator */
typedef struct
{
const decompressIOVec *iov; //!< I/O vector
size_t cnt; //!< Number of buffers
size_t num; //!< Current buffer number
size_t pos; //!< Current buffer position
} iov_iter;
/** @brief Initialize buffer object from memory
* @param[in] buffer Decompression buffer object
* @param[in] data Data to buffer
* @param[in] size Data size
*/
static inline void
buffer_memory(buffer_t *buffer, const void *data, size_t size)
{
buffer->data = (void*)data;
buffer->size = size;
buffer->pos = 0;
}
/** @brief Initialize buffer object
* @param[in] buffer Decompression buffer object
* @param[in] size Buffer size limit
* @returns Whether succeeded
*/
static inline bool
buffer_init(buffer_t *buffer, size_t size)
{
buffer->data = (uint8_t*)malloc(size);
if(!buffer->data)
return false;
buffer->limit = size;
buffer->size = 0;
buffer->pos = 0;
return true;
}
/** @brief Destroy buffer object
* @param[in] buffer Decompression buffer object
*/
static inline void
buffer_destroy(buffer_t *buffer)
{
free(buffer->data);
}
/** @brief Read from buffer object
* @param[in] buffer Decompression buffer object
* @param[out] dest Output buffer
* @param[in] size Amount to read
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static bool
buffer_read(buffer_t *buffer, void *dest, size_t size,
decompressCallback callback, void *userdata)
{
while(size > 0)
{
// entire request is in our buffer
if(size <= buffer->size - buffer->pos)
{
memcpy(dest, buffer->data + buffer->pos, size);
buffer->pos += size;
return true;
}
// copy partial data
if(buffer->pos != buffer->size)
{
memcpy(dest, buffer->data + buffer->pos, buffer->size - buffer->pos);
dest = (uint8_t*)dest + (buffer->size - buffer->pos);
size -= buffer->size - buffer->pos;
assert(size != 0);
}
if(!callback)
return false;
// fetch some more data
buffer->size = buffer->pos = 0;
ssize_t rc = callback(userdata, buffer->data, buffer->limit);
if(rc <= 0)
return false;
buffer->size = rc;
}
return true;
}
/** @brief Read a byte from a buffer object
* @param[in] buffer Decompression buffer object
* @param[out] dest Output buffer
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static inline bool
buffer_get(buffer_t *buffer, uint8_t *dest, decompressCallback callback,
void *userdata)
{
// fast-path; just read the byte if we have it
if(buffer->pos < buffer->size)
{
*dest = buffer->data[buffer->pos++];
return true;
}
// grab the byte with read-ahead
return buffer_read(buffer, dest, sizeof(*dest), callback, userdata);
}
/*! Create I/O vector iterator
* @param[in] iov I/O vector
* @param[in] iovcnt Number of buffers
* @returns I/O vector iterator
*/
static inline iov_iter
iov_begin(const decompressIOVec *iov, size_t iovcnt)
{
iov_iter it;
it.iov = iov;
it.cnt = iovcnt;
it.num = 0;
it.pos = 0;
return it;
}
/*! Get I/O vector total size
* @param[in] iov I/O vector
* @param[in] iovcnt Number of buffers
* @returns Total buffer size
*/
static inline size_t
iov_size(const decompressIOVec *iov, size_t iovcnt)
{
size_t size = 0;
for(size_t i = 0; i < iovcnt; ++i)
{
assert(SIZE_MAX - size >= iov[i].size);
size += iov[i].size;
}
return size;
}
/*! Get address for current iterator position
* @param[in] it I/O vector iterator
* @returns address for current iterator position
*/
static inline uint8_t*
iov_addr(const iov_iter *it)
{
assert(it->num < it->cnt);
assert(it->pos < it->iov[it->num].size);
return (uint8_t*)it->iov[it->num].data + it->pos;
}
/*! Increment iterator by one position
* @param[in] it Iterator to increment
*/
static inline void
iov_increment(iov_iter *it)
{
assert(it->num < it->cnt);
assert(it->pos < it->iov[it->num].size);
++it->pos;
if(it->pos == it->iov[it->num].size)
{
// advance to next buffer
it->pos = 0;
++it->num;
}
}
/*! Increment iterator by size
* @param[in] it Iterator to increment
* @param[in] size Size to increment
*/
static inline void
iov_add(iov_iter *it, size_t size)
{
while(true)
{
assert(it->num <= it->cnt);
assert(it->iov[it->num].size > it->pos);
if(it->iov[it->num].size - it->pos > size)
{
// position is within current buffer
it->pos += size;
return;
}
// advance to next buffer
size -= it->iov[it->num].size - it->pos;
++it->num;
it->pos = 0;
}
}
/*! Decrement iterator by size
* @param[in] it Iterator to decrement
* @param[in] size Size to decrement
*/
static inline void
iov_sub(iov_iter *it, size_t size)
{
while(true)
{
if(it->pos >= size)
{
// position is within current buffer
it->pos -= size;
return;
}
// move to previous buffer
size -= it->pos;
assert(it->num > 0);
--it->num;
it->pos = it->iov[it->num].size;
}
}
static bool
iov_read(buffer_t *buffer, iov_iter *out, size_t size,
decompressCallback callback, void *userdata)
{
while(size > 0)
{
assert(out->num < out->cnt);
assert(out->pos < out->iov[out->num].size);
size_t bytes = out->iov[out->num].size - out->pos;
if(size < bytes)
bytes = size;
if(!buffer_read(buffer, iov_addr(out), bytes, callback, userdata))
return false;
size -= bytes;
iov_add(out, bytes);
}
return true;
}
static void
iov_memmove(iov_iter *out, iov_iter *in, size_t size)
{
while(size > 0)
{
assert(out->num < out->cnt);
assert(out->pos < out->iov[out->num].size);
assert(in->num < in->cnt);
assert(in->pos < in->iov[in->num].size);
size_t bytes;
uint8_t *outbuf = iov_addr(out);
uint8_t *inbuf = iov_addr(in);
if(out->iov[out->num].size - out->pos < in->iov[in->num].size - in->pos)
bytes = out->iov[out->num].size - out->pos;
else
bytes = in->iov[in->num].size - in->pos;
if(size < bytes)
bytes = size;
size -= bytes;
iov_add(out, bytes);
iov_add(in, bytes);
while(bytes-- > 0)
*outbuf++ = *inbuf++;
}
}
static void
iov_memset(iov_iter *out, char val, size_t size)
{
while(size > 0)
{
assert(out->num < out->cnt);
assert(out->pos < out->iov[out->num].size);
size_t bytes = out->iov[out->num].size - out->pos;
if(size < bytes)
bytes = size;
memset(iov_addr(out), val, bytes);
size -= bytes;
iov_add(out, bytes);
}
}
/** @brief Decompress LZSS/LZ10
* @param[in] buffer Decompression buffer object
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] size Output size limit
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static bool
decompress_lzss(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
size_t size, decompressCallback callback, void *userdata)
{
iov_iter out = iov_begin(iov, iovcnt);
uint8_t flags = 0;
uint8_t mask = 0;
unsigned int len;
unsigned int disp;
while(size > 0)
{
if(mask == 0)
{
// read in the flags data
// from bit 7 to bit 0:
// 0: raw byte
// 1: compressed block
if(!buffer_get(buffer, &flags, callback, userdata))
return false;
mask = 0x80;
}
if(flags & mask) // compressed block
{
uint8_t displen[2];
if(!buffer_get(buffer, &displen[0], callback, userdata)
|| !buffer_get(buffer, &displen[1], callback, userdata))
return false;
// disp: displacement
// len: length
len = ((displen[0] & 0xF0) >> 4) + 3;
disp = displen[0] & 0x0F;
disp = disp << 8 | displen[1];
if(len > size)
len = size;
size -= len;
iov_iter in = out;
iov_sub(&in, disp+1);
iov_memmove(&out, &in, len);
}
else // uncompressed block
{
// copy a raw byte from the input to the output
if(!buffer_get(buffer, iov_addr(&out), callback, userdata))
return false;
--size;
iov_increment(&out);
}
mask >>= 1;
}
return true;
}
/** @brief Decompress LZ11
* @param[in] buffer Decompression buffer object
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] size Output size limit
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static bool
decompress_lz11(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
size_t size, decompressCallback callback, void *userdata)
{
iov_iter out = iov_begin(iov, iovcnt);
int i;
uint8_t flags;
while(size > 0)
{
// read in the flags data
// from bit 7 to bit 0, following blocks:
// 0: raw byte
// 1: compressed block
if(!buffer_get(buffer, &flags, callback, userdata))
return false;
for(i = 0; i < 8 && size > 0; i++, flags <<= 1)
{
if(flags & 0x80) // compressed block
{
uint8_t displen[4];
if(!buffer_get(buffer, &displen[0], callback, userdata))
return false;
size_t len; // length
size_t disp; // displacement
size_t pos = 0; // displen position
switch(displen[pos] >> 4)
{
case 0: // extended block
if(!buffer_get(buffer, &displen[1], callback, userdata)
|| !buffer_get(buffer, &displen[2], callback, userdata))
return false;
len = displen[pos++] << 4;
len |= displen[pos] >> 4;
len += 0x11;
break;
case 1: // extra extended block
if(!buffer_get(buffer, &displen[1], callback, userdata)
|| !buffer_get(buffer, &displen[2], callback, userdata)
|| !buffer_get(buffer, &displen[3], callback, userdata))
return false;
len = (displen[pos++] & 0x0F) << 12;
len |= (displen[pos++]) << 4;
len |= displen[pos] >> 4;
len += 0x111;
break;
default: // normal block
if(!buffer_get(buffer, &displen[1], callback, userdata))
return false;
len = (displen[pos] >> 4) + 1;
break;
}
disp = (displen[pos++] & 0x0F) << 8;
disp |= displen[pos];
if(len > size)
len = size;
size -= len;
iov_iter in = out;
iov_sub(&in, disp+1);
iov_memmove(&out, &in, len);
}
else // uncompressed block
{
// copy a raw byte from the input to the output
if(!buffer_get(buffer, iov_addr(&out), callback, userdata))
return false;
--size;
iov_increment(&out);
}
}
}
return true;
}
/** @brief Decompress Huffman
* @param[in] buffer Decompression buffer object
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] size Output size limit
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static bool
decompress_huff(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
size_t size, decompressCallback callback, void *userdata)
{
uint8_t *tree = (uint8_t*)malloc(512);
if(!tree)
return false;
// get tree size
if(!buffer_read(buffer, &tree[0], 1, callback, userdata))
{
free(tree);
return false;
}
// read tree
if(!buffer_read(buffer, &tree[1], (((size_t)tree[0])+1)*2-1, callback, userdata))
{
free(tree);
return false;
}
iov_iter out = iov_begin(iov, iovcnt);
const size_t bits = 8;
uint32_t word = 0; // 32-bits of input bitstream
uint32_t mask = 0; // which bit we are reading
uint32_t dataMask = (1<<bits)-1; // mask to apply to data
size_t node; // node in the huffman tree
size_t child; // child of a node
uint32_t offset; // offset from node to child
// point to the root of the huffman tree
node = 1;
while(size > 0)
{
if(mask == 0) // we exhausted 32 bits
{
// reset the mask
mask = 0x80000000;
// read the next 32 bits
uint8_t wordbuf[4];
if(!buffer_get(buffer, &wordbuf[0], callback, userdata)
|| !buffer_get(buffer, &wordbuf[1], callback, userdata)
|| !buffer_get(buffer, &wordbuf[2], callback, userdata)
|| !buffer_get(buffer, &wordbuf[3], callback, userdata))
{
free(tree);
return false;
}
word = (wordbuf[0] << 0)
| (wordbuf[1] << 8)
| (wordbuf[2] << 16)
| (wordbuf[3] << 24);
}
// read the current node's offset value
offset = tree[node] & 0x1F;
child = (node & ~1) + offset*2 + 2;
if(word & mask) // we read a 1
{
// point to the "right" child
++child;
if(tree[node] & 0x40) // "right" child is a data node
{
// copy the child node into the output buffer and apply mask
*iov_addr(&out) = tree[child] & dataMask;
iov_increment(&out);
--size;
// start over at the root node
node = 1;
}
else // traverse to the "right" child
node = child;
}
else // we read a 0
{
// pointed to the "left" child
if(tree[node] & 0x80) // "left" child is a data node
{
// copy the child node into the output buffer and apply mask
*iov_addr(&out) = tree[child] & dataMask;
iov_increment(&out);
--size;
// start over at the root node
node = 1;
}
else // traverse to the "left" child
node = child;
}
// shift to read next bit (read bit 31 to bit 0)
mask >>= 1;
}
free(tree);
return true;
}
/** @brief Decompress Run-length encoding
* @param[in] buffer Decompression buffer object
* @param[in] iov Output vector
* @param[in] iovcnt Number of buffers
* @param[in] size Output size limit
* @param[in] callback Data callback
* @param[in] userdata User data passed to callback
* @returns Whether succeeded
*/
static bool
decompress_rle(buffer_t *buffer, const decompressIOVec *iov, size_t iovcnt,
size_t size, decompressCallback callback, void *userdata)
{
iov_iter out = iov_begin(iov, iovcnt);
uint8_t byte;
size_t len;
while(size > 0)
{
// read in the data header
if(!buffer_get(buffer, &byte, callback, userdata))
return false;
if(byte & 0x80) // compressed block
{
// read the length of the run
len = (byte & 0x7F) + 3;
if(len > size)
len = size;
size -= len;
// read in the byte used for the run
if(!buffer_get(buffer, &byte, callback, userdata))
return false;
// for len, copy byte into output
iov_memset(&out, byte, len);
}
else // uncompressed block
{
// read the length of uncompressed bytes
len = (byte & 0x7F) + 1;
if(len > size)
len = size;
size -= len;
// for len, copy from input to output
if(!iov_read(buffer, &out, len, callback, userdata))
return false;
}
}
return true;
}
ssize_t
decompressCallback_FD(void *userdata, void *buffer, size_t size)
{
int fd = *(int*)userdata;
return read(fd, buffer, size);
}
ssize_t
decompressCallback_Stdio(void *userdata, void *buffer, size_t size)
{
FILE *fp = (FILE*)userdata;
return fread(buffer, 1, size, fp);
}
bool
decompressV(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t usersize)
{
if(iovcnt == 0)
return false;
buffer_t buffer;
if(!callback)
buffer_memory(&buffer, userdata, usersize);
else if(!buffer_init(&buffer, BUFFERSIZE))
return false;
uint8_t header[8];
if(!buffer_read(&buffer, header, 4, callback, userdata))
{
if(callback)
buffer_destroy(&buffer);
return false;
}
uint8_t type = header[0];
size_t size = (header[1] << 0)
| (header[2] << 8)
| (header[3] << 16);
if(type & 0x80)
{
type &= ~0x80;
if(!buffer_read(&buffer, &header[4], 4, callback, userdata))
{
if(callback)
buffer_destroy(&buffer);
return false;
}
size |= header[4] << 24;
}
size_t iovsize = iov_size(iov, iovcnt);
if(iovsize < size)
size = iovsize;
bool result = false;
switch(type)
{
case 0x00:
{
iov_iter out = iov_begin(iov, iovcnt);
result = iov_read(&buffer, &out, size, callback, userdata);
break;
}
case 0x10:
result = decompress_lzss(&buffer, iov, iovcnt, size, callback, userdata);
break;
case 0x11:
result = decompress_lz11(&buffer, iov, iovcnt, size, callback, userdata);
break;
case 0x28:
result = decompress_huff(&buffer, iov, iovcnt, size, callback, userdata);
break;
case 0x30:
result = decompress_rle(&buffer, iov, iovcnt, size, callback, userdata);
break;
}
if(callback)
buffer_destroy(&buffer);
return result;
}
bool
decompressV_LZSS(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t usersize)
{
buffer_t buffer;
if(!callback)
buffer_memory(&buffer, userdata, usersize);
else if(!buffer_init(&buffer, BUFFERSIZE))
return false;
size_t size = iov_size(iov, iovcnt);
bool result = decompress_lzss(&buffer, iov, iovcnt, size, callback, userdata);
if(callback)
buffer_destroy(&buffer);
return result;
}
bool
decompressV_LZ11(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t usersize)
{
buffer_t buffer;
if(!callback)
buffer_memory(&buffer, userdata, usersize);
else if(!buffer_init(&buffer, BUFFERSIZE))
return false;
size_t size = iov_size(iov, iovcnt);
bool result = decompress_lz11(&buffer, iov, iovcnt, size, callback, userdata);
if(callback)
buffer_destroy(&buffer);
return result;
}
bool
decompressV_Huff(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t usersize)
{
buffer_t buffer;
if(!callback)
buffer_memory(&buffer, userdata, usersize);
else if(!buffer_init(&buffer, BUFFERSIZE))
return false;
size_t size = iov_size(iov, iovcnt);
bool result = decompress_huff(&buffer, iov, iovcnt, size, callback, userdata);
if(callback)
buffer_destroy(&buffer);
return result;
}
bool
decompressV_RLE(const decompressIOVec *iov, size_t iovcnt,
decompressCallback callback, void *userdata, size_t usersize)
{
buffer_t buffer;
if(!callback)
buffer_memory(&buffer, userdata, usersize);
else if(!buffer_init(&buffer, BUFFERSIZE))
return false;
size_t size = iov_size(iov, iovcnt);
bool result = decompress_rle(&buffer, iov, iovcnt, size, callback, userdata);
if(callback)
buffer_destroy(&buffer);
return result;
}