Exemplo n.º 1
0
static int
update_archive_file( char *archive_file, libspectrum_tape *tape )
{
  libspectrum_tape_block* info_block;
  libspectrum_error error;
  libspectrum_tape *tzx;
  libspectrum_tape_iterator iterator;

  if( read_tape( archive_file, &tzx ) ) return 1;

  /* Get the new archive block */
  info_block = libspectrum_tape_iterator_init( &iterator, tzx );
  while( info_block &&
         libspectrum_tape_block_type( info_block ) !=
           LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO ) {
    info_block = libspectrum_tape_iterator_next( &iterator );
  }

  if( !info_block ) {
    libspectrum_tape_free( tzx );
    return 1;
  }

  /* Remove any existing archive block */
  error = remove_block_type( tape, LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO );
  if( error ) { libspectrum_tape_free( tzx ); return error; }

  /* Finally, put the new info block at the beginning of the block list */
  error = libspectrum_tape_insert_block( tape, info_block, 0 );
  if( error ) { libspectrum_tape_free( tzx ); return error; }

  return 0;
}
Exemplo n.º 2
0
/* Free the memory used by a list of blocks, but not the object itself */
libspectrum_error
libspectrum_tape_clear( libspectrum_tape *tape )
{
  g_slist_foreach( tape->blocks, block_free, NULL );
  g_slist_free( tape->blocks );
  tape->blocks = NULL;
  libspectrum_tape_iterator_init( &(tape->state.current_block), tape );

  return LIBSPECTRUM_ERROR_NONE;
}
Exemplo n.º 3
0
static int
remove_block_type( libspectrum_tape *tape, libspectrum_tape_type id )
{
  libspectrum_tape_block* block;
  libspectrum_tape_iterator iterator;

  for( block = libspectrum_tape_iterator_init( &iterator, tape );
       block;
       block = libspectrum_tape_iterator_next( &iterator ) ) {
    if( libspectrum_tape_block_type( block ) == id ) {
      libspectrum_tape_remove_block( tape, iterator );

      /* Iterator is invalidated by delete, so start again */
      block = libspectrum_tape_iterator_init( &iterator, tape );
    }
  }

  return 0;
}
Exemplo n.º 4
0
/* Call a user-supplied function for every block in the current tape */
int
tape_foreach( void (*function)( libspectrum_tape_block *block,
				void *user_data),
	      void *user_data )
{
  libspectrum_tape_block *block;
  libspectrum_tape_iterator iterator;

  for( block = libspectrum_tape_iterator_init( &iterator, tape );
       block;
       block = libspectrum_tape_iterator_next( &iterator ) )
    function( block, user_data );

  return 0;
}
Exemplo n.º 5
0
/* Allocate a list of blocks */
libspectrum_error
libspectrum_tape_alloc( libspectrum_tape **tape )
{
  (*tape) = (libspectrum_tape*)malloc( sizeof( libspectrum_tape ) );
  if( !(*tape) ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
			     "libspectrum_tape_alloc: out of memory" );
    return LIBSPECTRUM_ERROR_MEMORY;
  }

  (*tape)->blocks = NULL;
  libspectrum_tape_iterator_init( &((*tape)->state.current_block), *tape );
  (*tape)->state.loop_block = NULL;

  return LIBSPECTRUM_ERROR_NONE;
}
Exemplo n.º 6
0
/* Cause the next block on the tape to be active, initialise it
   and return it */
