ogrebattle64/tools/splat_ext/lib/lhafile/lhafile/lzhlib.c

1412 lines
38 KiB
C

/*
lzhlib - lzh library modules for lhafile
Copyright (c) 2010 Hidekazu Ohnishi.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of the author nor the names of its contributors
may be used to endorse or promote products derived from this
software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "Python.h"
#include "structmember.h"
static char __author__[] =
"The lzhlib python module was written by:\n\
\n\
Hidekazu Ohnishi\n\
";
#ifdef MS_WINDOWS
#define inline __inline
#endif
typedef long long Py_off_t;
#define FILE_BUFFER_SIZE (64*1024)
/* ===================================================================== */
/* Constant definitions. */
typedef enum {
COMPRESS_TYPE_LH0 = 1,
COMPRESS_TYPE_LH5,
COMPRESS_TYPE_LH6,
COMPRESS_TYPE_LH7,
} lzhlib_compress_type;
typedef enum {
ERR_UNEXPECT_EOF = 1,
ERR_OUT_OF_RANGE,
ERR_VALUE_ERROR,
ERR_OUT_OF_MEMORY,
ERR_IO_ERROR,
ERR_BIT_LENGTH_TABLE_ERROR,
ERR_BIT_PATTERN_TABLE_ERROR,
ERR_BIT_LENGTH_SIZE_ERROR,
ERR_DATA_ERROR,
ERR_BUFFER_OVER_FLOW,
} lzhlib_error;
const char *lzhlib_error_msg[] = {
"Unexpehct EOF. It is seemed this file is broken",
"It is seemd the compressed data is too short",
"Input argument error",
"Out of mwmoey",
"I/O error is happend",
"Lzh file is seemed broken",
"Lzh file is seemed broken",
"Lzh file is seemed broken",
"Can't write file",
"Buffer overflow will happened",
};
typedef enum {
BIT_STREAM_ERR_OVERFLOW = 0x01,
BIT_STREAM_ERR_IOERROR = 0x02,
} bit_stream_err_type;
/* ===================================================================== */
/* Structure definitions. */
typedef struct {
PyObject *fp;
PyObject *read_buf;
unsigned char *buf, *end;
unsigned int cache;
int bit;
int remain_bit;
Py_off_t pos;
int eof;
} bit_stream_reader;
typedef struct {
PyObject *fp;
PyObject *write_buf;
unsigned char *start,*buf,*end;
Py_off_t pos;
int crc16;
bit_stream_err_type error;
} bit_stream_writer;
typedef struct {
int len;
unsigned char *s;
} string;
typedef struct{
string *table;
int bitMax;
} bit_length_table;
typedef struct{
int table[510];
int len;
int _freqTable[17];
int _weight[17];
int _startPattern[17];
} bit_pattern_table;
typedef struct{
int bitMax;
int bitlength;
unsigned short blen_code[65536];
bit_length_table _blt;
bit_pattern_table _bpt;
} huffman_decoder;
/* ===================================================================== */
/* crc16 */
const static int _crc16Table[256] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040,
};
static inline int
crc16(unsigned char *data, int len, int crc){
for(; len > 0 ; data++, len--){
crc = (crc >> 8) ^ _crc16Table[(crc ^ *data) & 0xFF];
}
return crc;
}
/* ===================================================================== */
/* lzh decode */
/* STRING OPERATIONS */
static inline void
string_init(string *self, unsigned char*s, int len)
{
self->s = s;
self->len = len;
}
static inline int
string_len(string *self){
return self->len;
}
static inline unsigned char *
string_str(string *self){
return self->s;
}
static inline int
string_get(string *self, int i){
return (int)(self->s[i]);
}
static inline void
string_set(string *self, int i, int c){
self->s[i] = (unsigned char)c;
}
static inline void
string_clear(string *self){
int i;
for(i = 0; i < self->len; i++){
self->s[i] = 0;
}
}
static inline string*
new_string(int len){
string *s;
unsigned char *str;
str = PyMem_Malloc(len * sizeof(unsigned char));
if(str == NULL){
return NULL;
}
s = PyMem_Malloc(sizeof(string));
if(s == NULL){
PyMem_Free(str);
return NULL;
}
string_init(s, str, len);
return s;
}
static inline void
del_string(string *s){
if(s != NULL){
if(s->s != NULL){
PyMem_Free(s->s);
}
PyMem_Free(s);
}
}
/* BITSTREAM OPERATIONS */
static inline int
bit_stream_reader_init_fileio(bit_stream_reader *self, PyObject *file)
{
int error_no = 0;
int i;
unsigned char *buf, *end;
unsigned int cache;
PyObject *read_obj = NULL;
/* Argument check */
if(!file){ error_no = ERR_VALUE_ERROR; goto error;}
/* Read ahead data */
read_obj = PyObject_CallMethod(file, "read", "(i)", FILE_BUFFER_SIZE);
if(!read_obj){ error_no = ERR_VALUE_ERROR; goto error;}
self->fp = file;
self->read_buf = read_obj;
self->bit = 0;
self->pos = 0;
buf = (unsigned char*)PyString_AsString(read_obj);
end = buf + PyString_Size(read_obj);
/* Fill Cache */
cache = 0;
self->remain_bit = 0;
for(i=0; i < sizeof(unsigned int) && buf != end; i++){
cache = (cache << 8) | *buf++;
self->remain_bit += 8;
}
self->buf = buf;
self->end = end;
self->cache = cache;
if(buf == end){
self->eof = 1;
self->cache <<= (8 * sizeof(unsigned int) - self->remain_bit);
}else{
self->remain_bit = 0;
self->eof = 0;
}
return 0;
error:
Py_XDECREF(read_obj);
return error_no;
}
static inline void
bit_stream_reader_close(bit_stream_reader *self)
{
Py_XDECREF(self->read_buf);
self->read_buf = NULL;
}
static inline Py_off_t
bit_stream_reader_pos(bit_stream_reader *self)
{
return self->pos;
}
static inline int
bit_stream_reader_pre_fetch(bit_stream_reader *self, int n)
{
return (int)(self->cache >> (8 * sizeof(int) - n));
}
static inline int
bit_stream_reader_fetch(bit_stream_reader *self, int n)
{
int ret;
if(n > 16 || n <= 0){
if(n == 0){
return 0;
}
return -2;
}
ret = (int)(self->cache >> (8 * sizeof(int) - n));
self->cache <<= n;
self->bit += n;
if(self->eof){
if(self->bit > self->remain_bit){
return -1;
}
}else if(sizeof(unsigned int) * 8 - self->bit <= 16){
self->cache >>= self->bit;
/* if remain data cahce size is under 16 then read ahead */
while(sizeof(unsigned int) * 8 - self->bit <= 16){
if(self->buf == self->end){
PyGILState_STATE state;
PyObject *read_obj = NULL;
state = PyGILState_Ensure();
/* free old buffer */
Py_DECREF(self->read_buf);
self->read_buf = NULL;
/* read ahead data*/
read_obj = PyObject_CallMethod(self->fp, "read", "(i)", FILE_BUFFER_SIZE);
if(!read_obj){
ret = ERR_VALUE_ERROR;
goto error;
}
self->buf = (unsigned char*)PyString_AsString(read_obj);
self->end = self->buf + PyString_Size(read_obj);
if(self->buf != self->end){
self->read_buf = read_obj;
}else{
/* this condition means eof */
self->eof = 1;
self->remain_bit = sizeof(unsigned int) * 8;
Py_DECREF(read_obj);
PyGILState_Release(state);
break;
}
PyGILState_Release(state);
}
self->cache <<= 8;
self->cache |= *self->buf++;
self->bit -= 8;
self->pos += 1;
}
self->cache <<= self->bit;
}
error:
return ret;
}
static inline bit_stream_reader *
new_bit_stream_reader(void)
{
return PyMem_Malloc(sizeof(bit_stream_reader));
}
/* */
static inline int
bit_stream_writer_init_fileio(bit_stream_writer *self, PyObject *file)
{
int error_no = 0;
PyObject *write_obj = NULL;
unsigned char *buf, *end;
/* Argument check */
if(!file){ error_no = ERR_VALUE_ERROR; goto error;}
/* Allocate write buffer */
write_obj = PyString_FromStringAndSize(NULL, 65556);
if(!write_obj){ error_no = ERR_OUT_OF_MEMORY; goto error;}
self->fp = file;
self->write_buf = write_obj;
self->crc16 = 0;
self->pos = 0;
buf = (unsigned char*)PyString_AsString(write_obj);
end = buf + PyString_Size(write_obj);
self->start = buf;
self->buf = buf;
self->end = end;
self->error = 0;
return 0;
error:
Py_XDECREF(write_obj);
return error_no;
}
static inline int
bit_stream_writer_flush(bit_stream_writer *self)
{
int error_no = 0;
PyObject *ret = NULL, *write_obj = NULL;
int s;
if(self->write_buf){
s = (int)(self->buf - self->start);
if(s > 0){
self->crc16 = crc16(self->start, s, self->crc16);
write_obj = PyString_FromStringAndSize(PyString_AsString(self->write_buf), s);
if(!write_obj){ error_no = ERR_OUT_OF_MEMORY; goto error; }
ret = PyObject_CallMethod(self->fp, "write", "(O)", write_obj);
Py_DECREF(write_obj);
Py_DECREF(ret);
ret = PyErr_Occurred();
if(ret){
PyErr_Clear();
error_no = ERR_IO_ERROR;
goto error;
}
}
self->buf = self->start;
}
error:
return error_no;
}
static inline int
bit_stream_writer_close(bit_stream_writer *self)
{
int error_no = 0;
error_no = bit_stream_writer_flush(self);
Py_XDECREF(self->write_buf);
self->write_buf = NULL;
return error_no;
}
static inline int
bit_stream_writer_overflow(bit_stream_writer *self)
{
return ((self->error & BIT_STREAM_ERR_OVERFLOW) != 0);
}
static inline int
bit_stream_writer_ioerror(bit_stream_writer *self)
{
return ((self->error & BIT_STREAM_ERR_IOERROR) != 0);
}
static inline Py_off_t
bit_stream_writer_pos(bit_stream_writer *self)
{
return self->pos;
}
static inline int
bit_stream_writer_crc(bit_stream_writer *self)
{
return self->crc16;
}
static inline void
bit_stream_writer_write(bit_stream_writer *self, int c)
{
self->pos++;
*self->buf++ = (unsigned char)c;
if(self->buf == self->end){
int s;
s = (int)(self->buf - self->start);
self->crc16 = crc16(self->start, s, self->crc16);
{
PyObject *ret;
PyGILState_STATE state;
state = PyGILState_Ensure();
ret = PyObject_CallMethod(self->fp, "write", "(O)", self->write_buf);
Py_DECREF(ret);
ret = PyErr_Occurred();
if(ret){
self->error |= BIT_STREAM_ERR_OVERFLOW;
PyErr_Clear();
}
PyGILState_Release(state);
}
self->buf = self->start;
}
}
/* BIT LENGTH TABLE OPERATIONS */
static inline int
bit_length_table_init(bit_length_table *self, string *s)
{
int error_no = 0;
int bitMax = 0;
int blen, i;
for(i = 0; i < string_len(s); i++){
blen = string_get(s, i);
if(bitMax < blen){
bitMax = blen;
}
}
if( bitMax == 0 || bitMax > 16 || string_len(s) == 0){
error_no = ERR_BIT_LENGTH_TABLE_ERROR;
goto error;
}
self->table = s;
self->bitMax = bitMax;
error:
return error_no;
}
static inline string*
bit_length_table_table(bit_length_table *self){
return self->table;
}
static inline int
bit_length_table_bitMax(bit_length_table *self){
return self->bitMax;
}
static inline int
bit_length_table_table_num(bit_length_table *self, int i){
return string_get(self->table, i);
}
/* BIT PATTERN TABLE OPERATIONS */
static inline int
bit_pattern_table_init(bit_pattern_table *self, bit_length_table *blt)
{
int error_no = 0;
int i, ptn, w, bl;
int bitMax, tableMax;
int *table = self->table;
int *freqTable = self->_freqTable;
int *weight = self->_weight;
int *startPattern = self->_startPattern;
bitMax = bit_length_table_bitMax(blt);
tableMax = string_len(bit_length_table_table(blt));
memset(freqTable, 0, sizeof(int) * (bitMax + 1));
memset(weight, 0, sizeof(int) * (bitMax + 1));
memset(startPattern, 0, sizeof(int) * (bitMax + 1));
for(i = 0; i < string_len(bit_length_table_table(blt)); i++){
bl = bit_length_table_table_num(blt, i);
if(bl == 0){
continue;
}
freqTable[bl] += 1;
}
ptn = 0;
w = 1 << (bitMax - 1);
for(i = 1; i <= bitMax ; i++){
startPattern[i] = ptn;
weight[i] = w;
ptn += (w * freqTable[i]);
w >>= 1;
}
if(ptn > (1 << bitMax)){
error_no = ERR_BIT_PATTERN_TABLE_ERROR;
goto error;
}
/* Make bit pattern table */
for(i = 0 ; i < tableMax ; i++){
bl = bit_length_table_table_num(blt, i);
if(bl == 0){
table[i] = 0;
continue;
}
ptn = startPattern[bl];
table[i] = ptn >> (bitMax - bl);
startPattern[bl] += weight[bl];
}
self->len = tableMax;
error:
return error_no;
}
static inline int
bit_pattern_table_table_num(bit_pattern_table *self, int i){
return self->table[i];
}
/* HUFFMAN DECODER OPERATIONS */
static int
huffman_decoder_init(huffman_decoder *self, string *s)
{
int error_no = 0;
int i;
int bitMax;
int ptn, blen;
unsigned short *blen_code = self->blen_code;
bit_length_table *blt = &self->_blt;
bit_pattern_table *bpt = &self->_bpt;
error_no = bit_length_table_init(blt, s);
if(error_no != 0){
goto error;
}
error_no = bit_pattern_table_init(bpt, blt);
if(error_no != 0){
goto error;
}
bitMax = bit_length_table_bitMax(blt);
memset(blen_code, 0, (sizeof(unsigned short) * (1 << (int)bitMax)));
for(i = 0; i < string_len(bit_length_table_table(blt)); i++){
blen = bit_length_table_table_num(blt, i);
if(blen == 0){
continue;
}
ptn = bit_pattern_table_table_num(bpt, i) << (bitMax - blen);
blen_code[ptn] = (blen << 11) | i;
}
if(bitMax == 1){
if(blen_code[1] == 0){
blen_code[0] &= 0x1FF;
}
}
blen = *blen_code++;
for(i = 1; i < (1 << bitMax) ; i++, blen_code++){
if(*blen_code == 0){
*blen_code = blen;
}else{
blen = *blen_code;
}
}
self->bitMax = bitMax;
error:
return error_no;
}
static inline int
huffman_decoder_decode(huffman_decoder *self, bit_stream_reader *bs)
{
int bits, blen, code;
bits = bit_stream_reader_pre_fetch(bs, self->bitMax);
blen = self->blen_code[bits] >> 11;
code = self->blen_code[bits] & 0x1FF;
bit_stream_reader_fetch(bs, blen);
return code;
}
static inline huffman_decoder *
new_huffman_decoder(void){
return (huffman_decoder *)PyMem_Malloc(sizeof(huffman_decoder));
}
static inline void
del_huffman_decoder(huffman_decoder *d){
if(d != NULL){
PyMem_Free(d);
}
}
/* LZH DECODE OPERATIONS */
#define EOF_CHECK(c) \
if(c < 0){ \
if(c == -1){ \
error_no = ERR_UNEXPECT_EOF; \
goto error; \
}else if(c == -2){ \
error_no = ERR_OUT_OF_RANGE; \
goto error; \
} \
}
static inline int
decodeUnary7(bit_stream_reader *bs, int *unary_code)
{
int error_no = 0;
int c, code;
code = bit_stream_reader_fetch(bs, 3);
EOF_CHECK(code);
if(code == 7){
while((c = bit_stream_reader_fetch(bs, 1)) == 1){
code += 1;
}
EOF_CHECK(c);
}
*unary_code = code;
error:
return error_no;
}
static inline int
decodeBitLengthDecoder(bit_stream_reader *bs, string *blenlen19)
{
int error_no = 0;
int i, c;
int blenSize, blenLeafCode, nmax;
blenSize = bit_stream_reader_fetch(bs, 5);
EOF_CHECK(blenSize);
if(blenSize > 19){
error_no = ERR_BIT_LENGTH_SIZE_ERROR;
goto error;
}
if(blenSize == 0){
blenLeafCode = bit_stream_reader_fetch(bs, 5);
EOF_CHECK(blenLeafCode);
if(blenLeafCode >= 19){
error_no = ERR_BIT_LENGTH_SIZE_ERROR;
goto error;
}
string_clear(blenlen19);
string_set(blenlen19, blenLeafCode, 1);
}else{
i = 0;
while(i < blenSize){
error_no = decodeUnary7(bs, &c);
if(error_no != 0){
goto error;
}
string_set(blenlen19, i, c);
i += 1;
if(i == 3){
nmax = bit_stream_reader_fetch(bs, 2);
EOF_CHECK(nmax);
while(nmax > 0){
string_set(blenlen19, i, 0);
i += 1;
nmax -= 1;
}
}
}
while(i < 19){
string_set(blenlen19, i, 0);
i += 1;
}
}
error:
return error_no;
}
static int
decodeBitLengthLiteral(bit_stream_reader *bs, string *blenlen510, huffman_decoder *bitlen_decoder)
{
int error_no = 0;
int i, n, code, c, leafCode;
n = bit_stream_reader_fetch(bs, 9);
EOF_CHECK(n);
if(n == 0){
leafCode = bit_stream_reader_fetch(bs, 9);
EOF_CHECK(leafCode);
string_clear(blenlen510);
string_set(blenlen510, leafCode, 1);
}else{
i = 0;
while(i < n){
code = huffman_decoder_decode(bitlen_decoder, bs);
if(code > 2){
string_set(blenlen510, i, code - 2);
i += 1;
continue;
}else if(code == 0){
string_set(blenlen510, i, 0);
i += 1;
continue;
}else if(code == 1){
c = bit_stream_reader_fetch(bs, 4);
EOF_CHECK(c);
c += 3;
}else if(code == 2){
c = bit_stream_reader_fetch(bs, 9);
EOF_CHECK(c);
c += 20;
}else{
error_no = ERR_DATA_ERROR;
goto error;
}
while(c > 0){
c -= 1;
string_set(blenlen510, i, 0);
i += 1;
}
}
while(i < 510){
string_set(blenlen510, i, 0);
i += 1;
}
}
error:
return error_no;
}
static inline int
decodeBitLengthDistance(bit_stream_reader *bs, string *blenlen_distance, int dispos_bit, int dis_bit)
{
int error_no = 0;
int i, unary;
int leafCode, tableSize;
tableSize = bit_stream_reader_fetch(bs, dis_bit);
EOF_CHECK(tableSize);
if(tableSize == 0){
leafCode = bit_stream_reader_fetch(bs, dis_bit);
EOF_CHECK(leafCode);
string_clear(blenlen_distance);
string_set(blenlen_distance, leafCode, 1);
}else{
i = 0;
while(i < tableSize){
error_no = decodeUnary7(bs, &unary);
if(error_no != 0){
goto error;
}
string_set(blenlen_distance, i, unary);
i += 1;
}
while(i <= dispos_bit){
string_set(blenlen_distance, i, 0);
i += 1;
}
}
error:
return error_no;
}
/*
*
*/
typedef struct {
PyObject_HEAD
/* */
PyObject *fin;
PyObject *fout;
lzhlib_compress_type compress_type;
Py_off_t info_compress_size;
Py_off_t info_file_size;
int info_crc;
bit_stream_reader *in;
bit_stream_writer *out;
huffman_decoder *bitlen_decoder;
huffman_decoder *literal_decoder;
huffman_decoder *distance_decoder;
string *bitlen_distance;
string *bitlen19;
string *bitlen510;
unsigned char *dic_buf;
int dic_pos;
int dic_size;
int blockSize;
int finish;
int error_no;
int dic_bit;
int dispos_bit;
int dis_bit;
/* buffer instances */
bit_stream_reader _in;
bit_stream_writer _out;
string _bitlen_distance;
string _bitlen19;
string _bitlen510;
huffman_decoder _literal_decoder;
huffman_decoder _distance_decoder;
unsigned char _bitlen_distance_buf[18];
unsigned char _bitlen19_buf[19];
unsigned char _bitlen510_buf[510];
unsigned char _dic_buf[65536];
} LZHDecodeSessionObject;
PyDoc_STRVAR(LZHDecodeSession_do_next__doc__,
"");
static PyObject *
LZHDecodeSession_do_next(LZHDecodeSessionObject *self)
{
int error_no = 0;
int loop, code, srcpos, mlen, bitl, dist;
PyObject *ret;
/* */
if(self->error_no){
goto exception;
}
if(self->finish){
Py_INCREF(Py_True);
return Py_True;
}
/* */
Py_BEGIN_ALLOW_THREADS
loop = 64*1024;
if(self->compress_type == COMPRESS_TYPE_LH0){
/* This code is slow, but this happens a little */
while(loop > 0){
code = bit_stream_reader_fetch(self->in, 8);
if(code == -1){
self->finish = 1;
break;
}
bit_stream_writer_write(self->out, code);
loop -= 1;
}
}else{
while(loop > 0){
if(self->blockSize <= 0){
/* Delayed check for tuning */
if(bit_stream_writer_overflow(self->out) != 0){
error_no = ERR_BUFFER_OVER_FLOW;
break;
}
if(bit_stream_writer_ioerror(self->out) != 0){
error_no = ERR_IO_ERROR;
break;
}
/* Read blockSize */
self->blockSize = bit_stream_reader_fetch(self->in, 16);
if(self->blockSize == -1){
self->finish = 1;
break;
}else{
/* Create bitlen_decoder for literal_decoder */
error_no = decodeBitLengthDecoder(self->in, self->bitlen19);
if(error_no != 0){goto error;}
error_no = huffman_decoder_init(self->bitlen_decoder, self->bitlen19);
if(error_no != 0){goto error;}
/* Create literal decoder */
error_no = decodeBitLengthLiteral(self->in, self->bitlen510, self->bitlen_decoder);
if(error_no != 0){goto error;}
error_no = huffman_decoder_init(self->literal_decoder, self->bitlen510);
if(error_no != 0){goto error;}
/* Create distance decoder */
error_no = decodeBitLengthDistance(self->in, self->bitlen_distance, self->dispos_bit, self->dis_bit);
if(error_no != 0){goto error;}
error_no = huffman_decoder_init(self->distance_decoder, self->bitlen_distance);
if(error_no != 0){goto error;}
}
}
code = huffman_decoder_decode(self->literal_decoder, self->in);
self->blockSize -= 1;
if(code < 256){
self->dic_buf[self->dic_pos++] = code;
bit_stream_writer_write(self->out, code);
loop -=1;
self->dic_pos &= (self->dic_size -1);
continue;
}
mlen = code - 256 + 3;
bitl = huffman_decoder_decode(self->distance_decoder, self->in);
if(bitl == 0){
dist = 1;
}else{
dist = bit_stream_reader_fetch(self->in, bitl - 1);
EOF_CHECK(dist);
dist += (1 << (bitl - 1));
dist += 1;
}
srcpos = self->dic_pos - dist;
if(srcpos < 0){
srcpos += self->dic_size;
}
for(; mlen > 0 ; mlen--){
code = self->dic_buf[self->dic_pos++] = self->dic_buf[srcpos++];
bit_stream_writer_write(self->out, code);
loop -= 1;
self->dic_pos &= (self->dic_size -1);
srcpos &= (self->dic_size -1);
}
}
}
error:
Py_END_ALLOW_THREADS
if(error_no != 0){
self->error_no = error_no;
bit_stream_reader_close(self->in);
bit_stream_writer_close(self->out);
goto exception;
}
if(self->finish){
bit_stream_reader_close(self->in);
error_no = bit_stream_writer_close(self->out);
if(error_no != 0){
self->error_no = error_no;
goto exception;
}
Py_INCREF(Py_True);
ret = Py_True;
}else{
Py_INCREF(Py_False);
ret = Py_False;
}
return ret;
exception:
return PyErr_Format(PyExc_RuntimeError, "internal error code = %d", self->error_no);
}
static PyMethodDef LZHDecodeSession_methods[] = {
{"do_next", (PyCFunction)LZHDecodeSession_do_next, METH_NOARGS, LZHDecodeSession_do_next__doc__},
{NULL, NULL}
};
static PyMemberDef LZHDecodeSession_members[] = {
{"input_file_size", T_LONGLONG, offsetof(LZHDecodeSessionObject, info_compress_size), RO},
{"input_pos", T_LONGLONG, offsetof(LZHDecodeSessionObject, _in) + offsetof(bit_stream_reader, pos), RO},
{"output_file_size", T_LONGLONG, offsetof(LZHDecodeSessionObject, info_file_size), RO},
{"output_pos", T_LONGLONG, offsetof(LZHDecodeSessionObject, _out) + offsetof(bit_stream_writer, pos), RO},
{"crc16", T_LONG, offsetof(LZHDecodeSessionObject, _out) + offsetof(bit_stream_writer, crc16), RO},
{NULL}
};
static long long
LhaInfo_GetAttr(PyObject *info, const char *attr_name){
PyObject *attr, *value;
long long num;
attr = PyString_FromString(attr_name);
if(!attr){ goto error; }
value = PyObject_GetAttr(info, attr);
Py_DECREF(attr);
if(!value){ goto error; }
if(PyInt_Check(value)){
num = (Py_off_t)PyInt_AsLong(value);
}else if(PyLong_Check(value)){
num = (Py_off_t)PyLong_AsLongLong(value);
}else{
Py_DECREF(value);
goto error;
}
Py_DECREF(value);
return num;
error:
return -1;
}
static int
LZHDecodeSession_init(LZHDecodeSessionObject *self, PyObject *args, PyObject *kwargs)
{
PyObject *fin, *fout, *info, *value, *attr;
int error_no;
/* Parse arguments */
if(!PyArg_ParseTuple(args, "OOO", &fin, &fout, &info)){
goto error;
}
/* compress_type */
attr = PyString_FromString("compress_type");
if(!attr){ goto error; }
value = PyObject_GetAttr(info, attr);
Py_DECREF(attr);
if(!value){ goto error; }
if(memcmp(PyString_AsString(value), "-lh0-\x00", 6) == 0){
self->compress_type = COMPRESS_TYPE_LH0;
self->dic_size = 0;
}else if(memcmp(PyString_AsString(value), "-lh5-\x00", 6) == 0){
self->compress_type = COMPRESS_TYPE_LH5;
self->dic_size = 8192;
self->dic_bit = 13;
self->dispos_bit = 14;
self->dis_bit = 4;
}else if(memcmp(PyString_AsString(value), "-lh6-\x00", 6) == 0){
self->compress_type = COMPRESS_TYPE_LH6;
self->dic_size = 32768;
self->dic_bit = 15;
self->dispos_bit = 16;
self->dis_bit = 5;
}else if(memcmp(PyString_AsString(value), "-lh7-\x00", 6) == 0){
self->compress_type = COMPRESS_TYPE_LH7;
self->dic_size = 65536;
self->dic_bit = 16;
self->dispos_bit = 17;
self->dis_bit = 5;
}else{
goto error;
}
Py_DECREF(value);
/* Initialize each buffer and decoder */
string_init(&self->_bitlen_distance, self->_bitlen_distance_buf, self->dispos_bit + 1);
string_init(&self->_bitlen19, self->_bitlen19_buf, 19);
string_init(&self->_bitlen510, self->_bitlen510_buf, 510);
/* */
self->finish = 0;
self->error_no = 0;
self->in = &self->_in;
self->out = &self->_out;
self->bitlen_distance = &self->_bitlen_distance;
self->bitlen19 = &self->_bitlen19;
self->bitlen510 = &self->_bitlen510;
self->literal_decoder = &self->_literal_decoder;
self->distance_decoder = &self->_distance_decoder;
self->bitlen_decoder = &self->_distance_decoder;
self->dic_buf = self->_dic_buf;
self->dic_pos = 0;
self->blockSize = 0;
self->info_compress_size = (Py_off_t)LhaInfo_GetAttr(info, "compress_size");
self->info_file_size = (Py_off_t)LhaInfo_GetAttr(info, "file_size");
self->info_crc = (int)LhaInfo_GetAttr(info, "CRC");
self->fin = fin;
self->fout = fout;
error_no = bit_stream_reader_init_fileio(self->in, self->fin);
if(error_no != 0){
goto error;
}
error_no = bit_stream_writer_init_fileio(self->out, self->fout);
if(error_no != 0){
bit_stream_reader_close(self->in);
goto error;
}
Py_INCREF(self->fin);
Py_INCREF(self->fout);
return 0;
error:
return -1;
}
static void
LZHDecodeSession_dealloc(LZHDecodeSessionObject *self)
{
/* If deocde is not finished */
if(!self->finish && self->error_no == 0){
bit_stream_reader_close(self->in);
bit_stream_writer_close(self->out);
}
Py_DECREF(self->fin);
Py_DECREF(self->fout);
self->ob_type->tp_free((PyObject *)self);
}
static PyTypeObject LZHDecodeSession_Type = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"lhafile.LZHDecodeSession", /*tp_name*/
sizeof(LZHDecodeSessionObject), /*tp_basicsize*/
0, /*tp_itemsize*/
(destructor)LZHDecodeSession_dealloc, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
0, /*tp_call*/
0, /*tp_str*/
PyObject_GenericGetAttr, /*tp_getattro*/
PyObject_GenericSetAttr, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /*tp_flags*/
0, /*tp_doc*/
0, /*tp_traverse*/
0, /*tp_clear*/
0, /*tp_richcompare*/
0, /*tp_weaklistoffset*/
0, /*tp_iter*/
0, /*tp_iternext*/
LZHDecodeSession_methods, /*tp_methods*/
LZHDecodeSession_members, /*tp_members*/
0, /*tp_getset*/
0, /*tp_base*/
0, /*tp_dict*/
0, /*tp_descr_get*/
0, /*tp_descr_set*/
0, /*tp_dictoffset*/
(initproc)LZHDecodeSession_init, /*tp_init*/
PyType_GenericAlloc, /*tp_alloc*/
PyType_GenericNew, /*tp_new*/
_PyObject_Del, /*tp_free*/
0, /*tp_is_gc*/
};
/*
*
*/
static PyObject*
lzhlib_crc16(PyObject* self, PyObject* args)
{
unsigned char *data;
int len;
int crc;
crc = 0;
if(!PyArg_ParseTuple(args, "s#|i", &data, &len, &crc)){
return NULL;
}
crc = crc16(data, len, crc);
return Py_BuildValue("i", (int)crc);
}
static PyMethodDef lzhlib_methods[] = {
{"crc16", lzhlib_crc16, METH_VARARGS,
"Execute crc16 function: (s, crc) -> crc"},
{ NULL, NULL, 0, NULL}
};
PyMODINIT_FUNC
initlzhlib(void)
{
PyObject *m;
LZHDecodeSession_Type.ob_type = &PyType_Type;
m = Py_InitModule("lzhlib", lzhlib_methods);
if (m == NULL)
return;
PyModule_AddObject(m, "__author__", PyString_FromString(__author__));
Py_INCREF(&LZHDecodeSession_Type);
PyModule_AddObject(m, "LZHDecodeSession", (PyObject *)&LZHDecodeSession_Type);
}