Fix rerecord counting

This also fixes the off-by-one in rerecord count.
This commit is contained in:
Ilari Liusvaara 2011-09-19 21:45:35 +03:00
parent d9ed993a4a
commit 8c8fc98d19
6 changed files with 65 additions and 40 deletions

View file

@ -514,6 +514,14 @@ class my_interface : public SNES::Interface
namespace namespace
{ {
function_ptr_command<> count_rerecords("count-rerecords", "Count rerecords",
"Syntax: count-rerecords\nCounts rerecords.\n",
[]() throw(std::bad_alloc, std::runtime_error) {
std::vector<char> tmp;
uint64_t x = rrdata::write(tmp);
messages << x << " rerecord(s)" << std::endl;
});
function_ptr_command<const std::string&> quit_emulator("quit-emulator", "Quit the emulator", function_ptr_command<const std::string&> quit_emulator("quit-emulator", "Quit the emulator",
"Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n", "Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
[](const std::string& args) throw(std::bad_alloc, std::runtime_error) { [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {

View file

@ -210,6 +210,7 @@ void do_load_state(struct moviefile& _movie, int lmode)
//Negative return. //Negative return.
rrdata::read_base(_movie.projectid); rrdata::read_base(_movie.projectid);
rrdata::read(_movie.c_rrdata);
rrdata::add_internal(); rrdata::add_internal();
try { try {
our_rom->region = gtype::toromregion(_movie.gametype); our_rom->region = gtype::toromregion(_movie.gametype);

View file

@ -99,18 +99,10 @@ void read_authors_file(zip_reader& r, std::vector<std::pair<std::string, std::st
} }
} }
std::string read_rrdata(zip_reader& r, const std::string& projectid) throw(std::bad_alloc, std::runtime_error) std::string read_rrdata(zip_reader& r, std::vector<char>& out) throw(std::bad_alloc, std::runtime_error)
{ {
std::istream& m = r["rrdata"]; out = read_raw_file(r, "rrdata");
uint64_t count; uint64_t count = rrdata::count(out);
try {
rrdata::read_base(projectid);
count = rrdata::read(m);
delete &m;
} catch(...) {
delete &m;
throw;
}
std::ostringstream x; std::ostringstream x;
x << count; x << count;
return x.str(); return x.str();
@ -118,17 +110,10 @@ std::string read_rrdata(zip_reader& r, const std::string& projectid) throw(std::
void write_rrdata(zip_writer& w) throw(std::bad_alloc, std::runtime_error) void write_rrdata(zip_writer& w) throw(std::bad_alloc, std::runtime_error)
{ {
std::ostream& m = w.create_file("rrdata");
uint64_t count; uint64_t count;
try { std::vector<char> out;
count = rrdata::write(m); count = rrdata::write(out);
if(!m) write_raw_file(w, "rrdata", out);
throw std::runtime_error("Can't write ZIP file member");
w.close_file();
} catch(...) {
w.close_file();
throw;
}
std::ostream& m2 = w.create_file("rerecords"); std::ostream& m2 = w.create_file("rerecords");
try { try {
m2 << count << std::endl; m2 << count << std::endl;
@ -254,7 +239,7 @@ moviefile::moviefile(const std::string& movie) throw(std::bad_alloc, std::runtim
port2 = port_type::lookup(tmp, true).ptype; port2 = port_type::lookup(tmp, true).ptype;
read_linefile(r, "gamename", gamename, true); read_linefile(r, "gamename", gamename, true);
read_linefile(r, "projectid", projectid); read_linefile(r, "projectid", projectid);
rerecords = read_rrdata(r, projectid); rerecords = read_rrdata(r, c_rrdata);
read_linefile(r, "coreversion", coreversion); read_linefile(r, "coreversion", coreversion);
read_linefile(r, "rom.sha256", rom_sha256, true); read_linefile(r, "rom.sha256", rom_sha256, true);
read_linefile(r, "romxml.sha256", romxml_sha256, true); read_linefile(r, "romxml.sha256", romxml_sha256, true);

View file

@ -128,6 +128,10 @@ struct moviefile
* State of movie code (if is_savestate is true). * State of movie code (if is_savestate is true).
*/ */
std::vector<char> movie_state; std::vector<char> movie_state;
/**
* Compressed rrdata.
*/
std::vector<char> c_rrdata;
/** /**
* Input for each (sub)frame. * Input for each (sub)frame.
*/ */

View file

@ -111,7 +111,7 @@ void rrdata::close() throw()
void rrdata::add(const struct rrdata::instance& i) throw(std::bad_alloc) void rrdata::add(const struct rrdata::instance& i) throw(std::bad_alloc)
{ {
if(rrset.insert(i).second) { if(rrset.insert(i).second && handle_open) {
//std::cerr << "New symbol: " << i << std::endl; //std::cerr << "New symbol: " << i << std::endl;
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES); ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
ohandle.flush(); ohandle.flush();
@ -127,7 +127,7 @@ void rrdata::add_internal() throw(std::bad_alloc)
namespace namespace
{ {
void flush_symbol(std::ostream& strm, const rrdata::instance& base, const rrdata::instance& predicted, void flush_symbol(std::vector<char>& strm, const rrdata::instance& base, const rrdata::instance& predicted,
unsigned count) unsigned count)
{ {
char opcode; char opcode;
@ -158,13 +158,15 @@ namespace
buf2[1] = (count - bias) >> 8; buf2[1] = (count - bias) >> 8;
buf2[2] = (count - bias); buf2[2] = (count - bias);
memcpy(buf1 + (RRDATA_BYTES - j + 1), buf2 + (3 - (opcode >> 5)), opcode >> 5); memcpy(buf1 + (RRDATA_BYTES - j + 1), buf2 + (3 - (opcode >> 5)), opcode >> 5);
strm.write(buf1, (RRDATA_BYTES - j + 1) + (opcode >> 5)); for(size_t s = 0; s < (RRDATA_BYTES - j + 1) + (opcode >> 5); s++)
strm.push_back(buf1[s]);
//std::cerr << "Encoding " << count << " symbols starting from " << base << std::endl; //std::cerr << "Encoding " << count << " symbols starting from " << base << std::endl;
} }
} }
uint64_t rrdata::write(std::ostream& strm) throw(std::bad_alloc) uint64_t rrdata::write(std::vector<char>& strm) throw(std::bad_alloc)
{ {
strm.clear();
uint64_t count = 0; uint64_t count = 0;
instance last_encode_end; instance last_encode_end;
memset(last_encode_end.bytes, 0, RRDATA_BYTES); memset(last_encode_end.bytes, 0, RRDATA_BYTES);
@ -194,28 +196,33 @@ uint64_t rrdata::write(std::ostream& strm) throw(std::bad_alloc)
} }
if(encode_count > 0) if(encode_count > 0)
flush_symbol(strm, encode_base, last_encode_end, encode_count); flush_symbol(strm, encode_base, last_encode_end, encode_count);
return count; if(count)
return count - 1;
else
return 0;
} }
uint64_t rrdata::read(std::istream& strm) throw(std::bad_alloc) uint64_t rrdata::read(std::vector<char>& strm, bool dummy) throw(std::bad_alloc)
{ {
uint64_t count = 0; uint64_t count = 0;
instance decoding; instance decoding;
uint64_t ptr = 0;
memset(decoding.bytes, 0, RRDATA_BYTES); memset(decoding.bytes, 0, RRDATA_BYTES);
while(strm) { while(ptr < strm.size()) {
char opcode; char opcode;
char buf1[RRDATA_BYTES]; char buf1[RRDATA_BYTES];
char buf2[3]; char buf2[3];
strm.read(&opcode, 1); opcode = strm[ptr++];
if(!strm)
continue;
unsigned validbytes = (opcode & 0x1F); unsigned validbytes = (opcode & 0x1F);
unsigned lengthbytes = (opcode & 0x60) >> 5; unsigned lengthbytes = (opcode & 0x60) >> 5;
unsigned repeat = 1; unsigned repeat = 1;
strm.read(buf1, RRDATA_BYTES - validbytes); memcpy(buf1, &strm[ptr], RRDATA_BYTES - validbytes);
ptr += (RRDATA_BYTES - validbytes);
memcpy(decoding.bytes + validbytes, buf1, RRDATA_BYTES - validbytes); memcpy(decoding.bytes + validbytes, buf1, RRDATA_BYTES - validbytes);
if(lengthbytes > 0) if(lengthbytes > 0) {
strm.read(buf2, lengthbytes); memcpy(buf2, &strm[ptr], lengthbytes);
ptr += lengthbytes;
}
if(lengthbytes == 1) if(lengthbytes == 1)
repeat = 2 + buf2[0]; repeat = 2 + buf2[0];
if(lengthbytes == 2) if(lengthbytes == 2)
@ -224,11 +231,20 @@ uint64_t rrdata::read(std::istream& strm) throw(std::bad_alloc)
repeat = 65794 + static_cast<unsigned>(buf2[0]) * 65536 + static_cast<unsigned>(buf2[1]) * repeat = 65794 + static_cast<unsigned>(buf2[0]) * 65536 + static_cast<unsigned>(buf2[1]) *
256 + buf2[2]; 256 + buf2[2];
//std::cerr << "Decoding " << count << " symbols starting from " << decoding << std::endl; //std::cerr << "Decoding " << count << " symbols starting from " << decoding << std::endl;
if(!dummy)
for(unsigned i = 0; i < repeat; i++) for(unsigned i = 0; i < repeat; i++)
rrdata::add(decoding++); rrdata::add(decoding++);
count += repeat; count += repeat;
} }
return count; if(count)
return count - 1;
else
return 0;
}
uint64_t rrdata::count(std::vector<char>& strm) throw(std::bad_alloc)
{
return read(strm, true);
} }
const char* hexes = "0123456789ABCDEF"; const char* hexes = "0123456789ABCDEF";

View file

@ -4,6 +4,7 @@
#define RRDATA_BYTES 32 #define RRDATA_BYTES 32
#include <cstdint> #include <cstdint>
#include <stdexcept> #include <stdexcept>
#include <vector>
/** /**
* Set of load IDs * Set of load IDs
@ -90,17 +91,27 @@ public:
* Write compressed representation of current load ID set to stream. * Write compressed representation of current load ID set to stream.
* *
* parameter strm: The stream to write to. * parameter strm: The stream to write to.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory. * throws std::bad_alloc: Not enough memory.
*/ */
static uint64_t write(std::ostream& strm) throw(std::bad_alloc); static uint64_t write(std::vector<char>& strm) throw(std::bad_alloc);
/** /**
* Load compressed representation of load ID set from stream and union it with current set to form new current * Load compressed representation of load ID set from stream and union it with current set to form new current
* set. * set.
* *
* parameter strm: The stream to read from. * parameter strm: The stream to read from.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory. * throws std::bad_alloc: Not enough memory.
*/ */
static uint64_t read(std::istream& strm) throw(std::bad_alloc); static uint64_t read(std::vector<char>& strm, bool dummy = false) throw(std::bad_alloc);
/**
* Load compressed representation of load ID set from stream, but don't do anything to it.
*
* parameter strm: The stream to read from.
* returns: Rerecord count.
* throws std::bad_alloc: Not enough memory.
*/
static uint64_t count(std::vector<char>& strm) throw(std::bad_alloc);
/** /**
* Internal pointer used by add_internal. * Internal pointer used by add_internal.
*/ */