libspectrum_tape_block*
libspectrum_tape_select_next_block( libspectrum_tape *tape )
{
  libspectrum_tape_block *block;

  if( !tape->state.current_block ) return NULL;

  block = libspectrum_tape_iterator_next( &(tape->state.current_block) );

  if( !block )
    block = libspectrum_tape_iterator_init( &(tape->state.current_block), tape );

  if( libspectrum_tape_block_init( block, &(tape->state) ) )
    return NULL;

  return block;
}
Exemplo n.º 7
0
int
tape_blocks_entries(char entries[][256],int length)
{
  libspectrum_tape_block *block;
  libspectrum_tape_iterator iterator;
  int num_entries=0;

  for( block = libspectrum_tape_iterator_init( &iterator, tape );
       block;
       block = libspectrum_tape_iterator_next( &iterator ),num_entries++)
  {     
      
       char *p=entries[num_entries];
       sprintf(p,"%4d: ",num_entries);
       tape_block_details(p+6,length-6,block );    
  }
  
  return num_entries;
}
Exemplo n.º 8
0
libspectrum_error
libspectrum_tape_get_next_edge_internal( libspectrum_dword *tstates,
                                         int *flags,
                                         libspectrum_tape *tape,
                                         libspectrum_tape_block_state *it )
{
  int error;

  libspectrum_tape_block *block =
    libspectrum_tape_iterator_current( it->current_block );

  /* Has this edge ended the block? */
  int end_of_block = 0;

  /* After getting a new block, do we want to advance to the next one? */
  int no_advance = 0;

  /* Assume no special flags by default */
  *flags = 0;

  if( block ) {
    switch( block->type ) {
    case LIBSPECTRUM_TAPE_BLOCK_ROM:
      error = rom_edge( &(block->types.rom), &(it->block_state.rom), tstates,
                        &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_TURBO:
      error = turbo_edge( &(block->types.turbo), &(it->block_state.turbo), tstates,
                          &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
      error = tone_edge( &(block->types.pure_tone), &(it->block_state.pure_tone),
                         tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PULSES:
      error = pulses_edge( &(block->types.pulses), &(it->block_state.pulses),
                           tstates, &end_of_block );
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
      error = pure_data_edge( &(block->types.pure_data),
                              &(it->block_state.pure_data), tstates, &end_of_block);
      if( error ) return error;
      break;
    case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
      error = raw_data_edge( &(block->types.raw_data), &(it->block_state.raw_data),
                             tstates, &end_of_block );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
      error = generalised_data_edge( &(block->types.generalised_data),
                                     &(it->block_state.generalised_data),
                                     tstates, &end_of_block, flags );
      if( error ) return error;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
      *tstates = ( block->types.pause.length * 69888 ) / 20; end_of_block = 1;
      /* 0 ms pause => stop tape */
      if( *tstates == 0 ) { *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP; }
      break;

    case LIBSPECTRUM_TAPE_BLOCK_JUMP:
      error = jump_blocks( tape, block->types.jump.offset );
      if( error ) return error;
      *tstates = 0; end_of_block = 1; no_advance = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
      if( it->current_block->next && block->types.loop_start.count ) {
        it->loop_block = it->current_block->next;
        it->loop_count = block->types.loop_start.count;
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
      if( it->loop_block ) {
        if( --(it->loop_count) ) {
          it->current_block = it->loop_block;
          no_advance = 1;
        } else {
          it->loop_block = NULL;
        }
      }
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_STOP48:
      *tstates = 0; *flags |= LIBSPECTRUM_TAPE_FLAGS_STOP48; end_of_block = 1;
      break;

    /* For blocks which contain no Spectrum-readable data, return zero
       tstates and set end of block set so we instantly get the next block */
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_START: 
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
    case LIBSPECTRUM_TAPE_BLOCK_SELECT:
    case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
    case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
    case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
    case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
    case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
      *tstates = 0; end_of_block = 1;
      break;

    case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
      error = rle_pulse_edge( &(block->types.rle_pulse),
                              &(it->block_state.rle_pulse), tstates, &end_of_block);
      if( error ) return error;
      break;

    default:
      *tstates = 0;
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_LOGIC,
        "libspectrum_tape_get_next_edge: unknown block type 0x%02x",
        block->type
      );
      return LIBSPECTRUM_ERROR_LOGIC;
    }
  } else {
    *tstates = 0;
    end_of_block = 1;
  }

  /* If that ended the block, move onto the next block */
  if( end_of_block ) {

    *flags |= LIBSPECTRUM_TAPE_FLAGS_BLOCK;

    /* Advance to the next block, unless we've been told not to */
    if( !no_advance ) {

      libspectrum_tape_iterator_next( &(it->current_block) );

      /* If we've just hit the end of the tape, stop the tape (and
	 then `rewind' to the start) */
      if( libspectrum_tape_iterator_current( it->current_block ) == NULL ) {
	*flags |= LIBSPECTRUM_TAPE_FLAGS_STOP;
        libspectrum_tape_iterator_init( &(it->current_block), tape );
      }
    }

    /* Initialise the new block */
    error = libspectrum_tape_block_init(
                      libspectrum_tape_iterator_current( it->current_block ),
                      it );
    if( error ) return error;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Exemplo n.º 9
0
static libspectrum_dword
find_sample_rate( libspectrum_tape *tape )
{
    libspectrum_tape_iterator iterator;
    libspectrum_tape_block *block;
    libspectrum_dword sample_rate = 44100;
    int found = 0;

    /* FIXME: If tape has only one block that is a sampled type, just use it's rate
       and if it RLE, we should just zlib and write */
    for( block = libspectrum_tape_iterator_init( &iterator, tape );
            block;
            block = libspectrum_tape_iterator_next( &iterator ) )
    {
        switch( libspectrum_tape_block_type( block ) ) {

        case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
        case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
        {
            libspectrum_dword block_rate =
                3500000 / libspectrum_tape_block_bit_length( block );

            if( found ) {
                if( block_rate != sample_rate ) {
                    libspectrum_print_error(
                        LIBSPECTRUM_ERROR_WARNING,
                        "find_sample_rate: converting tape with mixed sample rates; conversion may well not work"
                    );
                }
            }
            sample_rate = block_rate;
            found = 1;
        }
        break;

        case LIBSPECTRUM_TAPE_BLOCK_ROM:
        case LIBSPECTRUM_TAPE_BLOCK_TURBO:
        case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
        case LIBSPECTRUM_TAPE_BLOCK_PULSES:
        case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
        case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
        case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
        case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
        case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
        case LIBSPECTRUM_TAPE_BLOCK_JUMP:
        case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
        case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
        case LIBSPECTRUM_TAPE_BLOCK_SELECT:
        case LIBSPECTRUM_TAPE_BLOCK_STOP48:
        case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
        case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
        case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
        case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
        case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
        case LIBSPECTRUM_TAPE_BLOCK_CONCAT:
            break;

        default:
            libspectrum_print_error(
                LIBSPECTRUM_ERROR_LOGIC,
                "libspectrum_csw_write: unknown block type 0x%02x",
                libspectrum_tape_block_type( block )
            );

        }
    }

    return sample_rate;
}
Exemplo n.º 10
0
libspectrum_error
internal_tzx_write( libspectrum_byte **buffer, size_t *length,
		    libspectrum_tape *tape )
{
  libspectrum_error error;
  libspectrum_tape_iterator iterator;
  libspectrum_tape_block *block;
  libspectrum_byte *ptr = *buffer;

  size_t signature_length = strlen( libspectrum_tzx_signature );

  /* First, write the .tzx signature and the version numbers */
  libspectrum_make_room( buffer, signature_length + 2, &ptr, length );

  memcpy( ptr, libspectrum_tzx_signature, signature_length );
  ptr += signature_length;

  *ptr++ = 1;		/* Major version number */
  *ptr++ = 20;		/* Minor version number */

  for( block = libspectrum_tape_iterator_init( &iterator, tape );
       block;
       block = libspectrum_tape_iterator_next( &iterator )       )
  {
    switch( libspectrum_tape_block_type( block ) ) {

    case LIBSPECTRUM_TAPE_BLOCK_ROM:
      tzx_write_rom( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_TURBO:
      tzx_write_turbo( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
      tzx_write_pure_tone( block, buffer, &ptr, length );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PULSES:
      tzx_write_pulses( block, buffer, &ptr, length );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
      tzx_write_data( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
      tzx_write_raw_data( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
      error = tzx_write_generalised_data( block, buffer, &ptr, length );
      if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( *buffer ); return error; }
      break;

    case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
      tzx_write_pause( block, buffer, &ptr, length );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
      tzx_write_group_start( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
      tzx_write_empty_block( buffer, &ptr, length, libspectrum_tape_block_type( block ) );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_JUMP:
      tzx_write_jump( block, buffer, &ptr, length );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
      tzx_write_loop_start( block, buffer, &ptr, length );
      break;
    case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
      tzx_write_empty_block( buffer, &ptr, length, libspectrum_tape_block_type( block ) );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_SELECT:
      tzx_write_select( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_STOP48:
      tzx_write_stop( buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
      tzx_write_comment( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
      tzx_write_message( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
      tzx_write_archive_info( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
      tzx_write_hardware( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
      tzx_write_custom( block, buffer, &ptr, length );
      break;

    case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
      error = tzx_write_rle( block, buffer, &ptr, length, tape, iterator );
      if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( *buffer ); return error; }
      break;

    default:
      libspectrum_free( *buffer );
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_LOGIC,
	"libspectrum_tzx_write: unknown block type 0x%02x",
	libspectrum_tape_block_type( block )
      );
      return LIBSPECTRUM_ERROR_LOGIC;
    }
  }

  (*length) = ptr - *buffer;

  return LIBSPECTRUM_ERROR_NONE;
}