added page flipping/scrolling VBE calls
[dosrtxon] / libs / mikmod / depackers / mmcmp.c
1 /* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
2  * see AUTHORS file for a complete list.
3  *
4  * This library is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU Library General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
17  * 02111-1307, USA.
18  */
19
20 /* MMCMP ("ziRCONia") decompression support
21  *
22  * Based on the public domain version from the libmodplug library by
23  * Olivier Lapicque <olivierl@jps.net> (sezero's fork of libmodplug
24  * at github: http://github.com/sezero/libmodplug/tree/sezero )
25  *
26  * Rewritten for libmikmod by O. Sezer <sezero@users.sourceforge.net>
27  * with some extra ideas from the libxmp version by Claudio Matsuoka.
28  */
29
30 #ifdef HAVE_CONFIG_H
31 #include "config.h"
32 #endif
33
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #include <stdio.h>
39 #ifdef HAVE_MEMORY_H
40 #include <memory.h>
41 #endif
42 #include <string.h>
43
44 #include "mikmod_internals.h"
45
46 #ifdef SUNOS
47 extern int fprintf(FILE *, const char *, ...);
48 #endif
49
50 /*#define MMCMP_DEBUG*/
51
52 typedef struct MMCMPFILEHDR
53 {
54         UBYTE id[8]; /* string 'ziRCONia' */
55         UWORD hdrsize; /* sizeof MMCMPHEADER */
56 } MMCMPFILEHDR; /* 10 bytes */
57
58 typedef struct MMCMPHEADER
59 {
60         UWORD version;
61         UWORD nblocks;
62         ULONG filesize;
63         ULONG blktable;
64         UBYTE glb_comp;
65         UBYTE fmt_comp;
66 } MMCMPHEADER; /* 14 bytes */
67
68 typedef struct MMCMPBLOCK
69 {
70         ULONG unpk_size;
71         ULONG pk_size;
72         ULONG xor_chk;
73         UWORD sub_blk;
74         UWORD flags;
75         UWORD tt_entries;
76         UWORD num_bits;
77 } MMCMPBLOCK; /* 20 bytes */
78
79 typedef struct MMCMPSUBBLOCK
80 {
81         ULONG unpk_pos;
82         ULONG unpk_size;
83 } MMCMPSUBBLOCK; /* 8 bytes */
84
85 #define MMCMP_COMP      0x0001
86 #define MMCMP_DELTA     0x0002
87 #define MMCMP_16BIT     0x0004
88 #define MMCMP_STEREO    0x0100
89 #define MMCMP_ABS16     0x0200
90 #define MMCMP_ENDIAN    0x0400
91
92
93 typedef struct MMCMPBITBUFFER
94 {
95         ULONG bitcount;
96         ULONG bitbuffer;
97         const UBYTE *start;
98         const UBYTE *end;
99 } MMCMPBITBUFFER;
100
101 static ULONG MMCMP_GetBits(MMCMPBITBUFFER* b, ULONG nBits)
102 {
103         ULONG d;
104         if (!nBits) return 0;
105         while (b->bitcount < 24)
106         {
107                 b->bitbuffer |= ((b->start < b->end) ? *b->start++ : 0) << b->bitcount;
108                 b->bitcount += 8;
109         }
110         d = b->bitbuffer & ((1 << nBits) - 1);
111         b->bitbuffer >>= nBits;
112         b->bitcount -= nBits;
113         return d;
114 }
115
116 static const ULONG MMCMP8BitCommands[8] =
117 {
118         0x01, 0x03,     0x07, 0x0F,     0x1E, 0x3C,     0x78, 0xF8
119 };
120
121 static const ULONG MMCMP8BitFetch[8] =
122 {
123         3, 3, 3, 3, 2, 1, 0, 0
124 };
125
126 static const ULONG MMCMP16BitCommands[16] =
127 {
128         0x01, 0x03,     0x07, 0x0F,     0x1E, 0x3C,     0x78, 0xF0,
129         0x1F0, 0x3F0, 0x7F0, 0xFF0, 0x1FF0, 0x3FF0, 0x7FF0, 0xFFF0
130 };
131
132 static const ULONG MMCMP16BitFetch[16] =
133 {
134         4, 4, 4, 4, 3, 2, 1, 0,
135         0, 0, 0, 0, 0, 0, 0, 0
136 };
137
138
139 BOOL MMCMP_Unpack(MREADER* reader, void** out, long* outlen)
140 {
141         ULONG srclen, destlen;
142         UBYTE *destbuf, *destptr;
143         MMCMPHEADER mmh;
144         ULONG *pblk_table;
145         MMCMPSUBBLOCK *subblocks;
146         ULONG i, blockidx, numsubs;
147         UBYTE *buf;  ULONG bufsize;
148
149         _mm_fseek(reader,0,SEEK_END);
150         srclen = _mm_ftell(reader);
151         if (srclen < 256) return 0;
152
153         _mm_rewind(reader);
154         if (_mm_read_I_ULONG(reader) != 0x4352697A)     /* 'ziRC' */
155                 return 0;
156         if (_mm_read_I_ULONG(reader) != 0x61694e4f)     /* 'ONia' */
157                 return 0;
158         if (_mm_read_I_UWORD(reader) != 14)             /* header size */
159                 return 0;
160
161         mmh.version = _mm_read_I_UWORD(reader);
162         mmh.nblocks = _mm_read_I_UWORD(reader);
163         mmh.filesize = _mm_read_I_ULONG(reader);
164         mmh.blktable = _mm_read_I_ULONG(reader);
165         mmh.glb_comp = _mm_read_UBYTE(reader);
166         mmh.fmt_comp = _mm_read_UBYTE(reader);
167
168         if ((!mmh.nblocks) || (mmh.filesize < 16) || (mmh.filesize > 0x8000000) ||
169             (mmh.blktable >= srclen) || (mmh.blktable + 4*mmh.nblocks > srclen)) {
170                 return 0;
171         }
172         destlen = mmh.filesize;
173         numsubs = 32;
174         bufsize = 65536;
175
176         destbuf = (UBYTE*)MikMod_malloc(destlen);
177         buf = (UBYTE*)MikMod_malloc(bufsize);
178         pblk_table = (ULONG*)MikMod_malloc(mmh.nblocks*4);
179         subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK));
180         if (!destbuf || !buf || !pblk_table || !subblocks)
181                 goto err;
182
183         _mm_fseek(reader,mmh.blktable,SEEK_SET);
184         for (blockidx = 0; blockidx < mmh.nblocks; blockidx++) {
185                 pblk_table[blockidx] = _mm_read_I_ULONG(reader);
186         }
187
188         for (blockidx = 0; blockidx < mmh.nblocks; blockidx++)
189         {
190                 ULONG srcpos = pblk_table[blockidx];
191                 MMCMPBLOCK block;
192
193                 if (srcpos + 20 >= srclen) goto err;
194
195                 _mm_fseek(reader,srcpos,SEEK_SET);
196                 block.unpk_size = _mm_read_I_ULONG(reader);
197                 block.pk_size = _mm_read_I_ULONG(reader);
198                 block.xor_chk = _mm_read_I_ULONG(reader);
199                 block.sub_blk = _mm_read_I_UWORD(reader);
200                 block.flags = _mm_read_I_UWORD(reader);
201                 block.tt_entries = _mm_read_I_UWORD(reader);
202                 block.num_bits = _mm_read_I_UWORD(reader);
203
204                 if (!block.unpk_size || !block.pk_size || !block.sub_blk)
205                         goto err;
206                 if (block.pk_size <= block.tt_entries)
207                         goto err;
208                 if (block.flags & MMCMP_COMP) {
209                         if (block.flags & MMCMP_16BIT) {
210                                 if (block.num_bits >= 16)
211                                         goto err;
212                         }
213                         else {
214                                 if (block.num_bits >=  8)
215                                         goto err;
216                         }
217                 }
218
219                 srcpos += 20 + block.sub_blk*8;
220                 if (srcpos >= srclen) goto err;
221
222                 if (numsubs < block.sub_blk) {
223                         numsubs = (block.sub_blk + 31) & ~31;
224                         MikMod_free(subblocks);
225                         subblocks = (MMCMPSUBBLOCK*)MikMod_malloc(numsubs*sizeof(MMCMPSUBBLOCK));
226                         if (!subblocks) goto err;
227                 }
228                 for (i = 0; i < block.sub_blk; i++) {
229                         subblocks[i].unpk_pos = _mm_read_I_ULONG(reader);
230                         subblocks[i].unpk_size = _mm_read_I_ULONG(reader);
231                         if (subblocks[i].unpk_pos >= destlen) goto err;
232                         if (subblocks[i].unpk_size > destlen) goto err;
233                         if (subblocks[i].unpk_size > destlen - subblocks[i].unpk_pos) goto err;
234                 }
235
236 #ifdef MMCMP_DEBUG
237                 fprintf(stderr, "block %u: flags=%04X sub_blocks=%u",
238                                   blockidx, (unsigned)block.flags, (unsigned)block.sub_blk);
239                 fprintf(stderr, " pksize=%u unpksize=%u", block.pk_size, block.unpk_size);
240                 fprintf(stderr, " tt_entries=%u num_bits=%u\n", block.tt_entries, block.num_bits);
241 #endif
242                 if (!(block.flags & MMCMP_COMP))
243                 { /* Data is not packed */
244                         _mm_fseek(reader,srcpos,SEEK_SET);
245                         destptr = destbuf + subblocks[0].unpk_pos;
246                         i = 0;
247
248                         while (1) {
249 #ifdef MMCMP_DEBUG
250                                 fprintf(stderr, "  Unpacked sub-block %u: offset %u, size=%u\n",
251                                                 i, subblocks[i].unpk_pos, subblocks[i].unpk_size);
252 #endif
253                                 _mm_read_UBYTES(destptr,subblocks[i].unpk_size,reader);
254                                 destptr += subblocks[i].unpk_size;
255                                 if (++i == block.sub_blk) break;
256                         }
257                 }
258                 else if (block.flags & MMCMP_16BIT)
259                 { /* Data is 16-bit packed */
260                         MMCMPBITBUFFER bb;
261                         ULONG size;
262                         ULONG pos = 0;
263                         ULONG numbits = block.num_bits;
264                         ULONG oldval = 0;
265
266 #ifdef MMCMP_DEBUG
267                         fprintf(stderr, "  16-bit block: pos=%u size=%u ",
268                                         subblocks[0].unpk_pos, subblocks[0].unpk_size);
269                         if (block.flags & MMCMP_DELTA) fprintf(stderr, "DELTA ");
270                         if (block.flags & MMCMP_ABS16) fprintf(stderr, "ABS16 ");
271                         fprintf(stderr, "\n");
272 #endif
273                         size = block.pk_size - block.tt_entries;
274                         if (bufsize < size) {
275                                 while (bufsize < size) bufsize += 65536;
276                                 MikMod_free(buf);
277                                 if (!(buf = (UBYTE*)MikMod_malloc(bufsize)))
278                                         goto err;
279                         }
280
281                         bb.bitcount = 0;
282                         bb.bitbuffer = 0;
283                         bb.start = buf;
284                         bb.end = buf + size;
285
286                         _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET);
287                         _mm_read_UBYTES(buf,size,reader);
288                         destptr = destbuf + subblocks[0].unpk_pos;
289                         size = subblocks[0].unpk_size;
290                         i = 0;
291
292                         while (1)
293                         {
294                                 ULONG newval = 0x10000;
295                                 ULONG d = MMCMP_GetBits(&bb, numbits+1);
296
297                                 if (d >= MMCMP16BitCommands[numbits])
298                                 {
299                                         ULONG nFetch = MMCMP16BitFetch[numbits];
300                                         ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP16BitCommands[numbits]) << nFetch);
301                                         if (newbits != numbits)
302                                         {
303                                                 numbits = newbits & 0x0F;
304                                         } else
305                                         {
306                                                 if ((d = MMCMP_GetBits(&bb, 4)) == 0x0F)
307                                                 {
308                                                         if (MMCMP_GetBits(&bb, 1)) break;
309                                                         newval = 0xFFFF;
310                                                 } else
311                                                 {
312                                                         newval = 0xFFF0 + d;
313                                                 }
314                                         }
315                                 } else
316                                 {
317                                         newval = d;
318                                 }
319                                 if (newval < 0x10000)
320                                 {
321                                         newval = (newval & 1) ? (ULONG)(-(SLONG)((newval+1) >> 1)) : (ULONG)(newval >> 1);
322                                         if (block.flags & MMCMP_DELTA)
323                                         {
324                                                 newval += oldval;
325                                                 oldval = newval;
326                                         } else
327                                         if (!(block.flags & MMCMP_ABS16))
328                                         {
329                                                 newval ^= 0x8000;
330                                         }
331                                         destptr[pos++] = (UBYTE) (((UWORD)newval) & 0xff);
332                                         destptr[pos++] = (UBYTE) (((UWORD)newval) >> 8);
333                                 }
334                                 if (pos >= size)
335                                 {
336                                         if (++i == block.sub_blk) break;
337                                         size = subblocks[i].unpk_size;
338                                         destptr = destbuf + subblocks[i].unpk_pos;
339                                         pos = 0;
340                                 }
341                         }
342                 }
343                 else
344                 { /* Data is 8-bit packed */
345                         MMCMPBITBUFFER bb;
346                         ULONG size;
347                         ULONG pos = 0;
348                         ULONG numbits = block.num_bits;
349                         ULONG oldval = 0;
350                         UBYTE ptable[0x100];
351
352                         size = block.pk_size - block.tt_entries;
353                         if (bufsize < size) {
354                                 while (bufsize < size) bufsize += 65536;
355                                 MikMod_free(buf);
356                                 if (!(buf = (UBYTE*)MikMod_malloc(bufsize)))
357                                         goto err;
358                         }
359
360                         bb.bitcount = 0;
361                         bb.bitbuffer = 0;
362                         bb.start = buf;
363                         bb.end = buf + size;
364
365                         _mm_read_UBYTES(ptable,0x100,reader);
366                         _mm_fseek(reader,srcpos+block.tt_entries,SEEK_SET);
367                         _mm_read_UBYTES(buf,size,reader);
368                         destptr = destbuf + subblocks[0].unpk_pos;
369                         size = subblocks[0].unpk_size;
370                         i = 0;
371
372                         while (1)
373                         {
374                                 ULONG newval = 0x100;
375                                 ULONG d = MMCMP_GetBits(&bb, numbits+1);
376
377                                 if (d >= MMCMP8BitCommands[numbits])
378                                 {
379                                         ULONG nFetch = MMCMP8BitFetch[numbits];
380                                         ULONG newbits = MMCMP_GetBits(&bb, nFetch) + ((d - MMCMP8BitCommands[numbits]) << nFetch);
381                                         if (newbits != numbits)
382                                         {
383                                                 numbits = newbits & 0x07;
384                                         } else
385                                         {
386                                                 if ((d = MMCMP_GetBits(&bb, 3)) == 7)
387                                                 {
388                                                         if (MMCMP_GetBits(&bb, 1)) break;
389                                                         newval = 0xFF;
390                                                 } else
391                                                 {
392                                                         newval = 0xF8 + d;
393                                                 }
394                                         }
395                                 } else
396                                 {
397                                         newval = d;
398                                 }
399                                 if (newval < 0x100)
400                                 {
401                                         int n = ptable[newval];
402                                         if (block.flags & MMCMP_DELTA)
403                                         {
404                                                 n += oldval;
405                                                 oldval = n;
406                                         }
407                                         destptr[pos++] = (UBYTE)n;
408                                 }
409                                 if (pos >= size)
410                                 {
411                                         if (++i == block.sub_blk) break;
412                                         size = subblocks[i].unpk_size;
413                                         destptr = destbuf + subblocks[i].unpk_pos;
414                                         pos = 0;
415                                 }
416                         }
417                 }
418         }
419
420         MikMod_free(buf);
421         MikMod_free(pblk_table);
422         MikMod_free(subblocks);
423         *out = destbuf;
424         *outlen = destlen;
425         return 1;
426
427   err:
428         MikMod_free(buf);
429         MikMod_free(pblk_table);
430         MikMod_free(subblocks);
431         MikMod_free(destbuf);
432         return 0;
433 }