X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Fmikmod%2Fdepackers%2Fs404.c;fp=libs%2Fmikmod%2Fdepackers%2Fs404.c;h=7ca41cdbe078366d085e50c5efbee56abbb1a6de;hp=0000000000000000000000000000000000000000;hb=cf94899f4f4d8535074db6421245b973d2fcde8c;hpb=8024ae981f39d370af5cceb3cb97f62820b0a120 diff --git a/libs/mikmod/depackers/s404.c b/libs/mikmod/depackers/s404.c new file mode 100644 index 0000000..7ca41cd --- /dev/null +++ b/libs/mikmod/depackers/s404.c @@ -0,0 +1,393 @@ +/* MikMod sound library (c) 2003-2015 Raphael Assenat and others - + * see AUTHORS file for a complete list. + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Library 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 Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +/* + * StoneCracker S404 algorithm data decompression routine + * (c) 2006 Jouni 'Mr.Spiv' Korhonen. The code is in public domain. + * + * modified for xmp by Claudio Matsuoka, Jan 2010 + * modified for libmikmod by O. Sezer -- May 2015 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include +/*#include */ + +#include "mikmod_internals.h" + +#ifdef SUNOS +extern int fprintf(FILE *, const char *, ...); +#endif + + +/*#define STC_DEBUG*/ + +static UWORD readmem16b(UBYTE *m) +{ + ULONG a, b; + a = m[0]; + b = m[1]; + return (a << 8) | b; +} + +struct bitstream { + /* bit buffer for rolling data bit by bit from the compressed file */ + ULONG word; + + /* bits left in the bit buffer */ + int left; + + /* compressed data source */ + UWORD *src; + UBYTE *orgsrc; +}; + +static int initGetb(struct bitstream *bs, UBYTE *src, ULONG src_length) +{ + int eff; + + bs->src = (UWORD *) (src + src_length); + bs->orgsrc = src; + + bs->left = readmem16b((UBYTE *)bs->src); /* bit counter */ +#ifdef STC_DEBUG + if (bs->left & (~0xf)) + fprintf(stderr, "Worked around an ancient stc bug\n"); +#endif + /* mask off any corrupt bits */ + bs->left &= 0x000f; + bs->src--; + + /* get the first 16-bits of the compressed stream */ + bs->word = readmem16b((UBYTE *)bs->src); + bs->src--; + + eff = readmem16b((UBYTE *)bs->src); /* efficiency */ + bs->src--; + + return eff; +} + +/* get nbits from the compressed stream */ +static int getb(struct bitstream *bs, int nbits) +{ + bs->word &= 0x0000ffff; + + /* If not enough bits in the bit buffer, get more */ + if (bs->left < nbits) { + bs->word <<= bs->left; + /*assert((bs->word & 0x0000ffffU) == 0);*/ + + /* Check that we don't go out of bounds */ + if (bs->orgsrc > (UBYTE *)bs->src) { + return -1; + } + + bs->word |= readmem16b((UBYTE *)bs->src); + bs->src--; + + nbits -= bs->left; + bs->left = 16; /* 16 unused (and some used) bits left in the word */ + } + + /* Shift nbits off the word and return them */ + bs->left -= nbits; + bs->word <<= nbits; + return bs->word >> 16; +} + +static int decompressS404(UBYTE *src, UBYTE *orgdst, + SLONG dst_length, SLONG src_length) +{ + UWORD w; + SLONG eff; + SLONG n; + UBYTE *dst; + SLONG oLen = dst_length; + struct bitstream bs; + int x; + + dst = orgdst + oLen; + + eff = initGetb(&bs, src, src_length); + + while (oLen > 0) { + x = getb(&bs, 9); + /* Sanity check */ + if (x < 0) { + return -1; + } + + w = x; + + if (w < 0x100) { + if (orgdst >= dst) { + return -1; + } + *--dst = w; + oLen--; + } else if (w == 0x13e || w == 0x13f) { + w <<= 4; + x = getb(&bs, 4); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + + n = (w & 0x1f) + 14; + oLen -= n; + while (n-- > 0) { + x = getb(&bs, 8); + /* Sanity check */ + if (x < 0) { + return -1; + } + w = x; + + if (orgdst >= dst) { + return -1; + } + + *--dst = w; + } + } else { + if (w >= 0x180) { + /* copy 2-3 */ + n = w & 0x40 ? 3 : 2; + + if (w & 0x20) { + /* dist 545 -> */ + w = (w & 0x1f) << (eff - 5); + x = getb(&bs, eff - 5); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 544; + } else if (w & 0x30) { + /* dist 1 -> 32 */ + w = (w & 0x0f) << 1; + x = getb(&bs, 1); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + } else { + /* dist 33 -> 544 */ + w = (w & 0x0f) << 5; + x = getb(&bs, 5); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 32; + } + } else if (w >= 0x140) { + /* copy 4-7 */ + n = ((w & 0x30) >> 4) + 4; + + if (w & 0x08) { + /* dist 545 -> */ + w = (w & 0x07) << (eff - 3); + x = getb(&bs, eff - 3); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 544; + } else if (w & 0x0c) { + /* dist 1 -> 32 */ + w = (w & 0x03) << 3; + x = getb(&bs, 3); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + } else { + /* dist 33 -> 544 */ + w = (w & 0x03) << 7; + x = getb(&bs, 7); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 32; + } + } else if (w >= 0x120) { + /* copy 8-22 */ + n = ((w & 0x1e) >> 1) + 8; + + if (w & 0x01) { + /* dist 545 -> */ + x = getb(&bs, eff); + /* Sanity check */ + if (x < 0) { + return -1; + } + w = x; + w += 544; + } else { + x = getb(&bs, 6); + /* Sanity check */ + if (x < 0) { + return -1; + } + w = x; + + if (w & 0x20) { + /* dist 1 -> 32 */ + w &= 0x1f; + } else { + /* dist 33 -> 544 */ + w <<= 4; + x = getb(&bs, 4); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 32; + } + } + } else { + w = (w & 0x1f) << 3; + x = getb(&bs, 3); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + n = 23; + + while (w == 0xff) { + n += w; + x = getb(&bs, 8); + /* Sanity check */ + if (x < 0) { + return -1; + } + w = x; + } + n += w; + + x = getb(&bs, 7); + w = x; + + if (w & 0x40) { + /* dist 545 -> */ + w = (w & 0x3f) << (eff - 6); + x = getb(&bs, eff - 6); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 544; + } else if (w & 0x20) { + /* dist 1 -> 32 */ + w &= 0x1f; + } else { + /* dist 33 -> 544; */ + w <<= 4; + x = getb(&bs, 4); + /* Sanity check */ + if (x < 0) { + return -1; + } + w |= x; + w += 32; + } + } + + oLen -= n; + + while (n-- > 0) { + dst--; + if (dst < orgdst || (dst + w + 1) >= (orgdst + dst_length)) + return -1; + *dst = dst[w + 1]; + } + } + } + + return 0; +} + +BOOL S404_Unpack(MREADER *reader, void **out, long *outlen) +{ + SLONG iLen, sLen, oLen, pLen; + UBYTE *src, *dst = NULL; + int err; + + _mm_fseek(reader,0,SEEK_END); + iLen = _mm_ftell(reader); + if (iLen <= 16) return 0; + + _mm_rewind(reader); + if (_mm_read_M_ULONG(reader) != 0x53343034) /* S404 */ + return 0; + + sLen = _mm_read_M_SLONG(reader); /* Security length */ + oLen = _mm_read_M_SLONG(reader); /* Depacked length */ + pLen = _mm_read_M_SLONG(reader); /* Packed length */ +#ifdef STC_DEBUG + fprintf(stderr,"S404: iLen= %d, sLen= %d, pLen= %d, oLen= %d\n", + iLen, sLen, pLen, oLen); +#endif + if (sLen < 0 || oLen <= 0 || pLen <= 0) return 0; + if (pLen + 16 >= iLen) return 0; /* sanity check */ + + if (!(src = (UBYTE*) MikMod_malloc(iLen - 16))) + return 0; + if (!(dst = (UBYTE*) MikMod_malloc(oLen))) { + MikMod_free(src); + return 0; + } + + _mm_read_UBYTES(src, iLen - 16, reader); + err = decompressS404(src, dst, oLen, pLen); + MikMod_free(src); + + if (!err) { + *out = dst; + *outlen = oLen; + return 1; + } + + MikMod_free(dst); + return 0; +}