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