Esempio n. 1
0
blargg_err_t Nes_Snapshot::read( Data_Reader& in )
{
	Nes_Snapshot_Reader reader;
	BLARGG_RETURN_ERR( reader.begin( &in, this ) );
	while ( !reader.done() )
		BLARGG_RETURN_ERR( reader.next_block() );
	
	return blargg_success;
}
Esempio n. 2
0
static blargg_err_t apply_ips_patch( Data_Reader& patch, byte** file, long* file_size )
{
	byte signature [5];
	BLARGG_RETURN_ERR( patch.read( signature, sizeof signature ) );
	if ( memcmp( signature, "PATCH", sizeof signature ) )
		return "Not an IPS patch file";
	
	while ( patch.remain() )
	{
		// read offset
		byte buf [6];
		BLARGG_RETURN_ERR( patch.read( buf, 3 ) );
		long offset = buf [0] * 0x10000 + buf [1] * 0x100 + buf [2];
		if ( offset == 'EOF' )
			break;
		
		// read size
		BLARGG_RETURN_ERR( patch.read( buf, 2 ) );
		long size = buf [0] * 0x100 + buf [1];
		
		// size = 0 signals a run of identical bytes
		int fill = -1;
		if ( size == 0 )
		{
			BLARGG_RETURN_ERR( patch.read( buf, 3 ) );
			size = buf [0] * 0x100 + buf [1];
			fill = buf [2];
		}
		
		// expand file if new data is at exact end of file
		if ( offset == *file_size )
		{
			*file_size = offset + size;
			void* p = realloc( *file, *file_size );
			BLARGG_CHECK_ALLOC( p );
			*file = (byte*) p;
		}
		
		//dprintf( "Patch offset: 0x%04X, size: 0x%04X\n", (int) offset, (int) size );
		
		if ( offset < 0 || *file_size < offset + size )
			return "IPS tried to patch past end of file";
		
		// read/fill data
		if ( fill < 0 )
			BLARGG_RETURN_ERR( patch.read( *file + offset, size ) );
		else
			memset( *file + offset, fill, size );
	}
	
	return blargg_success;
}
Esempio n. 3
0
blargg_err_t Nes_Snapshot_Reader::begin( Data_Reader* dr, Nes_Snapshot* out )
{
	snapshot_ = out;
	if ( !out )
	{
		BLARGG_RETURN_ERR( snapshots.resize( 1 ) );
		snapshot_ = &snapshots [0];
	}
	
	BLARGG_RETURN_ERR( Nes_File_Reader::begin( dr ) );
	if ( block_tag() != snapshot_file_tag )
		return "Not a snapshot file";
	return blargg_success;
}
Esempio n. 4
0
// Read big-endian 32-bit int
static blargg_err_t read_be32( Emu_Reader& in, long* out )
{
	unsigned char tag [4];
	BLARGG_RETURN_ERR( in.read( tag, sizeof tag ) );
	*out = tag [0] * 0x1000000L + tag [1] * 0x10000L + tag [2] * 0x100L + tag [3];
	return blargg_success;
}
Esempio n. 5
0
blargg_err_t Nes_Snapshot_Writer::end( Nes_Emu const& emu )
{
	Nes_Snapshot_Array snapshots;
	BLARGG_RETURN_ERR( snapshots.resize( 1 ) );
	emu.save_snapshot( &snapshots [0] );
	return end( snapshots [0] );
}
Esempio n. 6
0
blargg_err_t Nes_Rewinder::load_ines_rom( Data_Reader& in, Data_Reader* ips )
{
	if ( !frames )
		BLARGG_RETURN_ERR( init() );
	
	return recorder::load_ines_rom( in, ips );
}
Esempio n. 7
0
blargg_err_t Nes_Rewinder::init()
{
	if ( !frames )
	{
		BLARGG_RETURN_ERR( recorder::init() );
		
		frames = BLARGG_NEW frame_t [frames_size];
		BLARGG_CHECK_ALLOC( frames );
	}
	
	return blargg_success;
}
Esempio n. 8
0
blargg_err_t Nes_Snapshot::read_sta_file( Data_Reader& in )
{
	sram_size = 0x2000;
	BLARGG_RETURN_ERR( in.read( sram, sram_size ) );
	
	ram_valid = true;
	BLARGG_RETURN_ERR( in.read( ram, 0x800 ) );
	
	sta_regs_t r;
	BLARGG_RETURN_ERR( in.read( &r, sizeof r ) );
	this->cpu.pc = r.pc [1] * 0x100 + r.pc [0];
	this->cpu.a = r.a;
	this->cpu.status = r.p;
	this->cpu.x = r.x;
	this->cpu.y = r.y;
	this->cpu.sp = r.s;
	cpu_valid = true;
	
	BLARGG_RETURN_ERR( in.read( spr_ram, 0x100 ) );
	spr_ram_valid = true;
	
	chr_size = 0x2000;
	BLARGG_RETURN_ERR( in.read( chr, chr_size ) );
	
	nametable_size = 0x1000;
	BLARGG_RETURN_ERR( in.read( nametable, nametable_size ) );
	
	return blargg_success;
}
Esempio n. 9
0
// Read multiple strings and separate into individual strings
static blargg_err_t read_strs( Emu_Reader& in, long size, std::vector<char>& chars,
		std::vector<const char*>& strs )
{
	chars.resize( size + 1 );
	chars [size] = 0; // in case last string doesn't have terminator
	BLARGG_RETURN_ERR( in.read( &(*chars.begin()), size ) );
	
	for ( int i = 0; i < size; i++ )
	{
        //TODO WARNING Not quite sure how this memory is being used, or why we are holding char pointers in a vector
        // as opposed to making a copy... seems a little dicey and need to come back to it later
        assert(0);
		strs.push_back( &(*chars.begin()) + i );
		while ( i < size && chars [i] )
			i++;
	}
	
	return blargg_success;
}
Esempio n. 10
0
blargg_err_t Nes_Rewinder::next_frame( int joypad, int joypad2 )
{
	if ( reverse_enabled )
	{
		if ( !get_film().empty() ) // if empty then we can't seek
			recorder::seek_( reversed_time );
		clear_reverse();
	}
	
	current_frame = 0;
	if ( quick_reverse )
	{
		current_frame = recorder::tell() % frames_size;
		if ( buffer_scrambled )
			buffer_scrambled--;
	}
	set_output( current_frame );
	
	BLARGG_RETURN_ERR( recorder::next_frame( joypad, joypad2 ) );
	frame_rendered( current_frame, quick_reverse );
	
	return blargg_success;
}
Esempio n. 11
0
blargg_err_t Nes_Rom::load_ines_rom( Data_Reader& in )
{
	ines_header_t h;
	BLARGG_RETURN_ERR( in.read( &h, sizeof h ) );
	
	if ( 0 != memcmp( h.signature, "NES\x1A", 4 ) )
		return "Not a iNES ROM file";
	
	if ( h.zero [7] ) // handle header defaced by a f*****g idiot's handle
		h.flags2 = 0;
	
	set_mapper( h.flags, h.flags2 );
	
	if ( h.flags & 0x04 ) // skip trainer
		BLARGG_RETURN_ERR( in.skip( 512 ) );
	
	BLARGG_RETURN_ERR( resize_prg( h.prg_count * 16 * 1024L ) );
	BLARGG_RETURN_ERR( resize_chr( h.chr_count * 8 * 1024L ) );
	
	BLARGG_RETURN_ERR( in.read( prg(), prg_size() ) );
	BLARGG_RETURN_ERR( in.read( chr(), chr_size() ) );
	
	return blargg_success;
}
Esempio n. 12
0
blargg_err_t Nes_Snapshot_Writer::end( Nes_Snapshot const& ss )
{
	BLARGG_RETURN_ERR( ss.write_blocks( *this ) );
	return Nes_File_Writer::end();
}
Esempio n. 13
0
blargg_err_t Nsfe_Emu::load( Emu_Reader& in )
{
	header_t h;
	BLARGG_RETURN_ERR( in.read( &h, sizeof h ) );
	return load( h, in );
}
Esempio n. 14
0
blargg_err_t Nsfe_Emu::load( const header_t& nsfe_tag, Emu_Reader& in )
{
	// check header
	if ( memcmp( nsfe_tag.tag, "NSFE", 4 ) )
		return "Not an NSFE file";
	
	// free previous info
	track_name_data.clear();
	track_names.clear();
	playlist.clear();
	track_times.clear();
	
	// default nsf header
	static const Nsf_Emu::header_t base_header =
	{
		'N','E','S','M','\x1A', // tag
		1,              // version
		1, 1,           // track count, first track
		0,0,0,0,0,0,    // addresses
		"","","",       // strings
		{ 0x1A, 0x41 }, // NTSC rate
		{ 0 },          // banks
		{ 0x20, 0x4E }, // PAL rate
		0,0,            // flags
		0,0,0,0         // unused
	};
	Nsf_Emu::header_t& header = info_;
	header = base_header;
	
	// parse tags
	int phase = 0;
	while ( phase != 3 )
	{
		// read size and tag
		long size = 0;
		long tag = 0;
		BLARGG_RETURN_ERR( read_le32( in, &size ) );
		BLARGG_RETURN_ERR( read_be32( in, &tag ) );
		
		switch ( tag )
		{
			case 'INFO': {
				check( phase == 0 );
				if ( size < 8 )
					return "Bad NSFE file";
				
				nsfe_info_t info;
				info.track_count = 1;
				info.first_track = 0;
				
				int s = size;
				if ( s > sizeof info )
					s = sizeof info;
				BLARGG_RETURN_ERR( in.read( &info, s ) );
				BLARGG_RETURN_ERR( in.skip( size - s ) );
				phase = 1;
				info_.speed_flags = info.speed_flags;
				info_.chip_flags = info.chip_flags;
				info_.track_count = info.track_count;
				info_.first_track = info.first_track;
				std::memcpy( info_.load_addr, info.load_addr, 2 * 3 );
				break;
			}
			
			case 'BANK':
				if ( size > sizeof info_.banks )
					return "Bad NSFE file";
				BLARGG_RETURN_ERR( in.read( info_.banks, size ) );
				break;
			
			case 'auth': {
				std::vector<char> chars;
				std::vector<const char*> strs;
				BLARGG_RETURN_ERR( read_strs( in, size, chars, strs ) );
				int n = strs.size();
				
				if ( n > 3 )
					copy_str( strs [3], info_.ripper, sizeof info_.ripper );
				
				if ( n > 2 )
					copy_str( strs [2], info_.copyright, sizeof info_.copyright );
				
				if ( n > 1 )
					copy_str( strs [1], info_.author, sizeof info_.author );
				
				if ( n > 0 )
					copy_str( strs [0], info_.game, sizeof info_.game );
				
				break;
			}
			
			case 'time': {
				track_times.resize( size / 4 );
				for ( int i = 0; i < track_times.size(); i++ )
					BLARGG_RETURN_ERR( read_le32( in, &track_times [i] ) );
				break;
			}
			
			case 'tlbl':
				BLARGG_RETURN_ERR( read_strs( in, size, track_name_data, track_names ) );
				break;
			
			case 'plst':
				playlist.resize( size );
				BLARGG_RETURN_ERR( in.read( &(*playlist.begin()), size ) );
				break;
			
			case 'DATA': {
				check( phase == 1 );
				phase = 2;
				Subset_Reader sub( &in, size ); // limit emu to nsf data
				BLARGG_RETURN_ERR( Nsf_Emu::load( info_, sub ) );
				check( sub.remain() == 0 );
				break;
			}
			
			case 'NEND':
				check( phase == 2 );
				phase = 3;
				break;
			
			default:
				// tags that can be skipped start with a lowercase character
				check( islower( (tag >> 24) & 0xff ) );
				BLARGG_RETURN_ERR( in.skip( size ) );
				break;
		}
	}
	
	return blargg_success;
}
Esempio n. 15
0
blargg_err_t Nes_Snapshot::read_blocks( Nes_File_Reader& in )
{
	while ( true )
	{
		BLARGG_RETURN_ERR( in.next_block() );
		switch ( in.block_tag() )
		{
			case nes.tag:
				memset( &nes, 0, sizeof nes );
				BLARGG_RETURN_ERR( read_nes_state( in, &nes ) );
				set_nes_state( nes );
				break;
			
			case cpu_state_t::tag: {
				cpu_state_t s;
				memset( &s, 0, sizeof s );
				BLARGG_RETURN_ERR( read_nes_state( in, &s ) );
				cpu.pc = s.pc;
				cpu.sp = s.s;
				cpu.a = s.a;
				cpu.x = s.x;
				cpu.y = s.y;
				cpu.status = s.p;
				cpu_valid = true;
				break;
			}
			
			case ppu.tag:
				memset( &ppu, 0, sizeof ppu );
				BLARGG_RETURN_ERR( read_nes_state( in, &ppu ) );
				ppu_valid = true;
				break;
			
			case apu.tag:
				memset( &apu, 0, sizeof apu );
				BLARGG_RETURN_ERR( read_nes_state( in, &apu ) );
				apu_valid = true;
				break;
			
			case joypad.tag:
				memset( &joypad, 0, sizeof joypad );
				BLARGG_RETURN_ERR( read_nes_state( in, &joypad ) );
				joypad_valid = true;
				break;
			
			case 'MAPR':
				mapper.size = in.remain();
				BLARGG_RETURN_ERR( in.read_block_data( mapper.data, sizeof mapper.data ) );
				mapper_valid = true;
				break;
			
			case 'SPRT':
				spr_ram_valid = true;
				BLARGG_RETURN_ERR( in.read_block_data( spr_ram, sizeof spr_ram ) );
				break;
				
			case 'NTAB':
				nametable_size = in.remain();
				BLARGG_RETURN_ERR( in.read_block_data( nametable, sizeof nametable ) );
				break;
				
			case 'LRAM':
				ram_valid = true;
				BLARGG_RETURN_ERR( in.read_block_data( ram, sizeof ram ) );
				break;
				
			case 'CHRR':
				chr_size = in.remain();
				BLARGG_RETURN_ERR( in.read_block_data( chr, sizeof chr ) );
				break;
				
			case 'SRAM':
				sram_size = in.remain();
				BLARGG_RETURN_ERR( in.read_block_data( sram, sizeof sram ) );
				break; 
			
			default:
				return blargg_success;
		}
	}
}
Esempio n. 16
0
blargg_err_t Nes_Snapshot::write( Data_Writer& out ) const
{
	Nes_Snapshot_Writer writer;
	BLARGG_RETURN_ERR( writer.begin( &out ) );
	return writer.end( *this );
}
Esempio n. 17
0
blargg_err_t Stereo_Buffer::sample_rate( long rate, int msec )
{
	for ( int i = 0; i < buf_count; i++ )
		BLARGG_RETURN_ERR( bufs [i].sample_rate( rate, msec ) );
	return Multi_Buffer::sample_rate( bufs [0].sample_rate(), bufs [0].length() );
}
Esempio n. 18
0
blargg_err_t Nes_Snapshot::write_blocks( Nes_File_Writer& out ) const
{
	if ( nes_valid )
	{
		nes_state_t s = nes;
		s.pal = false;
		s.timestamp = nes.timestamp * 15;
		BLARGG_RETURN_ERR( write_nes_state( out, s ) );
	}
	
	if ( cpu_valid )
	{
		cpu_state_t s;
		memset( &s, 0, sizeof s );
		s.pc = cpu.pc;
		s.s = cpu.sp;
		s.a = cpu.a;
		s.x = cpu.x;
		s.y = cpu.y;
		s.p = cpu.status;
		BLARGG_RETURN_ERR( write_nes_state( out, s ) );
	}
	
	if ( ppu_valid )
	{
		ppu_state_t s = ppu;
		BLARGG_RETURN_ERR( write_nes_state( out, s ) );
	}
	
	if ( apu_valid )
	{
		apu_snapshot_t s = apu;
		BLARGG_RETURN_ERR( write_nes_state( out, s ) );
	}
	
	if ( joypad_valid )
	{
		joypad_state_t s = joypad;
		BLARGG_RETURN_ERR( write_nes_state( out, s ) );
	}
	
	if ( mapper_valid )
		BLARGG_RETURN_ERR( out.write_block( 'MAPR', mapper.data, mapper.size ) );
	
	if ( ram_valid )
		BLARGG_RETURN_ERR( out.write_block( 'LRAM', ram, sizeof ram ) );
	
	if ( spr_ram_valid )
		BLARGG_RETURN_ERR( out.write_block( 'SPRT', spr_ram, sizeof spr_ram ) );
	
	if ( nametable_size )
		BLARGG_RETURN_ERR( out.write_block( 'NTAB', nametable, nametable_size ) );
	
	if ( chr_size )
		BLARGG_RETURN_ERR( out.write_block( 'CHRR', chr, chr_size ) );
	
	if ( sram_size )
		BLARGG_RETURN_ERR( out.write_block( 'SRAM', sram, sram_size ) );
	
	return blargg_success;
}
Esempio n. 19
0
blargg_err_t Mono_Buffer::sample_rate( long rate, int msec )
{
	BLARGG_RETURN_ERR( buf.sample_rate( rate, msec ) );
	return Multi_Buffer::sample_rate( buf.sample_rate(), buf.length() );
}