diff options
Diffstat (limited to 'apps/plugins/zxbox/tapefile.c')
-rw-r--r-- | apps/plugins/zxbox/tapefile.c | 1047 |
1 files changed, 1047 insertions, 0 deletions
diff --git a/apps/plugins/zxbox/tapefile.c b/apps/plugins/zxbox/tapefile.c new file mode 100644 index 0000000000..19f6aba980 --- /dev/null +++ b/apps/plugins/zxbox/tapefile.c | |||
@@ -0,0 +1,1047 @@ | |||
1 | /* | ||
2 | * Copyright (C) 1996-1998 Szeredi Miklos | ||
3 | * Email: mszeredi@inf.bme.hu | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; either version 2 of the License, or | ||
8 | * (at your option) any later version. See the file COPYING. | ||
9 | * | ||
10 | * This program 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 | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | /* This module deals with the different tape file formats (.TAP and .TZX) */ | ||
22 | /* 'sptape.c' uses the functions provided by this module. */ | ||
23 | |||
24 | |||
25 | #include "tapefile.h" | ||
26 | #include "tapef_p.h" | ||
27 | |||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <string.h> | ||
31 | #include <errno.h> | ||
32 | #include <sys/types.h> | ||
33 | #include "zxconfig.h" | ||
34 | #include "helpers.h" | ||
35 | #define max(x, y) ((x) > (y) ? (x) : (y)) | ||
36 | |||
37 | #define DESC_LEN 256 | ||
38 | |||
39 | char seg_desc[DESC_LEN]; | ||
40 | |||
41 | #define TZXMAJPROG 1 | ||
42 | #define TZXMINPROG 2 | ||
43 | |||
44 | /*static FILE *tapefp = NULL;*/ | ||
45 | static int tapefd=-1; | ||
46 | |||
47 | static dbyte segi, currsegi; | ||
48 | static int segbeg; | ||
49 | |||
50 | static int endtype, endnext, endplay; | ||
51 | static dbyte endpause; | ||
52 | static int finished; | ||
53 | |||
54 | static long firstseg_offs; | ||
55 | |||
56 | static struct tape_options tapeopt; | ||
57 | |||
58 | long tf_segoffs; | ||
59 | struct tapeinfo tf_tpi; | ||
60 | |||
61 | static dbyte loopctr, loopbeg; | ||
62 | static dbyte callctr, callbeg; | ||
63 | |||
64 | #define ST_NORM 0 | ||
65 | #define ST_PSEQ 1 | ||
66 | #define ST_DIRE 2 | ||
67 | #define ST_MISC 3 | ||
68 | |||
69 | #define PL_NONE 0 | ||
70 | #define PL_PAUSE 1 | ||
71 | #define PL_LEADER 2 | ||
72 | #define PL_DATA 3 | ||
73 | #define PL_END 4 | ||
74 | #define PL_PSEQ 5 | ||
75 | #define PL_DIRE 6 | ||
76 | |||
77 | #define IMP_1MS 3500 | ||
78 | |||
79 | static dbyte lead_pause; | ||
80 | static int playstate = PL_NONE; | ||
81 | static int currlev; | ||
82 | |||
83 | #define DEF_LEAD_PAUSE 2000 | ||
84 | |||
85 | struct seginfo tf_cseg; | ||
86 | |||
87 | struct tzxblock { | ||
88 | int type; | ||
89 | int lenbytes; | ||
90 | int lenmul; | ||
91 | int hlen; | ||
92 | }; | ||
93 | |||
94 | #define NUMBLOCKID 0x60 | ||
95 | /* changed NONE because of warinigs */ | ||
96 | /*#define NONE 0*/ | ||
97 | #define NONE 0,0,0,0 | ||
98 | #define COMM 1 | ||
99 | #define STAN 2 | ||
100 | |||
101 | |||
102 | #define RBUFLEN 1024 | ||
103 | |||
104 | static byte rbuf[RBUFLEN]; | ||
105 | |||
106 | /* Table containing information on TZX blocks */ | ||
107 | |||
108 | static struct tzxblock tzxb[NUMBLOCKID] = { | ||
109 | { NONE }, /* ID: 00 */ | ||
110 | { NONE }, | ||
111 | { NONE }, | ||
112 | { NONE }, | ||
113 | { NONE }, | ||
114 | { NONE }, | ||
115 | { NONE }, | ||
116 | { NONE }, | ||
117 | |||
118 | { NONE }, /* ID: 08 */ | ||
119 | { NONE }, | ||
120 | { NONE }, | ||
121 | { NONE }, | ||
122 | { NONE }, | ||
123 | { NONE }, | ||
124 | { NONE }, | ||
125 | { NONE }, | ||
126 | |||
127 | { COMM, 2, 1, 0x04 }, /* ID: 10 */ | ||
128 | { COMM, 3, 1, 0x12 }, | ||
129 | { COMM, 0, 1, 0x04 }, | ||
130 | { COMM, 1, 2, 0x01 }, | ||
131 | { COMM, 3, 1, 0x0A }, | ||
132 | { COMM, 3, 1, 0x08 }, | ||
133 | { NONE }, | ||
134 | { NONE }, | ||
135 | |||
136 | { NONE }, /* ID: 18 */ | ||
137 | { NONE }, | ||
138 | { NONE }, | ||
139 | { NONE }, | ||
140 | { NONE }, | ||
141 | { NONE }, | ||
142 | { NONE }, | ||
143 | { NONE }, | ||
144 | |||
145 | { COMM, 0, 1, 0x02 }, /* ID: 20 */ | ||
146 | { COMM, 1, 1, 0x01 }, | ||
147 | { COMM, 0, 1, 0x00 }, | ||
148 | { COMM, 0, 1, 0x02 }, | ||
149 | { COMM, 0, 1, 0x02 }, | ||
150 | { COMM, 0, 1, 0x00 }, | ||
151 | { COMM, 2, 2, 0x02 }, | ||
152 | { COMM, 0, 1, 0x00 }, | ||
153 | |||
154 | { COMM, 2, 1, 0x02 }, /* ID: 28 */ | ||
155 | { NONE }, | ||
156 | { STAN, 0, 1, 0x00 }, | ||
157 | { NONE }, | ||
158 | { NONE }, | ||
159 | { NONE }, | ||
160 | { NONE }, | ||
161 | { NONE }, | ||
162 | |||
163 | { COMM, 1, 1, 0x01 }, /* ID: 30 */ | ||
164 | { COMM, 1, 1, 0x02 }, | ||
165 | { COMM, 2, 1, 0x02 }, | ||
166 | { COMM, 1, 3, 0x01 }, | ||
167 | { COMM, 0, 1, 0x08 }, | ||
168 | { COMM, 4, 1, 0x14 }, | ||
169 | { NONE }, | ||
170 | { NONE }, | ||
171 | |||
172 | { NONE }, /* ID: 38 */ | ||
173 | { NONE }, | ||
174 | { NONE }, | ||
175 | { NONE }, | ||
176 | { NONE }, | ||
177 | { NONE }, | ||
178 | { NONE }, | ||
179 | { NONE }, | ||
180 | |||
181 | { COMM, 3, 1, 0x04 }, /* ID: 40 */ | ||
182 | { NONE }, | ||
183 | { NONE }, | ||
184 | { NONE }, | ||
185 | { NONE }, | ||
186 | { NONE }, | ||
187 | { NONE }, | ||
188 | { NONE }, | ||
189 | |||
190 | { NONE }, /* ID: 48 */ | ||
191 | { NONE }, | ||
192 | { NONE }, | ||
193 | { NONE }, | ||
194 | { NONE }, | ||
195 | { NONE }, | ||
196 | { NONE }, | ||
197 | { NONE }, | ||
198 | |||
199 | { NONE }, /* ID: 50 */ | ||
200 | { NONE }, | ||
201 | { NONE }, | ||
202 | { NONE }, | ||
203 | { NONE }, | ||
204 | { NONE }, | ||
205 | { NONE }, | ||
206 | { NONE }, | ||
207 | |||
208 | { NONE }, /* ID: 58 */ | ||
209 | { NONE }, | ||
210 | { COMM, 0, 1, 0x09 }, | ||
211 | { NONE }, | ||
212 | { NONE }, | ||
213 | { NONE }, | ||
214 | { NONE }, | ||
215 | { NONE } | ||
216 | }; | ||
217 | |||
218 | |||
219 | #define PTRDIFF(pe, ps) ((int) (((long) (pe) - (long) (ps)) / sizeof(*pe))) | ||
220 | |||
221 | static char tzxheader[] = {'Z','X','T','a','p','e','!',0x1A}; | ||
222 | |||
223 | static int readbuf(void *ptr, int size, /*FILE *fp*/ int fd) | ||
224 | { | ||
225 | /*return (int) fread(ptr, 1, (size_t) size, tapefp);*/ | ||
226 | return (int) rb->read(fd, ptr, (size_t) size); | ||
227 | } | ||
228 | |||
229 | static void premature(struct seginfo *csp) | ||
230 | { | ||
231 | csp->segtype = SEG_ERROR; | ||
232 | rb->snprintf(seg_desc,DESC_LEN, "Premature end of segment"); | ||
233 | } | ||
234 | |||
235 | static int read_tzx_header(byte *hb, struct seginfo *csp) | ||
236 | { | ||
237 | int res; | ||
238 | int segid, seght; | ||
239 | int lenoffs, lenbytes, lenmul, lenadd; | ||
240 | int hlen; | ||
241 | long length; | ||
242 | byte *hip; | ||
243 | |||
244 | segid = getc(tapefd); | ||
245 | if(segid == EOF) { | ||
246 | csp->segtype = SEG_END; | ||
247 | rb->snprintf(seg_desc,DESC_LEN, "End of Tape"); | ||
248 | return 0; | ||
249 | } | ||
250 | |||
251 | hb[0] = (byte) segid; | ||
252 | |||
253 | if(segid < NUMBLOCKID) seght = tzxb[segid].type; | ||
254 | else seght = 0; /* was NONE here*/ | ||
255 | |||
256 | if(seght == COMM) { | ||
257 | lenbytes = tzxb[segid].lenbytes; | ||
258 | lenmul = tzxb[segid].lenmul; | ||
259 | hlen = tzxb[segid].hlen; | ||
260 | lenadd = hlen; | ||
261 | lenoffs = hlen - lenbytes; | ||
262 | } | ||
263 | else { | ||
264 | lenoffs = 0x00; | ||
265 | lenbytes = 4; | ||
266 | lenmul = 1; | ||
267 | lenadd = 0x00; | ||
268 | hlen = 0x04; | ||
269 | } | ||
270 | |||
271 | if(seght == STAN) hlen += tzxb[segid].hlen; | ||
272 | |||
273 | hip = hb+1; | ||
274 | res = readbuf(hip, hlen, tapefd); | ||
275 | if(res != hlen) { | ||
276 | premature(csp); | ||
277 | return 0; | ||
278 | } | ||
279 | length = 0; | ||
280 | for(;lenbytes; lenbytes--) | ||
281 | length = (length << 8) + hip[lenoffs + lenbytes - 1]; | ||
282 | |||
283 | length = (length * lenmul) + lenadd - hlen; | ||
284 | |||
285 | csp->len = length; | ||
286 | return 1; | ||
287 | } | ||
288 | |||
289 | static int read_tap_header(byte *hb, struct seginfo *csp) | ||
290 | { | ||
291 | int res; | ||
292 | |||
293 | res = readbuf(hb, 2, tapefd); | ||
294 | if(res < 2) { | ||
295 | if(res == 0) { | ||
296 | csp->segtype = SEG_END; | ||
297 | rb->snprintf(seg_desc,DESC_LEN, "End of Tape"); | ||
298 | } | ||
299 | else premature(csp); | ||
300 | return 0; | ||
301 | } | ||
302 | csp->len = DBYTE(hb, 0); | ||
303 | return 1; | ||
304 | } | ||
305 | |||
306 | static int read_header(byte *hb, struct seginfo *csp) | ||
307 | { | ||
308 | segbeg = 0; | ||
309 | csp->ptr = 0; | ||
310 | |||
311 | csp->segtype = SEG_OTHER; | ||
312 | if(tf_tpi.type == TAP_TAP) | ||
313 | return read_tap_header(hb, csp); | ||
314 | else if(tf_tpi.type == TAP_TZX) | ||
315 | return read_tzx_header(hb, csp); | ||
316 | |||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static void isbeg(void) | ||
321 | { | ||
322 | segbeg = 1; | ||
323 | tf_cseg.len = tf_cseg.ptr = 0; | ||
324 | } | ||
325 | |||
326 | |||
327 | static int end_seg(struct seginfo *csp) | ||
328 | { | ||
329 | if(!segbeg) { | ||
330 | if(csp->len != csp->ptr) { | ||
331 | /*fseek(tapefp, tf_cseg.len - tf_cseg.ptr - 1, SEEK_CUR);*/ | ||
332 | rb->lseek(tapefd, tf_cseg.len - tf_cseg.ptr - 1, SEEK_CUR); | ||
333 | |||
334 | if(getc(tapefd) == EOF) { | ||
335 | premature(csp); | ||
336 | return 0; | ||
337 | } | ||
338 | } | ||
339 | segi++; | ||
340 | isbeg(); | ||
341 | } | ||
342 | playstate = PL_NONE; | ||
343 | return 1; | ||
344 | } | ||
345 | |||
346 | |||
347 | static int jump_to_segment(int newsegi, struct seginfo *csp) | ||
348 | { | ||
349 | if(newsegi <= segi) { | ||
350 | segi = 0; | ||
351 | isbeg(); | ||
352 | /*fseek(tapefp, firstseg_offs, SEEK_SET);*/ | ||
353 | rb->lseek(tapefd, firstseg_offs, SEEK_SET); | ||
354 | } | ||
355 | else if(!end_seg(csp)) return 0; | ||
356 | |||
357 | while(segi != newsegi) { | ||
358 | if(!read_header(rbuf, csp)) return 0; | ||
359 | if(!end_seg(csp)) return 0; | ||
360 | } | ||
361 | return 1; | ||
362 | } | ||
363 | |||
364 | |||
365 | static int next_data(void) | ||
366 | { | ||
367 | int res; | ||
368 | if(tf_cseg.ptr == tf_cseg.len) return DAT_END; | ||
369 | |||
370 | res = getc(tapefd); | ||
371 | if(res == EOF) { | ||
372 | rb->snprintf(seg_desc, DESC_LEN,"Premature end of segment"); | ||
373 | return DAT_ERR; | ||
374 | } | ||
375 | tf_cseg.ptr++; | ||
376 | return res; | ||
377 | } | ||
378 | |||
379 | |||
380 | static void normal_segment(struct seginfo *csp) | ||
381 | { | ||
382 | rb->snprintf(seg_desc,DESC_LEN, "Data"); | ||
383 | csp->type = ST_NORM; | ||
384 | csp->segtype = SEG_DATA; | ||
385 | csp->pulse = 2168; /* 2016 */ | ||
386 | csp->num = 3220; | ||
387 | csp->sync1p = 667; | ||
388 | csp->sync2p = 735; | ||
389 | csp->zerop = 855; /* 672 */ | ||
390 | csp->onep = 1710; /* 1568 */ | ||
391 | csp->bused = 8; | ||
392 | } | ||
393 | |||
394 | |||
395 | static int interpret_tzx_header(byte *hb, struct seginfo *csp) | ||
396 | { | ||
397 | int res; | ||
398 | int segid; | ||
399 | byte *hip; | ||
400 | int offs; | ||
401 | dbyte dtmp; | ||
402 | |||
403 | segid = hb[0]; | ||
404 | hip = hb+1; | ||
405 | |||
406 | switch(segid) { | ||
407 | case 0x10: | ||
408 | normal_segment(csp); | ||
409 | csp->pause = DBYTE(hip, 0x00); | ||
410 | break; | ||
411 | |||
412 | case 0x11: | ||
413 | rb->snprintf(seg_desc,DESC_LEN, "Turbo Data"); | ||
414 | csp->type = ST_NORM; | ||
415 | csp->segtype = SEG_DATA_TURBO; | ||
416 | csp->pulse = DBYTE(hip, 0x00); | ||
417 | csp->sync1p = DBYTE(hip, 0x02); | ||
418 | csp->sync2p = DBYTE(hip, 0x04); | ||
419 | csp->zerop = DBYTE(hip, 0x06); | ||
420 | csp->onep = DBYTE(hip, 0x08); | ||
421 | csp->num = DBYTE(hip, 0x0A); | ||
422 | csp->bused = BYTE(hip, 0x0C); | ||
423 | csp->pause = DBYTE(hip, 0x0D); | ||
424 | break; | ||
425 | |||
426 | case 0x12: | ||
427 | rb->snprintf(seg_desc,DESC_LEN, "Pure Tone"); | ||
428 | csp->type = ST_NORM; | ||
429 | csp->segtype = SEG_OTHER; | ||
430 | csp->pulse = DBYTE(hip, 0x00); | ||
431 | csp->num = DBYTE(hip, 0x02); | ||
432 | csp->sync1p = 0; | ||
433 | csp->sync2p = 0; | ||
434 | csp->zerop = 0; | ||
435 | csp->onep = 0; | ||
436 | csp->bused = 0; | ||
437 | csp->pause = 0; | ||
438 | break; | ||
439 | |||
440 | case 0x13: | ||
441 | rb->snprintf(seg_desc,DESC_LEN, "Pulse Sequence"); | ||
442 | csp->type = ST_PSEQ; | ||
443 | csp->segtype = SEG_OTHER; | ||
444 | csp->pause = 0; | ||
445 | break; | ||
446 | |||
447 | case 0x14: | ||
448 | rb->snprintf(seg_desc,DESC_LEN, "Pure Data"); | ||
449 | csp->type = ST_NORM; | ||
450 | csp->segtype = SEG_DATA_PURE; | ||
451 | csp->zerop = DBYTE(hip, 0x00); | ||
452 | csp->onep = DBYTE(hip, 0x02); | ||
453 | csp->bused = BYTE(hip, 0x04); | ||
454 | csp->pause = DBYTE(hip, 0x05); | ||
455 | csp->pulse = 0; | ||
456 | csp->num = 0; | ||
457 | csp->sync1p = 0; | ||
458 | csp->sync2p = 0; | ||
459 | break; | ||
460 | |||
461 | case 0x15: | ||
462 | rb->snprintf(seg_desc,DESC_LEN, "Direct Recording"); | ||
463 | csp->type = ST_DIRE; | ||
464 | csp->segtype = SEG_OTHER; | ||
465 | csp->pulse = DBYTE(hip, 0x00); | ||
466 | csp->pause = DBYTE(hip, 0x02); | ||
467 | csp->bused = BYTE(hip, 0x04); | ||
468 | break; | ||
469 | |||
470 | case 0x20: | ||
471 | dtmp = DBYTE(hip, 0x00); | ||
472 | if(dtmp == 0) { | ||
473 | if(!tapeopt.stoppause) { | ||
474 | csp->type = ST_MISC; | ||
475 | csp->segtype = SEG_STOP; | ||
476 | } | ||
477 | else { | ||
478 | csp->pause = tapeopt.stoppause * 1000; | ||
479 | csp->type = ST_NORM; | ||
480 | csp->segtype = SEG_PAUSE; | ||
481 | } | ||
482 | rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape Mark"); | ||
483 | } | ||
484 | else { | ||
485 | csp->pause = dtmp; | ||
486 | csp->type = ST_NORM; | ||
487 | csp->segtype = SEG_PAUSE; | ||
488 | rb->snprintf(seg_desc,DESC_LEN, "Pause for %i.%03is", | ||
489 | csp->pause / 1000, csp->pause % 1000); | ||
490 | } | ||
491 | csp->pulse = 0; | ||
492 | csp->num = 0; | ||
493 | csp->sync1p = 0; | ||
494 | csp->sync2p = 0; | ||
495 | csp->zerop = 0; | ||
496 | csp->onep = 0; | ||
497 | csp->bused = 0; | ||
498 | break; | ||
499 | |||
500 | case 0x21: | ||
501 | csp->type = ST_MISC; | ||
502 | csp->segtype = SEG_GRP_BEG; | ||
503 | res = readbuf(rbuf, csp->len, tapefd); | ||
504 | if(res != (int) csp->len) { | ||
505 | premature(csp); | ||
506 | return 0; | ||
507 | } | ||
508 | csp->ptr += csp->len; | ||
509 | { | ||
510 | int blen; | ||
511 | rb->snprintf(seg_desc,DESC_LEN, "Begin Group: "); | ||
512 | blen = (int) rb->strlen(seg_desc); | ||
513 | rb->strncpy(seg_desc+blen, (char *) rbuf, (unsigned) csp->len); | ||
514 | seg_desc[csp->len + blen] = '\0'; | ||
515 | } | ||
516 | break; | ||
517 | |||
518 | case 0x22: | ||
519 | rb->snprintf(seg_desc,DESC_LEN, "End Group"); | ||
520 | csp->type = ST_MISC; | ||
521 | csp->segtype = SEG_GRP_END; | ||
522 | break; | ||
523 | |||
524 | case 0x23: | ||
525 | offs = (signed short) DBYTE(hip, 0x00); | ||
526 | if(offs == 0) { | ||
527 | rb->snprintf(seg_desc,DESC_LEN, "Infinite loop"); | ||
528 | csp->type = ST_MISC; | ||
529 | csp->segtype = SEG_STOP; | ||
530 | } | ||
531 | else { | ||
532 | csp->type = ST_MISC; | ||
533 | csp->segtype = SEG_SKIP; | ||
534 | rb->snprintf(seg_desc,DESC_LEN, "Jump to %i", segi+offs); | ||
535 | jump_to_segment(segi + offs, csp); | ||
536 | } | ||
537 | break; | ||
538 | |||
539 | case 0x24: | ||
540 | loopctr = DBYTE(hip, 0x00); | ||
541 | rb->snprintf(seg_desc,DESC_LEN, "Loop %i times", loopctr); | ||
542 | loopbeg = segi+1; | ||
543 | csp->type = ST_MISC; | ||
544 | csp->segtype = SEG_SKIP; | ||
545 | break; | ||
546 | |||
547 | case 0x25: | ||
548 | csp->type = ST_MISC; | ||
549 | csp->segtype = SEG_SKIP; | ||
550 | if(loopctr) loopctr--; | ||
551 | if(loopctr) { | ||
552 | jump_to_segment(loopbeg, csp); | ||
553 | rb->snprintf(seg_desc,DESC_LEN, "Loop to: %i", loopbeg); | ||
554 | } | ||
555 | else rb->snprintf(seg_desc,DESC_LEN, "Loop End"); | ||
556 | break; | ||
557 | |||
558 | case 0x26: | ||
559 | csp->type = ST_MISC; | ||
560 | csp->segtype = SEG_SKIP; | ||
561 | dtmp = DBYTE(hip, 0x00); | ||
562 | if(callctr < dtmp) { | ||
563 | int offset; | ||
564 | callbeg = segi; | ||
565 | /*fseek(tapefp, callctr*2, SEEK_CUR);*/ | ||
566 | rb->lseek(tapefd, callctr*2, SEEK_CUR); | ||
567 | csp->ptr += callctr*2; | ||
568 | res = readbuf(rbuf, 2, tapefd); | ||
569 | if(res != 2) { | ||
570 | premature(csp); | ||
571 | return 0; | ||
572 | } | ||
573 | csp->ptr += 2; | ||
574 | offset = (signed short) DBYTE(rbuf, 0x00); | ||
575 | rb->snprintf(seg_desc,DESC_LEN, "Call to %i", segi+offset); | ||
576 | jump_to_segment(segi+offset, csp); | ||
577 | callctr++; | ||
578 | } | ||
579 | else { | ||
580 | callctr = 0; | ||
581 | rb->snprintf(seg_desc,DESC_LEN, "Call Sequence End"); | ||
582 | } | ||
583 | break; | ||
584 | |||
585 | case 0x27: | ||
586 | csp->type = ST_MISC; | ||
587 | csp->segtype = SEG_SKIP; | ||
588 | rb->snprintf(seg_desc,DESC_LEN, "Return"); | ||
589 | if(callctr > 0) jump_to_segment(callbeg, csp); | ||
590 | break; | ||
591 | |||
592 | case 0x28: | ||
593 | rb->snprintf(seg_desc,DESC_LEN, "Selection (Not yet supported)"); | ||
594 | csp->type = ST_MISC; | ||
595 | csp->segtype = SEG_SKIP; | ||
596 | break; | ||
597 | |||
598 | case 0x2A: | ||
599 | if(tapeopt.machine == MACHINE_48) { | ||
600 | rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Stopped)"); | ||
601 | csp->type = ST_MISC; | ||
602 | csp->segtype = SEG_STOP; | ||
603 | } | ||
604 | else { | ||
605 | rb->snprintf(seg_desc,DESC_LEN, "Stop the Tape in 48k Mode (Not Stopped)"); | ||
606 | csp->type = ST_MISC; | ||
607 | csp->segtype = SEG_SKIP; | ||
608 | } | ||
609 | break; | ||
610 | |||
611 | case 0x31: | ||
612 | case 0x30: | ||
613 | csp->type = ST_MISC; | ||
614 | csp->segtype = SEG_SKIP; | ||
615 | res = readbuf(rbuf, csp->len, tapefd); | ||
616 | if(res != (int) csp->len) { | ||
617 | premature(csp); | ||
618 | return 0; | ||
619 | } | ||
620 | csp->ptr += csp->len; | ||
621 | rb->strncpy(seg_desc, (char *) rbuf, (unsigned) csp->len); | ||
622 | seg_desc[csp->len] = '\0'; | ||
623 | break; | ||
624 | |||
625 | case 0x32: | ||
626 | csp->type = ST_MISC; | ||
627 | csp->segtype = SEG_SKIP; | ||
628 | { | ||
629 | int numstr, i; | ||
630 | |||
631 | i = 0; | ||
632 | numstr = next_data(); | ||
633 | for(;numstr > 0; numstr--) { | ||
634 | int tlen, tid, b; | ||
635 | |||
636 | tid = next_data(); | ||
637 | tlen = next_data(); | ||
638 | if(tid < 0 || tlen < 0) return 0; | ||
639 | |||
640 | for(; tlen; tlen--) { | ||
641 | b = next_data(); | ||
642 | if(b < 0) return 0; | ||
643 | seg_desc[i++] = b; | ||
644 | } | ||
645 | seg_desc[i++] = '\n'; | ||
646 | } | ||
647 | seg_desc[i] = '\0'; | ||
648 | } | ||
649 | break; | ||
650 | |||
651 | case 0x33: | ||
652 | rb->snprintf(seg_desc,DESC_LEN, "Hardware Information (Not yet supported)"); | ||
653 | csp->type = ST_MISC; | ||
654 | csp->segtype = SEG_SKIP; | ||
655 | break; | ||
656 | |||
657 | case 0x34: | ||
658 | rb->snprintf(seg_desc, DESC_LEN,"Emulation Information (Not yet supported)"); | ||
659 | csp->type = ST_MISC; | ||
660 | csp->segtype = SEG_SKIP; | ||
661 | break; | ||
662 | |||
663 | case 0x35: | ||
664 | rb->snprintf(seg_desc,DESC_LEN, "Custom Information (Not yet supported)"); | ||
665 | csp->type = ST_MISC; | ||
666 | csp->segtype = SEG_SKIP; | ||
667 | break; | ||
668 | |||
669 | case 0x40: | ||
670 | rb->snprintf(seg_desc, DESC_LEN,"Snapshot (Not yet supported)"); | ||
671 | csp->type = ST_MISC; | ||
672 | csp->segtype = SEG_SKIP; | ||
673 | break; | ||
674 | |||
675 | case 0x5A: | ||
676 | rb->snprintf(seg_desc, DESC_LEN,"Tapefile Concatenation Point"); | ||
677 | csp->type = ST_MISC; | ||
678 | csp->segtype = SEG_SKIP; | ||
679 | |||
680 | default: | ||
681 | csp->type = ST_MISC; | ||
682 | csp->segtype = SEG_SKIP; | ||
683 | rb->snprintf(seg_desc,DESC_LEN, "Unknown TZX block (id: %02X, version: %i.%02i)", | ||
684 | segid, tf_tpi.tzxmajver, tf_tpi.tzxminver); | ||
685 | break; | ||
686 | } | ||
687 | |||
688 | return 1; | ||
689 | } | ||
690 | |||
691 | static int interpret_header(byte *hb, struct seginfo *csp) | ||
692 | { | ||
693 | if(tf_tpi.type == TAP_TAP) { | ||
694 | normal_segment(csp); | ||
695 | csp->pause = DEF_LEAD_PAUSE; | ||
696 | |||
697 | return 1; | ||
698 | } | ||
699 | else if(tf_tpi.type == TAP_TZX) | ||
700 | return interpret_tzx_header(hb, csp); | ||
701 | |||
702 | return 0; | ||
703 | } | ||
704 | |||
705 | byte *tf_get_block(int i) | ||
706 | { | ||
707 | seg_desc[0] = '\0'; | ||
708 | |||
709 | if(jump_to_segment(i, &tf_cseg)) { | ||
710 | tf_segoffs = ftell(tapefd); | ||
711 | |||
712 | if(read_header(rbuf, &tf_cseg) && | ||
713 | interpret_header(rbuf, &tf_cseg)) return rbuf; | ||
714 | } | ||
715 | return NULL; | ||
716 | } | ||
717 | |||
718 | |||
719 | int next_byte(void) | ||
720 | { | ||
721 | playstate = PL_NONE; | ||
722 | return next_data(); | ||
723 | } | ||
724 | |||
725 | #define DPULSE(v1,v2) (*impbuf++=(v1), *impbuf++=(v2), timelen-=(v1)+(v2)) | ||
726 | #define PULSE(v) (*impbuf++=(v), currlev = !currlev, timelen-=(v)) | ||
727 | |||
728 | int next_imps(unsigned short *impbuf, int buflen, long timelen) | ||
729 | { | ||
730 | static int toput; | ||
731 | static int bitrem; | ||
732 | static dbyte dirpulse; | ||
733 | unsigned short *impbufend, *impbufstart; | ||
734 | |||
735 | impbufstart = impbuf; | ||
736 | impbufend = impbuf + buflen; | ||
737 | |||
738 | while(impbuf < impbufend - 1 && timelen > 0) { | ||
739 | switch(playstate) { | ||
740 | |||
741 | case PL_PAUSE: | ||
742 | if(currlev && lead_pause) { | ||
743 | PULSE(IMP_1MS); | ||
744 | lead_pause --; | ||
745 | } | ||
746 | else if(lead_pause > 10) { | ||
747 | if(tapeopt.blanknoise && !(rb->rand() % 64)) | ||
748 | DPULSE(IMP_1MS * 10 - 1000, 1000); | ||
749 | else | ||
750 | DPULSE(IMP_1MS * 10, 0); | ||
751 | lead_pause -= 10; | ||
752 | } | ||
753 | else if(lead_pause) { | ||
754 | DPULSE(IMP_1MS, 0); | ||
755 | lead_pause --; | ||
756 | } | ||
757 | else { | ||
758 | if(tf_cseg.num || tf_cseg.sync1p || tf_cseg.sync2p || | ||
759 | tf_cseg.ptr != tf_cseg.len) finished = 0; | ||
760 | |||
761 | switch (tf_cseg.type) { | ||
762 | case ST_NORM: playstate = PL_LEADER; break; | ||
763 | case ST_DIRE: playstate = PL_DIRE; dirpulse = 0; break; | ||
764 | case ST_PSEQ: playstate = PL_PSEQ; break; | ||
765 | default: playstate = PL_NONE; | ||
766 | } | ||
767 | } | ||
768 | break; | ||
769 | |||
770 | case PL_LEADER: | ||
771 | if(tf_cseg.num >= 2) { | ||
772 | DPULSE(tf_cseg.pulse, tf_cseg.pulse); | ||
773 | tf_cseg.num -= 2; | ||
774 | } | ||
775 | else | ||
776 | if(tf_cseg.num) { | ||
777 | PULSE(tf_cseg.pulse); | ||
778 | tf_cseg.num --; | ||
779 | } | ||
780 | else { /* PL_SYNC */ | ||
781 | if(tf_cseg.sync1p || tf_cseg.sync2p) | ||
782 | DPULSE(tf_cseg.sync1p, tf_cseg.sync2p); | ||
783 | bitrem = 0; | ||
784 | playstate = PL_DATA; | ||
785 | } | ||
786 | break; | ||
787 | |||
788 | case PL_DATA: | ||
789 | if(!bitrem) { | ||
790 | toput = next_data(); | ||
791 | if(toput < 0) { | ||
792 | playstate = PL_END; | ||
793 | break; | ||
794 | } | ||
795 | if(tf_cseg.ptr != tf_cseg.len) { | ||
796 | if(timelen > 16 * max(tf_cseg.onep, tf_cseg.zerop) && | ||
797 | impbuf <= impbufend - 16) { | ||
798 | int p1, p2, br, tp; | ||
799 | |||
800 | p1 = tf_cseg.onep; | ||
801 | p2 = tf_cseg.zerop; | ||
802 | br = 8; | ||
803 | tp = toput; | ||
804 | |||
805 | while(br) { | ||
806 | if(tp & 0x80) DPULSE(p1, p1); | ||
807 | else DPULSE(p2, p2); | ||
808 | br--; | ||
809 | tp <<= 1; | ||
810 | } | ||
811 | bitrem = 0; | ||
812 | break; | ||
813 | } | ||
814 | bitrem = 8; | ||
815 | } | ||
816 | else { | ||
817 | bitrem = tf_cseg.bused; | ||
818 | if(!bitrem) break; | ||
819 | } | ||
820 | } | ||
821 | if(toput & 0x80) DPULSE(tf_cseg.onep, tf_cseg.onep); | ||
822 | else DPULSE(tf_cseg.zerop, tf_cseg.zerop); | ||
823 | bitrem--, toput <<= 1; | ||
824 | break; | ||
825 | |||
826 | case PL_PSEQ: | ||
827 | { | ||
828 | int b1, b2; | ||
829 | dbyte pulse1, pulse2; | ||
830 | b1 = next_data(); | ||
831 | b2 = next_data(); | ||
832 | if(b1 < 0 || b2 < 0) { | ||
833 | playstate = PL_END; | ||
834 | break; | ||
835 | } | ||
836 | pulse1 = b1 + (b2 << 8); | ||
837 | |||
838 | b1 = next_data(); | ||
839 | b2 = next_data(); | ||
840 | if(b1 < 0 || b2 < 0) { | ||
841 | PULSE(pulse1); | ||
842 | playstate = PL_END; | ||
843 | break; | ||
844 | } | ||
845 | pulse2 = b1 + (b2 << 8); | ||
846 | DPULSE(pulse1, pulse2); | ||
847 | } | ||
848 | break; | ||
849 | |||
850 | case PL_DIRE: | ||
851 | for(;;) { | ||
852 | if(!bitrem) { | ||
853 | toput = next_data(); | ||
854 | if(toput < 0) { | ||
855 | playstate = PL_END; | ||
856 | DPULSE(dirpulse, 0); | ||
857 | break; | ||
858 | } | ||
859 | if(tf_cseg.ptr != tf_cseg.len) bitrem = 8; | ||
860 | else { | ||
861 | bitrem = tf_cseg.bused; | ||
862 | if(!bitrem) break; | ||
863 | } | ||
864 | } | ||
865 | bitrem--; | ||
866 | toput <<= 1; | ||
867 | if(((toput & 0x0100) ^ (currlev ? 0x0100 : 0x00))) { | ||
868 | PULSE(dirpulse); | ||
869 | dirpulse = tf_cseg.pulse; | ||
870 | break; | ||
871 | } | ||
872 | dirpulse += tf_cseg.pulse; | ||
873 | if(dirpulse >= 0x8000) { | ||
874 | DPULSE(dirpulse, 0); | ||
875 | dirpulse = 0; | ||
876 | break; | ||
877 | } | ||
878 | } | ||
879 | break; | ||
880 | |||
881 | case PL_END: | ||
882 | if(tf_cseg.pause) { | ||
883 | PULSE(IMP_1MS); | ||
884 | tf_cseg.pause--; | ||
885 | if(currlev) PULSE(0); | ||
886 | finished = 1; | ||
887 | } | ||
888 | playstate = PL_NONE; | ||
889 | break; | ||
890 | |||
891 | case PL_NONE: | ||
892 | default: | ||
893 | return PTRDIFF(impbuf, impbufstart); | ||
894 | } | ||
895 | } | ||
896 | |||
897 | return PTRDIFF(impbuf, impbufstart); | ||
898 | } | ||
899 | |||
900 | |||
901 | int next_segment(void) | ||
902 | { | ||
903 | if(endnext) { | ||
904 | endnext = 0; | ||
905 | tf_cseg.segtype = endtype; | ||
906 | tf_cseg.pause = endpause; | ||
907 | playstate = endplay; | ||
908 | return tf_cseg.segtype; | ||
909 | } | ||
910 | |||
911 | seg_desc[0] = '\0'; | ||
912 | lead_pause = tf_cseg.pause; | ||
913 | |||
914 | if(end_seg(&tf_cseg)) { | ||
915 | currsegi = segi; | ||
916 | if(read_header(rbuf, &tf_cseg)) interpret_header(rbuf, &tf_cseg); | ||
917 | } | ||
918 | |||
919 | if(tf_cseg.segtype >= SEG_DATA) { | ||
920 | playstate = PL_PAUSE; | ||
921 | if(lead_pause) finished = 1; | ||
922 | } | ||
923 | else playstate = PL_NONE; | ||
924 | |||
925 | if(tf_cseg.segtype <= SEG_STOP && !finished) { | ||
926 | endnext = 1; | ||
927 | endtype = tf_cseg.segtype; | ||
928 | endpause = tf_cseg.pause; | ||
929 | endplay = playstate; | ||
930 | if(lead_pause > 0) lead_pause--; | ||
931 | |||
932 | tf_cseg.pause = 1; | ||
933 | tf_cseg.segtype = SEG_VIRTUAL; | ||
934 | playstate = PL_END; | ||
935 | } | ||
936 | |||
937 | return tf_cseg.segtype; | ||
938 | } | ||
939 | |||
940 | int goto_segment(int at_seg) | ||
941 | { | ||
942 | int res; | ||
943 | |||
944 | res = jump_to_segment(at_seg, &tf_cseg); | ||
945 | tf_cseg.pause = DEF_LEAD_PAUSE; | ||
946 | |||
947 | return res; | ||
948 | } | ||
949 | |||
950 | unsigned segment_pos(void) | ||
951 | { | ||
952 | return currsegi; | ||
953 | } | ||
954 | |||
955 | void close_tapefile(void) | ||
956 | { | ||
957 | if(tapefd != -1) { | ||
958 | playstate = PL_NONE; | ||
959 | rb->close(tapefd); | ||
960 | tapefd = -1; | ||
961 | } | ||
962 | } | ||
963 | |||
964 | int open_tapefile(char *name, int type) | ||
965 | { | ||
966 | int res; | ||
967 | int ok; | ||
968 | |||
969 | seg_desc[0] = '\0'; | ||
970 | currlev = 0; | ||
971 | |||
972 | if(type != TAP_TAP && type != TAP_TZX) { | ||
973 | rb->snprintf(seg_desc,DESC_LEN, "Illegal tape type"); | ||
974 | return 0; | ||
975 | } | ||
976 | |||
977 | /*tapefp = fopen(name, "rb");*/ | ||
978 | tapefd = rb->open(name, O_RDONLY); | ||
979 | if(tapefd < 0 ) { | ||
980 | /*rb->snprintf(seg_desc,DESC_LEN, "Could not open `%s': %s", name, strerror(errno));*/ | ||
981 | return 0; | ||
982 | } | ||
983 | |||
984 | tf_tpi.type = type; | ||
985 | tf_cseg.pause = DEF_LEAD_PAUSE; | ||
986 | INITTAPEOPT(tapeopt); | ||
987 | |||
988 | currsegi = segi = 0; | ||
989 | isbeg(); | ||
990 | |||
991 | firstseg_offs = 0; | ||
992 | |||
993 | ok = 1; | ||
994 | |||
995 | if(tf_tpi.type == TAP_TZX) { | ||
996 | |||
997 | firstseg_offs = 10; | ||
998 | res = readbuf(rbuf, 10, tapefd); | ||
999 | if(res == 10 && rb->strncasecmp((char *)rbuf, tzxheader, 8) == 0) { | ||
1000 | tf_tpi.tzxmajver = rbuf[8]; | ||
1001 | tf_tpi.tzxminver = rbuf[9]; | ||
1002 | |||
1003 | if(tf_tpi.tzxmajver > TZXMAJPROG) { | ||
1004 | rb->snprintf(seg_desc, DESC_LEN, | ||
1005 | "Cannot handle TZX file version (%i.%02i)", | ||
1006 | tf_tpi.tzxmajver, tf_tpi.tzxminver); | ||
1007 | ok = 0; | ||
1008 | } | ||
1009 | } | ||
1010 | else { | ||
1011 | rb->snprintf(seg_desc,DESC_LEN, "Illegal TZX file header"); | ||
1012 | ok = 0; | ||
1013 | } | ||
1014 | } | ||
1015 | |||
1016 | if(!ok) { | ||
1017 | close_tapefile(); | ||
1018 | return 0; | ||
1019 | } | ||
1020 | endnext = 0; | ||
1021 | |||
1022 | loopctr = 0; | ||
1023 | callctr = 0; | ||
1024 | |||
1025 | return 1; | ||
1026 | } | ||
1027 | |||
1028 | int get_level(void) | ||
1029 | { | ||
1030 | return currlev; | ||
1031 | } | ||
1032 | |||
1033 | long get_seglen(void) | ||
1034 | { | ||
1035 | return tf_cseg.len; | ||
1036 | } | ||
1037 | |||
1038 | long get_segpos(void) | ||
1039 | { | ||
1040 | return tf_cseg.ptr; | ||
1041 | } | ||
1042 | |||
1043 | void set_tapefile_options(struct tape_options *to) | ||
1044 | { | ||
1045 | rb->memcpy(&tapeopt, to, sizeof(tapeopt)); | ||
1046 | } | ||
1047 | |||