diff options
Diffstat (limited to 'src/libs/decomp/lzdecode.c')
-rw-r--r-- | src/libs/decomp/lzdecode.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/src/libs/decomp/lzdecode.c b/src/libs/decomp/lzdecode.c new file mode 100644 index 0000000..3b64a90 --- /dev/null +++ b/src/libs/decomp/lzdecode.c @@ -0,0 +1,415 @@ +//Copyright Paul Reiche, Fred Ford. 1992-2002 + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + + /* + * LZHUF.C English version 1.0 + * Based on Japanese version 29-NOV-1988 + * LZSS coded by Haruhiko OKUMURA + * Adaptive Huffman Coding coded by Haruyasu YOSHIZAKI + * Edited and translated to English by Kenji RIKITAKE + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "lzh.h" +#include "libs/reslib.h" + +PLZHCODE_DESC _lpCurCodeDesc; +STREAM_TYPE _StreamType; +BYTE* _Stream; +UWORD _workbuf; +BYTE _workbuflen; + +/* get one bit */ +static SWORD +GetBit (void) +{ + SWORD i; + + while (_workbuflen <= 8) + { + if ((i = InChar ()) < 0) + i = 0; + _workbuf |= i << (8 - _workbuflen); + _workbuflen += 8; + } + i = (_workbuf & 0xFFFF) >> (16 - 1); + _workbuf = (_workbuf << 1) & 0xFFFF; + _workbuflen--; + + return (i); +} + +static UWORD +GetBits (BYTE num_bits) +{ + SWORD i; + + while (_workbuflen <= 8) + { + if ((i = InChar ()) < 0) + i = 0; + _workbuf |= i << (8 - _workbuflen); + _workbuflen += 8; + } + i = (_workbuf & 0xFFFF) >> (16 - num_bits); + _workbuf = (_workbuf << num_bits) & 0xFFFF; + _workbuflen -= num_bits; + + return (i); +} + +/* initialize freq tree */ + +void +StartHuff (void) +{ + COUNT i, j; + + for (i = 0; i < N_CHAR; i++) + { + _lpCurCodeDesc->freq[i] = 1; + _lpCurCodeDesc->son[i] = i + T; + _lpCurCodeDesc->prnt[i + T] = i; + } + i = 0; j = N_CHAR; + while (j <= R) + { + _lpCurCodeDesc->freq[j] = _lpCurCodeDesc->freq[i] + _lpCurCodeDesc->freq[i + 1]; + _lpCurCodeDesc->son[j] = i; + _lpCurCodeDesc->prnt[i] = _lpCurCodeDesc->prnt[i + 1] = j; + i += 2; j++; + } + _lpCurCodeDesc->freq[T] = 0xffff; + _lpCurCodeDesc->prnt[R] = 0; +} + +DECODE_REF +copen (void *InStream, STREAM_TYPE SType, STREAM_MODE SMode) +{ + DWORD StreamLength; + + _StreamType = SType; + _Stream = InStream; + if (SMode == STREAM_WRITE) /* writing */ + { + OutChar (0); /* skip future StreamLength */ + OutChar (0); + OutChar (0); + OutChar (0); + + StreamLength = 0; + } + else /* reading */ + { + BYTE lobyte, hibyte; + UWORD loword, hiword; + + lobyte = (BYTE)InChar (); + hibyte = (BYTE)InChar (); + loword = MAKE_WORD (lobyte, hibyte); + lobyte = (BYTE)InChar (); + hibyte = (BYTE)InChar (); + hiword = MAKE_WORD (lobyte, hibyte); + + StreamLength = MAKE_DWORD (loword, hiword); + } + + if (StreamLength == 0xFFFFFFFF + || (_lpCurCodeDesc = AllocCodeDesc ()) == NULL) + { + FreeCodeDesc (_lpCurCodeDesc); + _lpCurCodeDesc = NULL; + } + else + { + _lpCurCodeDesc->Stream = _Stream; + _lpCurCodeDesc->StreamType = _StreamType; + _lpCurCodeDesc->StreamMode = SMode; + _lpCurCodeDesc->StreamLength = StreamLength; + _lpCurCodeDesc->buf_index = N - F; + memset (&_lpCurCodeDesc->text_buf[0], ' ', N - F); + + StartHuff (); + } + + return ((DECODE_REF)_lpCurCodeDesc); +} + +DWORD +cclose (PLZHCODE_DESC lpCodeDesc) +{ + _lpCurCodeDesc = lpCodeDesc; + if (_lpCurCodeDesc) + { + DWORD StreamIndex; + + if (_lpCurCodeDesc->CleanupFunc) + (*_lpCurCodeDesc->CleanupFunc) (); + + StreamIndex = lpCodeDesc->StreamIndex; + FreeCodeDesc (lpCodeDesc); + _lpCurCodeDesc = NULL; + + return (StreamIndex); + } + + return (0); +} + +void +cfilelength (PLZHCODE_DESC lpCodeDesc, DWORD *pfilelen) +{ + if (lpCodeDesc == 0) + *pfilelen = 0; + else + *pfilelen = lpCodeDesc->StreamLength; +} + + /* decoder table */ +static const BYTE d_code[256] = +{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, + 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, + 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, + 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, 0x0A, + 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, 0x0B, + 0x0C, 0x0C, 0x0C, 0x0C, 0x0D, 0x0D, 0x0D, 0x0D, + 0x0E, 0x0E, 0x0E, 0x0E, 0x0F, 0x0F, 0x0F, 0x0F, + 0x10, 0x10, 0x10, 0x10, 0x11, 0x11, 0x11, 0x11, + 0x12, 0x12, 0x12, 0x12, 0x13, 0x13, 0x13, 0x13, + 0x14, 0x14, 0x14, 0x14, 0x15, 0x15, 0x15, 0x15, + 0x16, 0x16, 0x16, 0x16, 0x17, 0x17, 0x17, 0x17, + 0x18, 0x18, 0x19, 0x19, 0x1A, 0x1A, 0x1B, 0x1B, + 0x1C, 0x1C, 0x1D, 0x1D, 0x1E, 0x1E, 0x1F, 0x1F, + 0x20, 0x20, 0x21, 0x21, 0x22, 0x22, 0x23, 0x23, + 0x24, 0x24, 0x25, 0x25, 0x26, 0x26, 0x27, 0x27, + 0x28, 0x28, 0x29, 0x29, 0x2A, 0x2A, 0x2B, 0x2B, + 0x2C, 0x2C, 0x2D, 0x2D, 0x2E, 0x2E, 0x2F, 0x2F, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, +}; +static const BYTE d_len[256] = +{ + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, +}; + + /* decode upper 6 bits from given table */ +#define DecodePosition(p) \ +{ \ + while (_workbuflen <= 8) \ + { \ + *(p) = InChar (); \ + _workbuf |= *(p) << (8 - _workbuflen); \ + _workbuflen += 8; \ + } \ + *(p) = HIBYTE (_workbuf); \ + _workbuf = (_workbuf << 8) & 0xFFFF; \ + _workbuflen -= 8; \ + \ + /* input lower 6 bits directly */ \ + j = d_len[*(p)]; \ + *(p) = ((UWORD)d_code[*(p)] << 6) \ + | (((*(p) << j) | GetBits (j)) & 0x3f); \ +} + + /* start searching tree from the root to leaves. + * choose node #(son[]) if input bit == 0 + * else choose #(son[]+1) (input bit == 1) + */ +#define DecodeChar(c) \ +{ \ + for (*(c) = lpCodeDesc->son[R]; \ + *(c) < T; \ + *(c) = lpCodeDesc->son[*(c) + GetBit ()]) \ + ; \ + _update (*(c)); \ + *(c) -= T; \ +} + +COUNT +cread (void *buf, COUNT size, COUNT count, PLZHCODE_DESC lpCodeDesc) +{ + COUNT r, j, i; + BYTE *lpStr; + + if ((_lpCurCodeDesc = lpCodeDesc) == 0) + return (0); + + size *= count; + if (lpCodeDesc->StreamIndex + size > lpCodeDesc->StreamLength) + { + size /= count; + count = (COUNT)((lpCodeDesc->StreamLength + - lpCodeDesc->StreamIndex) / size); + + size *= count; + } + + if (size == 0) + return (0); + + lpStr = (BYTE*)buf; + _StreamType = lpCodeDesc->StreamType; + + _Stream = lpCodeDesc->Stream; + _workbuf = lpCodeDesc->workbuf; + _workbuflen = lpCodeDesc->workbuflen; + + lpCodeDesc->StreamIndex += size; + r = lpCodeDesc->buf_index; + j = lpCodeDesc->bytes_left; + if (j) + { + lpCodeDesc->bytes_left = 0; + i = lpCodeDesc->restart_index; + + goto ReenterRun; + } + + do + { + COUNT c; + + DecodeChar (&c); + + if (c < 256) + { + size--; + + *lpStr++ = lpCodeDesc->text_buf[r++ & (N - 1)] = (BYTE)c; + } + else + { + COUNT copy_size; + + //i is a COUNT; + DecodePosition(&i); + i = r - i - 1; + j = c - 255 + THRESHOLD; +ReenterRun: + if (j > size) + { + lpCodeDesc->bytes_left = j - size; + lpCodeDesc->restart_index = i + size; + j = size; + } + + size -= j; + do + { + COUNT loc_size; + + i &= (N - 1); + r &= (N - 1); + if ((i < r && i + j > r) || (i > r && i + j > r + N)) + copy_size = (r - i) & (N - 1); + else if ((copy_size = j) > N) + copy_size = N; + + loc_size = copy_size; + if (i + loc_size > N) + { + COUNT k; + + k = N - i; + memcpy (lpStr, &lpCodeDesc->text_buf[i], k); + lpStr += k; + loc_size -= k; + i = 0; + } + + memcpy (lpStr, &lpCodeDesc->text_buf[i], loc_size); + lpStr += loc_size; + i += loc_size; + + lpStr -= copy_size; + + loc_size = copy_size; + if (r + loc_size > N) + { + COUNT k; + + k = N - r; + memcpy (&lpCodeDesc->text_buf[r], lpStr, k); + lpStr += k; + loc_size -= k; + r = 0; + } + + memcpy (&lpCodeDesc->text_buf[r], lpStr, loc_size); + lpStr += loc_size; + r += loc_size; + } while (j -= copy_size); + } + } while (size); + + lpCodeDesc->buf_index = r; + lpCodeDesc->Stream = _Stream; + lpCodeDesc->workbuf = _workbuf; + lpCodeDesc->workbuflen = _workbuflen; + + return (count); +} + |