initial import
[dosrtxon] / libs / mikmod / depackers / xpk.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 /* XPK-SQSH depacker
21  * Algorithm from the portable decruncher by Bert Jahn (24.12.97)
22  * Checksum added by Sipos Attila <h430827@stud.u-szeged.hu>
23  * Rewritten for libxmp by Claudio Matsuoka
24  * Rewritten for libmikmod by O. Sezer
25  *
26  * Copyright (C) 2013 Claudio Matsuoka
27  *
28  * Permission is hereby granted, free of charge, to any person obtaining a
29  * copy of this software and associated documentation files (the "Software"),
30  * to deal in the Software without restriction, including without limitation
31  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
32  * and/or sell copies of the Software, and to permit persons to whom the
33  * Software is furnished to do so, subject to the following conditions:
34  *
35  * The above copyright notice and this permission notice shall be included in
36  * all copies or substantial portions of the Software.
37  *
38  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
39  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
40  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
41  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
42  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
43  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
44  * THE SOFTWARE.
45  */
46
47 #ifdef HAVE_CONFIG_H
48 #include "config.h"
49 #endif
50
51 #ifdef HAVE_UNISTD_H
52 #include <unistd.h>
53 #endif
54
55 #include <stdio.h>
56 #ifdef HAVE_MEMORY_H
57 #include <memory.h>
58 #endif
59 #include <string.h>
60
61 #include "mikmod_internals.h"
62
63 #ifdef SUNOS
64 extern int fprintf(FILE *, const char *, ...);
65 #endif
66
67 struct io {
68         UBYTE *src;
69         UBYTE *dest;
70         int offs;
71 };
72
73 static const UBYTE ctable[]={
74         2, 3, 4, 5, 6, 7, 8, 0,
75         3, 2, 4, 5, 6, 7, 8, 0,
76         4, 3, 5, 2, 6, 7, 8, 0,
77         5, 4, 6, 2, 3, 7, 8, 0,
78         6, 5, 7, 2, 3, 4, 8, 0,
79         7, 6, 8, 2, 3, 4, 5, 0,
80         8, 7, 6, 2, 3, 4, 5, 0
81 };
82
83 static UWORD readmem16b(UBYTE *m)
84 {
85         ULONG a, b;
86
87         a = m[0];
88         b = m[1];
89
90         return (a << 8) | b;
91 }
92
93 static ULONG readmem24b(UBYTE *m)
94 {
95         ULONG a, b, c;
96
97         a = m[0];
98         b = m[1];
99         c = m[2];
100
101         return (a << 16) | (b << 8) | c;
102 }
103
104 static UWORD xchecksum(ULONG * ptr, ULONG count)
105 {
106         register ULONG sum = 0;
107
108         while (count-- > 0) {
109                 sum ^= *ptr++;
110         }
111
112         return (UWORD) (sum ^ (sum >> 16));
113 }
114
115 static int get_bits(struct io *io, int count)
116 {
117         int r = readmem24b(io->src + (io->offs >> 3));
118
119         r <<= io->offs % 8;
120         r &= 0xffffff;
121         r >>= 24 - count;
122         io->offs += count;
123
124         return r;
125 }
126
127 static int get_bits_final(struct io *io, int count)
128 {
129         int r = readmem24b(io->src + (io->offs >> 3));
130
131         r <<= (io->offs % 8) + 8;
132         r >>= 32 - count;
133         io->offs += count;
134
135         return r;
136 }
137
138 static int copy_data(struct io *io, int d1, int *data, UBYTE *dest_start, UBYTE *dest_end)
139 {
140         UBYTE *copy_src;
141         int dest_offset, count, copy_len;
142
143         if (get_bits(io, 1) == 0) {
144                 copy_len = get_bits(io, 1) + 2;
145         } else if (get_bits(io, 1) == 0) {
146                 copy_len = get_bits(io, 1) + 4;
147         } else if (get_bits(io, 1) == 0) {
148                 copy_len = get_bits(io, 1) + 6;
149         } else if (get_bits(io, 1) == 0) {
150                 copy_len = get_bits(io, 3) + 8;
151         } else {
152                 copy_len = get_bits(io, 5) + 16;
153         }
154
155         if (get_bits(io, 1) == 0) {
156                 if (get_bits(io, 1) == 0) {
157                         count = 8;
158                         dest_offset = 0;
159                 } else {
160                         count = 14;
161                         dest_offset = -0x1100;
162                 }
163         } else {
164                 count = 12;
165                 dest_offset = -0x100;
166         }
167
168         copy_len -= 3;
169
170         if (copy_len >= 0) {
171                 if (copy_len != 0) {
172                         d1--;
173                 }
174                 d1--;
175                 if (d1 < 0) {
176                         d1 = 0;
177                 }
178         }
179
180         copy_len += 2;
181
182         copy_src = io->dest + dest_offset - get_bits(io, count) - 1;
183
184         /* Sanity check */
185         if (copy_src < dest_start || copy_src + copy_len >= dest_end) {
186                 return -1;
187         }
188
189         do {
190                 //printf("dest=%p src=%p end=%p\n", io->dest, copy_src, dest_end);
191                 *io->dest++ = *copy_src++;
192         } while (copy_len--);
193
194         *data = *(--copy_src);
195
196         return d1;
197 }
198
199 static int unsqsh_block(struct io *io, UBYTE *dest_start, UBYTE *dest_end)
200 {
201         int d1, d2, data, unpack_len, count, old_count;
202
203         d1 = d2 = data = old_count = 0;
204         io->offs = 0;
205
206         data = *(io->src++);
207         *(io->dest++) = data;
208
209         do {
210                 if (d1 < 8) {
211                         if (get_bits(io, 1)) {
212                                 d1 = copy_data(io, d1, &data, dest_start, dest_end);
213                                 if (d1 < 0)
214                                         return -1;
215                                 d2 -= d2 >> 3;
216                                 continue;
217                         } 
218                         unpack_len = 0;
219                         count = 8;
220                 } else {
221                         if (get_bits(io, 1)) {
222                                 count = 8;
223                                 if (count == old_count) {
224                                         if (d2 >= 20) {
225                                                 unpack_len = 1;
226                                                 d2 += 8;
227                                         } else {
228                                                 unpack_len = 0;
229                                         }
230                                 } else {
231                                         count = old_count;
232                                         unpack_len = 4;
233                                         d2 += 8;
234                                 }
235                         } else {
236                                 if (get_bits(io, 1) == 0) {
237                                         d1 = copy_data(io, d1, &data, dest_start, dest_end);
238                                         if (d1 < 0)
239                                                 return -1;
240                                         d2 -= d2 >> 3;
241                                         continue;
242                                 }
243
244                                 if (get_bits(io, 1) == 0) {
245                                         count = 2;
246                                 } else {
247                                         if (get_bits(io, 1)) {
248                                                 io->offs--;
249                                                 count = get_bits(io, 3);
250                                         } else {
251                                                 count = 3;
252                                         }
253                                 }
254
255                                 count = ctable[8 * old_count + count - 17];
256                                 if (count != 8) {
257                                         unpack_len = 4;
258                                         d2 += 8;
259                                 } else {
260                                         if (d2 >= 20) {
261                                                 unpack_len = 1;
262                                                 d2 += 8;
263                                         } else {
264                                                 unpack_len = 0;
265                                         }
266                                 }
267                         }
268                 }
269
270                 do {
271                         data -= get_bits_final(io, count);
272                         *io->dest++ = data;
273                 } while (unpack_len--);
274
275                 if (d1 != 31) {
276                         d1++;
277                 }
278
279                 old_count = count;
280
281                 d2 -= d2 >> 3;
282
283         } while (io->dest < dest_end);
284
285         return 0;
286 }
287
288 static int unsqsh(UBYTE *src, SLONG srclen, UBYTE *dest, SLONG destlen)
289 {
290         SLONG len = destlen;
291         SLONG decrunched = 0;
292         UBYTE type;
293         SLONG packed_size, unpacked_size;
294         ULONG sum, lchk;
295         UBYTE *c, *dest_start, *dest_end;
296         UBYTE bc[3];
297         struct io io;
298
299         io.src = src;
300         io.dest = dest;
301
302         dest_start = io.dest;
303
304         c = src + 20;
305
306         while (len) {
307                 /* Sanity check */
308                 if (c >= src + srclen) {
309                         return -1;
310                 }
311
312                 type = *c++;
313                 c++;                    /* hchk */
314
315                 sum = *(UWORD *)c;
316                 c += 2;                 /* checksum */
317
318                 packed_size = readmem16b(c);    /* packed */
319                 c += 2;
320
321                 unpacked_size = readmem16b(c);  /* unpacked */
322                 c += 2;
323
324                 /* Sanity check */
325                 if (packed_size <= 0 || unpacked_size <= 0) {
326                         return -1;
327                 }
328                 if (c + packed_size + 3 > src + srclen) {
329                         return -1;
330                 }
331
332                 io.src = c + 2;
333                 memcpy(bc, c + packed_size, 3);
334                 memset(c + packed_size, 0, 3);
335                 lchk = xchecksum((ULONG *) (c), (packed_size + 3) >> 2);
336                 memcpy(c + packed_size, bc, 3);
337
338                 if (lchk != sum) {
339                         return decrunched;
340                 }
341
342                 if (type == 0) {
343                         /* verbatim block */
344                         memcpy(io.dest, c, packed_size);
345                         io.dest += packed_size;
346                         c += packed_size;
347                         len -= packed_size;
348                         decrunched += packed_size;
349                         continue;
350                 }
351
352                 if (type != 1) {
353                         /* unknown type */
354                         return decrunched;
355                 }
356
357                 len -= unpacked_size;
358                 decrunched += unpacked_size;
359
360                 /* Sanity check */
361                 if (decrunched > destlen) {
362                         return -1;
363                 }
364
365                 packed_size = (packed_size + 3) & 0xfffc;
366                 c += packed_size;
367                 dest_end = io.dest + unpacked_size;
368
369                 if (unsqsh_block(&io, dest_start, dest_end) < 0) {
370                         return -1;
371                 }
372                 
373                 io.dest = dest_end;
374         }
375
376         return decrunched;
377
378 }
379
380 BOOL XPK_Unpack(MREADER *reader, void **out, long *outlen)
381 {
382         UBYTE *src, *dest;
383         SLONG inlen, srclen, destlen;
384
385         _mm_fseek(reader,0,SEEK_END);
386         inlen = _mm_ftell(reader);
387         if (inlen <= 8 || inlen > 0x100000)
388                 return 0;
389
390         _mm_rewind(reader);
391         if (_mm_read_M_ULONG(reader) != 0x58504b46) /* XPKF */
392                 return 0;
393         srclen = _mm_read_M_SLONG(reader);
394         if (srclen <= 8 || srclen > 0x100000 || srclen > inlen-8)
395                 return 0;
396         if (_mm_read_M_ULONG(reader) != 0x53515348) /* SQSH */
397                 return 0;
398         destlen = _mm_read_M_SLONG(reader);
399         if (destlen < 0 || destlen > 0x200000)
400                 return 0;
401
402         if ((src = (UBYTE*) MikMod_malloc(srclen + 3)) == NULL)
403                 return 0;
404         if ((dest = (UBYTE*) MikMod_malloc(destlen + 100)) == NULL) {
405                 MikMod_free(src);
406                 return 0;
407         }
408
409         if (!_mm_read_UBYTES(src, srclen - 8, reader))
410                 goto err;
411
412         if (unsqsh(src, srclen, dest, destlen) != destlen)
413                 goto err;
414
415         *out = dest;
416         *outlen = destlen;
417
418         MikMod_free(src);
419
420         return 1;
421
422     err:
423         MikMod_free(dest);
424         MikMod_free(src);
425         return 0;
426 }
427