1 /* tape_block.c: one tape block
2    Copyright (c) 2003-2008 Philip Kendall
3 
4    $Id: tape_block.c 4433 2011-05-14 05:44:47Z fredm $
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20    Author contact information:
21 
22    E-mail: philip-fuse@shadowmagic.org.uk
23 
24 */
25 
26 #include <config.h>
27 
28 #include <math.h>
29 
30 #include "tape_block.h"
31 
32 /* The number of pilot pulses for the standard ROM loader NB: These
33    disagree with the .tzx specification (they're 5 and 1 less
34    respectively), but are correct. Entering the loop at #04D8 in the
35    48K ROM with HL == #0001 will produce the first sync pulse, not a
36    pilot pulse, which gives a difference of one in both cases. The
37    further difference of 4 in the header count is just a screw-up in
38    the .tzx specification AFAICT */
39 static const size_t LIBSPECTRUM_TAPE_PILOTS_HEADER = 0x1f7f;
40 static const size_t LIBSPECTRUM_TAPE_PILOTS_DATA   = 0x0c97;
41 
42 /* Functions to initialise block types */
43 
44 static libspectrum_error
45 rom_init( libspectrum_tape_rom_block *block,
46           libspectrum_tape_rom_block_state *state );
47 static libspectrum_error
48 turbo_init( libspectrum_tape_turbo_block *block,
49             libspectrum_tape_turbo_block_state *state );
50 static libspectrum_error
51 pure_data_init( libspectrum_tape_pure_data_block *block,
52                 libspectrum_tape_pure_data_block_state *state );
53 static void
54 raw_data_init( libspectrum_tape_raw_data_block *block,
55                libspectrum_tape_raw_data_block_state *state );
56 static libspectrum_error
57 generalised_data_init( libspectrum_tape_generalised_data_block *block,
58                        libspectrum_tape_generalised_data_block_state *state );
59 static libspectrum_error
60 data_block_init( libspectrum_tape_data_block *block,
61                  libspectrum_tape_data_block_state *state );
62 
63 libspectrum_tape_block*
libspectrum_tape_block_alloc(libspectrum_tape_type type)64 libspectrum_tape_block_alloc( libspectrum_tape_type type )
65 {
66   libspectrum_tape_block *block = libspectrum_malloc( sizeof( *block ) );
67   libspectrum_tape_block_set_type( block, type );
68   return block;
69 }
70 
71 static void
free_symbol_table(libspectrum_tape_generalised_data_symbol_table * table)72 free_symbol_table( libspectrum_tape_generalised_data_symbol_table *table )
73 {
74   size_t i;
75 
76   if( table->symbols ) {
77     for( i = 0; i < table->symbols_in_table; i++ )
78       libspectrum_free( table->symbols[ i ].lengths );
79 
80     libspectrum_free( table->symbols );
81   }
82 }
83 
84 /* Free the memory used by one block */
85 libspectrum_error
libspectrum_tape_block_free(libspectrum_tape_block * block)86 libspectrum_tape_block_free( libspectrum_tape_block *block )
87 {
88   size_t i;
89 
90   switch( block->type ) {
91 
92   case LIBSPECTRUM_TAPE_BLOCK_ROM:
93     libspectrum_free( block->types.rom.data );
94     break;
95   case LIBSPECTRUM_TAPE_BLOCK_TURBO:
96     libspectrum_free( block->types.turbo.data );
97     break;
98   case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
99     break;
100   case LIBSPECTRUM_TAPE_BLOCK_PULSES:
101     libspectrum_free( block->types.pulses.lengths );
102     break;
103   case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
104     libspectrum_free( block->types.pure_data.data );
105     break;
106   case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
107     libspectrum_free( block->types.raw_data.data );
108     break;
109   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
110     free_symbol_table( &block->types.generalised_data.pilot_table );
111     free_symbol_table( &block->types.generalised_data.data_table );
112     libspectrum_free( block->types.generalised_data.pilot_symbols );
113     libspectrum_free( block->types.generalised_data.pilot_repeats );
114     libspectrum_free( block->types.generalised_data.data );
115     break;
116 
117   case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
118     break;
119   case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
120     libspectrum_free( block->types.group_start.name );
121     break;
122   case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
123     break;
124   case LIBSPECTRUM_TAPE_BLOCK_JUMP:
125     break;
126   case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
127     break;
128   case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
129     break;
130 
131   case LIBSPECTRUM_TAPE_BLOCK_SELECT:
132     for( i=0; i<block->types.select.count; i++ ) {
133       libspectrum_free( block->types.select.descriptions[i] );
134     }
135     libspectrum_free( block->types.select.descriptions );
136     libspectrum_free( block->types.select.offsets );
137     break;
138 
139   case LIBSPECTRUM_TAPE_BLOCK_STOP48:
140     break;
141 
142   case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
143     break;
144 
145   case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
146     libspectrum_free( block->types.comment.text );
147     break;
148   case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
149     libspectrum_free( block->types.message.text );
150     break;
151   case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
152     for( i=0; i<block->types.archive_info.count; i++ ) {
153       libspectrum_free( block->types.archive_info.strings[i] );
154     }
155     libspectrum_free( block->types.archive_info.ids );
156     libspectrum_free( block->types.archive_info.strings );
157     break;
158   case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
159     libspectrum_free( block->types.hardware.types  );
160     libspectrum_free( block->types.hardware.ids    );
161     libspectrum_free( block->types.hardware.values );
162     break;
163 
164   case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
165     libspectrum_free( block->types.custom.description );
166     libspectrum_free( block->types.custom.data );
167     break;
168 
169   /* Block types not present in .tzx follow here */
170 
171   case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
172     libspectrum_free( block->types.rle_pulse.data );
173     break;
174 
175   case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
176     libspectrum_free( block->types.pulse_sequence.lengths );
177     libspectrum_free( block->types.pulse_sequence.pulse_repeats );
178     break;
179 
180   case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
181     libspectrum_free( block->types.data_block.data );
182     libspectrum_free( block->types.data_block.bit0_pulses );
183     libspectrum_free( block->types.data_block.bit1_pulses );
184     break;
185 
186   case LIBSPECTRUM_TAPE_BLOCK_CONCAT: /* This should never occur */
187   default:
188     libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
189 			     "%s: unknown block type %d", __func__,
190 			     block->type );
191     return LIBSPECTRUM_ERROR_LOGIC;
192   }
193 
194   libspectrum_free( block );
195 
196   return LIBSPECTRUM_ERROR_NONE;
197 }
198 
199 libspectrum_tape_type
libspectrum_tape_block_type(libspectrum_tape_block * block)200 libspectrum_tape_block_type( libspectrum_tape_block *block )
201 {
202   return block->type;
203 }
204 
205 libspectrum_error
libspectrum_tape_block_set_type(libspectrum_tape_block * block,libspectrum_tape_type type)206 libspectrum_tape_block_set_type( libspectrum_tape_block *block,
207 				 libspectrum_tape_type type )
208 {
209   block->type = type;
210   return LIBSPECTRUM_ERROR_NONE;
211 }
212 
213 /* Called when a new block is started to initialise its internal state */
214 libspectrum_error
libspectrum_tape_block_init(libspectrum_tape_block * block,libspectrum_tape_block_state * state)215 libspectrum_tape_block_init( libspectrum_tape_block *block,
216                              libspectrum_tape_block_state *state )
217 {
218   if( !block ) return LIBSPECTRUM_ERROR_NONE;
219 
220   switch( libspectrum_tape_block_type( block ) ) {
221 
222   case LIBSPECTRUM_TAPE_BLOCK_ROM:
223     return rom_init( &(block->types.rom), &(state->block_state.rom) );
224   case LIBSPECTRUM_TAPE_BLOCK_TURBO:
225     return turbo_init( &(block->types.turbo), &(state->block_state.turbo) );
226   case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
227     state->block_state.pure_tone.edge_count = block->types.pure_tone.pulses;
228     break;
229   case LIBSPECTRUM_TAPE_BLOCK_PULSES:
230     state->block_state.pulses.edge_count = 0;
231     break;
232   case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
233     return pure_data_init( &(block->types.pure_data),
234                            &(state->block_state.pure_data) );
235   case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
236     raw_data_init( &(block->types.raw_data), &(state->block_state.raw_data) );
237     return LIBSPECTRUM_ERROR_NONE;
238   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
239     return generalised_data_init( &(block->types.generalised_data),
240                                   &(state->block_state.generalised_data) );
241   case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
242     state->block_state.rle_pulse.index = 0;
243     return LIBSPECTRUM_ERROR_NONE;
244   case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
245     state->block_state.pulse_sequence.index = 0;
246     state->block_state.pulse_sequence.pulse_count = 0;
247     state->block_state.pulse_sequence.level = 1;
248     return LIBSPECTRUM_ERROR_NONE;
249   case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
250     return data_block_init( &(block->types.data_block),
251                             &(state->block_state.data_block) );
252 
253   /* These blocks need no initialisation */
254   case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
255   case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
256   case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
257   case LIBSPECTRUM_TAPE_BLOCK_JUMP:
258   case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
259   case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
260   case LIBSPECTRUM_TAPE_BLOCK_SELECT:
261   case LIBSPECTRUM_TAPE_BLOCK_STOP48:
262   case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
263   case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
264   case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
265   case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
266   case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
267   case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
268     return LIBSPECTRUM_ERROR_NONE;
269 
270   default:
271     libspectrum_print_error(
272       LIBSPECTRUM_ERROR_LOGIC,
273       "libspectrum_tape_init_block: unknown block type 0x%02x",
274       block->type
275     );
276     return LIBSPECTRUM_ERROR_LOGIC;
277   }
278 
279   return LIBSPECTRUM_ERROR_NONE;
280 }
281 
282 static libspectrum_error
rom_init(libspectrum_tape_rom_block * block,libspectrum_tape_rom_block_state * state)283 rom_init( libspectrum_tape_rom_block *block,
284           libspectrum_tape_rom_block_state *state )
285 {
286   /* Initialise the number of pilot pulses */
287   state->edge_count = block->length && block->data[0] & 0x80 ?
288                       LIBSPECTRUM_TAPE_PILOTS_DATA           :
289                       LIBSPECTRUM_TAPE_PILOTS_HEADER;
290 
291   /* And that we're just before the start of the data */
292   state->bytes_through_block = -1; state->bits_through_byte = 7;
293   state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
294 
295   return LIBSPECTRUM_ERROR_NONE;
296 }
297 
298 static libspectrum_error
turbo_init(libspectrum_tape_turbo_block * block,libspectrum_tape_turbo_block_state * state)299 turbo_init( libspectrum_tape_turbo_block *block,
300             libspectrum_tape_turbo_block_state *state )
301 {
302   /* Initialise the number of pilot pulses */
303   state->edge_count = block->pilot_pulses;
304 
305   /* And that we're just before the start of the data */
306   state->bytes_through_block = -1; state->bits_through_byte = 7;
307   state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
308 
309   return LIBSPECTRUM_ERROR_NONE;
310 }
311 
312 static libspectrum_error
pure_data_init(libspectrum_tape_pure_data_block * block,libspectrum_tape_pure_data_block_state * state)313 pure_data_init( libspectrum_tape_pure_data_block *block,
314                 libspectrum_tape_pure_data_block_state *state )
315 {
316   libspectrum_error error;
317 
318   /* We're just before the start of the data */
319   state->bytes_through_block = -1; state->bits_through_byte = 7;
320   /* Set up the next bit */
321   error = libspectrum_tape_pure_data_next_bit( block, state );
322   if( error ) return error;
323 
324   return LIBSPECTRUM_ERROR_NONE;
325 }
326 
327 static void
raw_data_init(libspectrum_tape_raw_data_block * block,libspectrum_tape_raw_data_block_state * state)328 raw_data_init( libspectrum_tape_raw_data_block *block,
329                libspectrum_tape_raw_data_block_state *state )
330 {
331   if( block->data ) {
332 
333     /* We're just before the start of the data */
334     state->state = LIBSPECTRUM_TAPE_STATE_DATA1;
335     state->bytes_through_block = -1; state->bits_through_byte = 7;
336     state->last_bit = 0x80 & block->data[0];
337     /* Set up the next bit */
338     libspectrum_tape_raw_data_next_bit( block, state );
339 
340   } else {
341 
342     state->state = LIBSPECTRUM_TAPE_STATE_PAUSE;
343 
344   }
345 }
346 
347 static libspectrum_error
generalised_data_init(libspectrum_tape_generalised_data_block * block,libspectrum_tape_generalised_data_block_state * state)348 generalised_data_init( libspectrum_tape_generalised_data_block *block,
349                        libspectrum_tape_generalised_data_block_state *state )
350 {
351   state->state = LIBSPECTRUM_TAPE_STATE_PILOT;
352 
353   state->run = 0;
354   state->symbols_through_run = 0;
355   state->edges_through_symbol = 0;
356 
357   return LIBSPECTRUM_ERROR_NONE;
358 }
359 
360 static libspectrum_error
data_block_init(libspectrum_tape_data_block * block,libspectrum_tape_data_block_state * state)361 data_block_init( libspectrum_tape_data_block *block,
362                  libspectrum_tape_data_block_state *state )
363 {
364   libspectrum_error error;
365 
366   state->bit0_flags = 0;
367   state->bit1_flags = 0;
368 
369   /* If both bit0 and bit1 are two matching pulses, then assign them to be
370      flagged as short/long pulses respectively */
371   if( block->bit0_pulse_count == 2 && block->bit1_pulse_count == 2 &&
372       block->bit0_pulses[ 0 ] == block->bit0_pulses[ 1 ] &&
373       block->bit1_pulses[ 0 ] == block->bit1_pulses[ 1 ] &&
374       block->bit0_pulses[ 0 ] > 0  && block->bit1_pulses[ 0 ] > 0 ) {
375     if( block->bit0_pulses[ 0 ] < block->bit1_pulses[ 0 ] ) {
376       state->bit0_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_SHORT;
377       state->bit1_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_LONG;
378     } else if( block->bit0_pulses[ 0 ] > block->bit1_pulses[ 0 ] ) {
379       state->bit0_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_LONG;
380       state->bit1_flags = LIBSPECTRUM_TAPE_FLAGS_LENGTH_SHORT;
381     }
382   }
383 
384   state->level = block->initial_level;
385 
386   /* We're just before the start of the data */
387   state->bytes_through_block = -1; state->bits_through_byte = 7;
388   /* Set up the next bit */
389   error = libspectrum_tape_data_block_next_bit( block, state );
390   if( error ) return error;
391 
392   return LIBSPECTRUM_ERROR_NONE;
393 }
394 
395 /* Does this block consist solely of metadata? */
396 int
libspectrum_tape_block_metadata(libspectrum_tape_block * block)397 libspectrum_tape_block_metadata( libspectrum_tape_block *block )
398 {
399   switch( block->type ) {
400   case LIBSPECTRUM_TAPE_BLOCK_ROM:
401   case LIBSPECTRUM_TAPE_BLOCK_TURBO:
402   case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
403   case LIBSPECTRUM_TAPE_BLOCK_PULSES:
404   case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
405   case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
406   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
407   case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
408   case LIBSPECTRUM_TAPE_BLOCK_JUMP:
409   case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
410   case LIBSPECTRUM_TAPE_BLOCK_SELECT:
411   case LIBSPECTRUM_TAPE_BLOCK_STOP48:
412   case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
413   case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
414   case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
415   case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
416     return 0;
417 
418   case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
419   case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
420   case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
421   case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
422   case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
423   case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
424   case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
425   case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
426   case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
427     return 1;
428   }
429 
430   /* Should never happen */
431   return -1;
432 }
433 
434 libspectrum_error
libspectrum_tape_block_read_symbol_table_parameters(libspectrum_tape_block * block,int pilot,const libspectrum_byte ** ptr)435 libspectrum_tape_block_read_symbol_table_parameters(
436   libspectrum_tape_block *block, int pilot, const libspectrum_byte **ptr )
437 {
438   libspectrum_tape_generalised_data_block *generalised =
439     &block->types.generalised_data;
440 
441   libspectrum_tape_generalised_data_symbol_table *table =
442     pilot ? &generalised->pilot_table : &generalised->data_table;
443 
444   table->symbols_in_block = libspectrum_read_dword( ptr );
445   table->max_pulses = (*ptr)[0];
446 
447   table->symbols_in_table = (*ptr)[1];
448   if( !table->symbols_in_table ) table->symbols_in_table = 256;
449 
450   (*ptr) += 2;
451 
452   return LIBSPECTRUM_ERROR_NONE;
453 }
454 
455 libspectrum_error
libspectrum_tape_block_read_symbol_table(libspectrum_tape_generalised_data_symbol_table * table,const libspectrum_byte ** ptr,size_t length)456 libspectrum_tape_block_read_symbol_table(
457   libspectrum_tape_generalised_data_symbol_table *table,
458   const libspectrum_byte **ptr, size_t length )
459 {
460   if( table->symbols_in_block ) {
461 
462     libspectrum_tape_generalised_data_symbol *symbol;
463     size_t i, j;
464 
465     /* Sanity check */
466     if( length < ( 2 * table->max_pulses + 1 ) * table->symbols_in_table ) {
467       libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
468 			       "%s: not enough data in buffer", __func__ );
469       return LIBSPECTRUM_ERROR_CORRUPT;
470     }
471 
472 
473     table->symbols = libspectrum_malloc( table->symbols_in_table * sizeof( *table->symbols ) );
474 
475     for( i = 0, symbol = table->symbols;
476 	 i < table->symbols_in_table;
477 	 i++, symbol++ ) {
478       symbol->edge_type = **ptr; (*ptr)++;
479       symbol->lengths = libspectrum_malloc( table->max_pulses * sizeof( *symbol->lengths ) );
480       for( j = 0; j < table->max_pulses; j++ ) {
481 	symbol->lengths[ j ] = (*ptr)[0] + (*ptr)[1] * 0x100;
482 	(*ptr) += 2;
483       }
484     }
485 
486   }
487 
488   return LIBSPECTRUM_ERROR_NONE;
489 }
490 
491 void
libspectrum_tape_block_zero(libspectrum_tape_block * block)492 libspectrum_tape_block_zero( libspectrum_tape_block *block )
493 {
494   switch( block->type ) {
495   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
496     block->types.generalised_data.pilot_table.symbols = NULL;
497     block->types.generalised_data.data_table.symbols = NULL;
498     block->types.generalised_data.pilot_symbols = NULL;
499     block->types.generalised_data.pilot_repeats = NULL;
500     block->types.generalised_data.data = NULL;
501     break;
502   default:
503     break;
504   }
505 }
506 
507 /* Give the length of a tape block */
508 
509 #define BITS_SET_ARRAY_SIZE 256
510 static int bits_set[ BITS_SET_ARRAY_SIZE ];
511 
512 const int LIBSPECTRUM_BITS_IN_BYTE = 8;
513 
514 static int
libspectrum_bits_set_n_bits(libspectrum_byte byte,libspectrum_byte bits)515 libspectrum_bits_set_n_bits( libspectrum_byte byte, libspectrum_byte bits )
516 {
517   int i;
518   int retval = 0;
519 
520   if( bits > LIBSPECTRUM_BITS_IN_BYTE) bits = LIBSPECTRUM_BITS_IN_BYTE;
521 
522   for( i = 0; i < bits; i++ ) {
523     if( byte & 0x80 ) retval++;
524     byte <<= 1;
525   }
526 
527   return retval;
528 }
529 
530 void
libspectrum_init_bits_set(void)531 libspectrum_init_bits_set( void )
532 {
533   int i;
534 
535   /* Not big or clever, but easy to understand */
536   for( i = 0; i < BITS_SET_ARRAY_SIZE; i++ ) {
537     bits_set[ i ] = libspectrum_bits_set_n_bits( (libspectrum_byte)i,
538                                                  LIBSPECTRUM_BITS_IN_BYTE );
539   }
540 }
541 
542 static libspectrum_dword
convert_pulses_to_tstates(libspectrum_dword set_bit_length,libspectrum_dword unset_bit_length,int bits_set_in_block,int bit_block_size)543 convert_pulses_to_tstates( libspectrum_dword set_bit_length,
544                            libspectrum_dword unset_bit_length,
545                            int bits_set_in_block, int bit_block_size )
546 {
547   static const int pulses_in_bit = 2;
548   return ( pulses_in_bit * set_bit_length ) * bits_set_in_block +
549          ( pulses_in_bit * unset_bit_length ) * ( bit_block_size - bits_set_in_block );
550 }
551 
552 static libspectrum_dword
rom_block_length(libspectrum_tape_rom_block * rom)553 rom_block_length( libspectrum_tape_rom_block *rom )
554 {
555   libspectrum_dword length = rom->pause_tstates;
556   size_t i;
557 
558   size_t edge_count = rom->length && rom->data[0] & 0x80 ?
559                       LIBSPECTRUM_TAPE_PILOTS_DATA           :
560                       LIBSPECTRUM_TAPE_PILOTS_HEADER;
561   length += LIBSPECTRUM_TAPE_TIMING_PILOT * edge_count;
562   length += LIBSPECTRUM_TAPE_TIMING_SYNC1;
563   length += LIBSPECTRUM_TAPE_TIMING_SYNC2;
564 
565   for( i = 0; i < rom->length; i++ ) {
566     libspectrum_byte data = rom->data[ i ];
567     length += convert_pulses_to_tstates( LIBSPECTRUM_TAPE_TIMING_DATA1,
568                                          LIBSPECTRUM_TAPE_TIMING_DATA0,
569                                          bits_set[ data ],
570                                          LIBSPECTRUM_BITS_IN_BYTE );
571   }
572 
573   return length;
574 }
575 
576 static libspectrum_dword
turbo_block_length(libspectrum_tape_turbo_block * turbo)577 turbo_block_length( libspectrum_tape_turbo_block *turbo )
578 {
579   libspectrum_dword length =
580     turbo->pilot_pulses * turbo->pilot_length +
581     turbo->sync1_length + turbo->sync2_length +
582     turbo->pause_tstates;
583   size_t i;
584   if( turbo->length ) {
585     int bits_set_in_last_byte =
586       libspectrum_bits_set_n_bits( turbo->data[ turbo->length-1 ],
587                                    turbo->bits_in_last_byte );
588 
589     for( i = 0; i < turbo->length-1; i++ ) {
590       libspectrum_byte data = turbo->data[ i ];
591       length += convert_pulses_to_tstates( turbo->bit1_length,
592                                            turbo->bit0_length,
593                                            bits_set[ data ],
594                                            LIBSPECTRUM_BITS_IN_BYTE );
595     }
596 
597     /* handle bits in last byte correctly */
598     length += convert_pulses_to_tstates( turbo->bit1_length,
599                                          turbo->bit0_length,
600                                          bits_set_in_last_byte,
601                                          turbo->bits_in_last_byte );
602   }
603 
604   return length;
605 }
606 
607 static libspectrum_dword
pulses_block_length(libspectrum_tape_pulses_block * pulses)608 pulses_block_length( libspectrum_tape_pulses_block *pulses )
609 {
610   libspectrum_dword length = 0;
611   size_t i;
612 
613   for( i = 0; i < pulses->count; i++ ) length += pulses->lengths[ i ];
614 
615   return length;
616 }
617 
618 static libspectrum_dword
pure_data_block_length(libspectrum_tape_pure_data_block * pure_data)619 pure_data_block_length( libspectrum_tape_pure_data_block *pure_data )
620 {
621   libspectrum_dword length = pure_data->pause_tstates;
622   size_t i;
623   if( pure_data->length ) {
624     int bits_set_in_last_byte =
625       libspectrum_bits_set_n_bits( pure_data->data[ pure_data->length-1 ],
626                                    pure_data->bits_in_last_byte );
627 
628     for( i = 0; i < pure_data->length-1; i++ ) {
629       libspectrum_byte data = pure_data->data[ i ];
630       length += convert_pulses_to_tstates( pure_data->bit1_length,
631                                            pure_data->bit0_length,
632                                            bits_set[ data ],
633                                            LIBSPECTRUM_BITS_IN_BYTE );
634     }
635 
636     /* handle bits in last byte correctly */
637     length += convert_pulses_to_tstates( pure_data->bit1_length,
638                                          pure_data->bit0_length,
639                                          bits_set_in_last_byte,
640                                          pure_data->bits_in_last_byte );
641   }
642 
643   return length;
644 }
645 
646 static libspectrum_dword
raw_data_block_length(libspectrum_tape_raw_data_block * raw_data)647 raw_data_block_length( libspectrum_tape_raw_data_block *raw_data )
648 {
649   libspectrum_dword length = raw_data->pause_tstates;
650 
651   length += ( LIBSPECTRUM_BITS_IN_BYTE * raw_data->length -
652               ( LIBSPECTRUM_BITS_IN_BYTE - raw_data->bits_in_last_byte ) ) *
653               raw_data->bit_length;
654 
655   return length;
656 }
657 
658 static libspectrum_dword
rle_pulse_block_length(libspectrum_tape_rle_pulse_block * rle_pulse)659 rle_pulse_block_length( libspectrum_tape_rle_pulse_block *rle_pulse )
660 {
661   libspectrum_dword length = 0;
662   size_t i;
663 
664   for( i = 0; i < rle_pulse->length; i++ ) {
665     length += rle_pulse->data[ i ] * rle_pulse->scale;
666   }
667 
668   return length;
669 }
670 
671 static libspectrum_dword
generalised_data_block_length(libspectrum_tape_generalised_data_block * generalised_data)672 generalised_data_block_length(
673                     libspectrum_tape_generalised_data_block *generalised_data )
674 {
675   libspectrum_dword length = 0;
676   libspectrum_tape_generalised_data_block_state state;
677   libspectrum_dword tstates = 0;
678   /* Assume no special flags by default */
679   int flags = 0;
680   /* Has this edge ended the block? */
681   int end_of_block = 0;
682   libspectrum_error error = generalised_data_init( generalised_data, &state );
683 
684   if( error ) return -1;
685 
686   /* just reuse tape iteration for this as it is so nasty */
687   while( !end_of_block ) {
688     error = generalised_data_edge( generalised_data, &state, &tstates,
689                                    &end_of_block, &flags );
690     if( error ) return -1;
691 
692     length += tstates;
693   }
694 
695   return length;
696 }
697 
698 static libspectrum_dword
pulse_sequence_block_length(libspectrum_tape_pulse_sequence_block * pulses)699 pulse_sequence_block_length(
700                     libspectrum_tape_pulse_sequence_block *pulses )
701 {
702   libspectrum_dword length = 0;
703   size_t i;
704 
705   for( i = 0; i < pulses->count; i++ )
706     length += pulses->lengths[ i ] * pulses->pulse_repeats[ i ];
707 
708   return length;
709 }
710 
711 static libspectrum_dword
data_block_length(libspectrum_tape_data_block * data_block)712 data_block_length( libspectrum_tape_data_block *data_block )
713 {
714   libspectrum_dword length = 0;
715   size_t i;
716   if( data_block->count ) {
717     int bits_set_in_last_byte =
718       libspectrum_bits_set_n_bits( data_block->data[ data_block->length-1 ],
719                                    data_block->bits_in_last_byte );
720     size_t bit0_length = 0;
721     size_t bit1_length = 0;
722 
723     for( i = 0; i < data_block->bit0_pulse_count; i++ ) {
724       bit0_length += data_block->bit0_pulses[ i ];
725     }
726     bit0_length /=
727       data_block->bit0_pulse_count ? data_block->bit0_pulse_count : 1;
728 
729     for( i = 0; i < data_block->bit1_pulse_count; i++ ) {
730       bit1_length += data_block->bit1_pulses[ i ];
731     }
732     bit1_length /=
733       data_block->bit1_pulse_count ? data_block->bit1_pulse_count : 1;
734 
735     for( i = 0; i < data_block->length-1; i++ ) {
736       libspectrum_byte data = data_block->data[ i ];
737       length += convert_pulses_to_tstates( bit1_length,
738                                            bit0_length,
739                                            bits_set[ data ],
740                                            LIBSPECTRUM_BITS_IN_BYTE );
741     }
742 
743     /* handle bits in last byte correctly */
744     length += convert_pulses_to_tstates( bit1_length,
745                                          bit0_length,
746                                          bits_set_in_last_byte,
747                                          data_block->bits_in_last_byte );
748   }
749 
750   return length;
751 }
752 
753 libspectrum_dword
libspectrum_tape_block_length(libspectrum_tape_block * block)754 libspectrum_tape_block_length( libspectrum_tape_block *block )
755 {
756   libspectrum_tape_pure_tone_block *pure_tone;
757 
758   switch( block->type ) {
759   case LIBSPECTRUM_TAPE_BLOCK_ROM:
760     return rom_block_length( &block->types.rom );
761   case LIBSPECTRUM_TAPE_BLOCK_TURBO:
762     return turbo_block_length( &block->types.turbo );
763   case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
764     pure_tone = &block->types.pure_tone;
765     return pure_tone->pulses * pure_tone->length;
766   case LIBSPECTRUM_TAPE_BLOCK_PULSES:
767     return pulses_block_length( &block->types.pulses );
768   case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
769     return pure_data_block_length( &block->types.pure_data );
770   case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
771     return block->types.pause.length_tstates;
772   case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
773     return raw_data_block_length( &block->types.raw_data );
774   case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
775     return rle_pulse_block_length( &block->types.rle_pulse );
776   case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
777     return generalised_data_block_length( &block->types.generalised_data );
778   case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
779     return pulse_sequence_block_length( &block->types.pulse_sequence );
780   case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
781     return data_block_length( &block->types.data_block );
782   case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
783   case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
784   case LIBSPECTRUM_TAPE_BLOCK_JUMP:
785   case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
786   case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
787   case LIBSPECTRUM_TAPE_BLOCK_STOP48:
788   case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
789   case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
790   case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
791   case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
792   case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
793   case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
794   case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
795   case LIBSPECTRUM_TAPE_BLOCK_SELECT:
796     return 0;
797   default:
798     return -1;
799   }
800 }
801