Beispiel #1
0
static libspectrum_error
rzx_read_sign_start( libspectrum_rzx *rzx, const libspectrum_byte **ptr,
		     const libspectrum_byte *end )
{
  rzx_block_t *block;
  libspectrum_dword length;

  /* Check we've got enough data for the length */

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

  length = libspectrum_read_dword( ptr );

  /* Check the length is at least the expected 13 bytes */
  if( length < 13 ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "rzx_read_sign_start: block length %lu less than the minimum 13 bytes",
      (unsigned long)length
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* Check there's still enough data (the -5 is because we've already read
     the length and the block ID) */
  if( end - (*ptr) < (ptrdiff_t)length - 5 ) {
    libspectrum_print_error(
      LIBSPECTRUM_ERROR_CORRUPT,
      "rzx_read_sign_start: not enough data in buffer"
    );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  block_alloc( &block, LIBSPECTRUM_RZX_SIGN_START_BLOCK );

  block->types.keyid = libspectrum_read_dword( ptr );

  /* Skip the week code */
  *ptr += 4;

  /* Skip anything we don't know about */
  *ptr += length - 13;

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

  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #2
0
static libspectrum_error
rzx_read_creator( const libspectrum_byte **ptr, const libspectrum_byte *end )
{
  size_t length;

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

  /* Get the length */
  length = libspectrum_read_dword( ptr );

  /* Check there's still enough data (the -5 is because we've already read
     the block ID and the length) */
  if( end - (*ptr) < (ptrdiff_t)length - 5 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_creator: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  (*ptr) += length - 5;

  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #3
0
static libspectrum_error
rzx_read_header( const libspectrum_byte **ptr, const libspectrum_byte *end )
{
  libspectrum_dword flags;

  /* Check the header exists */
  if( end - (*ptr) < (ptrdiff_t)strlen( rzx_signature ) + 6 ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
			     "rzx_read_header: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;
  }

  /* Check the RZX signature exists */
  if( memcmp( *ptr, rzx_signature, strlen( rzx_signature ) ) ) {
    libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
			     "rzx_read_header: RZX signature not found" );
    return LIBSPECTRUM_ERROR_SIGNATURE;
  }

  /* Skip over the signature and the version numbers */
  (*ptr) += strlen( rzx_signature ) + 2;

  flags = libspectrum_read_dword( ptr );

  /* FIXME: how to handle signatures */

  /* This is where the signed data starts (if it's signed at all) */
/*   if( signature && ( flags & 0x01 ) ) signature->start = *ptr; */

  return LIBSPECTRUM_ERROR_NONE;
}
libspectrum_error
libspectrum_tape_block_read_symbol_table_parameters(
  libspectrum_tape_block *block, int pilot, const libspectrum_byte **ptr )
{
  libspectrum_tape_generalised_data_block *generalised =
    &block->types.generalised_data;

  libspectrum_tape_generalised_data_symbol_table *table =
    pilot ? &generalised->pilot_table : &generalised->data_table;

  table->symbols_in_block = libspectrum_read_dword( ptr );
  table->max_pulses = (*ptr)[0];

  table->symbols_in_table = (*ptr)[1];
  if( !table->symbols_in_table ) table->symbols_in_table = 256;

  (*ptr) += 2;

  return LIBSPECTRUM_ERROR_NONE;
}
Beispiel #5
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 */

}
Beispiel #6
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;
}
Beispiel #7
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;
}
Beispiel #8
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;
}