1 /* MikMod sound library (c) 2003-2015 Raphael Assenat and others -
2 * see AUTHORS file for a complete list.
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.
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.
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
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
26 * Copyright (C) 2013 Claudio Matsuoka
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:
35 * The above copyright notice and this permission notice shall be included in
36 * all copies or substantial portions of the Software.
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
61 #include "mikmod_internals.h"
64 extern int fprintf(FILE *, const char *, ...);
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
83 static UWORD readmem16b(UBYTE *m)
93 static ULONG readmem24b(UBYTE *m)
101 return (a << 16) | (b << 8) | c;
104 static UWORD xchecksum(ULONG * ptr, ULONG count)
106 register ULONG sum = 0;
108 while (count-- > 0) {
112 return (UWORD) (sum ^ (sum >> 16));
115 static int get_bits(struct io *io, int count)
117 int r = readmem24b(io->src + (io->offs >> 3));
127 static int get_bits_final(struct io *io, int count)
129 int r = readmem24b(io->src + (io->offs >> 3));
131 r <<= (io->offs % 8) + 8;
138 static int copy_data(struct io *io, int d1, int *data, UBYTE *dest_start, UBYTE *dest_end)
141 int dest_offset, count, copy_len;
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;
152 copy_len = get_bits(io, 5) + 16;
155 if (get_bits(io, 1) == 0) {
156 if (get_bits(io, 1) == 0) {
161 dest_offset = -0x1100;
165 dest_offset = -0x100;
182 copy_src = io->dest + dest_offset - get_bits(io, count) - 1;
185 if (copy_src < dest_start || copy_src + copy_len >= dest_end) {
190 //printf("dest=%p src=%p end=%p\n", io->dest, copy_src, dest_end);
191 *io->dest++ = *copy_src++;
192 } while (copy_len--);
194 *data = *(--copy_src);
199 static int unsqsh_block(struct io *io, UBYTE *dest_start, UBYTE *dest_end)
201 int d1, d2, data, unpack_len, count, old_count;
203 d1 = d2 = data = old_count = 0;
207 *(io->dest++) = data;
211 if (get_bits(io, 1)) {
212 d1 = copy_data(io, d1, &data, dest_start, dest_end);
221 if (get_bits(io, 1)) {
223 if (count == old_count) {
236 if (get_bits(io, 1) == 0) {
237 d1 = copy_data(io, d1, &data, dest_start, dest_end);
244 if (get_bits(io, 1) == 0) {
247 if (get_bits(io, 1)) {
249 count = get_bits(io, 3);
255 count = ctable[8 * old_count + count - 17];
271 data -= get_bits_final(io, count);
273 } while (unpack_len--);
283 } while (io->dest < dest_end);
288 static int unsqsh(UBYTE *src, SLONG srclen, UBYTE *dest, SLONG destlen)
291 SLONG decrunched = 0;
293 SLONG packed_size, unpacked_size;
295 UBYTE *c, *dest_start, *dest_end;
302 dest_start = io.dest;
308 if (c >= src + srclen) {
316 c += 2; /* checksum */
318 packed_size = readmem16b(c); /* packed */
321 unpacked_size = readmem16b(c); /* unpacked */
325 if (packed_size <= 0 || unpacked_size <= 0) {
328 if (c + packed_size + 3 > src + srclen) {
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);
344 memcpy(io.dest, c, packed_size);
345 io.dest += packed_size;
348 decrunched += packed_size;
357 len -= unpacked_size;
358 decrunched += unpacked_size;
361 if (decrunched > destlen) {
365 packed_size = (packed_size + 3) & 0xfffc;
367 dest_end = io.dest + unpacked_size;
369 if (unsqsh_block(&io, dest_start, dest_end) < 0) {
380 BOOL XPK_Unpack(MREADER *reader, void **out, long *outlen)
383 SLONG inlen, srclen, destlen;
385 _mm_fseek(reader,0,SEEK_END);
386 inlen = _mm_ftell(reader);
387 if (inlen <= 8 || inlen > 0x100000)
391 if (_mm_read_M_ULONG(reader) != 0x58504b46) /* XPKF */
393 srclen = _mm_read_M_SLONG(reader);
394 if (srclen <= 8 || srclen > 0x100000 || srclen > inlen-8)
396 if (_mm_read_M_ULONG(reader) != 0x53515348) /* SQSH */
398 destlen = _mm_read_M_SLONG(reader);
399 if (destlen < 0 || destlen > 0x200000)
402 if ((src = (UBYTE*) MikMod_malloc(srclen + 3)) == NULL)
404 if ((dest = (UBYTE*) MikMod_malloc(destlen + 100)) == NULL) {
409 if (!_mm_read_UBYTES(src, srclen - 8, reader))
412 if (unsqsh(src, srclen, dest, destlen) != destlen)