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
{
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",
"Syntax: quit-emulator [/y]\nQuits emulator (/y => don't ask for confirmation).\n",
[](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.
rrdata::read_base(_movie.projectid);
rrdata::read(_movie.c_rrdata);
rrdata::add_internal();
try {
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"];
uint64_t count;
try {
rrdata::read_base(projectid);
count = rrdata::read(m);
delete &m;
} catch(...) {
delete &m;
throw;
}
out = read_raw_file(r, "rrdata");
uint64_t count = rrdata::count(out);
std::ostringstream x;
x << count;
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)
{
std::ostream& m = w.create_file("rrdata");
uint64_t count;
try {
count = rrdata::write(m);
if(!m)
throw std::runtime_error("Can't write ZIP file member");
w.close_file();
} catch(...) {
w.close_file();
throw;
}
std::vector<char> out;
count = rrdata::write(out);
write_raw_file(w, "rrdata", out);
std::ostream& m2 = w.create_file("rerecords");
try {
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;
read_linefile(r, "gamename", gamename, true);
read_linefile(r, "projectid", projectid);
rerecords = read_rrdata(r, projectid);
rerecords = read_rrdata(r, c_rrdata);
read_linefile(r, "coreversion", coreversion);
read_linefile(r, "rom.sha256", rom_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).
*/
std::vector<char> movie_state;
/**
* Compressed rrdata.
*/
std::vector<char> c_rrdata;
/**
* 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)
{
if(rrset.insert(i).second) {
if(rrset.insert(i).second && handle_open) {
//std::cerr << "New symbol: " << i << std::endl;
ohandle.write(reinterpret_cast<const char*>(i.bytes), RRDATA_BYTES);
ohandle.flush();
@ -127,7 +127,7 @@ void rrdata::add_internal() throw(std::bad_alloc)
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)
{
char opcode;
@ -158,13 +158,15 @@ namespace
buf2[1] = (count - bias) >> 8;
buf2[2] = (count - bias);
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;
}
}
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;
instance last_encode_end;
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)
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;
instance decoding;
uint64_t ptr = 0;
memset(decoding.bytes, 0, RRDATA_BYTES);
while(strm) {
while(ptr < strm.size()) {
char opcode;
char buf1[RRDATA_BYTES];
char buf2[3];
strm.read(&opcode, 1);
if(!strm)
continue;
opcode = strm[ptr++];
unsigned validbytes = (opcode & 0x1F);
unsigned lengthbytes = (opcode & 0x60) >> 5;
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);
if(lengthbytes > 0)
strm.read(buf2, lengthbytes);
if(lengthbytes > 0) {
memcpy(buf2, &strm[ptr], lengthbytes);
ptr += lengthbytes;
}
if(lengthbytes == 1)
repeat = 2 + buf2[0];
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]) *
256 + buf2[2];
//std::cerr << "Decoding " << count << " symbols starting from " << decoding << std::endl;
if(!dummy)
for(unsigned i = 0; i < repeat; i++)
rrdata::add(decoding++);
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";

View file

@ -4,6 +4,7 @@
#define RRDATA_BYTES 32
#include <cstdint>
#include <stdexcept>
#include <vector>
/**
* Set of load IDs
@ -90,17 +91,27 @@ public:
* Write compressed representation of current load ID set to stream.
*
* parameter strm: The stream to write to.
* returns: Rerecord count.
* 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
* set.
*
* parameter strm: The stream to read from.
* returns: Rerecord count.
* 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.
*/