pollymc/depends/lzma/wrapper/lzma_header.c

135 lines
3.3 KiB
C

/*
* Written in 2009 by Lloyd Hilaiel
*
* License
*
* All the cruft you find here is public domain. You don't have to credit
* anyone to use this code, but my personal request is that you mention
* Igor Pavlov for his hard, high quality work.
*/
/* XXX: clean this up, it's mostly lifted from pavel */
#include "lzma_header.h"
#include <string.h>
#include <assert.h>
#define ELZMA_LZMA_HEADER_SIZE 13
#define ELZMA_LZMA_PROPSBUF_SIZE 5
/****************
Header parsing
****************/
#ifndef UINT64_MAX
#define UINT64_MAX ((unsigned long long)-1)
#endif
/* Parse the properties byte */
static char lzmadec_header_properties(unsigned char *pb, unsigned char *lp, unsigned char *lc,
const unsigned char c)
{
/* pb, lp and lc are encoded into a single byte. */
if (c > (9 * 5 * 5))
return -1;
*pb = c / (9 * 5); /* 0 <= pb <= 4 */
*lp = (c % (9 * 5)) / 9; /* 0 <= lp <= 4 */
*lc = c % 9; /* 0 <= lc <= 8 */
assert(*pb < 5 && *lp < 5 && *lc < 9);
return 0;
}
/* Parse the dictionary size (4 bytes, little endian) */
static char lzmadec_header_dictionary(unsigned int *size, const unsigned char *buffer)
{
unsigned int i;
*size = 0;
for (i = 0; i < 4; i++)
*size += (unsigned int)(*buffer++) << (i * 8);
/* The dictionary size is limited to 256 MiB (checked from
* LZMA SDK 4.30) */
if (*size > (1 << 28))
return -1;
return 0;
}
/* Parse the uncompressed size field (8 bytes, little endian) */
static void lzmadec_header_uncompressed(unsigned long long *size, unsigned char *is_streamed,
const unsigned char *buffer)
{
unsigned int i;
/* Streamed files have all 64 bits set in the size field.
* We don't know the uncompressed size beforehand. */
*is_streamed = 1; /* Assume streamed. */
*size = 0;
for (i = 0; i < 8; i++)
{
*size += (unsigned long long)buffer[i] << (i * 8);
if (buffer[i] != 255)
*is_streamed = 0;
}
assert((*is_streamed == 1 && *size == UINT64_MAX) ||
(*is_streamed == 0 && *size < UINT64_MAX));
}
static void initLzmaHeader(struct elzma_file_header *hdr)
{
memset((void *)hdr, 0, sizeof(struct elzma_file_header));
}
static int parseLzmaHeader(const unsigned char *hdrBuf, struct elzma_file_header *hdr)
{
if (lzmadec_header_properties(&(hdr->pb), &(hdr->lp), &(hdr->lc), *hdrBuf) ||
lzmadec_header_dictionary(&(hdr->dictSize), hdrBuf + 1))
{
return 1;
}
lzmadec_header_uncompressed(&(hdr->uncompressedSize), &(hdr->isStreamed), hdrBuf + 5);
return 0;
}
static int serializeLzmaHeader(unsigned char *hdrBuf, const struct elzma_file_header *hdr)
{
unsigned int i;
memset((void *)hdrBuf, 0, ELZMA_LZMA_HEADER_SIZE);
/* encode lc, pb, and lp */
*hdrBuf++ = hdr->lc + (hdr->pb * 45) + (hdr->lp * 45 * 9);
/* encode dictionary size */
for (i = 0; i < 4; i++)
{
*(hdrBuf++) = (unsigned char)(hdr->dictSize >> (i * 8));
}
/* encode uncompressed size */
for (i = 0; i < 8; i++)
{
if (hdr->isStreamed)
{
*(hdrBuf++) = 0xff;
}
else
{
*(hdrBuf++) = (unsigned char)(hdr->uncompressedSize >> (i * 8));
}
}
return 0;
}
void initializeLZMAFormatHandler(struct elzma_format_handler *hand)
{
hand->header_size = ELZMA_LZMA_HEADER_SIZE;
hand->init_header = initLzmaHeader;
hand->parse_header = parseLzmaHeader;
hand->serialize_header = serializeLzmaHeader;
hand->footer_size = 0;
hand->serialize_footer = NULL;
}