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; }
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; }
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; }