X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=libs%2Fmikmod%2Fdepackers%2Fmmcmp.c;fp=libs%2Fmikmod%2Fdepackers%2Fmmcmp.c;h=2a83540ca81c84e81a4dd3eba821e86cd18290a9;hp=0000000000000000000000000000000000000000;hb=cf94899f4f4d8535074db6421245b973d2fcde8c;hpb=8024ae981f39d370af5cceb3cb97f62820b0a120 diff --git a/libs/mikmod/depackers/mmcmp.c b/libs/mikmod/depackers/mmcmp.c new file mode 100644 index 0000000..2a83540 --- /dev/null +++ b/libs/mikmod/depackers/mmcmp.c @@ -0,0 +1,433 @@ +/* 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. + */ + +/* MMCMP ("ziRCONia") decompression support + * + * Based on the public domain version from the libmodplug library by + * Olivier Lapicque (sezero's fork of libmodplug + * at github: http://github.com/sezero/libmodplug/tree/sezero ) + * + * Rewritten for libmikmod by O. Sezer + * with some extra ideas from the libxmp version by Claudio Matsuoka. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#include +#ifdef HAVE_MEMORY_H +#include +#endif +#include + +#include "mikmod_internals.h" + +#ifdef SUNOS +extern int fprintf(FILE *, const char *, ...); +#endif + +/*#define MMCMP_DEBUG*/ + +typedef struct MMCMPFILEHDR +{ + UBYTE id[8]; /* string 'ziRCONia' */ + UWORD hdrsize; /* sizeof MMCMPHEADER */ +} MMCMPFILEHDR; /* 10 bytes */ + +typedef struct MMCMPHEADER +{ + UWORD version; + UWORD nblocks; + ULONG filesize; + ULONG blktable; + UBYTE glb_comp; + UBYTE fmt_comp; +} MMCMPHEADER; /* 14 bytes */ + +typedef struct MMCMPBLOCK +{ + ULONG unpk_size; + ULONG pk_size; + ULONG xor_chk; + UWORD sub_blk; + UWORD flags; + UWORD tt_entries; + UWORD num_bits; +} MMCMPBLOCK; /* 20 bytes */ + +typedef struct MMCMPSUBBLOCK +{ + ULONG unpk_pos; + ULONG unpk_size; +} MMCMPSUBBLOCK; /* 8 bytes */ + +#define MMCMP_COMP 0x0001 +#define MMCMP_DELTA 0x0002 +#define MMCMP_16BIT 0x0004 +#define MMCMP_STEREO 0x0100 +#define MMCMP_ABS16 0x0200 +#define MMCMP_ENDIAN 0x0400 + + +typedef struct MMCMPBITBUFFER +{ + ULONG bitcount; + ULONG bitbuffer; + const UBYTE *start; + const UBYTE *end; +} MMCMPBITBUFFER; + +static ULONG MMCMP_GetBits(MMCMPBITBUFFER* b, ULONG nBits) +{ + ULONG d; + if (!nBits) return 0; + while (b->bitcount < 24) + { + b->bitbuffer |= ((b->start < b->end) ? *b->start++ : 0) << b->bitcount; + b->bitcount += 8; + } + d = b->bitbuffer & ((1 << nBits) - 1); + b->bitbuffer >>= nBits; + b->bitcount -= nBits; + return d; +} + +static const ULONG MMCMP8BitCommands[8] = +{ + 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF8 +}; + +static const ULONG MMCMP8BitFetch[8] = +{ + 3, 3, 3, 3, 2, 1, 0, 0 +}; + +static const ULONG MMCMP16BitCommands[16] = +{ + 0x01, 0x03, 0x07, 0x0F, 0x1E, 0x3C, 0x78, 0xF0, + 0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0 +}; + +static const ULONG MMCMP16BitFetch[16] = +{ + 4, 4, 4, 4, 3, 2, 1, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + + +BOOL MMCMP_Unpack(MREADER* reader, void** out, long* outlen) +{ + ULONG srclen, destlen; + UBYTE *destbuf, *destptr; + MMCMPHEADER mmh; + ULONG *pblk_table; + MMCMPSUBBLOCK *subblocks; + ULONG i, blockidx, numsubs; + UBYTE *buf; ULONG bufsize; + + _mm_fseek(reader,0,SEEK_END); + srclen = _mm_ftell(reader); + if (srclen < 256) return 0; + + _mm_rewind(reader); + if (_mm_read_I_ULONG(reader) != 0x4352697A) /* 'ziRC' */ + return 0; + if (_mm_read_I_ULONG(reader) != 0x61694e4f) /* 'ONia' */ + return 0; + if (_mm_read_I_UWORD(reader) != 14) /* header size */ + return 0; + + mmh.version = _mm_read_I_UWORD(reader); + mmh.nblocks = _mm_read_I_UWORD(reader); + mmh.filesize = _mm_read_I_ULONG(reader); + mmh.blktable = _mm_read_I_ULONG(reader); + mmh.glb_comp = _mm_read_UBYTE(reader); + mmh.fmt_comp = _mm_read_UBYTE(reader); + + if ((!mmh.nblocks) || (mmh.filesize < 16) || (mmh.filesize > 0x8000000) || + (mmh.blktable >= srclen) || (mmh.blktable + 4*mmh.nblocks > srclen)) { + return 0; + } + destlen = mmh.filesize; + numsubs = 32; + bufsize = 65536; + + destbuf = (UBYTE*)MikMod_malloc(destlen); + buf = (UBYTE*)MikMod_malloc(bufsize); + pblk_table = (ULONG*)MikMod_malloc(mmh.nblocks*4); + subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK)); + if (!destbuf || !buf || !pblk_table || !subblocks) + goto err; + + _mm_fseek(reader,mmh.blktable,SEEK_SET); + for (blockidx = 0; blockidx < mmh.nblocks; blockidx++) { + pblk_table[blockidx] = _mm_read_I_ULONG(reader); + } + + for (blockidx = 0; blockidx < mmh.nblocks; blockidx++) + { + ULONG srcpos = pblk_table[blockidx]; + MMCMPBLOCK block; + + if (srcpos + 20 >= srclen) goto err; + + _mm_fseek(reader,srcpos,SEEK_SET); + block.unpk_size = _mm_read_I_ULONG(reader); + block.pk_size = _mm_read_I_ULONG(reader); + block.xor_chk = _mm_read_I_ULONG(reader); + block.sub_blk = _mm_read_I_UWORD(reader); + block.flags = _mm_read_I_UWORD(reader); + block.tt_entries = _mm_read_I_UWORD(reader); + block.num_bits = _mm_read_I_UWORD(reader); + + if (!block.unpk_size || !block.pk_size || !block.sub_blk) + goto err; + if (block.pk_size <= block.tt_entries) + goto err; + if (block.flags & MMCMP_COMP) { + if (block.flags & MMCMP_16BIT) { + if (block.num_bits >= 16) + goto err; + } + else { + if (block.num_bits >= 8) + goto err; + } + } + + srcpos += 20 + block.sub_blk*8; + if (srcpos >= srclen) goto err; + + if (numsubs < block.sub_blk) { + numsubs = (block.sub_blk + 31) & ~31; + MikMod_free(subblocks); + subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK)); + if (!subblocks) goto err; + } + for (i = 0; i < block.sub_blk; i++) { + subblocks[i].unpk_pos = _mm_read_I_ULONG(reader); + subblocks[i].unpk_size = _mm_read_I_ULONG(reader); + if (subblocks[i].unpk_pos >= destlen) goto err; + if (subblocks[i].unpk_size > destlen) goto err; + if (subblocks[i].unpk_size > destlen - subblocks[i].unpk_pos) goto err; + } + +#ifdef MMCMP_DEBUG + fprintf(stderr, "block %u: flags=%04X sub_blocks=%u", + blockidx, (unsigned)block.flags, (unsigned)block.sub_blk); + fprintf(stderr, " pksize=%u unpksize=%u", block.pk_size, block.unpk_size); + fprintf(stderr, " tt_entries=%u num_bits=%u\n", block.tt_entries, block.num_bits); +#endif + if (!(block.flags & MMCMP_COMP)) + { /* Data is not packed */ + _mm_fseek(reader,srcpos,SEEK_SET); + destptr = destbuf + subblocks[0].unpk_pos; + i = 0; + + while (1) { +#ifdef MMCMP_DEBUG + fprintf(stderr, " Unpacked sub-block %u: offset %u, size=%u\n", + i, subblocks[i].unpk_pos, subblocks[i].unpk_size); +#endif + _mm_read_UBYTES(destptr,subblocks[i].unpk_size,reader); + destptr += subblocks[i].unpk_size; + if (++i == block.sub_blk) break; + } + } + else if (block.flags & MMCMP_16BIT) + { /* Data is 16-bit packed */ + MMCMPBITBUFFER bb; + ULONG size; + ULONG pos = 0; + ULONG numbits = block.num_bits; + ULONG oldval = 0; + +#ifdef MMCMP_DEBUG + fprintf(stderr, " 16-bit block: pos=%u size=%u ", + subblocks[0].unpk_pos, subblocks[0].unpk_size); + if (block.flags & MMCMP_DELTA) fprintf(stderr, "DELTA "); + if (block.flags & MMCMP_ABS16) fprintf(stderr, "ABS16 "); + fprintf(stderr, "\n"); +#endif + size = block.pk_size - block.tt_entries; + if (bufsize < size) { + while (bufsize < size) bufsize += 65536; + MikMod_free(buf); + if (!(buf = (UBYTE*)MikMod_malloc(bufsize))) + goto err; + } + + bb.bitcount = 0; + bb.bitbuffer = 0; + bb.start = buf; + bb.end = buf + size; + + _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET); + _mm_read_UBYTES(buf,size,reader); + destptr = destbuf + subblocks[0].unpk_pos; + size = subblocks[0].unpk_size; + i = 0; + + while (1) + { + ULONG newval = 0x10000; + ULONG d = MMCMP_GetBits(&bb, numbits+1); + + if (d >= MMCMP16BitCommands[numbits]) + { + ULONG nFetch = MMCMP16BitFetch[numbits]; + ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch); + if (newbits != numbits) + { + numbits = newbits & 0x0F; + } else + { + if ((d = MMCMP_GetBits(&bb, 4)) == 0x0F) + { + if (MMCMP_GetBits(&bb, 1)) break; + newval = 0xFFFF; + } else + { + newval = 0xFFF0 + d; + } + } + } else + { + newval = d; + } + if (newval < 0x10000) + { + newval = (newval & 1) ? (ULONG)(-(SLONG)((newval+1) >> 1)) : (ULONG)(newval >> 1); + if (block.flags & MMCMP_DELTA) + { + newval += oldval; + oldval = newval; + } else + if (!(block.flags & MMCMP_ABS16)) + { + newval ^= 0x8000; + } + destptr[pos++] = (UBYTE) (((UWORD)newval) & 0xff); + destptr[pos++] = (UBYTE) (((UWORD)newval) >> 8); + } + if (pos >= size) + { + if (++i == block.sub_blk) break; + size = subblocks[i].unpk_size; + destptr = destbuf + subblocks[i].unpk_pos; + pos = 0; + } + } + } + else + { /* Data is 8-bit packed */ + MMCMPBITBUFFER bb; + ULONG size; + ULONG pos = 0; + ULONG numbits = block.num_bits; + ULONG oldval = 0; + UBYTE ptable[0x100]; + + size = block.pk_size - block.tt_entries; + if (bufsize < size) { + while (bufsize < size) bufsize += 65536; + MikMod_free(buf); + if (!(buf = (UBYTE*)MikMod_malloc(bufsize))) + goto err; + } + + bb.bitcount = 0; + bb.bitbuffer = 0; + bb.start = buf; + bb.end = buf + size; + + _mm_read_UBYTES(ptable,0x100,reader); + _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET); + _mm_read_UBYTES(buf,size,reader); + destptr = destbuf + subblocks[0].unpk_pos; + size = subblocks[0].unpk_size; + i = 0; + + while (1) + { + ULONG newval = 0x100; + ULONG d = MMCMP_GetBits(&bb, numbits+1); + + if (d >= MMCMP8BitCommands[numbits]) + { + ULONG nFetch = MMCMP8BitFetch[numbits]; + ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch); + if (newbits != numbits) + { + numbits = newbits & 0x07; + } else + { + if ((d = MMCMP_GetBits(&bb, 3)) == 7) + { + if (MMCMP_GetBits(&bb, 1)) break; + newval = 0xFF; + } else + { + newval = 0xF8 + d; + } + } + } else + { + newval = d; + } + if (newval < 0x100) + { + int n = ptable[newval]; + if (block.flags & MMCMP_DELTA) + { + n += oldval; + oldval = n; + } + destptr[pos++] = (UBYTE)n; + } + if (pos >= size) + { + if (++i == block.sub_blk) break; + size = subblocks[i].unpk_size; + destptr = destbuf + subblocks[i].unpk_pos; + pos = 0; + } + } + } + } + + MikMod_free(buf); + MikMod_free(pblk_table); + MikMod_free(subblocks); + *out = destbuf; + *outlen = destlen; + return 1; + + err: + MikMod_free(buf); + MikMod_free(pblk_table); + MikMod_free(subblocks); + MikMod_free(destbuf); + return 0; +}