Beispiel #1
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;
}
Beispiel #2
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;
}
Beispiel #3
0
static libspectrum_error
csw_write_body( libspectrum_byte **buffer, size_t *length,
                libspectrum_tape *tape, libspectrum_dword sample_rate,
                size_t length_offset, libspectrum_byte *ptr )
{
    libspectrum_error error;
    int flags = 0;
    libspectrum_dword pulse_tstates = 0;
    libspectrum_dword balance_tstates = 0;
    libspectrum_byte *data = NULL;
    size_t data_size;
    size_t data_length = 0;
    libspectrum_byte *data_ptr = data;
    long scale = 3500000/sample_rate;
    libspectrum_tape_block_state it;
    libspectrum_byte *length_ptr;

    libspectrum_make_room( &data, 8192, &data_ptr, &data_size );

    if( libspectrum_tape_block_internal_init( &it, tape ) ) {
        while( !(flags & LIBSPECTRUM_TAPE_FLAGS_STOP) ) {
            libspectrum_dword pulse_length = 0;

            /* Use internal version of this that doesn't bugger up the
               external tape status */
            error = libspectrum_tape_get_next_edge_internal( &pulse_tstates, &flags,
                    tape, &it );
            if( error != LIBSPECTRUM_ERROR_NONE ) return error;

            balance_tstates += pulse_tstates;

            if( flags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE ) continue;

            /* next RLE value is: balance_tstates / scale; */
            pulse_length = balance_tstates / scale;
            balance_tstates = balance_tstates % scale;

            if( pulse_length ) {
                if( data_size < (data_length + 1 + sizeof(libspectrum_dword) ) )
                    libspectrum_make_room( &data, data_size*2, &data_ptr, &data_size );

                if( pulse_length <= 0xff ) {
                    *data_ptr++ = pulse_length;
                    data_length++;
                } else {
                    *data_ptr++ = 0;
                    data_length++;
                    libspectrum_write_dword( &data_ptr, pulse_length );
                    data_length+=sizeof(libspectrum_dword);
                }
            }
        }
    }

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

    /* compression type */
#ifdef HAVE_ZLIB_H
    if( data_length ) {
        libspectrum_byte *compressed_data = NULL;
        size_t compressed_length;

        error = libspectrum_zlib_compress( data, data_length,
                                           &compressed_data, &compressed_length );
        libspectrum_free( data );
        if( error ) return error;

        data = compressed_data;
        data_length = compressed_length;
    }
#endif

    if( data_length ) {
        libspectrum_make_room( buffer, data_length, &ptr, length );
        memcpy( ptr, data, data_length );
        ptr += data_length;
        libspectrum_free( data );
    }

    return LIBSPECTRUM_ERROR_NONE;
}