Пример #1
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;
}
Пример #2
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;
}
Пример #3
0
libspectrum_error
libspectrum_csw_read( libspectrum_tape *tape,
                      const libspectrum_byte *buffer, size_t length )
{
    libspectrum_tape_block *block = NULL;
    libspectrum_tape_rle_pulse_block *csw_block;

    int compressed;

    size_t signature_length = strlen( csw_signature );

    if( length < signature_length + 2 ) goto csw_short;

    if( memcmp( csw_signature, buffer, signature_length ) ) {
        libspectrum_print_error( LIBSPECTRUM_ERROR_SIGNATURE,
                                 "libspectrum_csw_read: wrong signature" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    /* Claim memory for the block */
    block = libspectrum_new( libspectrum_tape_block, 1 );

    /* Set the block type */
    block->type = LIBSPECTRUM_TAPE_BLOCK_RLE_PULSE;
    csw_block = &block->types.rle_pulse;

    buffer += signature_length;
    length -= signature_length;

    switch( buffer[0] ) {

    case 1:
        if( length < 9 ) goto csw_short;
        csw_block->scale = buffer[2] | buffer[3] << 8;
        if( buffer[4] != 1 ) goto csw_bad_compress;
        compressed = 0;
        buffer += 9;
        length -= 9;
        break;

    case 2:
        if( length < 29 ) goto csw_short;

        csw_block->scale =
            buffer[2]       |
            buffer[3] <<  8 |
            buffer[4] << 16 |
            buffer[5] << 24;
        compressed = buffer[10] - 1;

        if( compressed != 0 && compressed != 1 ) goto csw_bad_compress;

        if( length < 29 - buffer[12] ) goto csw_short;
        length -= 29 - buffer[12];
        buffer += 29 + buffer[12];

        break;

    default:
        libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: unknown CSW version" );
        return LIBSPECTRUM_ERROR_SIGNATURE;
    }

    if (csw_block->scale)
        csw_block->scale = 3500000 / csw_block->scale; /* approximate CPU speed */

    if( csw_block->scale < 0 || csw_block->scale >= 0x80000 ) {
        libspectrum_print_error (LIBSPECTRUM_ERROR_MEMORY,
                                 "libspectrum_csw_read: bad sample rate" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
    }

    if( !length ) goto csw_empty;

    if( compressed ) {
        /* Compressed data... */
#ifdef HAVE_ZLIB_H
        libspectrum_error error;

        csw_block->data = NULL;
        csw_block->length = 0;
        error = libspectrum_zlib_inflate( buffer, length, &csw_block->data,
                                          &csw_block->length );
        if( error != LIBSPECTRUM_ERROR_NONE ) return error;
#else
        libspectrum_print_error( LIBSPECTRUM_ERROR_UNKNOWN,
                                 "zlib not available to decompress gzipped file" );
        return LIBSPECTRUM_ERROR_UNKNOWN;
#endif
    } else {
        /* Claim memory for the data (it's one big lump) */
        csw_block->length = length;
        csw_block->data = libspectrum_new( libspectrum_byte, length );

        /* Copy the data across */
        memcpy( csw_block->data, buffer, length );
    }

    libspectrum_tape_append_block( tape, block );

    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;

    /* Error returns */

csw_bad_compress:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_MEMORY,
                             "libspectrum_csw_read: unknown compression type" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_short:
    libspectrum_free( block );
    libspectrum_print_error( LIBSPECTRUM_ERROR_CORRUPT,
                             "libspectrum_csw_read: not enough data in buffer" );
    return LIBSPECTRUM_ERROR_CORRUPT;

csw_empty:
    libspectrum_free( block );
    /* Successful completion */
    return LIBSPECTRUM_ERROR_NONE;
}