Mercurial > audlegacy
annotate Plugins/Input/adplug/core/cff.cpp @ 1376:c71e2ef2dcf4 trunk
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
author | chainsaw |
---|---|
date | Sat, 08 Jul 2006 08:29:18 -0700 |
parents | 8df427a314a8 |
children | f12d7e208b43 |
rev | line source |
---|---|
359 | 1 /* |
2 AdPlug - Replayer for many OPL2/OPL3 audio file formats. | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
3 Copyright (C) 1999 - 2006 Simon Peter <dn.tlp@gmx.net>, et al. |
359 | 4 |
5 This library is free software; you can redistribute it and/or | |
6 modify it under the terms of the GNU Lesser General Public | |
7 License as published by the Free Software Foundation; either | |
8 version 2.1 of the License, or (at your option) any later version. | |
9 | |
10 This library is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 Lesser General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU Lesser General Public | |
16 License along with this library; if not, write to the Free Software | |
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
18 | |
19 cff.cpp - BoomTracker loader by Riven the Mage <riven@ok.ru> | |
20 */ | |
21 /* | |
22 NOTE: Conversion of slides is not 100% accurate. Original volume slides | |
23 have effect on carrier volume only. Also, original arpeggio, frequency & volume | |
24 slides use previous effect data instead of current. | |
25 */ | |
26 | |
27 #include <stdlib.h> | |
28 | |
29 #include "cff.h" | |
30 | |
31 /* -------- Public Methods -------------------------------- */ | |
32 | |
33 CPlayer *CcffLoader::factory(Copl *newopl) | |
34 { | |
35 return new CcffLoader(newopl); | |
36 } | |
37 | |
38 bool CcffLoader::load(const std::string &filename, const CFileProvider &fp) | |
39 { | |
40 binistream *f = fp.open(filename); if(!f) return false; | |
41 const unsigned char conv_inst[11] = { 2,1,10,9,4,3,6,5,0,8,7 }; | |
42 const unsigned short conv_note[12] = { 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE }; | |
43 | |
44 int i,j,k,t=0; | |
45 | |
46 // '<CUD-FM-File>' - signed ? | |
47 f->readString(header.id, 16); | |
48 header.version = f->readInt(1); header.size = f->readInt(2); | |
49 header.packed = f->readInt(1); f->readString((char *)header.reserved, 12); | |
50 if (memcmp(header.id,"<CUD-FM-File>""\x1A\xDE\xE0",16)) | |
51 { fp.close(f); return false; } | |
52 | |
53 unsigned char *module = new unsigned char [0x10000]; | |
54 | |
55 // packed ? | |
56 if (header.packed) | |
57 { | |
58 cff_unpacker *unpacker = new cff_unpacker; | |
59 | |
60 unsigned char *packed_module = new unsigned char [header.size + 4]; | |
61 | |
62 memset(packed_module,0,header.size + 4); | |
63 | |
64 f->readString((char *)packed_module, header.size); | |
65 fp.close(f); | |
66 | |
67 if (!unpacker->unpack(packed_module,module)) | |
68 { | |
69 delete unpacker; | |
70 delete packed_module; | |
71 delete module; | |
72 return false; | |
73 } | |
74 | |
75 delete unpacker; | |
76 delete packed_module; | |
77 | |
78 if (memcmp(&module[0x5E1],"CUD-FM-File - SEND A POSTCARD -",31)) | |
79 { | |
80 delete module; | |
81 return false; | |
82 } | |
83 } | |
84 else | |
85 { | |
86 f->readString((char *)module, header.size); | |
87 fp.close(f); | |
88 } | |
89 | |
90 // init CmodPlayer | |
91 realloc_instruments(47); | |
92 realloc_order(64); | |
93 realloc_patterns(36,64,9); | |
94 init_notetable(conv_note); | |
95 init_trackord(); | |
96 | |
97 // load instruments | |
98 for (i=0;i<47;i++) | |
99 { | |
100 memcpy(&instruments[i],&module[i*32],sizeof(cff_instrument)); | |
101 | |
102 for (j=0;j<11;j++) | |
103 inst[i].data[conv_inst[j]] = instruments[i].data[j]; | |
104 | |
105 instruments[i].name[20] = 0; | |
106 } | |
107 | |
108 // number of patterns | |
109 nop = module[0x5E0]; | |
110 | |
111 // load title & author | |
112 memcpy(song_title,&module[0x614],20); | |
113 memcpy(song_author,&module[0x600],20); | |
114 | |
115 // load order | |
116 memcpy(order,&module[0x628],64); | |
117 | |
118 // load tracks | |
119 for (i=0;i<nop;i++) | |
120 { | |
121 unsigned char old_event_byte2[9]; | |
122 | |
123 memset(old_event_byte2,0,9); | |
124 | |
125 for (j=0;j<9;j++) | |
126 { | |
127 for (k=0;k<64;k++) | |
128 { | |
129 cff_event *event = (cff_event *)&module[0x669 + ((i*64+k)*9+j)*3]; | |
130 | |
131 // convert note | |
132 if (event->byte0 == 0x6D) | |
133 tracks[t][k].note = 127; | |
134 else | |
135 if (event->byte0) | |
136 tracks[t][k].note = event->byte0; | |
137 | |
138 if (event->byte2) | |
139 old_event_byte2[j] = event->byte2; | |
140 | |
141 // convert effect | |
142 switch (event->byte1) | |
143 { | |
144 case 'I': // set instrument | |
145 tracks[t][k].inst = event->byte2 + 1; | |
146 tracks[t][k].param1 = tracks[t][k].param2 = 0; | |
147 break; | |
148 | |
149 case 'H': // set tempo | |
150 tracks[t][k].command = 7; | |
151 if (event->byte2 < 16) | |
152 { | |
153 tracks[t][k].param1 = 0x07; | |
154 tracks[t][k].param2 = 0x0D; | |
155 } | |
156 break; | |
157 | |
158 case 'A': // set speed | |
159 tracks[t][k].command = 19; | |
160 tracks[t][k].param1 = event->byte2 >> 4; | |
161 tracks[t][k].param2 = event->byte2 & 15; | |
162 break; | |
163 | |
164 case 'L': // pattern break | |
165 tracks[t][k].command = 13; | |
166 tracks[t][k].param1 = event->byte2 >> 4; | |
167 tracks[t][k].param2 = event->byte2 & 15; | |
168 break; | |
169 | |
170 case 'K': // order jump | |
171 tracks[t][k].command = 11; | |
172 tracks[t][k].param1 = event->byte2 >> 4; | |
173 tracks[t][k].param2 = event->byte2 & 15; | |
174 break; | |
175 | |
176 case 'M': // set vibrato/tremolo | |
177 tracks[t][k].command = 27; | |
178 tracks[t][k].param1 = event->byte2 >> 4; | |
179 tracks[t][k].param2 = event->byte2 & 15; | |
180 break; | |
181 | |
182 case 'C': // set modulator volume | |
183 tracks[t][k].command = 21; | |
184 tracks[t][k].param1 = (0x3F - event->byte2) >> 4; | |
185 tracks[t][k].param2 = (0x3F - event->byte2) & 15; | |
186 break; | |
187 | |
188 case 'G': // set carrier volume | |
189 tracks[t][k].command = 22; | |
190 tracks[t][k].param1 = (0x3F - event->byte2) >> 4; | |
191 tracks[t][k].param2 = (0x3F - event->byte2) & 15; | |
192 break; | |
193 | |
194 case 'B': // set carrier waveform | |
195 tracks[t][k].command = 25; | |
196 tracks[t][k].param1 = event->byte2; | |
197 tracks[t][k].param2 = 0x0F; | |
198 break; | |
199 | |
200 case 'E': // fine frequency slide down | |
201 tracks[t][k].command = 24; | |
202 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
203 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
204 break; | |
205 | |
206 case 'F': // fine frequency slide up | |
207 tracks[t][k].command = 23; | |
208 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
209 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
210 break; | |
211 | |
212 case 'D': // fine volume slide | |
213 tracks[t][k].command = 14; | |
214 if (old_event_byte2[j] & 15) | |
215 { | |
216 // slide down | |
217 tracks[t][k].param1 = 5; | |
218 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
219 } | |
220 else | |
221 { | |
222 // slide up | |
223 tracks[t][k].param1 = 4; | |
224 tracks[t][k].param2 = old_event_byte2[j] >> 4; | |
225 } | |
226 break; | |
227 | |
228 case 'J': // arpeggio | |
229 tracks[t][k].param1 = old_event_byte2[j] >> 4; | |
230 tracks[t][k].param2 = old_event_byte2[j] & 15; | |
231 break; | |
232 } | |
233 } | |
234 | |
235 t++; | |
236 } | |
237 } | |
238 | |
239 delete [] module; | |
240 | |
241 // order loop | |
242 restartpos = 0; | |
243 | |
244 // order length | |
245 for (i=0;i<64;i++) | |
246 { | |
247 if (order[i] >= 0x80) | |
248 { | |
249 length = i; | |
250 break; | |
251 } | |
252 } | |
253 | |
254 // default tempo | |
255 bpm = 0x7D; | |
256 | |
257 rewind(0); | |
258 | |
259 return true; | |
260 } | |
261 | |
262 void CcffLoader::rewind(int subsong) | |
263 { | |
264 CmodPlayer::rewind(subsong); | |
265 | |
266 // default instruments | |
267 for (int i=0;i<9;i++) | |
268 { | |
269 channel[i].inst = i; | |
270 | |
271 channel[i].vol1 = 63 - (inst[i].data[10] & 63); | |
272 channel[i].vol2 = 63 - (inst[i].data[9] & 63); | |
273 } | |
274 } | |
275 | |
276 std::string CcffLoader::gettype() | |
277 { | |
278 if (header.packed) | |
279 return std::string("BoomTracker 4, packed"); | |
280 else | |
281 return std::string("BoomTracker 4"); | |
282 } | |
283 | |
284 std::string CcffLoader::gettitle() | |
285 { | |
286 return std::string(song_title,20); | |
287 } | |
288 | |
289 std::string CcffLoader::getauthor() | |
290 { | |
291 return std::string(song_author,20); | |
292 } | |
293 | |
294 std::string CcffLoader::getinstrument(unsigned int n) | |
295 { | |
296 return std::string(instruments[n].name); | |
297 } | |
298 | |
299 unsigned int CcffLoader::getinstruments() | |
300 { | |
301 return 47; | |
302 } | |
303 | |
304 /* -------- Private Methods ------------------------------- */ | |
305 | |
306 #ifdef _WIN32 | |
307 #pragma warning(disable:4244) | |
308 #pragma warning(disable:4018) | |
309 #endif | |
310 | |
311 /* | |
312 Lempel-Ziv-Tyr ;-) | |
313 */ | |
314 long CcffLoader::cff_unpacker::unpack(unsigned char *ibuf, unsigned char *obuf) | |
315 { | |
316 if (memcmp(ibuf,"YsComp""\x07""CUD1997""\x1A\x04",16)) | |
317 return 0; | |
318 | |
319 input = ibuf + 16; | |
320 output = obuf; | |
321 | |
322 output_length = 0; | |
323 | |
324 heap = (unsigned char *)malloc(0x10000); | |
325 dictionary = (unsigned char **)malloc(sizeof(unsigned char *)*0x8000); | |
326 | |
327 memset(heap,0,0x10000); | |
328 memset(dictionary,0,0x8000); | |
329 | |
330 cleanup(); | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
331 if(!startup()) |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
332 goto out; |
359 | 333 |
334 // LZW | |
335 while (1) | |
336 { | |
337 new_code = get_code(); | |
338 | |
339 // 0x00: end of data | |
340 if (new_code == 0) | |
341 break; | |
342 | |
343 // 0x01: end of block | |
344 if (new_code == 1) | |
345 { | |
346 cleanup(); | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
347 if(!startup()) |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
348 goto out; |
359 | 349 |
350 continue; | |
351 } | |
352 | |
353 // 0x02: expand code length | |
354 if (new_code == 2) | |
355 { | |
356 code_length++; | |
357 | |
358 continue; | |
359 } | |
360 | |
361 // 0x03: RLE | |
362 if (new_code == 3) | |
363 { | |
364 unsigned char old_code_length = code_length; | |
365 | |
366 code_length = 2; | |
367 | |
368 unsigned char repeat_length = get_code() + 1; | |
369 | |
370 code_length = 4 << get_code(); | |
371 | |
372 unsigned long repeat_counter = get_code(); | |
373 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
374 if(output_length + repeat_counter * repeat_length > 0x10000) { |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
375 output_length = 0; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
376 goto out; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
377 } |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
378 |
359 | 379 for (unsigned int i=0;i<repeat_counter*repeat_length;i++) |
380 output[output_length++] = output[output_length - repeat_length]; | |
381 | |
382 code_length = old_code_length; | |
383 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
384 if(!startup()) |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
385 goto out; |
359 | 386 |
387 continue; | |
388 } | |
389 | |
390 if (new_code >= (0x104 + dictionary_length)) | |
391 { | |
392 // dictionary <- old.code.string + old.code.char | |
393 the_string[++the_string[0]] = the_string[1]; | |
394 } | |
395 else | |
396 { | |
397 // dictionary <- old.code.string + new.code.char | |
398 unsigned char temp_string[256]; | |
399 | |
400 translate_code(new_code,temp_string); | |
401 | |
402 the_string[++the_string[0]] = temp_string[1]; | |
403 } | |
404 | |
405 expand_dictionary(the_string); | |
406 | |
407 // output <- new.code.string | |
408 translate_code(new_code,the_string); | |
409 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
410 if(output_length + the_string[0] > 0x10000) { |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
411 output_length = 0; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
412 goto out; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
413 } |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
414 |
359 | 415 for (int i=0;i<the_string[0];i++) |
416 output[output_length++] = the_string[i+1]; | |
417 | |
418 old_code = new_code; | |
419 } | |
420 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
421 out: |
359 | 422 free(heap); |
423 free(dictionary); | |
424 return output_length; | |
425 } | |
426 | |
427 unsigned long CcffLoader::cff_unpacker::get_code() | |
428 { | |
429 unsigned long code; | |
430 | |
431 while (bits_left < code_length) | |
432 { | |
433 bits_buffer |= ((*input++) << bits_left); | |
434 bits_left += 8; | |
435 } | |
436 | |
437 code = bits_buffer & ((1 << code_length) - 1); | |
438 | |
439 bits_buffer >>= code_length; | |
440 bits_left -= code_length; | |
441 | |
442 return code; | |
443 } | |
444 | |
445 void CcffLoader::cff_unpacker::translate_code(unsigned long code, unsigned char *string) | |
446 { | |
447 unsigned char translated_string[256]; | |
448 | |
449 if (code >= 0x104) | |
450 { | |
451 memcpy(translated_string,dictionary[code - 0x104],(*(dictionary[code - 0x104])) + 1); | |
452 } | |
453 else | |
454 { | |
455 translated_string[0] = 1; | |
456 translated_string[1] = (code - 4) & 0xFF; | |
457 } | |
458 | |
459 memcpy(string,translated_string,256); | |
460 } | |
461 | |
462 void CcffLoader::cff_unpacker::cleanup() | |
463 { | |
464 code_length = 9; | |
465 | |
466 bits_buffer = 0; | |
467 bits_left = 0; | |
468 | |
469 heap_length = 0; | |
470 dictionary_length = 0; | |
471 } | |
472 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
473 int CcffLoader::cff_unpacker::startup() |
359 | 474 { |
475 old_code = get_code(); | |
476 | |
477 translate_code(old_code,the_string); | |
478 | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
479 if(output_length + the_string[0] > 0x10000) { |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
480 output_length = 0; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
481 return 0; |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
482 } |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
483 |
359 | 484 for (int i=0;i<the_string[0];i++) |
485 output[output_length++] = the_string[i+1]; | |
1376
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
486 |
c71e2ef2dcf4
[svn] Security fixes from AdPlug CVS (their July 7 commit shortly before the secunia announcement).
chainsaw
parents:
359
diff
changeset
|
487 return 1; |
359 | 488 } |
489 | |
490 void CcffLoader::cff_unpacker::expand_dictionary(unsigned char *string) | |
491 { | |
492 if (string[0] >= 0xF0) | |
493 return; | |
494 | |
495 memcpy(&heap[heap_length],string,string[0] + 1); | |
496 | |
497 dictionary[dictionary_length] = &heap[heap_length]; | |
498 | |
499 dictionary_length++; | |
500 | |
501 heap_length += (string[0] + 1); | |
502 } | |
503 | |
504 #ifdef _WIN32 | |
505 #pragma warning(default:4244) | |
506 #pragma warning(default:4018) | |
507 #endif |