1 /*
2  * ProPacker_21.c   Copyright (C) 1997 Sylvain "Asle" Chipaux
3  *
4  * Converts PP21 packed MODs back to PTK MODs
5  * thanks to Gryzor and his ProWizard tool ! ... without it, this prog
6  * would not exist !!!
7  *
8  * Modified in 2006,2009,2014 by Claudio Matsuoka
9  * - Code cleanup
10  *
11  * Modified in 2015 by Claudio Matsuoka
12  * - Add PP30 support
13  */
14 
15 #include "prowiz.h"
16 
17 
depack_pp21_pp30(HIO_HANDLE * in,FILE * out,int is_30)18 static int depack_pp21_pp30(HIO_HANDLE *in, FILE *out, int is_30)
19 {
20 	uint8 ptable[128];
21 	int max = 0;
22 	uint8 trk[4][128];
23 	int tptr[512][64];
24 	uint8 numpat;
25 	uint8 *tab;
26 	uint8 buf[1024];
27 	int i, j;
28 	int size;
29 	int ssize;
30 	int tabsize;		/* Reference Table Size */
31 
32 	memset(ptable, 0, sizeof(ptable));
33 	memset(trk, 0, sizeof(trk));
34 	memset(tptr, 0, sizeof(tptr));
35 
36 	pw_write_zero(out, 20);			/* title */
37 
38 	ssize = 0;
39 	for (i = 0; i < 31; i++) {
40 		pw_write_zero(out, 22);		/* sample name */
41 		write16b(out, size = hio_read16b(in));
42 		ssize += size * 2;
43 		write8(out, hio_read8(in));	/* finetune */
44 		write8(out, hio_read8(in));	/* volume */
45 		write16b(out, hio_read16b(in));	/* loop start */
46 		write16b(out, hio_read16b(in));	/* loop size */
47 	}
48 
49 	numpat = hio_read8(in);			/* number of patterns */
50 
51 	/* Sanity check */
52 	if (numpat > 128) {
53 		return -1;
54 	}
55 
56 	write8(out, numpat);			/* number of patterns */
57 	write8(out, hio_read8(in));		/* NoiseTracker restart byte */
58 
59 	max = 0;
60 	for (j = 0; j < 4; j++) {
61 		for (i = 0; i < 128; i++) {
62 			trk[j][i] = hio_read8(in);
63 			if (trk[j][i] > max)
64 				max = trk[j][i];
65 		}
66 	}
67 
68 	/* write pattern table without any optimizing ! */
69 	for (i = 0; i < numpat; i++)
70 		write8(out, i);
71 	pw_write_zero(out, 128 - i);
72 
73 	write32b(out, PW_MOD_MAGIC);		/* M.K. */
74 
75 	/* PATTERN DATA code starts here */
76 
77 	/*printf ("Highest track number : %d\n", max); */
78 	for (j = 0; j <= max; j++) {
79 		for (i = 0; i < 64; i++) {
80 			tptr[j][i] = hio_read16b(in);
81 			if (is_30) {
82 				tptr[j][i] >>= 2;
83 			}
84 		}
85 	}
86 
87 	/* read "reference table" size */
88 	tabsize = hio_read32b(in);
89 	if (tabsize == 0) {
90 		return -1;
91 	}
92 
93 	/* read "reference Table" */
94 	tab = (uint8 *)malloc(tabsize);
95 	if (hio_read(tab, tabsize, 1, in) != 1) {
96 		free(tab);
97 		return -1;
98 	}
99 
100 	for (i = 0; i < numpat; i++) {
101 		memset(buf, 0, sizeof(buf));
102 		for (j = 0; j < 64; j++) {
103 			uint8 *b = buf + j * 16;
104 			memcpy(b, tab + tptr[trk[0][i]][j] * 4, 4);
105 			memcpy(b + 4, tab + tptr[trk[1][i]][j] * 4, 4);
106 			memcpy(b + 8, tab + tptr[trk[2][i]][j] * 4, 4);
107 			memcpy(b + 12, tab + tptr[trk[3][i]][j] * 4, 4);
108 		}
109 		fwrite (buf, 1024, 1, out);
110 	}
111 
112 	free (tab);
113 
114 	/* Now, it's sample data ... though, VERY quickly handled :) */
115 	pw_move_data(out, in, ssize);
116 
117 	return 0;
118 }
119 
depack_pp21(HIO_HANDLE * in,FILE * out)120 static int depack_pp21(HIO_HANDLE *in, FILE *out)
121 {
122 	return depack_pp21_pp30(in, out, 0);
123 }
124 
depack_pp30(HIO_HANDLE * in,FILE * out)125 static int depack_pp30(HIO_HANDLE *in, FILE *out)
126 {
127 	return depack_pp21_pp30(in, out, 1);
128 }
129 
test_pp21(const uint8 * data,char * t,int s)130 static int test_pp21(const uint8 *data, char *t, int s)
131 {
132 	int i;
133 	int ssize, tsize, npat, max_ref;
134 
135 	PW_REQUEST_DATA(s, 762);
136 
137 	ssize = 0;
138 	for (i = 0; i < 31; i++) {
139 		const uint8 *d = data + i * 8;
140 		int len = readmem16b(d) << 1;
141 		int start = readmem16b(d + 4) << 1;
142 
143 		ssize += len;
144 
145 		/* finetune > 0x0f ? */
146 		if (d[2] > 0x0f)
147 			return -1;
148 
149 		/* volume > 0x40 ? */
150 		if (d[3] > 0x40)
151 			return -1;
152 
153 		/* loop start > size ? */
154 		if (start > len)
155 			return -1;
156 	}
157 
158 	if (ssize <= 2)
159 		return -1;
160 
161 	/* test #3   about size of pattern list */
162 	npat = data[248];
163 	if (npat == 0 || npat > 127)
164 		return -1;
165 
166 	/* get the highest track value */
167 	tsize = 0;
168 	for (i = 0; i < 512; i++) {
169 		int trk = data[250 + i];
170 		if (trk > tsize)
171 			tsize = trk;
172 	}
173 
174 	tsize++;
175 	tsize <<= 6;
176 
177 	PW_REQUEST_DATA(s, tsize * 2 + 4 + 762);
178 
179 	/* test #4  track data value > $4000 ? */
180 	max_ref = 0;
181 	for (i = 0; i < tsize; i++) {
182 		int ref = readmem16b(data + i * 2 + 762);
183 
184 		if (ref > 0x4000)
185 			return -1;
186 
187 		if (ref > max_ref)
188 			max_ref = ref;
189 
190 	}
191 
192 	/* test #5  reference table size *4 ? */
193 	if (readmem32b(data + (tsize << 1) + 762) != (max_ref + 1) * 4)
194 		return -1;
195 
196 	pw_read_title(NULL, t, 0);
197 
198 	return 0;
199 }
200 
201 
test_pp30(const uint8 * data,char * t,int s)202 static int test_pp30(const uint8 *data, char *t, int s)
203 {
204 	int i;
205 	int ssize, tsize, npat, max_ref, ref_size;
206 
207 	PW_REQUEST_DATA(s, 762);
208 
209 	ssize = 0;
210 	for (i = 0; i < 31; i++) {
211 		const uint8 *d = data + i * 8;
212 		int len = readmem16b(d) << 1;
213 		int start = readmem16b(d + 4) << 1;
214 
215 		ssize += len;
216 
217 		/* finetune > 0x0f ? */
218 		if (d[2] > 0x0f)
219 			return -1;
220 
221 		/* volume > 0x40 ? */
222 		if (d[3] > 0x40)
223 			return -1;
224 
225 		/* loop start > size ? */
226 		if (start > len)
227 			return -1;
228 	}
229 
230 	if (ssize <= 2)
231 		return -1;
232 
233 	/* test #3   about size of pattern list */
234 	npat = data[248];
235 	if (npat == 0 || npat > 127)
236 		return -1;
237 
238 	/* get the highest track value */
239 	tsize = 0;
240 	for (i = 0; i < 512; i++) {
241 		int trk = data[250 + i];
242 		if (trk > tsize)
243 			tsize = trk;
244 	}
245 
246 	tsize++;
247 	tsize <<= 6;
248 
249 	PW_REQUEST_DATA(s, (tsize * 2) + 4 + 762);
250 
251 	/* test #4  track data value *4 ? */
252 	max_ref = 0;
253 	for (i = 0; i < tsize; i++) {
254 		int ref = readmem16b(data + i * 2 + 762);
255 
256 		if (ref > max_ref)
257 			max_ref = ref;
258 
259 		if (ref & 0x0003) {
260 			return -1;
261 		}
262 	}
263 	max_ref >>= 2;
264 
265 	/* test #5  reference table size *4 ? */
266 	ref_size = readmem32b(data + (tsize << 1) + 762);
267 
268 	if (ref_size > 0xffff) {
269 		return -1;
270 	}
271 
272 	if (ref_size != ((max_ref + 1) << 2)) {
273 		return -1;
274 	}
275 
276 	ref_size >>= 2;
277 
278 	PW_REQUEST_DATA(s, (ref_size * 4) + (tsize * 2) + 4 + 762);
279 
280 	/* test #6  data in reference table ... */
281 	for (i = 0; i < ref_size; i++) {
282 		const uint8 *d = data + (tsize * 2) + 766 + i * 4;
283 		uint8 fxt = d[2] & 0x0f;
284 		uint8 fxp = d[3];
285 
286 		/* volume > 41 ? */
287 		if (fxt == 0x0c && fxp > 0x41) {
288 			return -1;
289 		}
290 
291 		/* break > 64 (packed decimal) ? */
292 		if (fxt == 0x0d && (fxp > 0x64 || (fxp & 0xf) > 9)) {
293 			return -1;
294 		}
295 
296 		/* jump > 128 */
297 		if (fxt == 0x0b && fxp > 0x7f) {
298 			return -1;
299 		}
300 
301 		/* smp > 1f ? */
302 		if ((d[0] & 0xf0) > 0x10) {
303 			return -1;
304 		}
305 	}
306 
307 	pw_read_title(NULL, t, 0);
308 
309 	return 0;
310 }
311 
312 const struct pw_format pw_pp21 = {
313 	"ProPacker 2.1",
314 	test_pp21,
315 	depack_pp21
316 };
317 
318 const struct pw_format pw_pp30 = {
319 	"ProPacker 3.0",
320 	test_pp30,
321 	depack_pp30
322 };
323