1 /* tzx_read.c: Routines for reading .tzx files
2 Copyright (c) 2001-2015 Philip Kendall, Darren Salt
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (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 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18 Author contact information:
19
20 E-mail: philip-fuse@shadowmagic.org.uk
21
22 */
23
24 #include "config.h"
25
26 #include <math.h>
27 #include <stddef.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "internals.h"
32
33 /* The .tzx file signature (first 8 bytes) */
34 const char * const libspectrum_tzx_signature = "ZXTape!\x1a";
35
36 /*** Local function prototypes ***/
37
38 static libspectrum_error
39 tzx_read_rom_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
40 const libspectrum_byte *end );
41 static libspectrum_error
42 tzx_read_turbo_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
43 const libspectrum_byte *end );
44 static libspectrum_error
45 tzx_read_pure_tone( libspectrum_tape *tape, const libspectrum_byte **ptr,
46 const libspectrum_byte *end );
47 static libspectrum_error
48 tzx_read_pulses_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
49 const libspectrum_byte *end );
50 static libspectrum_error
51 tzx_read_pure_data( libspectrum_tape *tape, const libspectrum_byte **ptr,
52 const libspectrum_byte *end );
53 static libspectrum_error
54 tzx_read_raw_data( libspectrum_tape *tape, const libspectrum_byte **ptr,
55 const libspectrum_byte *end );
56 static libspectrum_error
57 tzx_read_generalised_data( libspectrum_tape *tape,
58 const libspectrum_byte **ptr,
59 const libspectrum_byte *end );
60 static libspectrum_error
61 tzx_read_pause( libspectrum_tape *tape, const libspectrum_byte **ptr,
62 const libspectrum_byte *end );
63 static libspectrum_error
64 tzx_read_group_start( libspectrum_tape *tape, const libspectrum_byte **ptr,
65 const libspectrum_byte *end );
66 static libspectrum_error
67 tzx_read_jump( libspectrum_tape *tape, const libspectrum_byte **ptr,
68 const libspectrum_byte *end );
69 static libspectrum_error
70 tzx_read_loop_start( libspectrum_tape *tape, const libspectrum_byte **ptr,
71 const libspectrum_byte *end );
72 static libspectrum_error
73 tzx_read_select( libspectrum_tape *tape, const libspectrum_byte **ptr,
74 const libspectrum_byte *end );
75 static libspectrum_error
76 tzx_read_stop( libspectrum_tape *tape, const libspectrum_byte **ptr,
77 const libspectrum_byte *end );
78 static libspectrum_error
79 tzx_read_set_signal_level( libspectrum_tape *tape, const libspectrum_byte **ptr,
80 const libspectrum_byte *end );
81 static libspectrum_error
82 tzx_read_comment( libspectrum_tape *tape, const libspectrum_byte **ptr,
83 const libspectrum_byte *end );
84 static libspectrum_error
85 tzx_read_message( libspectrum_tape *tape, const libspectrum_byte **ptr,
86 const libspectrum_byte *end );
87 static libspectrum_error
88 tzx_read_archive_info( libspectrum_tape *tape, const libspectrum_byte **ptr,
89 const libspectrum_byte *end );
90 static libspectrum_error
91 tzx_read_hardware( libspectrum_tape *tape, const libspectrum_byte **ptr,
92 const libspectrum_byte *end );
93 static libspectrum_error
94 tzx_read_custom( libspectrum_tape *tape, const libspectrum_byte **ptr,
95 const libspectrum_byte *end );
96 static libspectrum_error
97 tzx_read_concat( const libspectrum_byte **ptr, const libspectrum_byte *end );
98
99 static void
100 tzx_read_empty_block( libspectrum_tape *tape, libspectrum_tape_type id );
101
102 static libspectrum_error
103 tzx_read_data( const libspectrum_byte **ptr, const libspectrum_byte *end,
104 size_t *length, int bytes, libspectrum_byte **data );
105 static libspectrum_error
106 tzx_read_string( const libspectrum_byte **ptr, const libspectrum_byte *end,
107 char **dest );
108
109 /*** Function definitions ***/
110
111 /* The main load function */
112
113 libspectrum_error
internal_tzx_read(libspectrum_tape * tape,const libspectrum_byte * buffer,const size_t length)114 internal_tzx_read( libspectrum_tape *tape, const libspectrum_byte *buffer,
115 const size_t length )
116 {
117
118 libspectrum_error error;
119
120 const libspectrum_byte *ptr, *end;
121 size_t signature_length = strlen( libspectrum_tzx_signature );
122
123 ptr = buffer; end = buffer + length;
124
125 /* Must be at least as many bytes as the signature, and the major/minor
126 version numbers */
127 if( length < signature_length + 2 ) {
128 libspectrum_print_error(
129 LIBSPECTRUM_ERROR_CORRUPT,
130 "libspectrum_tzx_create: not enough data in buffer"
131 );
132 return LIBSPECTRUM_ERROR_CORRUPT;
133 }
134
135 /* Now check the signature */
136 if( memcmp( ptr, libspectrum_tzx_signature, signature_length ) ) {
137 libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
138 "libspectrum_tzx_create: wrong signature" );
139 return LIBSPECTRUM_ERROR_SIGNATURE;
140 }
141 ptr += signature_length;
142
143 /* Just skip the version numbers */
144 ptr += 2;
145
146 while( ptr < end ) {
147
148 /* Get the ID of the next block */
149 libspectrum_tape_type id = *ptr++;
150
151 switch( id ) {
152 case LIBSPECTRUM_TAPE_BLOCK_ROM:
153 error = tzx_read_rom_block( tape, &ptr, end );
154 if( error ) { libspectrum_tape_clear( tape ); return error; }
155 break;
156 case LIBSPECTRUM_TAPE_BLOCK_TURBO:
157 error = tzx_read_turbo_block( tape, &ptr, end );
158 if( error ) { libspectrum_tape_clear( tape ); return error; }
159 break;
160 case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
161 error = tzx_read_pure_tone( tape, &ptr, end );
162 if( error ) { libspectrum_tape_clear( tape ); return error; }
163 break;
164 case LIBSPECTRUM_TAPE_BLOCK_PULSES:
165 error = tzx_read_pulses_block( tape, &ptr, end );
166 if( error ) { libspectrum_tape_clear( tape ); return error; }
167 break;
168 case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
169 error = tzx_read_pure_data( tape, &ptr, end );
170 if( error ) { libspectrum_tape_clear( tape ); return error; }
171 break;
172 case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
173 error = tzx_read_raw_data( tape, &ptr, end );
174 if( error ) { libspectrum_tape_clear( tape ); return error; }
175 break;
176
177 case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
178 error = tzx_read_generalised_data( tape, &ptr, end );
179 if( error ) { libspectrum_tape_clear( tape ); return error; }
180 break;
181
182 case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
183 error = tzx_read_pause( tape, &ptr, end );
184 if( error ) { libspectrum_tape_clear( tape ); return error; }
185 break;
186 case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
187 error = tzx_read_group_start( tape, &ptr, end );
188 if( error ) { libspectrum_tape_clear( tape ); return error; }
189 break;
190 case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
191 tzx_read_empty_block( tape, id );
192 break;
193 case LIBSPECTRUM_TAPE_BLOCK_JUMP:
194 error = tzx_read_jump( tape, &ptr, end );
195 if( error ) { libspectrum_tape_clear( tape ); return error; }
196 break;
197 case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
198 error = tzx_read_loop_start( tape, &ptr, end );
199 if( error ) { libspectrum_tape_clear( tape ); return error; }
200 break;
201 case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
202 tzx_read_empty_block( tape, id );
203 break;
204
205 case LIBSPECTRUM_TAPE_BLOCK_SELECT:
206 error = tzx_read_select( tape, &ptr, end );
207 if( error ) { libspectrum_tape_clear( tape ); return error; }
208 break;
209
210 case LIBSPECTRUM_TAPE_BLOCK_STOP48:
211 error = tzx_read_stop( tape, &ptr, end );
212 if( error ) { libspectrum_tape_clear( tape ); return error; }
213 break;
214
215 case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
216 error = tzx_read_set_signal_level( tape, &ptr, end );
217 if( error ) { libspectrum_tape_clear( tape ); return error; }
218 break;
219
220 case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
221 error = tzx_read_comment( tape, &ptr, end );
222 if( error ) { libspectrum_tape_clear( tape ); return error; }
223 break;
224 case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
225 error = tzx_read_message( tape, &ptr, end );
226 if( error ) { libspectrum_tape_clear( tape ); return error; }
227 break;
228 case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
229 error = tzx_read_archive_info( tape, &ptr, end );
230 if( error ) { libspectrum_tape_clear( tape ); return error; }
231 break;
232 case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
233 error = tzx_read_hardware( tape, &ptr, end );
234 if( error ) { libspectrum_tape_clear( tape ); return error; }
235 break;
236
237 case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
238 error = tzx_read_custom( tape, &ptr, end );
239 if( error ) { libspectrum_tape_clear( tape ); return error; }
240 break;
241
242 case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
243 error = tzx_read_concat( &ptr, end );
244 if( error ) { libspectrum_tape_clear( tape ); return error; }
245 break;
246
247 default: /* For now, don't handle anything else */
248 libspectrum_tape_clear( tape );
249 libspectrum_print_error(
250 LIBSPECTRUM_ERROR_UNKNOWN,
251 "libspectrum_tzx_create: unknown block type 0x%02x", id
252 );
253 return LIBSPECTRUM_ERROR_UNKNOWN;
254 }
255 }
256
257 return LIBSPECTRUM_ERROR_NONE;
258 }
259
260 static libspectrum_error
tzx_read_rom_block(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)261 tzx_read_rom_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
262 const libspectrum_byte *end )
263 {
264 libspectrum_tape_block* block;
265 size_t length; libspectrum_byte *data;
266 libspectrum_error error;
267
268 /* Check there's enough left in the buffer for the pause and the
269 data length */
270 if( end - (*ptr) < 4 ) {
271 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
272 "tzx_read_rom_block: not enough data in buffer" );
273 return LIBSPECTRUM_ERROR_CORRUPT;
274 }
275
276 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_ROM );
277
278 /* Get the pause length */
279 libspectrum_set_pause_ms( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
280 (*ptr) += 2;
281
282 /* And the data */
283 error = tzx_read_data( ptr, end, &length, 2, &data );
284 if( error ) { libspectrum_free( block ); return error; }
285 libspectrum_tape_block_set_data_length( block, length );
286 libspectrum_tape_block_set_data( block, data );
287
288 libspectrum_tape_append_block( tape, block );
289
290 return LIBSPECTRUM_ERROR_NONE;
291 }
292
293 static libspectrum_error
tzx_read_turbo_block(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)294 tzx_read_turbo_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
295 const libspectrum_byte *end )
296 {
297 libspectrum_tape_block* block;
298 size_t length; libspectrum_byte *data;
299 libspectrum_byte bits_in_last_byte;
300 libspectrum_error error;
301
302 /* Check there's enough left in the buffer for all the metadata */
303 if( end - (*ptr) < 18 ) {
304 libspectrum_print_error(
305 LIBSPECTRUM_ERROR_CORRUPT,
306 "tzx_read_turbo_block: not enough data in buffer"
307 );
308 return LIBSPECTRUM_ERROR_CORRUPT;
309 }
310
311 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_TURBO );
312
313 /* Get the metadata */
314 libspectrum_tape_block_set_pilot_length( block,
315 (*ptr)[0] + (*ptr)[1] * 0x100 );
316 (*ptr) += 2;
317 libspectrum_tape_block_set_sync1_length( block,
318 (*ptr)[0] + (*ptr)[1] * 0x100 );
319 (*ptr) += 2;
320 libspectrum_tape_block_set_sync2_length( block,
321 (*ptr)[0] + (*ptr)[1] * 0x100 );
322 (*ptr) += 2;
323 libspectrum_tape_block_set_bit0_length ( block,
324 (*ptr)[0] + (*ptr)[1] * 0x100 );
325 (*ptr) += 2;
326 libspectrum_tape_block_set_bit1_length ( block,
327 (*ptr)[0] + (*ptr)[1] * 0x100 );
328 (*ptr) += 2;
329 libspectrum_tape_block_set_pilot_pulses( block,
330 (*ptr)[0] + (*ptr)[1] * 0x100 );
331 (*ptr) += 2;
332
333 bits_in_last_byte = **ptr;
334 (*ptr)++;
335
336 libspectrum_set_pause_ms ( block,
337 (*ptr)[0] + (*ptr)[1] * 0x100 );
338 (*ptr) += 2;
339
340 /* Read the data in */
341 error = tzx_read_data( ptr, end, &length, 3, &data );
342 if( error ) { libspectrum_free( block ); return error; }
343
344 if( bits_in_last_byte == 0 && length >= 1 ) {
345 bits_in_last_byte = 8;
346 length -= 1;
347 }
348
349 if( bits_in_last_byte > 8 ) {
350 bits_in_last_byte = 8;
351 }
352
353 libspectrum_tape_block_set_bits_in_last_byte( block, bits_in_last_byte );
354
355 libspectrum_tape_block_set_data_length( block, length );
356 libspectrum_tape_block_set_data( block, data );
357
358 libspectrum_tape_append_block( tape, block );
359
360 return LIBSPECTRUM_ERROR_NONE;
361 }
362
363 static libspectrum_error
tzx_read_pure_tone(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)364 tzx_read_pure_tone( libspectrum_tape *tape, const libspectrum_byte **ptr,
365 const libspectrum_byte *end )
366 {
367 libspectrum_tape_block* block;
368
369 /* Check we've got enough bytes */
370 if( end - (*ptr) < 4 ) {
371 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
372 "tzx_read_pure_tone: not enough data in buffer" );
373 return LIBSPECTRUM_ERROR_CORRUPT;
374 }
375
376 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_PURE_TONE );
377
378 /* Read in the data, and move along */
379 libspectrum_tape_block_set_pulse_length( block,
380 (*ptr)[0] + (*ptr)[1] * 0x100 );
381 (*ptr) += 2;
382 libspectrum_tape_block_set_count( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
383 (*ptr) += 2;
384
385 libspectrum_tape_append_block( tape, block );
386
387 return LIBSPECTRUM_ERROR_NONE;
388 }
389
390 static libspectrum_error
tzx_read_pulses_block(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)391 tzx_read_pulses_block( libspectrum_tape *tape, const libspectrum_byte **ptr,
392 const libspectrum_byte *end )
393 {
394 libspectrum_tape_block* block;
395 libspectrum_dword *lengths;
396 size_t i, count;
397
398 /* Check the count byte exists */
399 if( (*ptr) == end ) {
400 libspectrum_print_error(
401 LIBSPECTRUM_ERROR_CORRUPT,
402 "tzx_read_pulses_block: not enough data in buffer"
403 );
404 return LIBSPECTRUM_ERROR_CORRUPT;
405 }
406
407 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_PULSES );
408
409 /* Get the count byte */
410 count = **ptr; (*ptr)++;
411 libspectrum_tape_block_set_count( block, count );
412
413 /* Check enough data exists for every pulse */
414 if( end - (*ptr) < (ptrdiff_t)( 2 * count ) ) {
415 libspectrum_free( block );
416 libspectrum_print_error(
417 LIBSPECTRUM_ERROR_CORRUPT,
418 "tzx_read_pulses_block: not enough data in buffer"
419 );
420 return LIBSPECTRUM_ERROR_CORRUPT;
421 }
422
423 lengths = libspectrum_new( libspectrum_dword, count );
424
425 /* Copy the data across */
426 for( i = 0; i < count; i++ ) {
427 lengths[i] = (*ptr)[0] + (*ptr)[1] * 0x100; (*ptr) += 2;
428 }
429 libspectrum_tape_block_set_pulse_lengths( block, lengths );
430
431 libspectrum_tape_append_block( tape, block );
432
433 return LIBSPECTRUM_ERROR_NONE;
434 }
435
436 static libspectrum_error
tzx_read_pure_data(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)437 tzx_read_pure_data( libspectrum_tape *tape, const libspectrum_byte **ptr,
438 const libspectrum_byte *end )
439 {
440 libspectrum_tape_block* block;
441 size_t length; libspectrum_byte *data;
442 libspectrum_byte bits_in_last_byte;
443 libspectrum_error error;
444
445 /* Check there's enough left in the buffer for all the metadata */
446 if( end - (*ptr) < 10 ) {
447 libspectrum_print_error(
448 LIBSPECTRUM_ERROR_CORRUPT,
449 "tzx_read_pure_data: not enough data in buffer"
450 );
451 return LIBSPECTRUM_ERROR_CORRUPT;
452 }
453
454 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_PURE_DATA );
455
456 /* Get the metadata */
457 libspectrum_tape_block_set_bit0_length( block,
458 (*ptr)[0] + (*ptr)[1] * 0x100 );
459 (*ptr) += 2;
460 libspectrum_tape_block_set_bit1_length( block,
461 (*ptr)[0] + (*ptr)[1] * 0x100 );
462 (*ptr) += 2;
463
464 bits_in_last_byte = **ptr;
465 (*ptr)++;
466
467 libspectrum_set_pause_ms( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
468 (*ptr) += 2;
469
470 /* And the actual data */
471 error = tzx_read_data( ptr, end, &length, 3, &data );
472 if( error ) { libspectrum_free( block ); return error; }
473
474 if( bits_in_last_byte == 0 && length > 1 ) {
475 bits_in_last_byte = 8;
476 length -= 1;
477 }
478
479 if( bits_in_last_byte > 8 ) {
480 bits_in_last_byte = 8;
481 }
482
483 libspectrum_tape_block_set_bits_in_last_byte( block, bits_in_last_byte );
484 libspectrum_tape_block_set_data_length( block, length );
485 libspectrum_tape_block_set_data( block, data );
486
487 libspectrum_tape_append_block( tape, block );
488
489 return LIBSPECTRUM_ERROR_NONE;
490 }
491
492 static libspectrum_error
tzx_read_raw_data(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)493 tzx_read_raw_data (libspectrum_tape *tape, const libspectrum_byte **ptr,
494 const libspectrum_byte *end)
495 {
496 libspectrum_tape_block* block;
497 size_t length; libspectrum_byte *data;
498 libspectrum_byte bits_in_last_byte;
499 libspectrum_error error;
500
501 /* Check there's enough left in the buffer for all the metadata */
502 if (end - (*ptr) < 8) {
503 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
504 "tzx_read_raw_data: not enough data in buffer" );
505 return LIBSPECTRUM_ERROR_CORRUPT;
506 }
507
508 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_RAW_DATA );
509
510 /* Get the metadata */
511 libspectrum_tape_block_set_bit_length( block,
512 (*ptr)[0] + (*ptr)[1] * 0x100 );
513 libspectrum_set_pause_ms( block, (*ptr)[2] + (*ptr)[3] * 0x100 );
514
515 bits_in_last_byte = (*ptr)[4];
516 (*ptr) += 5;
517
518 /* And the actual data */
519 error = tzx_read_data( ptr, end, &length, 3, &data );
520 if( error ) { libspectrum_free( block ); return error; }
521
522 if( bits_in_last_byte == 0 && length >= 1 ) {
523 bits_in_last_byte = 8;
524 length -= 1;
525 }
526
527 if( bits_in_last_byte > 8 ) {
528 bits_in_last_byte = 8;
529 }
530
531 libspectrum_tape_block_set_bits_in_last_byte( block, bits_in_last_byte );
532 libspectrum_tape_block_set_data_length( block, length );
533 libspectrum_tape_block_set_data( block, data );
534
535 libspectrum_tape_append_block( tape, block );
536
537 /* And return with no error */
538 return LIBSPECTRUM_ERROR_NONE;
539 }
540
541 static libspectrum_error
tzx_read_generalised_data(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)542 tzx_read_generalised_data( libspectrum_tape *tape,
543 const libspectrum_byte **ptr,
544 const libspectrum_byte *end )
545 {
546 libspectrum_tape_block *block;
547 libspectrum_dword length, symbol_count, data_count;
548 libspectrum_word symbol_count2;
549 libspectrum_error error;
550 libspectrum_tape_generalised_data_symbol_table *table;
551 libspectrum_byte *symbols, *data;
552 libspectrum_word *repeats;
553
554 const libspectrum_byte *blockend, *ptr2;
555 size_t i, data_size;
556 int bits_per_symbol;
557
558 /* Check the length exists */
559 if( end - (*ptr) < 4 ) {
560 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
561 "%s: not enough data in buffer", __func__ );
562 return LIBSPECTRUM_ERROR_CORRUPT;
563 }
564
565 length = libspectrum_read_dword( ptr );
566
567 blockend = *ptr + length;
568
569 /* Sanity check */
570 if( length < 14 ) {
571 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
572 "%s: length less than minimum", __func__ );
573 return LIBSPECTRUM_ERROR_CORRUPT;
574 }
575
576 /* Check this much data exists */
577 if( end - (*ptr) < length ) {
578 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
579 "%s: not enough data in buffer", __func__ );
580 return LIBSPECTRUM_ERROR_CORRUPT;
581 }
582
583 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA );
584
585 libspectrum_tape_block_zero( block );
586
587 libspectrum_set_pause_ms( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
588 (*ptr) += 2;
589
590 error = libspectrum_tape_block_read_symbol_table_parameters( block, 1, ptr );
591 if( error ) { libspectrum_tape_block_free( block ); return error; }
592
593 error = libspectrum_tape_block_read_symbol_table_parameters( block, 0, ptr );
594 if( error ) { libspectrum_tape_block_free( block ); return error; }
595
596 length -= 14;
597
598 ptr2 = *ptr;
599
600 table = libspectrum_tape_block_pilot_table( block );
601 error = libspectrum_tape_block_read_symbol_table( table, ptr, length );
602 if( error ) { libspectrum_tape_block_free( block ); return error; }
603
604 length -= ptr2 - *ptr;
605
606 symbol_count = libspectrum_tape_generalised_data_symbol_table_symbols_in_block( table );
607
608 if( length < 3 * symbol_count ) {
609 libspectrum_tape_block_free( block );
610 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
611 "%s: not enough data in buffer", __func__ );
612 return LIBSPECTRUM_ERROR_CORRUPT;
613 }
614
615 symbols = libspectrum_new( libspectrum_byte, symbol_count );
616 repeats = libspectrum_new( libspectrum_word, symbol_count );
617
618 for( i = 0; i < symbol_count; i++ ) {
619 symbols[ i ] = **ptr; (*ptr)++;
620 repeats[ i ] = (*ptr)[0] + 0x100 * (*ptr)[1]; (*ptr) += 2;
621 }
622
623 libspectrum_tape_block_set_pilot_symbols( block, symbols );
624 libspectrum_tape_block_set_pilot_repeats( block, repeats );
625
626 length -= 3 * symbol_count;
627
628 ptr2 = *ptr;
629
630 table = libspectrum_tape_block_data_table( block );
631 libspectrum_tape_block_read_symbol_table( table, ptr, length );
632
633 length -= ptr2 - *ptr;
634
635 symbol_count2 = libspectrum_tape_generalised_data_symbol_table_symbols_in_table( table );
636
637 bits_per_symbol = ceil( log( symbol_count2 ) / M_LN2 );
638
639 libspectrum_tape_block_set_bits_per_data_symbol( block, bits_per_symbol );
640
641 symbol_count = libspectrum_tape_generalised_data_symbol_table_symbols_in_block( table );
642
643 data_count = ( ( bits_per_symbol * symbol_count ) + 7 ) / 8;
644 data_size = data_count * sizeof( *data );
645
646 data = libspectrum_new( libspectrum_byte, data_size );
647
648 if( end - (*ptr) < data_size ) {
649 libspectrum_free( data );
650 libspectrum_tape_block_free( block );
651 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
652 "%s: data extends beyond end of block", __func__ );
653 return LIBSPECTRUM_ERROR_CORRUPT;
654 }
655
656 memcpy( data, *ptr, data_count * sizeof( *data ) );
657 *ptr += data_count;
658
659 libspectrum_tape_block_set_data( block, data );
660
661 /* Sanity check */
662 if( *ptr != blockend ) {
663 libspectrum_tape_block_free( block );
664 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
665 "%s: sanity check failed", __func__ );
666 return LIBSPECTRUM_ERROR_CORRUPT;
667 }
668
669 libspectrum_tape_append_block( tape, block );
670
671 return LIBSPECTRUM_ERROR_NONE;
672 }
673
674 static libspectrum_error
tzx_read_pause(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)675 tzx_read_pause( libspectrum_tape *tape, const libspectrum_byte **ptr,
676 const libspectrum_byte *end )
677 {
678 libspectrum_tape_block *block;
679
680 /* Check the pause actually exists */
681 if( end - (*ptr) < 2 ) {
682 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
683 "tzx_read_pause: not enough data in buffer" );
684 return LIBSPECTRUM_ERROR_CORRUPT;
685 }
686
687 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_PAUSE );
688
689 /* Get the pause length */
690 libspectrum_set_pause_ms( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
691 /* Pause blocks should change the pulse level to ensure that the
692 * last edge is properly finished, so set the block level to -1 */
693 libspectrum_tape_block_set_level( block, -1 );
694 (*ptr) += 2;
695
696 libspectrum_tape_append_block( tape, block );
697
698 /* And return */
699 return LIBSPECTRUM_ERROR_NONE;
700 }
701
702 static libspectrum_error
tzx_read_group_start(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)703 tzx_read_group_start( libspectrum_tape *tape, const libspectrum_byte **ptr,
704 const libspectrum_byte *end )
705 {
706 libspectrum_tape_block *block;
707 char *name;
708 libspectrum_error error;
709
710 /* Check the length byte exists */
711 if( (*ptr) == end ) {
712 libspectrum_print_error(
713 LIBSPECTRUM_ERROR_CORRUPT,
714 "tzx_read_group_start: not enough data in buffer"
715 );
716 return LIBSPECTRUM_ERROR_CORRUPT;
717 }
718
719 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_GROUP_START );
720
721 /* Read in the description of the group */
722 error = tzx_read_string( ptr, end, &name );
723 if( error ) { libspectrum_free( block ); return error; }
724 libspectrum_tape_block_set_text( block, name );
725
726 libspectrum_tape_append_block( tape, block );
727
728 return LIBSPECTRUM_ERROR_NONE;
729 }
730
731 static libspectrum_error
tzx_read_jump(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)732 tzx_read_jump( libspectrum_tape *tape, const libspectrum_byte **ptr,
733 const libspectrum_byte *end )
734 {
735 libspectrum_tape_block *block;
736 int offset;
737
738 /* Check the offset exists */
739 if( end - (*ptr) < 2 ) {
740 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
741 "tzx_read_jump: not enough data in buffer" );
742 return LIBSPECTRUM_ERROR_CORRUPT;
743 }
744
745 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_JUMP );
746
747 /* Get the offset */
748 offset = (*ptr)[0] + (*ptr)[1] * 0x100; (*ptr) += 2;
749 if( offset >= 32768 ) offset -= 65536;
750 libspectrum_tape_block_set_offset( block, offset);
751
752 libspectrum_tape_append_block( tape, block );
753
754 return LIBSPECTRUM_ERROR_NONE;
755 }
756
757 static libspectrum_error
tzx_read_loop_start(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)758 tzx_read_loop_start( libspectrum_tape *tape, const libspectrum_byte **ptr,
759 const libspectrum_byte *end )
760 {
761 libspectrum_tape_block *block;
762
763 /* Check the count exists */
764 if( end - (*ptr) < 2 ) {
765 libspectrum_print_error(
766 LIBSPECTRUM_ERROR_CORRUPT,
767 "tzx_read_loop_start: not enough data in buffer"
768 );
769 return LIBSPECTRUM_ERROR_CORRUPT;
770 }
771
772 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_LOOP_START );
773
774 /* Get the repeat count */
775 libspectrum_tape_block_set_count( block, (*ptr)[0] + (*ptr)[1] * 0x100 );
776 (*ptr) += 2;
777
778 libspectrum_tape_append_block( tape, block );
779
780 return LIBSPECTRUM_ERROR_NONE;
781 }
782
783 static libspectrum_error
tzx_read_select(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)784 tzx_read_select( libspectrum_tape *tape, const libspectrum_byte **ptr,
785 const libspectrum_byte *end )
786 {
787 libspectrum_tape_block* block;
788 libspectrum_error error;
789
790 size_t length, count, i, j;
791 int *offsets;
792 char **descriptions;
793
794 /* Check there's enough left in the buffer for the length and the count
795 byte */
796 if( end - (*ptr) < 3 ) {
797 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
798 "tzx_read_select: not enough data in buffer" );
799 return LIBSPECTRUM_ERROR_CORRUPT;
800 }
801
802 /* Get the length, and check we've got that many bytes in the buffer */
803 length = (*ptr)[0] + (*ptr)[1] * 0x100; (*ptr) += 2;
804 if( end - (*ptr) < (ptrdiff_t)length ) {
805 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
806 "tzx_read_select: not enough data in buffer" );
807 return LIBSPECTRUM_ERROR_CORRUPT;
808 }
809
810 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_SELECT );
811
812 /* Get the number of selections */
813 count = **ptr; (*ptr)++;
814 libspectrum_tape_block_set_count( block, count );
815
816 /* Allocate memory */
817 offsets = libspectrum_new( int, count );
818 libspectrum_tape_block_set_offsets( block, offsets );
819
820 descriptions = libspectrum_new( char *, count );
821 libspectrum_tape_block_set_texts( block, descriptions );
822
823 /* Read in the data */
824 for( i = 0; i < count; i++ ) {
825
826 /* Check we've got the offset and a length byte */
827 if( end - (*ptr) < 3 ) {
828 for( j = 0; j < i; j++ ) libspectrum_free( descriptions[j] );
829 libspectrum_free( descriptions ); libspectrum_free( offsets ); libspectrum_free( block );
830 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
831 "tzx_read_select: not enough data in buffer" );
832 return LIBSPECTRUM_ERROR_CORRUPT;
833 }
834
835 /* Get the offset */
836 offsets[i] = (*ptr)[0] + (*ptr)[1] * 0x100; (*ptr) += 2;
837
838 /* Get the description of this selection */
839 error = tzx_read_string( ptr, end, &descriptions[i] );
840 if( error ) {
841 for( j = 0; j < i; j++ ) libspectrum_free( descriptions[j] );
842 libspectrum_free( descriptions ); libspectrum_free( offsets ); libspectrum_free( block );
843 return error;
844 }
845
846 }
847
848 libspectrum_tape_append_block( tape, block );
849
850 return LIBSPECTRUM_ERROR_NONE;
851 }
852
853 static libspectrum_error
tzx_read_stop(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)854 tzx_read_stop( libspectrum_tape *tape, const libspectrum_byte **ptr,
855 const libspectrum_byte *end )
856 {
857 libspectrum_tape_block *block;
858
859 /* Check the length field exists */
860 if( end - (*ptr) < 4 ) {
861 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
862 "tzx_read_stop: not enough data in buffer" );
863 return LIBSPECTRUM_ERROR_CORRUPT;
864 }
865
866 /* But then just skip over it, as I don't care what it is */
867 (*ptr) += 4;
868
869 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_STOP48 );
870
871 libspectrum_tape_append_block( tape, block );
872
873 return LIBSPECTRUM_ERROR_NONE;
874 }
875
876 static libspectrum_error
tzx_read_set_signal_level(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)877 tzx_read_set_signal_level( libspectrum_tape *tape, const libspectrum_byte **ptr,
878 const libspectrum_byte *end )
879 {
880 libspectrum_tape_block *block;
881
882 /* Check the length field exists and signal level is available */
883 if( end - (*ptr) < 5 ) {
884 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
885 "tzx_read_set_signal_level: not enough data in buffer" );
886 return LIBSPECTRUM_ERROR_CORRUPT;
887 }
888
889 /* But then just skip over it, as I don't care what it is */
890 (*ptr) += 4;
891
892 block =
893 libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL );
894
895 libspectrum_tape_block_set_level( block, !!(**ptr) ); (*ptr)++;
896
897 libspectrum_tape_append_block( tape, block );
898
899 return LIBSPECTRUM_ERROR_NONE;
900 }
901
902 static libspectrum_error
tzx_read_comment(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)903 tzx_read_comment( libspectrum_tape *tape, const libspectrum_byte **ptr,
904 const libspectrum_byte *end )
905 {
906 libspectrum_tape_block* block;
907 char *text;
908 libspectrum_error error;
909
910 /* Check the length byte exists */
911 if( (*ptr) == end ) {
912 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
913 "tzx_read_comment: not enough data in buffer" );
914 return LIBSPECTRUM_ERROR_CORRUPT;
915 }
916
917 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_COMMENT );
918
919 /* Get the actual comment */
920 error = tzx_read_string( ptr, end, &text );
921 if( error ) { libspectrum_free( block ); return error; }
922 libspectrum_tape_block_set_text( block, text );
923
924 libspectrum_tape_append_block( tape, block );
925
926 return LIBSPECTRUM_ERROR_NONE;
927 }
928
929 static libspectrum_error
tzx_read_message(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)930 tzx_read_message( libspectrum_tape *tape, const libspectrum_byte **ptr,
931 const libspectrum_byte *end )
932 {
933 libspectrum_tape_block* block;
934 char *text;
935 libspectrum_error error;
936
937 /* Check the time and length byte exists */
938 if( end - (*ptr) < 2 ) {
939 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
940 "tzx_read_message: not enough data in buffer" );
941 return LIBSPECTRUM_ERROR_CORRUPT;
942 }
943
944 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_MESSAGE );
945
946 /* Get the time in seconds */
947 libspectrum_set_pause_ms( block, (**ptr) * 1000 ); (*ptr)++;
948
949 /* Get the message itself */
950 error = tzx_read_string( ptr, end, &text );
951 if( error ) { libspectrum_free( block ); return error; }
952 libspectrum_tape_block_set_text( block, text );
953
954 libspectrum_tape_append_block( tape, block );
955
956 return LIBSPECTRUM_ERROR_NONE;
957 }
958
959 static libspectrum_error
tzx_read_archive_info(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)960 tzx_read_archive_info( libspectrum_tape *tape, const libspectrum_byte **ptr,
961 const libspectrum_byte *end )
962 {
963 libspectrum_tape_block* block;
964 libspectrum_error error;
965
966 size_t i, count;
967 int *ids;
968 char **strings;
969
970 /* Check there's enough left in the buffer for the length and the count
971 byte */
972 if( end - (*ptr) < 3 ) {
973 libspectrum_print_error(
974 LIBSPECTRUM_ERROR_CORRUPT,
975 "tzx_read_archive_info: not enough data in buffer"
976 );
977 return LIBSPECTRUM_ERROR_CORRUPT;
978 }
979
980 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO );
981
982 /* Skip the length, as I don't care about it */
983 (*ptr) += 2;
984
985 /* Get the number of string */
986 count = **ptr; (*ptr)++;
987 libspectrum_tape_block_set_count( block, count );
988
989 /* Allocate memory */
990 ids = libspectrum_new( int, count );
991 libspectrum_tape_block_set_ids( block, ids );
992
993 strings = libspectrum_new( char *, count );
994 libspectrum_tape_block_set_texts( block, strings );
995
996 for( i = 0; i < count; i++ ) {
997
998 /* Must be ID byte and length byte */
999 if( end - (*ptr) < 2 ) {
1000 size_t j;
1001 for( j=0; j<i; j++ ) libspectrum_free( strings[j] );
1002 libspectrum_free( strings ); libspectrum_free( ids ); libspectrum_free( block );
1003 libspectrum_print_error(
1004 LIBSPECTRUM_ERROR_CORRUPT,
1005 "tzx_read_archive_info: not enough data in buffer"
1006 );
1007 return LIBSPECTRUM_ERROR_CORRUPT;
1008 }
1009
1010 /* Get the ID byte */
1011 ids[i] = **ptr; (*ptr)++;
1012
1013 /* Read in the string itself */
1014 error = tzx_read_string( ptr, end, &strings[i] );
1015 if( error ) {
1016 size_t j;
1017 for( j = 0; j < i; j++ ) libspectrum_free( strings[j] );
1018 libspectrum_free( strings ); libspectrum_free( ids ); libspectrum_free( block );
1019 return error;
1020 }
1021
1022 }
1023
1024 libspectrum_tape_append_block( tape, block );
1025
1026 return LIBSPECTRUM_ERROR_NONE;
1027 }
1028
1029 static libspectrum_error
tzx_read_hardware(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)1030 tzx_read_hardware( libspectrum_tape *tape, const libspectrum_byte **ptr,
1031 const libspectrum_byte *end )
1032 {
1033 libspectrum_tape_block* block;
1034 size_t i, count;
1035 int *types, *ids, *values;
1036
1037 /* Check there's enough left in the buffer for the count byte */
1038 if( (*ptr) == end ) {
1039 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1040 "tzx_read_hardware: not enough data in buffer" );
1041 return LIBSPECTRUM_ERROR_CORRUPT;
1042 }
1043
1044 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_HARDWARE );
1045
1046 /* Get the number of string */
1047 count = **ptr; (*ptr)++;
1048 libspectrum_tape_block_set_count( block, count );
1049
1050 /* Check there's enough data in the buffer for all the data */
1051 if( end - (*ptr) < 3 * (ptrdiff_t)count ) {
1052 libspectrum_free( block );
1053 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1054 "tzx_read_hardware: not enough data in buffer" );
1055 return LIBSPECTRUM_ERROR_CORRUPT;
1056 }
1057
1058 /* Allocate memory */
1059 types = libspectrum_new( int, count );
1060 libspectrum_tape_block_set_types( block, types );
1061
1062 ids = libspectrum_new( int, count );
1063 libspectrum_tape_block_set_ids( block, ids );
1064
1065 values = libspectrum_new( int, count );
1066 libspectrum_tape_block_set_values( block, values );
1067
1068 /* Actually read in all the data */
1069 for( i = 0; i < count; i++ ) {
1070 types[i] = **ptr; (*ptr)++;
1071 ids[i] = **ptr; (*ptr)++;
1072 values[i] = **ptr; (*ptr)++;
1073 }
1074
1075 libspectrum_tape_append_block( tape, block );
1076
1077 return LIBSPECTRUM_ERROR_NONE;
1078 }
1079
1080 static libspectrum_error
tzx_read_custom(libspectrum_tape * tape,const libspectrum_byte ** ptr,const libspectrum_byte * end)1081 tzx_read_custom( libspectrum_tape *tape, const libspectrum_byte **ptr,
1082 const libspectrum_byte *end )
1083 {
1084 libspectrum_tape_block* block;
1085 char *description;
1086 libspectrum_byte* data; size_t length;
1087 libspectrum_error error;
1088
1089 /* Check the description (16) and length bytes (4) exist */
1090 if( end - (*ptr) < 20 ) {
1091 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1092 "tzx_read_custom: not enough data in buffer" );
1093 return LIBSPECTRUM_ERROR_CORRUPT;
1094 }
1095
1096 block = libspectrum_tape_block_alloc( LIBSPECTRUM_TAPE_BLOCK_CUSTOM );
1097
1098 /* Get the description */
1099 description = libspectrum_new( char, 17 );
1100 memcpy( description, *ptr, 16 ); (*ptr) += 16; description[16] = '\0';
1101 libspectrum_tape_block_set_text( block, description );
1102
1103 /* Read in the data */
1104 error = tzx_read_data( ptr, end, &length, 4, &data );
1105 if( error ) { libspectrum_free( description ); libspectrum_free( block ); return error; }
1106 libspectrum_tape_block_set_data_length( block, length );
1107 libspectrum_tape_block_set_data( block, data );
1108
1109 libspectrum_tape_append_block( tape, block );
1110
1111 return LIBSPECTRUM_ERROR_NONE;
1112 }
1113
1114 /* Concatenation block: just skip it entirely as it serves no useful
1115 purpose */
1116 static libspectrum_error
tzx_read_concat(const libspectrum_byte ** ptr,const libspectrum_byte * end)1117 tzx_read_concat( const libspectrum_byte **ptr, const libspectrum_byte *end )
1118 {
1119 size_t signature_length = strlen( libspectrum_tzx_signature );
1120
1121 /* Check there's enough data left; the -1 here is because we've already
1122 read the first byte of the signature as the block ID */
1123 if( end - (*ptr) < (ptrdiff_t)signature_length + 2 - 1 ) {
1124 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1125 "tzx_read_concat: not enough data in buffer" );
1126 return LIBSPECTRUM_ERROR_CORRUPT;
1127 }
1128
1129 /* Skip the data */
1130 *ptr += signature_length + 2 - 1;
1131
1132 return LIBSPECTRUM_ERROR_NONE;
1133 }
1134
1135 static void
tzx_read_empty_block(libspectrum_tape * tape,libspectrum_tape_type id)1136 tzx_read_empty_block( libspectrum_tape *tape, libspectrum_tape_type id )
1137 {
1138 libspectrum_tape_block *block;
1139 block = libspectrum_tape_block_alloc( id );
1140 libspectrum_tape_append_block( tape, block );
1141 }
1142
1143 static libspectrum_error
tzx_read_data(const libspectrum_byte ** ptr,const libspectrum_byte * end,size_t * length,int bytes,libspectrum_byte ** data)1144 tzx_read_data( const libspectrum_byte **ptr, const libspectrum_byte *end,
1145 size_t *length, int bytes, libspectrum_byte **data )
1146 {
1147 int i; libspectrum_dword multiplier = 0x01;
1148 size_t padding;
1149
1150 if( bytes < 0 ) {
1151 bytes = -bytes; padding = 1;
1152 } else {
1153 padding = 0;
1154 }
1155
1156 (*length) = 0;
1157 for( i=0; i<bytes; i++, multiplier *= 0x100 ) {
1158 *length += **ptr * multiplier; (*ptr)++;
1159 }
1160
1161 /* Have we got enough bytes left in buffer? */
1162 if( ( end - (*ptr) ) < (ptrdiff_t)(*length) ) {
1163 libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
1164 "tzx_read_data: not enough data in buffer" );
1165 return LIBSPECTRUM_ERROR_CORRUPT;
1166 }
1167
1168 /* Allocate memory for the data; the check for *length is to avoid
1169 the implementation-defined behaviour of malloc( 0 ) */
1170 if( *length || padding ) {
1171 *data = libspectrum_new( libspectrum_byte, *length + padding );
1172 /* Copy the block data across, and move along */
1173 memcpy( *data, *ptr, *length ); *ptr += *length;
1174 } else {
1175 *data = NULL;
1176 }
1177
1178 return LIBSPECTRUM_ERROR_NONE;
1179
1180 }
1181
1182 static libspectrum_error
tzx_read_string(const libspectrum_byte ** ptr,const libspectrum_byte * end,char ** dest)1183 tzx_read_string( const libspectrum_byte **ptr, const libspectrum_byte *end,
1184 char **dest )
1185 {
1186 size_t length;
1187 libspectrum_error error;
1188 char *ptr2;
1189
1190 error = tzx_read_data( ptr, end, &length, -1, (libspectrum_byte**)dest );
1191 if( error ) return error;
1192
1193 /* Null terminate the string */
1194 (*dest)[length] = '\0';
1195
1196 /* Translate line endings */
1197 for( ptr2 = (*dest); *ptr2; ptr2++ ) if( *ptr2 == '\r' ) *ptr2 = '\n';
1198
1199 return LIBSPECTRUM_ERROR_NONE;
1200 }
1201