Example #1
0
static libspectrum_error
rzx_write_signed_start( libspectrum_byte **buffer, libspectrum_byte **ptr,
			size_t *length, libspectrum_rzx_dsa_key *key,
			libspectrum_creator *creator )
{
#ifdef HAVE_GCRYPT_H
  
  libspectrum_make_room( buffer, 13, ptr, length );

  /* Block ID */
  *(*ptr)++ = LIBSPECTRUM_RZX_SIGN_START_BLOCK;

  /* Block length */
  libspectrum_write_dword( ptr, 13 );

  /* Key ID */
  if( !key || !key->y || strlen( key->y ) < 8 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID,
			     "rzx_write_signed_start: invalid key" );
    return LIBSPECTRUM_ERROR_INVALID;
  }

  libspectrum_write_dword(
    ptr, strtoul( &key->y[ strlen( key->y ) - 8 ], NULL, 16 )
  );

  /* Week code */
  if( creator ) {
    libspectrum_write_dword( ptr,
			     libspectrum_creator_competition_code( creator ) );
  } else {
    libspectrum_write_dword( ptr, 0 );
  }

#endif				/* #ifdef HAVE_GCRYPT_H */

  return LIBSPECTRUM_ERROR_NONE;
}
Example #2
0
libspectrum_error
libspectrum_rzx_rollback_to( libspectrum_rzx *rzx, libspectrum_snap **snap,
			     size_t which )
{
  GSList *previous = NULL, *list;
  rzx_block_t *block;
  size_t i;

  /* Find the nth snapshot block in the file */
  for( i = 0, list = rzx->blocks; i <= which; i++, list = list->next ) {
    list =
      g_slist_find_custom( list,
			   GINT_TO_POINTER( LIBSPECTRUM_RZX_SNAPSHOT_BLOCK ),
			   find_block );
    if( !list ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "snapshot block %lu not found in recording",
			       (unsigned long)which );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    previous = list;
  }

  if( rzx->current_input ) {
    libspectrum_error error;
    error = libspectrum_rzx_stop_input( rzx ); if( error ) return error;
  }

  /* Delete all blocks after the snapshot */
  g_slist_foreach( previous->next, block_free_wrapper, NULL );
  previous->next = NULL;

  block = previous->data;
  *snap = block->types.snap.snap;

  return LIBSPECTRUM_ERROR_NONE;
}
Example #3
0
static libspectrum_error
pure_data_edge( libspectrum_tape_pure_data_block *block,
		libspectrum_dword *tstates, int *end_of_block )
{
  int error;

  switch( block->state ) {

  case LIBSPECTRUM_TAPE_STATE_DATA1:
    /* The first edge for a bit of data */
    *tstates = block->bit_tstates;
    /* Followed by the second edge */
    block->state = LIBSPECTRUM_TAPE_STATE_DATA2;
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA2:
    /* The second edge for a bit of data */
    *tstates = block->bit_tstates;
    /* Followed by the next bit of data (or the end of data) */
    error = pure_data_next_bit( block ); if( error ) return error;
    break;

  case LIBSPECTRUM_TAPE_STATE_PAUSE:
    /* The pause at the end of the block */
    *tstates = (block->pause * 69888)/20; /* FIXME: should vary with tstates
					     per frame */
    *end_of_block = 1;
    break;

  default:
    libspectrum_print_error( "pure_data_edge: unknown state %d\n",
			     block->state );
    return LIBSPECTRUM_ERROR_LOGIC;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #4
0
/* Select the nth block on the tape */
libspectrum_error
libspectrum_tape_nth_block( libspectrum_tape *tape, int n )
{
  GSList *new_block;
  libspectrum_error error;

  new_block = g_slist_nth( tape->blocks, n );
  if( !new_block ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_tape_nth_block: tape does not have block %d", n
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  tape->state.current_block = new_block;

  error = libspectrum_tape_block_init( tape->state.current_block->data,
                                       &(tape->state) );
  if( error ) return error;

  return LIBSPECTRUM_ERROR_NONE;
}
libspectrum_error
libspectrum_tape_block_read_symbol_table(
  libspectrum_tape_generalised_data_symbol_table *table,
  const libspectrum_byte **ptr, size_t length )
{
  if( table->symbols_in_block ) {
    
    libspectrum_tape_generalised_data_symbol *symbol;
    size_t i, j;

    /* Sanity check */
    if( length < ( 2 * table->max_pulses + 1 ) * table->symbols_in_table ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "%s: not enough data in buffer", __func__ );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }


    table->symbols =
      libspectrum_new( libspectrum_tape_generalised_data_symbol,
                       table->symbols_in_table );

    for( i = 0, symbol = table->symbols;
	 i < table->symbols_in_table;
	 i++, symbol++ ) {
      symbol->edge_type = **ptr; (*ptr)++;
      symbol->lengths = libspectrum_new( libspectrum_word, table->max_pulses );
      for( j = 0; j < table->max_pulses; j++ ) {
	symbol->lengths[ j ] = (*ptr)[0] + (*ptr)[1] * 0x100;
	(*ptr) += 2;
      }
    }

  }
  
  return LIBSPECTRUM_ERROR_NONE;
}
Example #6
0
static libspectrum_error
write_48k_sna( libspectrum_byte **buffer, libspectrum_byte **ptr,
	       size_t *length, libspectrum_snap *snap )
{
  libspectrum_error error;
  libspectrum_byte *stack, *sp;

  /* Must have somewhere in RAM to store PC */
  if( libspectrum_snap_sp( snap ) < 0x4002 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_INVALID,
			     "SP is too low (0x%04x) to stack PC",
			     libspectrum_snap_sp( snap ) );
    return LIBSPECTRUM_ERROR_INVALID;
  }

  libspectrum_make_room( buffer, 0xc000, ptr, length );

  error = write_page( &( (*ptr)[ 0x0000 ] ), snap, 5 );
  if( error ) return error;
  error = write_page( &( (*ptr)[ 0x4000 ] ), snap, 2 );
  if( error ) return error;
  error = write_page( &( (*ptr)[ 0x8000 ] ), snap, 0 );
  if( error ) return error;

  /* Place PC on the stack */
  stack = &( (*ptr)[ libspectrum_snap_sp( snap ) - 0x4000 - 2 ] );
  libspectrum_write_word( &stack, libspectrum_snap_pc( snap ) );

  *ptr += 0xc000;

  /* Store the new value of SP */
  sp = *buffer + SNA_OFFSET_SP;
  libspectrum_write_word( &sp, libspectrum_snap_sp( snap ) - 2 );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #7
0
static libspectrum_error
get_signature( gcry_mpi_t *r, gcry_mpi_t *s, libspectrum_byte *data,
	       size_t data_length, libspectrum_rzx_dsa_key *key )
{
  libspectrum_error error;
  gcry_error_t gcrypt_error;
  gcry_sexp_t hash, s_key, s_signature;

  error = get_hash( &hash, data, data_length ); if( error ) return error;

  error = create_key( &s_key, key, 1 );
  if( error ) { gcry_sexp_release( hash ); return error; }

  gcrypt_error = gcry_pk_sign( &s_signature, hash, s_key );
  if( gcrypt_error ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "get_signature: error signing data: %s",
			     gcry_strerror( gcrypt_error ) );
    gcry_sexp_release( s_key ); gcry_sexp_release( hash );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  gcry_sexp_release( s_key ); gcry_sexp_release( hash );

  error = get_mpi( r, s_signature, "r" );
  if( error ) { gcry_sexp_release( s_signature ); return error; }
  error = get_mpi( s, s_signature, "s" );
  if( error ) {
    gcry_sexp_release( s_signature ); gcry_mpi_release( *r );
    return error;
  }

  gcry_sexp_release( s_signature );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #8
0
libspectrum_error
libspectrum_bzip2_inflate( const libspectrum_byte *bzptr, size_t bzlength,
			   libspectrum_byte **outptr, size_t *outlength )
{
  int error;
  unsigned int length2;

  /* Known length, so we can use the easy method */
  if( *outlength ) {

    *outptr = libspectrum_new( libspectrum_byte, *outlength );
    length2 = *outlength;

    error = BZ2_bzBuffToBuffDecompress( (char*)*outptr, &length2, (char*)bzptr,
					bzlength, 0, 0 );
    if( error != BZ_OK ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			       "error decompressing bzip data" );
      return LIBSPECTRUM_ERROR_LOGIC;
    }

    *outlength = length2;

    return LIBSPECTRUM_ERROR_NONE;

  } else {			/* Unknown length, have to stream */

    bz_stream stream;
    libspectrum_byte *ptr; size_t length;

    length = bzlength;

    *outptr = libspectrum_new( libspectrum_byte, length );

    /* Use standard memory allocation/free routines */
    stream.bzalloc = NULL; stream.bzfree = NULL; stream.opaque = NULL;

    error = BZ2_bzDecompressInit( &stream, 0, 0 );
    if( error != BZ_OK ) {
      switch( error ) {

      case BZ_MEM_ERROR:
	libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
				 "out of memory at %s:%d",
				 __FILE__, __LINE__ );
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_MEMORY;

      default:
	libspectrum_print_error(
          LIBSPECTRUM_ERROR_LOGIC,
	  "bzip2_inflate: serious error from BZ2_bzDecompressInit: %d", error
	);
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_LOGIC;

      }
    }

    stream.next_in = (char*)bzptr; stream.avail_in = bzlength;
    stream.next_out = (char*)*outptr; stream.avail_out = bzlength;

    while( 1 ) {

      error = BZ2_bzDecompress( &stream );

      switch( error ) {

      case BZ_STREAM_END:	/* Finished decompression */
	error = BZ2_bzDecompressEnd( &stream );
	if( error ) {
	  libspectrum_print_error(
	    LIBSPECTRUM_ERROR_LOGIC,
	    "bzip2_inflate: error from BZ2_bzDecompressEnd: %d", error
	  );
	  libspectrum_free( *outptr );
	  return LIBSPECTRUM_ERROR_LOGIC;
	}
	*outlength = stream.total_out_lo32;
	*outptr = libspectrum_renew( libspectrum_byte, *outptr, *outlength );
	return LIBSPECTRUM_ERROR_NONE;

      case BZ_OK:		/* More output space required */

	length += bzlength;
	ptr = libspectrum_renew( libspectrum_byte, *outptr, length );
	*outptr = ptr;
	stream.next_out = (char*)*outptr + stream.total_out_lo32;
	stream.avail_out += bzlength;
	break;

      default:
	libspectrum_print_error(
	  LIBSPECTRUM_ERROR_LOGIC,
	  "bzip2_inflate: serious error from BZ2_bzDecompress: %d", error
	);
	BZ2_bzDecompressEnd( &stream );
	libspectrum_free( *outptr );
	return LIBSPECTRUM_ERROR_LOGIC;
      }
    }				/* Matches while( 1 ) { ... } */

  }				/* Matches if( *outlength ) { ... } */
}
Example #9
0
static libspectrum_error
rzx_read_sign_end( libspectrum_rzx *rzx, const libspectrum_byte **ptr,
		   const libspectrum_byte *end )
{
  rzx_block_t *block;
  signature_block_t *signature;
  size_t length;

  /* Check we've got enough data for the length */
  if( end - (*ptr) < 4 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_sign_end: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* Get the length; the -5 is because we've read the block ID and the length
     bytes */
  length = libspectrum_read_dword( ptr ) - 5;

  /* Check there's still enough data */
  if( end - (*ptr) < (ptrdiff_t)length ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_sign_end: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  block_alloc( &block, LIBSPECTRUM_RZX_SIGN_END_BLOCK );

  signature = &( block->types.signature );

  /* - 5 as we don't sign the block ID and length of this block */
  signature->length = ( *ptr - rzx->signed_start ) - 5;

#ifdef HAVE_GCRYPT_H
  { 
    gcry_error_t error; size_t mpi_length;

    error = gcry_mpi_scan( &signature->r, GCRYMPI_FMT_PGP, *ptr, length,
			   &mpi_length );
    if( error ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "error reading 'r': %s",
			       gcry_strerror( error ) );
      libspectrum_free( block );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }
    (*ptr) += mpi_length; length -= mpi_length;

    error = gcry_mpi_scan( &signature->s, GCRYMPI_FMT_PGP, *ptr, length,
			   &mpi_length );
    if( error ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "error reading 's': %s",
			       gcry_strerror( error ) );
      gcry_mpi_release( signature->r );
      libspectrum_free( block );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }
    (*ptr) += mpi_length; length -= mpi_length;

  }
#endif				/* #ifdef HAVE_GCRYPT_H */

  (*ptr) += length;

  rzx->blocks = g_slist_append( rzx->blocks, block );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #10
0
libspectrum_error
libspectrum_sna_write( libspectrum_byte **buffer, size_t *length,
		       int *out_flags, libspectrum_snap *snap,
		       int in_flags GCC_UNUSED )
{
  libspectrum_error error = LIBSPECTRUM_ERROR_NONE;
  libspectrum_byte *ptr;

  /* Minor info loss already due to things like tstate count, halted state,
     etc which are not stored in .sna format */
  *out_flags = LIBSPECTRUM_FLAG_SNAPSHOT_MINOR_INFO_LOSS;

  /* We don't store +D info at all */
  if( libspectrum_snap_plusd_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't store Beta info at all */
  if( libspectrum_snap_beta_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't store Opus info at all */
  if( libspectrum_snap_opus_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save IDE interface info at all */
  if( libspectrum_snap_zxatasp_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
  if( libspectrum_snap_zxcf_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
  if( libspectrum_snap_simpleide_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
  if( libspectrum_snap_divide_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the Interface 2 ROM at all */
  if( libspectrum_snap_interface2_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the Timex Dock at all */
  if( libspectrum_snap_dock_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save custom ROMs at all */
  if( libspectrum_snap_custom_rom( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save AY interfaces  at all */
  if( libspectrum_snap_fuller_box_active( snap ) ||
      libspectrum_snap_melodik_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the Specdrum state at all */
  if( libspectrum_snap_specdrum_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the Spectranet state at all */
  if( libspectrum_snap_spectranet_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the uSource state at all */
  if( libspectrum_snap_usource_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the DISCiPLE state at all */
  if( libspectrum_snap_disciple_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  /* We don't save the Didaktik80 state at all */
  if( libspectrum_snap_didaktik80_active( snap ) )
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;

  ptr = *buffer;

  write_header( buffer, &ptr, length, snap );

  switch( libspectrum_snap_machine( snap ) ) {

  case LIBSPECTRUM_MACHINE_48_NTSC:
  case LIBSPECTRUM_MACHINE_TC2048:
  case LIBSPECTRUM_MACHINE_TC2068:
  case LIBSPECTRUM_MACHINE_TS2068:
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
    /* Fall through */
  case LIBSPECTRUM_MACHINE_16:
  case LIBSPECTRUM_MACHINE_48:
    error = write_48k_sna( buffer, &ptr, length, snap );
    break;
    
  case LIBSPECTRUM_MACHINE_128:
  case LIBSPECTRUM_MACHINE_128E:
  case LIBSPECTRUM_MACHINE_PENT512:
  case LIBSPECTRUM_MACHINE_PENT1024:
  case LIBSPECTRUM_MACHINE_PLUS2:
  case LIBSPECTRUM_MACHINE_PLUS2A:
  case LIBSPECTRUM_MACHINE_PLUS3:
  case LIBSPECTRUM_MACHINE_PLUS3E:
  case LIBSPECTRUM_MACHINE_SCORP:
  case LIBSPECTRUM_MACHINE_SE:
    *out_flags |= LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS;
    /* Fall through */
  case LIBSPECTRUM_MACHINE_PENT:
    error = write_128k_sna( buffer, &ptr, length, snap );
    break;

  case LIBSPECTRUM_MACHINE_UNKNOWN:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "Emulated machine type is set to 'unknown'!" );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  if( error ) return error;

  /* Set length to be actual length, not allocated length */
  *length = ptr - *buffer;

  return LIBSPECTRUM_ERROR_NONE;
}
Example #11
0
libspectrum_error
libspectrum_rzx_store_frame( libspectrum_rzx *rzx, size_t instructions,
			     size_t count, libspectrum_byte *in_bytes )
{
  input_block_t *input;
  libspectrum_rzx_frame_t *frame;
  libspectrum_error error;

  input = rzx->current_input;

  /* Check we've got an IRB to record to */
  if( !input ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_INVALID,
      "libspectrum_rzx_store_frame called with no active input block"
    );
    return LIBSPECTRUM_ERROR_INVALID;
  }

  /* Get more space if we need it */
  if( input->allocated == input->count ) {
    error = input_block_resize( input, input->count + 1 );
    if( error ) return error;
  }

  frame = &input->frames[ input->count ];

  frame->instructions = instructions;

  /* Check for repeated frames */
  if( input->count != 0 && count != 0 &&
      count == input->frames[ input->non_repeat ].count &&
      !memcmp( in_bytes, input->frames[ input->non_repeat ].in_bytes,
	       count )
    ) {
	
    frame->repeat_last = 1;
    frame->count = 0;
    frame->in_bytes = NULL;

  } else {

    frame->repeat_last = 0;
    frame->count = count;

    /* Note this as the last non-repeated frame */
    input->non_repeat = input->count;

    if( count ) {

      frame->in_bytes = libspectrum_new( libspectrum_byte, count );

      memcpy( frame->in_bytes, in_bytes,
	      count * sizeof( *( frame->in_bytes ) ) );

    } else {

      frame->in_bytes = NULL;

    }
  }

  /* Move along to the next frame */
  input->count++;

  return 0;
}
Example #12
0
libspectrum_error
libspectrum_rzx_read( libspectrum_rzx *rzx, const libspectrum_byte *buffer,
		      size_t length )
{
  libspectrum_error error;
  const libspectrum_byte *ptr, *end;
  int uncompressed;
  libspectrum_byte *new_buffer;
  libspectrum_id_t raw_type;
  libspectrum_class_t class;

  /* Find out if this file needs decompression */
  uncompressed = 0; new_buffer = NULL;

  error = libspectrum_identify_file_raw( &raw_type, NULL, buffer, length );
  if( error ) return error;

  error = libspectrum_identify_class( &class, raw_type );
  if( error ) return error;

  if( class == LIBSPECTRUM_CLASS_COMPRESSED ) {

    size_t new_length;

    error = libspectrum_uncompress_file( &new_buffer, &new_length, NULL,
					 raw_type, buffer, length, NULL );
    buffer = new_buffer; length = new_length;
    uncompressed = 1;
  }

  ptr = buffer; end = buffer + length;

  error = rzx_read_header( &ptr, end );
  if( error != LIBSPECTRUM_ERROR_NONE ) { libspectrum_free( new_buffer ); return error; }

  rzx->signed_start = ptr;

  while( ptr < end ) {

    libspectrum_byte id;

    id = *ptr++;

    switch( id ) {

    case LIBSPECTRUM_RZX_CREATOR_BLOCK:
      error = rzx_read_creator( &ptr, end );
      if( error != LIBSPECTRUM_ERROR_NONE ) {
	libspectrum_free( new_buffer );
	return error;
      }
      break;
      
    case LIBSPECTRUM_RZX_SNAPSHOT_BLOCK:
      error = rzx_read_snapshot( rzx, &ptr, end );
      if( error != LIBSPECTRUM_ERROR_NONE ) {
	libspectrum_free( new_buffer );
	return error;
      }
      break;

    case LIBSPECTRUM_RZX_INPUT_BLOCK:
      error = rzx_read_input( rzx, &ptr, end );
      if( error != LIBSPECTRUM_ERROR_NONE ) {
	libspectrum_free( new_buffer );
	return error;
      }
      break;

    case LIBSPECTRUM_RZX_SIGN_START_BLOCK:
      error = rzx_read_sign_start( rzx, &ptr, end );
      if( error != LIBSPECTRUM_ERROR_NONE ) {
	libspectrum_free( new_buffer );
	return error;
      }
      break;

    case LIBSPECTRUM_RZX_SIGN_END_BLOCK:
      error = rzx_read_sign_end( rzx, &ptr, end );
      if( error != LIBSPECTRUM_ERROR_NONE ) {
	libspectrum_free( new_buffer );
	return error;
      }
      break;

    default:
      libspectrum_print_error(
	LIBSPECTRUM_ERROR_UNKNOWN,
        "libspectrum_rzx_read: unknown RZX block ID 0x%02x", id
      );
      libspectrum_free( new_buffer );
      return LIBSPECTRUM_ERROR_UNKNOWN;
    }
  }

  libspectrum_free( new_buffer );
  return LIBSPECTRUM_ERROR_NONE;
}
Example #13
0
/* Read in a tape file, optionally guessing what sort of file it is */
libspectrum_error
libspectrum_tape_read( libspectrum_tape *tape, const libspectrum_byte *buffer,
		       size_t length, libspectrum_id_t type,
		       const char *filename )
{
  libspectrum_id_t raw_type;
  libspectrum_class_t class;
  libspectrum_byte *new_buffer;
  libspectrum_error error;
  int uncompressed;

  /* If we don't know what sort of file this is, make a best guess */
  if( type == LIBSPECTRUM_ID_UNKNOWN ) {
    error = libspectrum_identify_file( &type, filename, buffer, length );
    if( error ) return error;

    /* If we still can't identify it, give up */
    if( type == LIBSPECTRUM_ID_UNKNOWN ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_UNKNOWN,
	"libspectrum_tape_read: couldn't identify file"
      );
      return LIBSPECTRUM_ERROR_UNKNOWN;
    }
  }

  /* Find out if this file needs decompression */
  uncompressed = 0; new_buffer = NULL;

  error = libspectrum_identify_file_raw( &raw_type, filename, buffer, length );
  if( error ) return error;

  error = libspectrum_identify_class( &class, raw_type );
  if( error ) return error;

  if( class == LIBSPECTRUM_CLASS_COMPRESSED ) {

    size_t new_length;

    error = libspectrum_uncompress_file( &new_buffer, &new_length, NULL,
					 raw_type, buffer, length, NULL );
    buffer = new_buffer; length = new_length;
    uncompressed = 1;
  }

  switch( type ) {

  case LIBSPECTRUM_ID_TAPE_TAP:
  case LIBSPECTRUM_ID_TAPE_SPC:
  case LIBSPECTRUM_ID_TAPE_STA:
  case LIBSPECTRUM_ID_TAPE_LTP:
    error = internal_tap_read( tape, buffer, length, type ); break;

  case LIBSPECTRUM_ID_TAPE_TZX:
    error = internal_tzx_read( tape, buffer, length ); break;
/*
  case LIBSPECTRUM_ID_TAPE_WARAJEVO:
    error = internal_warajevo_read( tape, buffer, length ); break;

  case LIBSPECTRUM_ID_TAPE_Z80EM:
    error = libspectrum_z80em_read( tape, buffer, length ); break;

  case LIBSPECTRUM_ID_TAPE_CSW:
    error = libspectrum_csw_read( tape, buffer, length ); break;
  */

  case LIBSPECTRUM_ID_TAPE_WAV:
#ifdef HAVE_LIB_AUDIOFILE
    error = libspectrum_wav_read( tape, filename ); break;
#else     /* #ifdef HAVE_LIB_AUDIOFILE */
    error = LIBSPECTRUM_ERROR_LOGIC;
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_tape_read: format not supported without libaudiofile"
    );
    break;
#endif    /* #ifdef HAVE_LIB_AUDIOFILE */

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "libspectrum_tape_read: not a tape file" );
    free( new_buffer );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  free( new_buffer );
  return error;
}
Example #14
0
static libspectrum_error
rzx_read_input( libspectrum_rzx *rzx,
		const libspectrum_byte **ptr, const libspectrum_byte *end )
{
  size_t blocklength;
  libspectrum_dword flags; int compressed;
  libspectrum_error error;
  rzx_block_t *rzx_block;
  input_block_t *block;

  /* Check we've got enough data for the block */
  if( end - (*ptr) < 18 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_input: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  block_alloc( &rzx_block, LIBSPECTRUM_RZX_INPUT_BLOCK );

  block = &( rzx_block->types.input );

  /* Get the length and number of frames */
  blocklength = libspectrum_read_dword( ptr );
  block->count = libspectrum_read_dword( ptr );

  /* Frame size is undefined, so just skip it */
  (*ptr)++;

  /* Allocate memory for the frames */
  block->frames = libspectrum_malloc( block->count * sizeof( *block->frames ) );
  block->allocated = block->count;

  /* Fetch the T-state counter and the flags */
  block->tstates = libspectrum_read_dword( ptr );

  flags = libspectrum_read_dword( ptr );
  compressed = flags & 0x02;

  if( compressed ) {

#ifdef HAVE_ZLIB_H

    libspectrum_byte *data; const libspectrum_byte *data_ptr;
    size_t data_length = 0;

    /* Discount the block intro */
    blocklength -= 18;

    /* Check that we've got enough compressed data */
    if( end - (*ptr) < (ptrdiff_t)blocklength ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			       "rzx_read_input: not enough data in buffer" );
      libspectrum_free( rzx_block );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    error = libspectrum_zlib_inflate( *ptr, blocklength, &data, &data_length );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      block_free( rzx_block );
      return error;
    }

    *ptr += blocklength;

    data_ptr = data;

    error = rzx_read_frames( block, &data_ptr, data + data_length );
    if( error ) { libspectrum_free( rzx_block ); libspectrum_free( data ); return error; }

    libspectrum_free( data );

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "rzx_read_input: zlib needed for decompression" );
    libspectrum_free( rzx_block );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

  } else {			/* Data not compressed */

    error = rzx_read_frames( block, ptr, end );
    if( error ) { libspectrum_free( rzx_block ); return error; }
  }

  rzx->blocks = g_slist_append( rzx->blocks, rzx_block );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #15
0
libspectrum_error
libspectrum_rzx_store_frame( libspectrum_rzx *rzx, size_t instructions,
			     size_t count, libspectrum_byte *in_bytes )
{
  input_block_t *input;
  libspectrum_rzx_frame_t *frame;

  input = rzx->current_input;

  /* Check we've got an IRB to record to */
  if( !input ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_INVALID,
      "libspectrum_rzx_store_frame called with no active input block"
    );
    return LIBSPECTRUM_ERROR_INVALID;
  }

  /* Get more space if we need it; allocate twice as much as we currently
     have, with a minimum of 50 */
  if( input->count == input->allocated ) {

    libspectrum_rzx_frame_t *ptr; size_t new_allocated;

    new_allocated = input->allocated >= 25 ? 2 * input->allocated : 50;

    ptr = realloc( input->frames, new_allocated * sizeof( *ptr ) );
    if( !ptr ) return LIBSPECTRUM_ERROR_MEMORY;

    input->frames = ptr;
    input->allocated = new_allocated;
  }

  frame = &input->frames[ input->count ];

  frame->instructions = instructions;

  /* Check for repeated frames */
  if( input->count != 0 && count != 0 &&
      count == input->frames[ input->non_repeat ].count &&
      !memcmp( in_bytes, input->frames[ input->non_repeat ].in_bytes,
	       count )
    ) {
	
    frame->repeat_last = 1;

  } else {

    frame->repeat_last = 0;
    frame->count = count;

    /* Note this as the last non-repeated frame */
    input->non_repeat = input->count;

    if( count ) {

      frame->in_bytes = libspectrum_malloc( count * sizeof( *( frame->in_bytes ) ) );

      memcpy( frame->in_bytes, in_bytes,
	      count * sizeof( *( frame->in_bytes ) ) );

    } else {

      frame->in_bytes = NULL;

    }
  }

  /* Move along to the next frame */
  input->count++;

  return 0;
}
Example #16
0
/* Identify a file without attempting to decompress it */
libspectrum_error
libspectrum_identify_file_raw( libspectrum_id_t *type, const char *filename,
			       const unsigned char *buffer, size_t length )
{
  struct type {

    int type;

    const char *extension; int extension_score;

    const char *signature; size_t offset, length; int sig_score;
  };

  struct type *ptr,
    types[] = {
      
      { LIBSPECTRUM_ID_RECORDING_RZX, "rzx", 3, "RZX!",		    0, 4, 4 },

      { LIBSPECTRUM_ID_SNAPSHOT_SNA,  "sna", 3, NULL,		    0, 0, 0 },
      /* Peter McGavin's Spectrum Emulator on the Amiga used .snapshot for sna
         snaps */
      { LIBSPECTRUM_ID_SNAPSHOT_SNA,  "snapshot", 3, NULL,	    0, 0, 0 },
      { LIBSPECTRUM_ID_SNAPSHOT_SNP,  "snp", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_SNAPSHOT_SP,   "sp",  3, "\x53\x50\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_SNAPSHOT_SZX,  "szx", 3, "ZXST",		    0, 4, 4 },
      { LIBSPECTRUM_ID_SNAPSHOT_Z80,  "z80", 3, "\0\0",		    6, 2, 1 },
      /* .slt files also dealt with by the .z80 loading code */
      { LIBSPECTRUM_ID_SNAPSHOT_Z80,  "slt", 3, "\0\0",		    6, 2, 1 },
      { LIBSPECTRUM_ID_SNAPSHOT_ZXS,  "zxs", 3, "SNAP",		    8, 4, 4 },
      { LIBSPECTRUM_ID_SNAPSHOT_PLUSD,"mgtsnp", 3, NULL,	    0, 0, 0 },

      { LIBSPECTRUM_ID_CARTRIDGE_DCK, "dck", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_CARTRIDGE_IF2, "rom", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_MICRODRIVE_MDR, "mdr", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_TAPE_TAP,      "tap", 3, "\x13\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_SPC,      "spc", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_STA,      "sta", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_LTP,      "ltp", 3, "\x11\0\0",	    0, 3, 1 },
      { LIBSPECTRUM_ID_TAPE_TZX,      "tzx", 3, "ZXTape!",	    0, 7, 4 },
      { LIBSPECTRUM_ID_TAPE_WARAJEVO, "tap", 2, "\xff\xff\xff\xff", 8, 4, 2 },

      { LIBSPECTRUM_ID_DISK_DSK,      "dsk", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_DISK_SCL,      "scl", 3, "SINCLAIR",         0, 8, 4 },
      { LIBSPECTRUM_ID_DISK_TRD,      "trd", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_HARDDISK_HDF,  "hdf", 3, "RS-IDE\x1a",	    0, 7, 4 },

      { LIBSPECTRUM_ID_COMPRESSED_BZ2,"bz2", 3, "BZh",		    0, 3, 4 },
      { LIBSPECTRUM_ID_COMPRESSED_GZ, "gz",  3, "\x1f\x8b",	    0, 2, 4 },

      { LIBSPECTRUM_ID_TAPE_Z80EM,    "raw", 1, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0Raw tape sample",  0, 64, 0 },
      { LIBSPECTRUM_ID_TAPE_CSW,      "csw", 2, "Compressed Square Wave\x1a",  0, 23, 4 },

      { LIBSPECTRUM_ID_TAPE_WAV,      "wav", 3, NULL,		    0, 0, 0 },

      { LIBSPECTRUM_ID_DISK_MGT,      "mgt", 3, NULL,		    0, 0, 0 },
      { LIBSPECTRUM_ID_DISK_IMG,      "img", 3, NULL,		    0, 0, 0 },

      { -1, NULL, 0, NULL, 0, 0, 0 }, /* End marker */

    };

  const char *extension = NULL;
  int score, best_score, best_guess, duplicate_best;

  /* Get the filename extension, if it exists */
  if( filename ) {
    extension = strrchr( filename, '.' ); if( extension ) extension++;
  }

  best_guess = LIBSPECTRUM_ID_UNKNOWN; best_score = 0; duplicate_best = 0;

  /* Compare against known extensions and signatures */
  for( ptr = types; ptr->type != -1; ptr++ ) {

    score = 0;

    if( extension && ptr->extension &&
	!strcasecmp( extension, ptr->extension ) )
      score += ptr->extension_score;

    if( ptr->signature && length >= ptr->offset + ptr->length &&
	!memcmp( &buffer[ ptr->offset ], ptr->signature, ptr->length ) )
      score += ptr->sig_score;

    if( score > best_score ) {
      best_guess = ptr->type; best_score = score; duplicate_best = 0;
    } else if( score == best_score && ptr->type != best_guess ) {
      duplicate_best = 1;
    }
  }

#if defined AMIGA || defined __MORPHOS__
  /* Compressed file check through xfdmaster.library */

  /* this prevents most good matches and gz/bz2 from being run through xfd (xfd
     supports gz, but we want to use the internal code) */
  if( best_score <= 3 ) {
#ifndef __MORPHOS__
    struct ExecIFace *IExec =
      (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
#endif				/* #ifndef __MORPHOS__ */
    struct xfdBufferInfo *xfdobj;

#ifndef __MORPHOS__
    if( xfdMasterBase = IExec->OpenLibrary("xfdmaster.library",38 ) ) {
      if( IxfdMaster =
         (struct xfdMasterIFace *)IExec->GetInterface(xfdMasterBase,"main",1,NULL)){
        if( xfdobj = (struct xfdBufferInfo *)IxfdMaster->xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#else				/* #ifndef __MORPHOS__ */
    if( xfdMasterBase = OpenLibrary("xfdmaster.library",38 ) ) {
        if( xfdobj = (struct xfdBufferInfo *)xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#endif				/* #ifndef __MORPHOS__ */
          xfdobj->xfdbi_SourceBuffer = buffer;
          xfdobj->xfdbi_SourceBufLen = length;
          xfdobj->xfdbi_Flags = XFDFB_RECOGTARGETLEN | XFDFB_RECOGEXTERN;

#ifndef __MORPHOS__
          if( IxfdMaster->xfdRecogBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
          if( xfdRecogBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
            best_guess = LIBSPECTRUM_ID_COMPRESSED_XFD;
            duplicate_best=0;
          }
#ifndef __MORPHOS__
          IxfdMaster->xfdFreeObject( (APTR)xfdobj );
#else				/* #ifndef __MORPHOS__ */
          xfdFreeObject( (APTR)xfdobj );
#endif				/* #ifndef __MORPHOS__ */
        }
#ifndef __MORPHOS__
        IExec->DropInterface( (struct Interface *)IxfdMaster );
      }
      IExec->CloseLibrary( xfdMasterBase );
#else				/* #ifndef __MORPHOS__ */
      CloseLibrary( xfdMasterBase );
#endif				/* #ifndef __MORPHOS__ */
    }
  }
#endif /* #ifdef AMIGA */

  /* If two things were equally good, we can't identify this. Otherwise,
     return our best guess */
  if( duplicate_best ) {
    *type = LIBSPECTRUM_ID_UNKNOWN;
  } else {
    *type = best_guess;
  }

  return LIBSPECTRUM_ERROR_NONE;
}

/* What generic 'class' of file is this file */
libspectrum_error
libspectrum_identify_class( libspectrum_class_t *libspectrum_class,
			    libspectrum_id_t type )
{
  switch( type ) {

  case LIBSPECTRUM_ID_UNKNOWN:
    *libspectrum_class = LIBSPECTRUM_CLASS_UNKNOWN; return 0;
  
  case LIBSPECTRUM_ID_CARTRIDGE_DCK:
    *libspectrum_class = LIBSPECTRUM_CLASS_CARTRIDGE_TIMEX; return 0;

  case LIBSPECTRUM_ID_COMPRESSED_BZ2:
  case LIBSPECTRUM_ID_COMPRESSED_GZ:
  case LIBSPECTRUM_ID_COMPRESSED_XFD:
    *libspectrum_class = LIBSPECTRUM_CLASS_COMPRESSED; return 0;

  case LIBSPECTRUM_ID_DISK_DSK:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_PLUS3; return 0;

  case LIBSPECTRUM_ID_DISK_IMG:
  case LIBSPECTRUM_ID_DISK_MGT:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_PLUSD; return 0;

  case LIBSPECTRUM_ID_DISK_SCL:
  case LIBSPECTRUM_ID_DISK_TRD:
    *libspectrum_class = LIBSPECTRUM_CLASS_DISK_TRDOS; return 0;

  case LIBSPECTRUM_ID_HARDDISK_HDF:
    *libspectrum_class = LIBSPECTRUM_CLASS_HARDDISK; return 0;

  case LIBSPECTRUM_ID_MICRODRIVE_MDR:
    *libspectrum_class = LIBSPECTRUM_CLASS_MICRODRIVE; return 0;

  case LIBSPECTRUM_ID_RECORDING_RZX:
    *libspectrum_class = LIBSPECTRUM_CLASS_RECORDING; return 0;

  case LIBSPECTRUM_ID_SNAPSHOT_PLUSD:
  case LIBSPECTRUM_ID_SNAPSHOT_SNA:
  case LIBSPECTRUM_ID_SNAPSHOT_SNP:
  case LIBSPECTRUM_ID_SNAPSHOT_SP:
  case LIBSPECTRUM_ID_SNAPSHOT_SZX:
  case LIBSPECTRUM_ID_SNAPSHOT_Z80:
  case LIBSPECTRUM_ID_SNAPSHOT_ZXS:
    *libspectrum_class = LIBSPECTRUM_CLASS_SNAPSHOT; return 0;

  case LIBSPECTRUM_ID_TAPE_TAP:
  case LIBSPECTRUM_ID_TAPE_SPC:
  case LIBSPECTRUM_ID_TAPE_STA:
  case LIBSPECTRUM_ID_TAPE_LTP:
  case LIBSPECTRUM_ID_TAPE_TZX:
  case LIBSPECTRUM_ID_TAPE_WARAJEVO:
  case LIBSPECTRUM_ID_TAPE_Z80EM:
  case LIBSPECTRUM_ID_TAPE_CSW:
  case LIBSPECTRUM_ID_TAPE_WAV:
    *libspectrum_class = LIBSPECTRUM_CLASS_TAPE; return 0;

  case LIBSPECTRUM_ID_CARTRIDGE_IF2:
    *libspectrum_class = LIBSPECTRUM_CLASS_CARTRIDGE_IF2; return 0;

  }

  libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			   "Unknown file type %d", type );
  return LIBSPECTRUM_ERROR_UNKNOWN;
}

libspectrum_error
libspectrum_uncompress_file( unsigned char **new_buffer, size_t *new_length,
			     char **new_filename, libspectrum_id_t type,
			     const unsigned char *old_buffer,
			     size_t old_length, const char *old_filename )
{
  libspectrum_class_t class;
  libspectrum_error error;

  error = libspectrum_identify_class( &class, type );
  if( error ) return error;

  if( class != LIBSPECTRUM_CLASS_COMPRESSED ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "file type %d is not a compressed type", type );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  if( new_filename && old_filename ) {
    *new_filename = strdup( old_filename );
    if( !*new_filename ) {
      libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
			       "out of memory at %s:%d", __FILE__, __LINE__ );
      return LIBSPECTRUM_ERROR_MEMORY;
    }
  }

  /* Tells the inflation routines to allocate memory for us */
  *new_length = 0;
  
  switch( type ) {

  case LIBSPECTRUM_ID_COMPRESSED_BZ2:

#ifdef HAVE_LIBBZ2

    if( new_filename && *new_filename ) {
      if( strlen( *new_filename ) >= 4 &&
	  !strcasecmp( &(*new_filename)[ strlen( *new_filename ) - 4 ],
		       ".bz2" ) )
	(*new_filename)[ strlen( *new_filename ) - 4 ] = '\0';
    }

    error = libspectrum_bzip2_inflate( old_buffer, old_length,
				       new_buffer, new_length );
    if( error ) {
      if( new_filename ) free( *new_filename );
      return error;
    }

#else				/* #ifdef HAVE_LIBBZ2 */

    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "libbz2 not available to decompress bzipped file"
    );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_LIBBZ2 */

    break;

  case LIBSPECTRUM_ID_COMPRESSED_GZ:

#ifdef HAVE_ZLIB_H

    if( new_filename && *new_filename ) {
      if( strlen( *new_filename ) >= 3 &&
	  !strcasecmp( &(*new_filename)[ strlen( *new_filename ) - 3 ],
		       ".gz" ) )
	(*new_filename)[ strlen( *new_filename ) - 3 ] = '\0';
    }
      
    error = libspectrum_gzip_inflate( old_buffer, old_length,
				      new_buffer, new_length );
    if( error ) {
      if( new_filename ) free( *new_filename );
      return error;
    }

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "zlib not available to decompress gzipped file" );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

    break;

#if defined AMIGA || defined __MORPHOS__
  case LIBSPECTRUM_ID_COMPRESSED_XFD:
    {
#ifndef __MORPHOS__
      struct ExecIFace *IExec =
        (struct ExecIFace *)(*(struct ExecBase **)4)->MainInterface;
#endif				/* #ifndef __MORPHOS__ */
      struct xfdBufferInfo *xfdobj;

#ifndef __MORPHOS__
      if( xfdMasterBase = IExec->OpenLibrary( "xfdmaster.library", 38 ) ) {
        if( IxfdMaster =
            (struct xfdMasterIFace *)IExec->GetInterface(xfdMasterBase,"main",1,NULL)) {
          if( xfdobj =
              (struct xfdBufferInfo *)IxfdMaster->xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#else				/* #ifndef __MORPHOS__ */
      if( xfdMasterBase = OpenLibrary( "xfdmaster.library", 38 ) ) {
          if( xfdobj = (struct xfdBufferInfo *)xfdAllocObject(XFDOBJ_BUFFERINFO) ) {
#endif				/* #ifndef __MORPHOS__ */
            xfdobj->xfdbi_SourceBufLen = old_length;
            xfdobj->xfdbi_SourceBuffer = old_buffer;
            xfdobj->xfdbi_Flags = XFDFB_RECOGEXTERN | XFDFB_RECOGTARGETLEN;
            xfdobj->xfdbi_PackerFlags = XFDPFB_RECOGLEN;
#ifndef __MORPHOS__
            if( IxfdMaster->xfdRecogBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
            if( xfdRecogBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
              xfdobj->xfdbi_TargetBufMemType = MEMF_ANY;
#ifndef __MORPHOS__
              if( IxfdMaster->xfdDecrunchBuffer( xfdobj ) ) {
#else				/* #ifndef __MORPHOS__ */
              if( xfdDecrunchBuffer( xfdobj ) ) {
#endif				/* #ifndef __MORPHOS__ */
                *new_buffer = malloc( xfdobj->xfdbi_TargetBufSaveLen );
                *new_length = xfdobj->xfdbi_TargetBufSaveLen;
                memcpy( *new_buffer, xfdobj->xfdbi_TargetBuffer, *new_length );
#ifndef __MORPHOS__
                IExec->FreeMem( xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen );
#else				/* #ifndef __MORPHOS__ */
                FreeMem( xfdobj->xfdbi_TargetBuffer,xfdobj->xfdbi_TargetBufLen );
#endif				/* #ifndef __MORPHOS__ */
              } else {
                libspectrum_print_error(
                             LIBSPECTRUM_ERROR_UNKNOWN,
                             "xfdmaster.library not able to decrunch %s file",
                             xfdobj->xfdbi_PackerName );
                return LIBSPECTRUM_ERROR_UNKNOWN;
              }
            } else {
              libspectrum_print_error(
                                 LIBSPECTRUM_ERROR_UNKNOWN,
                                 "xfdmaster.library does not recognise file" );
              return LIBSPECTRUM_ERROR_UNKNOWN;
            }
#ifndef __MORPHOS__
            IxfdMaster->xfdFreeObject( xfdobj );
#else				/* #ifndef __MORPHOS__ */
            xfdFreeObject( xfdobj );
#endif				/* #ifndef __MORPHOS__ */
          }
#ifndef __MORPHOS__
          IExec->DropInterface( (struct Interface *)IxfdMaster );
        }
        IExec->CloseLibrary( xfdMasterBase );
#else				/* #ifndef __MORPHOS__ */
        CloseLibrary( xfdMasterBase );
#endif				/* #ifndef __MORPHOS__ */
      }
    }
    break;
#endif /* #ifdef AMIGA */

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "unknown compressed type %d", type );
    if( new_filename ) free( *new_filename );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  return LIBSPECTRUM_ERROR_NONE;
}

/* Ensure there is room for `requested' characters after the current
   position `ptr' in `buffer'. If not, realloc() and update the
   pointers as necessary */
int
libspectrum_make_room( libspectrum_byte **dest, size_t requested,
		       libspectrum_byte **ptr, size_t *allocated )
{
  size_t current_length;

  current_length = *ptr - *dest;

  if( *allocated == 0 ) {

    (*allocated) = requested;

    *dest = (libspectrum_byte*)malloc( requested * sizeof(libspectrum_byte) );
    if( *dest == NULL ) return 1;

  } else {

    /* If there's already enough room here, just return */
    if( current_length + requested <= (*allocated) ) return 0;

    /* Make the new size the maximum of the new needed size and the
     old allocated size * 2 */
    (*allocated) =
      current_length + requested > 2 * (*allocated) ?
      current_length + requested :
      2 * (*allocated);

    *dest = (libspectrum_byte*)
      realloc( *dest, (*allocated) * sizeof( libspectrum_byte ) );
    if( *dest == NULL ) return 1;

  }

  /* Update the secondary pointer to the block */
  *ptr = *dest + current_length;

  return 0;

}

/* Read an LSB word from 'buffer' */
libspectrum_word
libspectrum_read_word( const libspectrum_byte **buffer )
{
  libspectrum_word value;

  value = (*buffer)[0] + (*buffer)[1] * 0x100;

  (*buffer) += 2;

  return value;
}

/* Read an LSB dword from buffer */
libspectrum_dword
libspectrum_read_dword( const libspectrum_byte **buffer )
{
  libspectrum_dword value;

  value = (*buffer)[0]             +
          (*buffer)[1] *     0x100 +
	  (*buffer)[2] *   0x10000 +
          (*buffer)[3] * 0x1000000 ;

  (*buffer) += 4;

  return value;
}

/* Write an (LSB) word to buffer */
int
libspectrum_write_word( libspectrum_byte **buffer, libspectrum_word w )
{
  *(*buffer)++ = w & 0xff;
  *(*buffer)++ = w >> 8;
  return LIBSPECTRUM_ERROR_NONE;
}

/* Write an LSB dword to buffer */
int libspectrum_write_dword( libspectrum_byte **buffer, libspectrum_dword d )
{
  *(*buffer)++ = ( d & 0x000000ff )      ;
  *(*buffer)++ = ( d & 0x0000ff00 ) >>  8;
  *(*buffer)++ = ( d & 0x00ff0000 ) >> 16;
  *(*buffer)++ = ( d & 0xff000000 ) >> 24;
  return LIBSPECTRUM_ERROR_NONE;
}
Example #17
0
/* The main function: called with a tape object and returns the number of
   t-states until the next edge, and a marker if this was the last edge
   on the tape */
libspectrum_error
libspectrum_tape_get_next_edge( libspectrum_tape *tape,
				libspectrum_dword *tstates, int *flags )
{
  int error;

  libspectrum_tape_block *block =
    (libspectrum_tape_block*)tape->current_block->data;

  /* 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;

  switch( block->type ) {
  case LIBSPECTRUM_TAPE_BLOCK_ROM:
    error = rom_edge( &(block->types.rom), tstates, &end_of_block );
    if( error ) return error;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_TURBO:
    error = turbo_edge( &(block->types.turbo), tstates, &end_of_block );
    if( error ) return error;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
    error = tone_edge( &(block->types.pure_tone), tstates, &end_of_block );
    if( error ) return error;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PULSES:
    error = pulses_edge( &(block->types.pulses), tstates, &end_of_block );
    if( error ) return error;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
    error = pure_data_edge( &(block->types.pure_data), tstates, &end_of_block);
    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:
    tape->loop_block = tape->current_block->next;
    tape->loop_count = block->types.loop_start.count;
    *tstates = 0; end_of_block = 1;
    break;

  case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
    if( --tape->loop_count ) {
      tape->current_block = tape->loop_block;
      no_advance = 1;
    }
    *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;

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

  /* 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 ) {

      tape->current_block = tape->current_block->next;

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

    /* Initialise the new block */
    block = (libspectrum_tape_block*)tape->current_block->data;
    error = libspectrum_tape_init_block( block );
    if( error ) return error;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #18
0
static libspectrum_error
generalised_data_edge( libspectrum_tape_generalised_data_block *block,
                       libspectrum_tape_generalised_data_block_state *state,
		       libspectrum_dword *tstates, int *end_of_block,
		       int *flags )
{
  libspectrum_tape_generalised_data_symbol_table *table;
  libspectrum_tape_generalised_data_symbol *symbol;
  size_t current_symbol;

  switch( state->state ) {
  case LIBSPECTRUM_TAPE_STATE_PILOT:
    table = &( block->pilot_table );
    current_symbol = block->pilot_symbols[ state->run ];
    symbol = &( table->symbols[ current_symbol ] );

    set_tstates_and_flags( symbol, state->edges_through_symbol, tstates,
			   flags );

    state->edges_through_symbol++;
    if( state->edges_through_symbol == table->max_pulses    ||
	symbol->lengths[ state->edges_through_symbol ] == 0    ) {
      state->edges_through_symbol = 0;
      if( ++state->symbols_through_run == block->pilot_repeats[ state->run ] ) {
	state->symbols_through_run = 0;
	if( ++state->run == table->symbols_in_block ) {
	  state->state = LIBSPECTRUM_TAPE_STATE_DATA1;
	  state->bits_through_byte = 0;
	  state->bytes_through_stream = 0;
	  state->symbols_through_stream = 0;
	  state->current_byte = block->data[ 0 ];
	  state->current_symbol = get_generalised_data_symbol( block, state );
	}
      }
    }
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA1:
    table = &( block->data_table );
    symbol = &( table->symbols[ state->current_symbol ] );

    set_tstates_and_flags( symbol, state->edges_through_symbol, tstates,
			   flags );

    state->edges_through_symbol++;
    if( state->edges_through_symbol == table->max_pulses    ||
	symbol->lengths[ state->edges_through_symbol ] == 0    ) {
      if( ++state->symbols_through_stream == table->symbols_in_block ) {
	state->state = LIBSPECTRUM_TAPE_STATE_PAUSE;
      } else {
	state->edges_through_symbol = 0;
	state->current_symbol = get_generalised_data_symbol( block, state );
      }
    }
    break;

  case LIBSPECTRUM_TAPE_STATE_PAUSE:
    /* The pause at the end of the block */
    *tstates = ( block->pause * 69888 )/20; /* FIXME: should vary with tstates
					       per frame */
    *end_of_block = 1;
    break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC, "%s: unknown state %d",
			     __func__, state->state );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #19
0
static libspectrum_error
turbo_edge( libspectrum_tape_turbo_block *block,
            libspectrum_tape_turbo_block_state *state,
            libspectrum_dword *tstates, int *end_of_block )
{
  int error;

  switch( state->state ) {

  case LIBSPECTRUM_TAPE_STATE_PILOT:
    /* Check we actually have some edges */
    if( state->edge_count-- != 0 ) {
      *tstates = block->pilot_length;
      break;
    }
    /* Fall through */

  case LIBSPECTRUM_TAPE_STATE_SYNC1:
    /* The first short sync pulse */
    *tstates = block->sync1_length;
    /* Followed by the second sync pulse */
    state->state = LIBSPECTRUM_TAPE_STATE_SYNC2;
    break;

  case LIBSPECTRUM_TAPE_STATE_SYNC2:
    /* The second short sync pulse */
    *tstates = block->sync2_length;
    /* Followed by the first bit of data */
    error = turbo_next_bit( block, state ); if( error ) return error;
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA1:
    /* The first edge for a bit of data */
    *tstates = state->bit_tstates;
    /* Followed by the second edge */
    state->state = LIBSPECTRUM_TAPE_STATE_DATA2;
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA2:
    /* The second edge for a bit of data */
    *tstates = state->bit_tstates;
    /* Followed by the next bit of data (or the end of data) */
    error = turbo_next_bit( block, state ); if( error ) return error;
    break;

  case LIBSPECTRUM_TAPE_STATE_PAUSE:
    /* The pause at the end of the block */
    *tstates = (block->pause * 69888)/20; /* FIXME: should vary with tstates
					     per frame */
    *end_of_block = 1;
    break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "turbo_edge: unknown state %d", state->state );
    return LIBSPECTRUM_ERROR_LOGIC;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #20
0
static libspectrum_error
rom_edge( libspectrum_tape_rom_block *block,
          libspectrum_tape_rom_block_state *state,
          libspectrum_dword *tstates,
	  int *end_of_block )
{
  int error;

  switch( state->state ) {

  case LIBSPECTRUM_TAPE_STATE_PILOT:
    /* The next edge occurs in one pilot edge timing */
    *tstates = LIBSPECTRUM_TAPE_TIMING_PILOT;
    /* If that was the last pilot edge, change state */
    if( --(state->edge_count) == 0 )
      state->state = LIBSPECTRUM_TAPE_STATE_SYNC1;
    break;

  case LIBSPECTRUM_TAPE_STATE_SYNC1:
    /* The first short sync pulse */
    *tstates = LIBSPECTRUM_TAPE_TIMING_SYNC1;
    /* Followed by the second sync pulse */
    state->state = LIBSPECTRUM_TAPE_STATE_SYNC2;
    break;

  case LIBSPECTRUM_TAPE_STATE_SYNC2:
    /* The second short sync pulse */
    *tstates = LIBSPECTRUM_TAPE_TIMING_SYNC2;
    /* Followed by the first bit of data */
    error = rom_next_bit( block, state ); if( error ) return error;
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA1:
    /* The first edge for a bit of data */
    *tstates = state->bit_tstates;
    /* Followed by the second edge */
    state->state = LIBSPECTRUM_TAPE_STATE_DATA2;
    break;

  case LIBSPECTRUM_TAPE_STATE_DATA2:
    /* The second edge for a bit of data */
    *tstates = state->bit_tstates;
    /* Followed by the next bit of data (or the end of data) */
    error = rom_next_bit( block, state ); if( error ) return error;
    break;

  case LIBSPECTRUM_TAPE_STATE_PAUSE:
    /* The pause at the end of the block */
    *tstates = (block->pause * 69888)/20; /* FIXME: should vary with tstates
					     per frame */
    *end_of_block = 1;
    break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "rom_edge: unknown state %d", state->state );
    return LIBSPECTRUM_ERROR_LOGIC;

  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #21
0
static libspectrum_error
rzx_write_snapshot( libspectrum_byte **buffer, libspectrum_byte **ptr,
		    size_t *length, libspectrum_snap *snap,
		    libspectrum_id_t snap_format,
		    libspectrum_creator *creator, int compress )
{
  libspectrum_error error;
  libspectrum_byte *snap_buffer = NULL; size_t snap_length;
  libspectrum_byte *gzsnap = NULL; size_t gzlength = 0;
  int flags, done;
  snapshot_string_t *type;

  snap_length = 0;

  if( snap_format == LIBSPECTRUM_ID_UNKNOWN ) {
    /* If not given a snap format, try using .z80. If that would result
       in major information loss, use .szx instead */
    snap_format = LIBSPECTRUM_ID_SNAPSHOT_Z80;
    error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap,
				    snap_format, creator, 0 );
    if( error ) return error;

    if( flags & LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS ) {
      libspectrum_free( snap_buffer ); snap_length = 0;
      snap_format = LIBSPECTRUM_ID_SNAPSHOT_SZX;
      error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap,
				      snap_format, creator, 0 );
      if( error ) return error;
    }

  } else {
    error = libspectrum_snap_write( &snap_buffer, &snap_length, &flags, snap,
				    snap_format, creator, 0 );
    if( error ) return error;
  }

  if( flags & LIBSPECTRUM_FLAG_SNAPSHOT_MAJOR_INFO_LOSS ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_WARNING,
			     "%s:rzx_write_snapshot: embedded snapshot has lost a significant amount of information",
			     __FILE__ );
  }

  if( compress ) {

#ifdef HAVE_ZLIB_H

    error = libspectrum_zlib_compress( snap_buffer, snap_length,
				       &gzsnap, &gzlength );
    if( error != LIBSPECTRUM_ERROR_NONE ) {
      libspectrum_free( snap_buffer );
      return error;
    }

    libspectrum_make_room( buffer, 17 + gzlength, ptr, length );

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "rzx_write_snapshot: compression needs zlib" );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

  } else {
    libspectrum_make_room( buffer, 17 + snap_length, ptr, length );
  }

  *(*ptr)++ = LIBSPECTRUM_RZX_SNAPSHOT_BLOCK;
  if( compress ) {			/* Block length and flags */
    libspectrum_write_dword( ptr, 17 + gzlength );
    libspectrum_write_dword( ptr, 2 );
  } else {
    libspectrum_write_dword( ptr, 17 + snap_length );
    libspectrum_write_dword( ptr, 0 );
  }

  for( type = snapshot_strings, done = 0; type->format; type++ ) {
    if( type->format == snap_format ) {
      memcpy( *ptr, type->string, 4 ); *ptr += 4;
      done = 1;
      break;
    }
  }

  if( !done ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "%s:rzx_write_snapshot: unexpected snap type %d", __FILE__, snap_format
    );
    return LIBSPECTRUM_ERROR_UNKNOWN;
  }

  libspectrum_write_dword( ptr, snap_length );	/* Snapshot length */

  if( compress ) {
    memcpy( *ptr, gzsnap, gzlength ); (*ptr) += gzlength;
    libspectrum_free( gzsnap );
  } else {
    memcpy( *ptr, snap_buffer, snap_length ); (*ptr) += snap_length;
  }

  libspectrum_free( snap_buffer );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #22
0
static int
libspectrum_sna_read_data( const libspectrum_byte *buffer,
			   size_t buffer_length, libspectrum_snap *snap )
{
  int error, page, i;
  libspectrum_word sp, offset;

  if( buffer_length < 0xc000 ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_sna_read_data: not enough data in buffer"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  switch( libspectrum_snap_machine( snap ) ) {

  case LIBSPECTRUM_MACHINE_48:

    sp = libspectrum_snap_sp( snap );
    if( sp < 0x4000 || sp == 0xffff ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_CORRUPT,
        "libspectrum_sna_read_data: SP invalid (0x%04x)", sp
      );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }

    /* Rescue PC from the stack */
    offset = sp - 0x4000;
    libspectrum_snap_set_pc( snap, buffer[offset] + 0x100 * buffer[offset+1] );

    /* Increase SP as PC has been unstacked */
    libspectrum_snap_set_sp( snap, libspectrum_snap_sp( snap ) + 2 );

    /* And split the pages up */
    error = libspectrum_split_to_48k_pages( snap, buffer );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    break;

  case LIBSPECTRUM_MACHINE_PENT:
    
    for( i=0; i<8; i++ ) {
      libspectrum_byte *ram = libspectrum_new( libspectrum_byte, 0x4000 );
      libspectrum_snap_set_pages( snap, i, ram );
    }

    memcpy( libspectrum_snap_pages( snap, 5 ), &buffer[0x0000], 0x4000 );
    memcpy( libspectrum_snap_pages( snap, 2 ), &buffer[0x4000], 0x4000 );

    error = libspectrum_sna_read_128_header( buffer + 0xc000,
					     buffer_length - 0xc000, snap );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    page = libspectrum_snap_out_128_memoryport( snap ) & 0x07;
    if( page == 5 || page == 2 ) {
      if( memcmp( libspectrum_snap_pages( snap, page ),
		  &buffer[0x8000], 0x4000 ) ) {
	libspectrum_print_error(
          LIBSPECTRUM_ERROR_CORRUPT,
	  "libspectrum_sna_read_data: duplicated page not identical"
	);
	return LIBSPECTRUM_ERROR_CORRUPT;
      }
    } else {
      memcpy( libspectrum_snap_pages( snap, page ), &buffer[0x8000], 0x4000 );
    }

    buffer += 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
    buffer_length -= 0xc000 + LIBSPECTRUM_SNA_128_HEADER_LENGTH;
    error = libspectrum_sna_read_128_data( buffer, buffer_length, snap );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "libspectrum_sna_read_data: unknown machine" );
    return LIBSPECTRUM_ERROR_LOGIC;
  }
  
  return LIBSPECTRUM_ERROR_NONE;
}
Example #23
0
static libspectrum_error
rzx_write_input( input_block_t *block, libspectrum_byte **buffer,
		 libspectrum_byte **ptr, size_t *length, int compress )
{
  libspectrum_error error;
  size_t i, size;
  size_t length_offset, data_offset, flags_offset;
  libspectrum_byte *length_ptr; 

  libspectrum_make_room( buffer, 18, ptr, length );

  *(*ptr)++ = LIBSPECTRUM_RZX_INPUT_BLOCK;

  /* The length bytes: for uncompressed data, 18 for the block introduction
     and 4 per frame; the number of bytes in every frame is added in below.
     If compression is requested (and makes the data shorter), this will be
     overwritten with the compressed length */
  size = 18 + 4 * block->count;

  /* Store where the length will be written, and skip over those bytes */
  length_offset = *ptr - *buffer; (*ptr) += 4;

  /* How many frames? */
  libspectrum_write_dword( ptr, block->count );

  /* Each frame has an undefined length, so write a zero */
  *(*ptr)++ = 0;

  /* T-state counter */
  libspectrum_write_dword( ptr, block->tstates );

  /* Flags */
  flags_offset = *ptr - *buffer;
  libspectrum_write_dword( ptr, compress ? 0x02 : 0 );

  /* Write the frames */
  data_offset = *ptr - *buffer;
  for( i = 0; i < block->count; i++ ) {

    libspectrum_rzx_frame_t *frame = &block->frames[i];

    libspectrum_make_room( buffer, 4, ptr, length );
    libspectrum_write_word( ptr, frame->instructions );

    if( frame->repeat_last ) {
      libspectrum_write_word( ptr, libspectrum_rzx_repeat_frame );
    } else {

      size += frame->count;			/* Keep track of the size */

      libspectrum_write_word( ptr, frame->count );

      libspectrum_make_room( buffer, frame->count, ptr, length );
      memcpy( *ptr, frame->in_bytes, frame->count ); (*ptr) += frame->count;
    }
  }

  /* Write the length in */
  length_ptr = *buffer + length_offset;
  libspectrum_write_dword( &length_ptr, size ); length_ptr -= 4;

  if( compress ) {

#ifdef HAVE_ZLIB_H

    /* Compress the data the simple way. Really, we should stream the data */
    libspectrum_byte *gzsnap = NULL; size_t gzlength;
    libspectrum_byte *data_ptr = *buffer + data_offset;

    error = libspectrum_zlib_compress( data_ptr, *ptr - data_ptr,
				       &gzsnap, &gzlength );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    if( (ptrdiff_t)gzlength >= *ptr - data_ptr ) { /* Compression made it
						      bigger :-( */
      *(*buffer + flags_offset) &= ~0x02; /* Clear `compressed' bit */
    } else {
      /* Write the compressed data in */
      memcpy( data_ptr, gzsnap, gzlength );

      /* Correct the length word and the buffer length */
      libspectrum_write_dword( &length_ptr, 18 + gzlength );
      *ptr = *buffer + data_offset + gzlength;
    }

    libspectrum_free( gzsnap );

#else				/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "rzx_write_input: compression needs zlib" );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

  }

  return LIBSPECTRUM_ERROR_NONE;
}
/* Read in a snapshot, optionally guessing what type it is */
libspectrum_error
libspectrum_snap_read( libspectrum_snap *snap, const libspectrum_byte *buffer,
		       size_t length, libspectrum_id_t type,
		       const char *filename )
{
  libspectrum_id_t raw_type;
  libspectrum_class_t class;
  libspectrum_byte *new_buffer;
  libspectrum_error error;

  /* If we don't know what sort of file this is, make a best guess */
  if( type == LIBSPECTRUM_ID_UNKNOWN ) {
    error = libspectrum_identify_file( &type, filename, buffer, length );
    if( error ) return error;

    /* If we still can't identify it, give up */
    if( type == LIBSPECTRUM_ID_UNKNOWN ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_UNKNOWN,
	"libspectrum_snap_read: couldn't identify file"
      );
      return LIBSPECTRUM_ERROR_UNKNOWN;
    }
  }

  error = libspectrum_identify_class( &class, type );
  if( error ) return error;

  if( class != LIBSPECTRUM_CLASS_SNAPSHOT ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "libspectrum_snap_read: not a snapshot file" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* Find out if this file needs decompression */
  new_buffer = NULL;

  error = libspectrum_identify_file_raw( &raw_type, filename, buffer, length );
  if( error ) return error;

  error = libspectrum_identify_class( &class, raw_type );
  if( error ) return error;

  if( class == LIBSPECTRUM_CLASS_COMPRESSED ) {

    size_t new_length;

    error = libspectrum_uncompress_file( &new_buffer, &new_length, NULL,
					 raw_type, buffer, length, NULL );
    if( error ) return error;
    buffer = new_buffer; length = new_length;
  }

  switch( type ) {

  case LIBSPECTRUM_ID_SNAPSHOT_PLUSD:
    error = libspectrum_plusd_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_SNA:
    error = internal_sna_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_SNP:
    error = libspectrum_snp_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_SP:
    error = libspectrum_sp_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_SZX:
    error = libspectrum_szx_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_Z80:
    error = internal_z80_read( snap, buffer, length ); break;

  case LIBSPECTRUM_ID_SNAPSHOT_ZXS:
    error = libspectrum_zxs_read( snap, buffer, length ); break;

  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "libspectrum_snap_read: unknown snapshot type %d",
			     type );
    libspectrum_free( new_buffer );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  libspectrum_free( new_buffer );
  return error;
}
Example #25
0
libspectrum_error
libspectrum_rzx_playback_frame( libspectrum_rzx *rzx, int *finished,
				libspectrum_snap **snap )
{
  *snap = NULL;
  *finished = 0;

  /* Check we read the correct number of INs during this frame */
  if( rzx->in_count != rzx->data_frame->count ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "libspectrum_rzx_playback_frame: wrong number of INs in frame %lu: expected %lu, got %lu",
      (unsigned long)rzx->current_frame,
      (unsigned long)rzx->data_frame->count, (unsigned long)rzx->in_count
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* Increment the frame count and see if we've finished with this file */
  if( ++rzx->current_frame >= rzx->current_input->count ) {

    GSList *it = rzx->current_block->next;
    rzx->current_block = NULL;

    for( ; it; it = it->next ) {

      rzx_block_t *block = it->data;

      if( block->type == LIBSPECTRUM_RZX_INPUT_BLOCK ) {
	rzx->current_block = it;
	break;
      } else if( block->type == LIBSPECTRUM_RZX_SNAPSHOT_BLOCK ) {
	*snap = block->types.snap.snap;
      }

    }

    if( rzx->current_block ) {
    
      rzx_block_t *block = rzx->current_block->data;
      rzx->current_input = &( block->types.input );

      rzx->current_frame = 0; rzx->in_count = 0;
      rzx->data_frame = rzx->current_input->frames;

    } else {
      *finished = 1;
    }

    return LIBSPECTRUM_ERROR_NONE;
  }

  /* Move the data frame pointer along, unless we're supposed to be
     repeating the last frame */
  if( !rzx->current_input->frames[ rzx->current_frame ].repeat_last )
    rzx->data_frame = &rzx->current_input->frames[ rzx->current_frame ];

  /* And start with the first byte of the new frame */
  rzx->in_count = 0;

  return LIBSPECTRUM_ERROR_NONE;
}
/* Called when a new block is started to initialise its internal state */
libspectrum_error
libspectrum_tape_block_init( libspectrum_tape_block *block,
                             libspectrum_tape_block_state *state )
{
  if( !block ) return LIBSPECTRUM_ERROR_NONE;

  switch( libspectrum_tape_block_type( block ) ) {

  case LIBSPECTRUM_TAPE_BLOCK_ROM:
    return rom_init( &(block->types.rom), &(state->block_state.rom) );
  case LIBSPECTRUM_TAPE_BLOCK_TURBO:
    return turbo_init( &(block->types.turbo), &(state->block_state.turbo) );
  case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
    state->block_state.pure_tone.edge_count = block->types.pure_tone.pulses;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PULSES:
    state->block_state.pulses.edge_count = 0;
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
    return pure_data_init( &(block->types.pure_data),
                           &(state->block_state.pure_data) );
  case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
    raw_data_init( &(block->types.raw_data), &(state->block_state.raw_data) );
    return LIBSPECTRUM_ERROR_NONE;
  case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
    return generalised_data_init( &(block->types.generalised_data),
                                  &(state->block_state.generalised_data) );
  case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
    state->block_state.rle_pulse.index = 0;
    return LIBSPECTRUM_ERROR_NONE;
  case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
    state->block_state.pulse_sequence.index = 0;
    state->block_state.pulse_sequence.pulse_count = 0;
    state->block_state.pulse_sequence.level = -1;
    return LIBSPECTRUM_ERROR_NONE;
  case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
    return data_block_init( &(block->types.data_block),
                            &(state->block_state.data_block) );

  /* These blocks need no initialisation */
  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_SET_SIGNAL_LEVEL:
  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:
    return LIBSPECTRUM_ERROR_NONE;

  default:
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_LOGIC,
      "libspectrum_tape_init_block: unknown block type 0x%02x",
      block->type
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  return LIBSPECTRUM_ERROR_NONE;
}
Example #27
0
static libspectrum_error
rzx_read_snapshot( libspectrum_rzx *rzx, const libspectrum_byte **ptr,
		   const libspectrum_byte *end )
{
  rzx_block_t *block;
  libspectrum_snap *snap;
  size_t blocklength, snaplength;
  libspectrum_error error = LIBSPECTRUM_ERROR_NONE;
  libspectrum_dword flags;
  const libspectrum_byte *snap_ptr;
  int done;
  snapshot_string_t *type;

  /* For deflated snapshot data: */
  int compressed;
  libspectrum_byte *gzsnap = NULL; size_t uncompressed_length = 0;

  if( end - (*ptr) < 16 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_snapshot: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  blocklength = libspectrum_read_dword( ptr );

  if( end - (*ptr) < (ptrdiff_t)blocklength - 5 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_snapshot: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* See if we want a compressed snap */
  flags = libspectrum_read_dword( ptr );

  /* We don't handle 'links' to external snapshots. I really think these
     are just more trouble than they're worth */
  if( flags & 0x01 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "rzx_read_snapshot: skipping external snapshot" );
    (*ptr) += blocklength - 9;
    return LIBSPECTRUM_ERROR_NONE;
  }

  /* Do we have a compressed snapshot? */
  compressed = flags & 0x02;

  /* How long is the (uncompressed) snap? */
  (*ptr) += 4;
  snaplength = libspectrum_read_dword( ptr );
  (*ptr) -= 8;

  /* If compressed, uncompress the data */
  if( compressed ) {

#ifdef HAVE_ZLIB_H

    error = libspectrum_zlib_inflate( (*ptr) + 8, blocklength - 17,
				      &gzsnap, &uncompressed_length );
    if( error != LIBSPECTRUM_ERROR_NONE ) return error;

    if( uncompressed_length != snaplength ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_CORRUPT,
        "rzx_read_snapshot: compressed snapshot has wrong length"
      );
      libspectrum_free( gzsnap );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }   
    snap_ptr = gzsnap;

#else			/* #ifdef HAVE_ZLIB_H */

    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "rzx_read_snapshot: zlib needed for decompression\n"
    );
    return LIBSPECTRUM_ERROR_UNKNOWN;

#endif			/* #ifdef HAVE_ZLIB_H */

  } else {

    /* If not compressed, check things are consistent */
    if( blocklength != snaplength + 17 ) {
      libspectrum_print_error(
        LIBSPECTRUM_ERROR_CORRUPT,
        "rzx_read_snapshot: inconsistent snapshot lengths"
      );
      return LIBSPECTRUM_ERROR_CORRUPT;
    }
    snap_ptr = (*ptr) + 8;
    uncompressed_length = snaplength;

  }

  block_alloc( &block, LIBSPECTRUM_RZX_SNAPSHOT_BLOCK );
  block->types.snap.snap = libspectrum_snap_alloc();
  block->types.snap.automatic = 0;

  snap = block->types.snap.snap;

  for( done = 0, type = snapshot_strings; type->format; type++ ) {
    if( !strncasecmp( (char*)*ptr, type->string, 4 ) ) {
      error = libspectrum_snap_read( snap, snap_ptr, uncompressed_length,
				     type->format, NULL );
      done = 1;
    }
  }

  if( !done ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_UNKNOWN,
      "%s:rzx_read_snapshot: unrecognised snapshot format", __FILE__
    );
    if( compressed ) libspectrum_free( gzsnap );
    block_free( block );
    return LIBSPECTRUM_ERROR_UNKNOWN;
  }

  if( error != LIBSPECTRUM_ERROR_NONE ) {
    if( compressed ) libspectrum_free( gzsnap );
    block_free( block );
    return error;
  }

  /* Free the decompressed data (if we created it) */
  if( compressed ) libspectrum_free( gzsnap );

  /* Skip over the data */
  (*ptr) += blocklength - 9;

  rzx->blocks = g_slist_append( rzx->blocks, block );

  return LIBSPECTRUM_ERROR_NONE;
}
/* Free the memory used by one block */
libspectrum_error
libspectrum_tape_block_free( libspectrum_tape_block *block )
{
  size_t i;

  switch( block->type ) {

  case LIBSPECTRUM_TAPE_BLOCK_ROM:
    libspectrum_free( block->types.rom.data );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_TURBO:
    libspectrum_free( block->types.turbo.data );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PULSES:
    libspectrum_free( block->types.pulses.lengths );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
    libspectrum_free( block->types.pure_data.data );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_RAW_DATA:
    libspectrum_free( block->types.raw_data.data );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_GENERALISED_DATA:
    free_symbol_table( &block->types.generalised_data.pilot_table );
    free_symbol_table( &block->types.generalised_data.data_table );
    libspectrum_free( block->types.generalised_data.pilot_symbols );
    libspectrum_free( block->types.generalised_data.pilot_repeats );
    libspectrum_free( block->types.generalised_data.data );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
    break;
  case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
    libspectrum_free( block->types.group_start.name );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
    break;
  case LIBSPECTRUM_TAPE_BLOCK_JUMP:
    break;
  case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
    break;
  case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
    break;

  case LIBSPECTRUM_TAPE_BLOCK_SELECT:
    for( i=0; i<block->types.select.count; i++ ) {
      libspectrum_free( block->types.select.descriptions[i] );
    }
    libspectrum_free( block->types.select.descriptions );
    libspectrum_free( block->types.select.offsets );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_STOP48:
    break;

  case LIBSPECTRUM_TAPE_BLOCK_SET_SIGNAL_LEVEL:
    break;

  case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
    libspectrum_free( block->types.comment.text );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
    libspectrum_free( block->types.message.text );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
    for( i=0; i<block->types.archive_info.count; i++ ) {
      libspectrum_free( block->types.archive_info.strings[i] );
    }
    libspectrum_free( block->types.archive_info.ids );
    libspectrum_free( block->types.archive_info.strings );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
    libspectrum_free( block->types.hardware.types  );
    libspectrum_free( block->types.hardware.ids    );
    libspectrum_free( block->types.hardware.values );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
    libspectrum_free( block->types.custom.description );
    libspectrum_free( block->types.custom.data );
    break;

  /* Block types not present in .tzx follow here */

  case LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE:
    libspectrum_free( block->types.rle_pulse.data );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_PULSE_SEQUENCE:
    libspectrum_free( block->types.pulse_sequence.lengths );
    libspectrum_free( block->types.pulse_sequence.pulse_repeats );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_DATA_BLOCK:
    libspectrum_free( block->types.data_block.data );
    libspectrum_free( block->types.data_block.bit0_pulses );
    libspectrum_free( block->types.data_block.bit1_pulses );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_CONCAT: /* This should never occur */
  default:
    libspectrum_print_error( LIBSPECTRUM_ERROR_LOGIC,
			     "%s: unknown block type %d", __func__,
			     block->type );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  libspectrum_free( block );

  return LIBSPECTRUM_ERROR_NONE;
}
Example #29
0
static libspectrum_error
inflate_block( libspectrum_byte **uncompressed, size_t *uncompressed_length,
	       const libspectrum_byte **compressed, size_t compressed_length )
{

#ifdef HAVE_ZLIB_H

  libspectrum_dword header_length, expected_crc32, actual_crc32;
  libspectrum_byte *zlib_buffer;
  unsigned long actual_length;
  int error;

  /* First, look at the compression header */
  header_length = libspectrum_read_dword( compressed );
  if( header_length != 12 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
			     "zxs_inflate_block: unknown header length %lu",
			     (unsigned long)header_length );
    return LIBSPECTRUM_ERROR_UNKNOWN;
  }
  compressed_length -= 12;

  expected_crc32 = libspectrum_read_dword( compressed );
  *uncompressed_length = libspectrum_read_dword( compressed );

  /* Some space to put the zlib header for decompression */
  zlib_buffer =
    libspectrum_malloc( ( compressed_length + 6 ) * sizeof( *zlib_buffer ) );

  /* zlib's header */
  zlib_buffer[0] = 0x78; zlib_buffer[1] = 0xda;

  memcpy( &zlib_buffer[2], *compressed, compressed_length );
  *compressed += compressed_length;

  *uncompressed = libspectrum_malloc( *uncompressed_length * sizeof( **uncompressed ) );

  actual_length = *uncompressed_length;
  error = uncompress( *uncompressed, &actual_length, zlib_buffer,
		      compressed_length + 6 );

  /* At this point, we expect to get a Z_DATA_ERROR, as we don't have
     the Adler-32 checksum of the data. There is a 1 in 65521 chance
     that the random bytes will match, so we might (very rarely) get
     Z_OK */
  if( error != Z_DATA_ERROR && error != Z_OK ) {
    libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer );
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "zxs_inflate_block: unexpected zlib error" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  if( *uncompressed_length != actual_length ) {
    libspectrum_free( *uncompressed ); libspectrum_free( zlib_buffer );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "zxs_inflate_block: block expanded to 0x%04lx, not the expected 0x%04lx bytes",
      actual_length, (unsigned long)*uncompressed_length
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  libspectrum_free( zlib_buffer );

  actual_crc32 = crc32( 0, Z_NULL, 0 );
  actual_crc32 = crc32( actual_crc32, *uncompressed, *uncompressed_length );

  if( actual_crc32 != expected_crc32 ) {
    libspectrum_free( *uncompressed );
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "zxs_inflate_block: crc 0x%08x does not match expected 0x%08x",
      actual_crc32, expected_crc32
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  return LIBSPECTRUM_ERROR_NONE;

#else				/* #ifdef HAVE_ZLIB_H */

  /* No zlib, so can't inflate the block */
  return LIBSPECTRUM_ERROR_UNKNOWN;

#endif				/* #ifdef HAVE_ZLIB_H */

}
Example #30
0
libspectrum_error
libspectrum_tape_block_description( libspectrum_tape_block *block,
				    char *buffer, size_t length )
{
  switch( block->type ) {
  case LIBSPECTRUM_TAPE_BLOCK_ROM:
    strncpy( buffer, "Standard Speed Data Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_TURBO:
    strncpy( buffer, "Turbo Speed Data Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_TONE:
    strncpy( buffer, "Pure Tone Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PULSES:
    strncpy( buffer, "List of Pulses", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_PURE_DATA:
    strncpy( buffer, "Pure Data Block", length );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_PAUSE:
    strncpy( buffer, "Pause Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_GROUP_START:
    strncpy( buffer, "Group Start Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_GROUP_END:
    strncpy( buffer, "Group End Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_JUMP:
    strncpy( buffer, "Jump Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_LOOP_START:
    strncpy( buffer, "Loop Start Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_LOOP_END:
    strncpy( buffer, "Loop End Block", length );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_SELECT:
    strncpy( buffer, "Select Block", length );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_STOP48:
    strncpy( buffer, "Stop Tape If In 48K Mode Block", length );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_COMMENT:
    strncpy( buffer, "Comment Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_MESSAGE:
    strncpy( buffer, "Message Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_ARCHIVE_INFO:
    strncpy( buffer, "Archive Info Block", length );
    break;
  case LIBSPECTRUM_TAPE_BLOCK_HARDWARE:
    strncpy( buffer, "Hardware Information Block", length );
    break;

  case LIBSPECTRUM_TAPE_BLOCK_CUSTOM:
    strncpy( buffer, "Custom Info Block", length );
    break;

  default:
    libspectrum_print_error(
      "libspectrum_tape_block_description: unknown block type 0x%02x\n",
      block->type
    );
    return LIBSPECTRUM_ERROR_LOGIC;
  }

  buffer[ length-1 ] = '\0';
  return LIBSPECTRUM_ERROR_NONE;
}