Refactor some generic reading/writing routines out of moviefile.cpp

This commit is contained in:
Ilari Liusvaara 2014-01-31 05:20:52 +02:00
parent 2e4502896f
commit a2407c4e79
6 changed files with 276 additions and 210 deletions

View file

@ -17,6 +17,7 @@
#include <list>
#include <set>
#include "json.hpp"
#include "binarystream.hpp"
/**
* Memory to allocate for controller frame.
@ -1173,6 +1174,27 @@ public:
* Get content of given page.
*/
const unsigned char* get_page_buffer(size_t page) const { return pages.find(page)->second.content; }
/**
* Get binary save size.
*
* Returns: The number of bytes for binary save.
*/
uint64_t binary_size() const throw();
/**
* Save in binary form.
*
* Parameter stream: The stream to save to.
* Throws std::runtime_error: Error saving.
*/
void save_binary(binarystream::output& stream) const throw(std::runtime_error);
/**
* Load from binary form. May partially overwrite on failure.
*
* Parameter stream: The stream to load from.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Error saving.
*/
void load_binary(binarystream::input& stream) throw(std::bad_alloc, std::runtime_error);
/**
* Check that the movies are compatible up to a point.
*

View file

@ -9,6 +9,7 @@
#include <fstream>
#include <sstream>
#include <zlib.h>
#include "string.hpp"
namespace zip
{
@ -232,6 +233,48 @@ public:
* throws std::runtime_error: The specified member does not exist
*/
std::istream& operator[](const std::string& name) throw(std::bad_alloc, std::runtime_error);
/**
* Reads a file consisting of single line.
*
* Parameter member: Name of the member to read.
* Parameter out: String to write the output to.
* Parameter conditional: If true and the file does not exist, return false instead of throwing.
* Returns: True on success, false on failure.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Error reading file.
*/
bool read_linefile(const std::string& member, std::string& out, bool conditional = false)
throw(std::bad_alloc, std::runtime_error);
/**
* Read a raw file.
*
* Parameter member: Name of the member to read.
* Parameter out: Buffer to write the output to.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Error reading file.
*/
void read_raw_file(const std::string& member, std::vector<char>& out) throw(std::bad_alloc,
std::runtime_error);
/**
* Reads a file consisting of single numeric constant.
*
* Parameter member: Name of the member to read.
* Parameter out: The output value.
* Parameter conditional: If true and the file does not exist, return false instead of throwing.
* Returns: True on success, false on failure.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Error reading file.
*/
template<typename T>
bool read_numeric_file(const std::string& member, T& out, bool conditional = false)
throw(std::bad_alloc, std::runtime_error)
{
std::string _out;
if(!read_linefile(member, _out, conditional))
return false;
out = parse_value<T>(_out);
return true;
}
private:
reader(reader&);
reader& operator=(reader&);
@ -341,6 +384,40 @@ public:
* throws std::runtime_error: Error from operating system.
*/
void close_file() throw(std::bad_alloc, std::logic_error, std::runtime_error);
/**
* Write a file consisting of single line. No existing member may be open.
*
* Parameter member: The name of the member.
* Parameter value: The value to write.
* Parameter conditional: If true and the value is empty, skip the write.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Error from operating system.
*/
void write_linefile(const std::string& member, const std::string& value, bool conditional = false)
throw(std::bad_alloc, std::runtime_error);
/**
* Write a raw file. No existing member may be open.
*
* Parameter member: The name of the member.
* Parameter content: The contents for the file.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Error from operating system.
*/
void write_raw_file(const std::string& member, const std::vector<char>& content)
throw(std::bad_alloc, std::runtime_error);
/**
* Write a file consisting of a single number. No existing member may be open.
*
* Parameter member: The name of the member.
* Parameter value: The value to write.
* throws std::bad_alloc: Not enough memory.
* throws std::runtime_error: Error from operating system.
*/
template<typename T>
void write_numeric_file(const std::string& member, T value) throw(std::bad_alloc, std::runtime_error)
{
write_linefile(member, (stringfmt() << value).str());
}
private:
struct file_info
{

View file

@ -50,74 +50,8 @@ enum lsnes_movie_tags
TAG_ROMHINT = 0x6f715830
};
void read_linefile(zip::reader& r, const std::string& member, std::string& out, bool conditional = false)
throw(std::bad_alloc, std::runtime_error)
{
if(conditional && !r.has_member(member))
return;
std::istream& m = r[member];
try {
std::getline(m, out);
istrip_CR(out);
delete &m;
} catch(...) {
delete &m;
throw;
}
}
void write_linefile(zip::writer& w, const std::string& member, const std::string& value, bool conditional = false)
throw(std::bad_alloc, std::runtime_error)
{
if(conditional && value == "")
return;
std::ostream& m = w.create_file(member);
try {
m << value << std::endl;
w.close_file();
} catch(...) {
w.close_file();
throw;
}
}
namespace
{
void binary_read_movie(binarystream::input& in, controller_frame_vector& v)
{
uint64_t stride = v.get_stride();
uint64_t pageframes = v.get_frames_per_page();
uint64_t vsize = 0;
size_t pagenum = 0;
uint64_t pagesize = stride * pageframes;
while(in.get_left()) {
v.resize(vsize + pageframes);
unsigned char* contents = v.get_page_buffer(pagenum++);
uint64_t gcount = min(pagesize, in.get_left());
in.raw(contents, gcount);
vsize += (gcount / stride);
}
v.resize(vsize);
v.recount_frames();
}
void binary_write_movie(binarystream::output& out, controller_frame_vector& v)
{
uint64_t pages = v.get_page_count();
uint64_t stride = v.get_stride();
uint64_t pageframes = v.get_frames_per_page();
uint64_t vsize = v.size();
out.write_extension_tag(TAG_MOVIE, vsize * stride);
size_t pagenum = 0;
while(vsize > 0) {
uint64_t count = (vsize > pageframes) ? pageframes : vsize;
size_t bytes = count * stride;
unsigned char* content = v.get_page_buffer(pagenum++);
out.raw(content, bytes);
vsize -= count;
}
}
std::map<std::string, std::string> read_settings(zip::reader& r)
{
std::map<std::string, std::string> x;
@ -125,11 +59,13 @@ namespace
if(!regex_match("port[0-9]+|setting\\..+", i))
continue;
std::string s;
std::string v;
if(i.substr(0, 4) == "port")
s = i;
else
s = i.substr(8);
read_linefile(r, i, x[s], true);
if(r.read_linefile(i, v, true))
x[s] = v;
}
return x;
}
@ -198,77 +134,6 @@ namespace
}
}
template<typename T>
void read_numeric_file(zip::reader& r, const std::string& member, T& out, bool conditional = false)
throw(std::bad_alloc, std::runtime_error)
{
std::string _out;
read_linefile(r, member, _out, conditional);
if(conditional && _out == "")
return;
out = parse_value<int64_t>(_out);
}
template<typename T>
void write_numeric_file(zip::writer& w, const std::string& member, T value) throw(std::bad_alloc,
std::runtime_error)
{
std::ostringstream x;
x << value;
write_linefile(w, member, x.str());
}
void write_raw_file(zip::writer& w, const std::string& member, std::vector<char>& content) throw(std::bad_alloc,
std::runtime_error)
{
std::ostream& m = w.create_file(member);
try {
m.write(&content[0], content.size());
if(!m)
throw std::runtime_error("Can't write ZIP file member");
w.close_file();
} catch(...) {
w.close_file();
throw;
}
}
std::vector<char> read_raw_file(zip::reader& r, const std::string& member) throw(std::bad_alloc, std::runtime_error)
{
std::vector<char> out;
std::istream& m = r[member];
try {
boost::iostreams::back_insert_device<std::vector<char>> rd(out);
boost::iostreams::copy(m, rd);
delete &m;
} catch(...) {
delete &m;
throw;
}
return out;
}
uint64_t decode_uint64(unsigned char* buf)
{
return ((uint64_t)buf[0] << 56) |
((uint64_t)buf[1] << 48) |
((uint64_t)buf[2] << 40) |
((uint64_t)buf[3] << 32) |
((uint64_t)buf[4] << 24) |
((uint64_t)buf[5] << 16) |
((uint64_t)buf[6] << 8) |
((uint64_t)buf[7]);
}
uint32_t decode_uint32(unsigned char* buf)
{
return ((uint32_t)buf[0] << 24) |
((uint32_t)buf[1] << 16) |
((uint32_t)buf[2] << 8) |
((uint32_t)buf[3]);
}
void read_authors_file(zip::reader& r, std::vector<std::pair<std::string, std::string>>& authors)
throw(std::bad_alloc, std::runtime_error)
{
@ -289,7 +154,7 @@ void read_authors_file(zip::reader& r, std::vector<std::pair<std::string, std::s
std::string read_rrdata(zip::reader& r, std::vector<char>& out) throw(std::bad_alloc, std::runtime_error)
{
out = read_raw_file(r, "rrdata");
r.read_raw_file("rrdata", out);
uint64_t count = rrdata.count(out);
std::ostringstream x;
x << count;
@ -301,7 +166,7 @@ void write_rrdata(zip::writer& w) throw(std::bad_alloc, std::runtime_error)
uint64_t count;
std::vector<char> out;
count = rrdata.write(out);
write_raw_file(w, "rrdata", out);
w.write_raw_file("rrdata", out);
std::ostream& m2 = w.create_file("rerecords");
try {
m2 << count << std::endl;
@ -374,7 +239,6 @@ void read_subtitles(zip::reader& r, const std::string& file, std::map<moviefile_
delete &m;
throw;
}
}
void write_subtitles(zip::writer& w, const std::string& file, std::map<moviefile_subtiming, std::string>& x)
@ -491,29 +355,29 @@ moviefile::brief_info::brief_info(const std::string& filename)
}
zip::reader r(filename);
std::string tmp;
read_linefile(r, "systemid", tmp);
r.read_linefile("systemid", tmp);
if(tmp.substr(0, 8) != "lsnes-rr")
throw std::runtime_error("Not lsnes movie");
read_linefile(r, "gametype", sysregion);
read_linefile(r, "coreversion", corename);
read_linefile(r, "projectid", projectid);
r.read_linefile("gametype", sysregion);
r.read_linefile("coreversion", corename);
r.read_linefile("projectid", projectid);
if(r.has_member("savestate"))
read_numeric_file(r, "saveframe", current_frame);
r.read_numeric_file("saveframe", current_frame);
else
current_frame = 0;
read_numeric_file(r, "rerecords", rerecords);
read_linefile(r, "rom.sha256", hash[0], true);
read_linefile(r, "romxml.sha256", hashxml[0], true);
read_linefile(r, "rom.hint", hint[0], true);
r.read_numeric_file("rerecords", rerecords);
r.read_linefile("rom.sha256", hash[0], true);
r.read_linefile("romxml.sha256", hashxml[0], true);
r.read_linefile("rom.hint", hint[0], true);
unsigned base = 97;
if(r.has_member("slot`.sha256"))
base = 96;
for(size_t i = 1; i < ROM_SLOT_COUNT; i++) {
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << ".sha256").str(), hash[i],
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << ".sha256").str(), hash[i],
true);
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << "xml.sha256").str(),
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << "xml.sha256").str(),
hashxml[i], true);
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << ".hint").str(), hint[i],
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << ".hint").str(), hint[i],
true);
}
}
@ -600,13 +464,13 @@ moviefile::moviefile(const std::string& movie, core_type& romtype) throw(std::ba
delete &s;
}
zip::reader r(movie);
read_linefile(r, "systemid", tmp);
r.read_linefile("systemid", tmp);
if(tmp.substr(0, 8) != "lsnes-rr")
throw std::runtime_error("Not lsnes movie");
read_linefile(r, "controlsversion", tmp);
r.read_linefile("controlsversion", tmp);
if(tmp != "0")
throw std::runtime_error("Can't decode movie data");
read_linefile(r, "gametype", tmp);
r.read_linefile("gametype", tmp);
try {
gametype = &romtype.lookup_sysregion(tmp);
} catch(std::bad_alloc& e) {
@ -619,62 +483,62 @@ moviefile::moviefile(const std::string& movie, core_type& romtype) throw(std::ba
port_type_set& ports = port_type_set::make(ctrldata.ports, ctrldata.portindex());
input.clear(ports);
read_linefile(r, "gamename", gamename, true);
read_linefile(r, "projectid", projectid);
r.read_linefile("gamename", gamename, true);
r.read_linefile("projectid", projectid);
rerecords = read_rrdata(r, c_rrdata);
read_linefile(r, "coreversion", coreversion);
read_linefile(r, "rom.sha256", romimg_sha256[0], true);
read_linefile(r, "romxml.sha256", romxml_sha256[0], true);
read_linefile(r, "rom.hint", namehint[0], true);
r.read_linefile("coreversion", coreversion);
r.read_linefile("rom.sha256", romimg_sha256[0], true);
r.read_linefile("romxml.sha256", romxml_sha256[0], true);
r.read_linefile("rom.hint", namehint[0], true);
unsigned base = 97;
if(r.has_member("slot`.sha256"))
base = 96;
for(size_t i = 1; i < ROM_SLOT_COUNT; i++) {
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << ".sha256").str(), romimg_sha256[i],
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << ".sha256").str(), romimg_sha256[i],
true);
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << "xml.sha256").str(),
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << "xml.sha256").str(),
romxml_sha256[i], true);
read_linefile(r, (stringfmt() << "slot" << (char)(base + i - 1) << ".hint").str(), namehint[i],
r.read_linefile((stringfmt() << "slot" << (char)(base + i - 1) << ".hint").str(), namehint[i],
true);
}
read_subtitles(r, "subtitles", subtitles);
movie_rtc_second = DEFAULT_RTC_SECOND;
movie_rtc_subsecond = DEFAULT_RTC_SUBSECOND;
read_numeric_file(r, "starttime.second", movie_rtc_second, true);
read_numeric_file(r, "starttime.subsecond", movie_rtc_subsecond, true);
r.read_numeric_file("starttime.second", movie_rtc_second, true);
r.read_numeric_file("starttime.subsecond", movie_rtc_subsecond, true);
rtc_second = movie_rtc_second;
rtc_subsecond = movie_rtc_subsecond;
if(r.has_member("savestate.anchor"))
anchor_savestate = read_raw_file(r, "savestate.anchor");
r.read_raw_file("savestate.anchor", anchor_savestate);
if(r.has_member("savestate")) {
is_savestate = true;
read_numeric_file(r, "saveframe", save_frame, true);
read_numeric_file(r, "lagcounter", lagged_frames, true);
r.read_numeric_file("saveframe", save_frame, true);
r.read_numeric_file("lagcounter", lagged_frames, true);
read_pollcounters(r, "pollcounters", pollcounters);
if(r.has_member("hostmemory"))
host_memory = read_raw_file(r, "hostmemory");
savestate = read_raw_file(r, "savestate");
r.read_raw_file("hostmemory", host_memory);
r.read_raw_file("savestate", savestate);
for(auto name : r)
if(name.length() >= 5 && name.substr(0, 5) == "sram.")
sram[name.substr(5)] = read_raw_file(r, name);
screenshot = read_raw_file(r, "screenshot");
r.read_raw_file(name, sram[name.substr(5)]);
r.read_raw_file("screenshot", screenshot);
//If these can't be read, just use some (wrong) values.
read_numeric_file(r, "savetime.second", rtc_second, true);
read_numeric_file(r, "savetime.subsecond", rtc_subsecond, true);
r.read_numeric_file("savetime.second", rtc_second, true);
r.read_numeric_file("savetime.subsecond", rtc_subsecond, true);
uint64_t _poll_flag = 2; //Legacy behaviour is the default.
read_numeric_file(r, "pollflag", _poll_flag, true);
r.read_numeric_file("pollflag", _poll_flag, true);
poll_flag = _poll_flag;
active_macros = read_active_macros(r, "macros");
}
for(auto name : r)
if(name.length() >= 8 && name.substr(0, 8) == "initram.")
ramcontent[name.substr(8)] = read_raw_file(r, name);
r.read_raw_file(name, ramcontent[name.substr(8)]);
if(rtc_subsecond < 0 || movie_rtc_subsecond < 0)
throw std::runtime_error("Invalid RTC subsecond value");
std::string name = r.find_first();
for(auto name : r)
if(name.length() >= 10 && name.substr(0, 10) == "moviesram.")
movie_sram[name.substr(10)] = read_raw_file(r, name);
r.read_raw_file(name, movie_sram[name.substr(10)]);
read_authors_file(r, authors);
read_input(r, input, 0);
}
@ -718,55 +582,55 @@ void moviefile::save(std::ostream& stream) throw(std::bad_alloc, std::runtime_er
void moviefile::save(zip::writer& w) throw(std::bad_alloc, std::runtime_error)
{
write_linefile(w, "gametype", gametype->get_name());
w.write_linefile("gametype", gametype->get_name());
write_settings<zip::writer>(w, settings, gametype->get_type().get_settings(), [](zip::writer& w,
const std::string& name, const std::string& value) -> void {
if(regex_match("port[0-9]+", name))
write_linefile(w, name, value);
w.write_linefile(name, value);
else
write_linefile(w, "setting." + name, value);
w.write_linefile("setting." + name, value);
});
write_linefile(w, "gamename", gamename, true);
write_linefile(w, "systemid", "lsnes-rr1");
write_linefile(w, "controlsversion", "0");
w.write_linefile("gamename", gamename, true);
w.write_linefile("systemid", "lsnes-rr1");
w.write_linefile("controlsversion", "0");
coreversion = gametype->get_type().get_core_identifier();
write_linefile(w, "coreversion", coreversion);
write_linefile(w, "projectid", projectid);
w.write_linefile("coreversion", coreversion);
w.write_linefile("projectid", projectid);
write_rrdata(w);
write_linefile(w, "rom.sha256", romimg_sha256[0], true);
write_linefile(w, "romxml.sha256", romxml_sha256[0], true);
write_linefile(w, "rom.hint", namehint[0], true);
w.write_linefile("rom.sha256", romimg_sha256[0], true);
w.write_linefile("romxml.sha256", romxml_sha256[0], true);
w.write_linefile("rom.hint", namehint[0], true);
for(size_t i = 1; i < ROM_SLOT_COUNT; i++) {
write_linefile(w, (stringfmt() << "slot" << (char)(96 + i) << ".sha256").str(), romimg_sha256[i],
w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << ".sha256").str(), romimg_sha256[i],
true);
write_linefile(w, (stringfmt() << "slot" << (char)(96 + i) << "xml.sha256").str(), romxml_sha256[i],
w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << "xml.sha256").str(), romxml_sha256[i],
true);
write_linefile(w, (stringfmt() << "slot" << (char)(96 + i) << ".hint").str(), namehint[i],
w.write_linefile((stringfmt() << "slot" << (char)(96 + i) << ".hint").str(), namehint[i],
true);
}
write_subtitles(w, "subtitles", subtitles);
for(auto i : movie_sram)
write_raw_file(w, "moviesram." + i.first, i.second);
write_numeric_file(w, "starttime.second", movie_rtc_second);
write_numeric_file(w, "starttime.subsecond", movie_rtc_subsecond);
w.write_raw_file("moviesram." + i.first, i.second);
w.write_numeric_file("starttime.second", movie_rtc_second);
w.write_numeric_file("starttime.subsecond", movie_rtc_subsecond);
if(!anchor_savestate.empty())
write_raw_file(w, "savestate.anchor", anchor_savestate);
w.write_raw_file("savestate.anchor", anchor_savestate);
if(is_savestate) {
write_numeric_file(w, "saveframe", save_frame);
write_numeric_file(w, "lagcounter", lagged_frames);
w.write_numeric_file("saveframe", save_frame);
w.write_numeric_file("lagcounter", lagged_frames);
write_pollcounters(w, "pollcounters", pollcounters);
write_raw_file(w, "hostmemory", host_memory);
write_raw_file(w, "savestate", savestate);
write_raw_file(w, "screenshot", screenshot);
w.write_raw_file("hostmemory", host_memory);
w.write_raw_file("savestate", savestate);
w.write_raw_file("screenshot", screenshot);
for(auto i : sram)
write_raw_file(w, "sram." + i.first, i.second);
write_numeric_file(w, "savetime.second", rtc_second);
write_numeric_file(w, "savetime.subsecond", rtc_subsecond);
write_numeric_file(w, "pollflag", poll_flag);
w.write_raw_file("sram." + i.first, i.second);
w.write_numeric_file("savetime.second", rtc_second);
w.write_numeric_file("savetime.subsecond", rtc_subsecond);
w.write_numeric_file("pollflag", poll_flag);
write_active_macros(w, "macros", active_macros);
}
for(auto i : ramcontent)
write_raw_file(w, "initram." + i.first, i.second);
w.write_raw_file("initram." + i.first, i.second);
write_authors_file(w, authors);
write_input(w, input);
w.commit();
@ -919,7 +783,9 @@ void moviefile::binary_io(std::ostream& _stream) throw(std::bad_alloc, std::runt
});
}
binary_write_movie(out, input);
out.extension(TAG_MOVIE, [this](binarystream::output& s) {
input.save_binary(s);
}, true, input.binary_size());
}
void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std::bad_alloc, std::runtime_error)
@ -958,7 +824,7 @@ void moviefile::binary_io(std::istream& _stream, core_type& romtype) throw(std::
uint64_t n = s.number();
this->active_macros[s.string_implicit()] = n;
}},{TAG_MOVIE, [this](binarystream::input& s) {
binary_read_movie(s, input);
input.load_binary(s);
}},{TAG_MOVIE_SRAM, [this](binarystream::input& s) {
std::string a = s.string();
s.blob_implicit(this->movie_sram[a]);

View file

@ -8,7 +8,7 @@ __all__.files: $(CORES_FILES)
lua ../genfilelist.lua $^ >$@
cat $(CORES_FLAGS) >$(ALLFLAGS)
make-ports.exe: make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/controller-parse.cpp ../library/controller-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp
make-ports.exe: make-ports.cpp ../library/json.cpp ../library/utf8.cpp ../library/string.cpp ../library/controller-parse.cpp ../library/controller-data.cpp ../library/sha256.cpp ../library/assembler.cpp ../library/hex.cpp ../library/eatarg.cpp ../library/int24.cpp ../library/binarystream.cpp
$(HOSTCC) -g -std=gnu++0x -I../../include/library -o $@ $^ -lboost_regex$(HOST_BOOST_POSTFIX) -lboost_system$(HOST_BOOST_POSTFIX)
bsnes-legacy/$(ALLFILES): forcelook make-ports.exe

View file

@ -716,6 +716,45 @@ bool controller_frame_vector::compatible(controller_frame_vector& with, uint64_t
return true;
}
uint64_t controller_frame_vector::binary_size() const throw()
{
return size() * get_stride();
}
void controller_frame_vector::save_binary(binarystream::output& stream) const throw(std::runtime_error)
{
uint64_t pages = get_page_count();
uint64_t stride = get_stride();
uint64_t pageframes = get_frames_per_page();
uint64_t vsize = size();
size_t pagenum = 0;
while(vsize > 0) {
uint64_t count = (vsize > pageframes) ? pageframes : vsize;
size_t bytes = count * stride;
const unsigned char* content = get_page_buffer(pagenum++);
stream.raw(content, bytes);
vsize -= count;
}
}
void controller_frame_vector::load_binary(binarystream::input& stream) throw(std::bad_alloc, std::runtime_error)
{
uint64_t stride = get_stride();
uint64_t pageframes = get_frames_per_page();
uint64_t vsize = 0;
size_t pagenum = 0;
uint64_t pagesize = stride * pageframes;
while(stream.get_left()) {
resize(vsize + pageframes);
unsigned char* contents = get_page_buffer(pagenum++);
uint64_t gcount = min(pagesize, stream.get_left());
stream.raw(contents, gcount);
vsize += (gcount / stride);
}
resize(vsize);
recount_frames();
}
controller_frame::controller_frame() throw()
{
memset(memory, 0, sizeof(memory));

View file

@ -371,6 +371,38 @@ reader::reader(const std::string& zipfile) throw(std::bad_alloc, std::runtime_er
}
}
bool reader::read_linefile(const std::string& member, std::string& out, bool conditional)
throw(std::bad_alloc, std::runtime_error)
{
if(conditional && !has_member(member))
return false;
std::istream& m = (*this)[member];
try {
std::getline(m, out);
istrip_CR(out);
delete &m;
} catch(...) {
delete &m;
throw;
}
}
void reader::read_raw_file(const std::string& member, std::vector<char>& out) throw(std::bad_alloc,
std::runtime_error)
{
std::vector<char> _out;
std::istream& m = (*this)[member];
try {
boost::iostreams::back_insert_device<std::vector<char>> rd(_out);
boost::iostreams::copy(m, rd);
delete &m;
} catch(...) {
delete &m;
throw;
}
out = _out;
}
writer::writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error)
{
compression = _compression;
@ -519,6 +551,36 @@ void writer::close_file() throw(std::bad_alloc, std::logic_error, std::runtime_e
open_file = "";
}
void writer::write_linefile(const std::string& member, const std::string& value, bool conditional)
throw(std::bad_alloc, std::runtime_error)
{
if(conditional && value == "")
return;
std::ostream& m = create_file(member);
try {
m << value << std::endl;
close_file();
} catch(...) {
close_file();
throw;
}
}
void writer::write_raw_file(const std::string& member, const std::vector<char>& content) throw(std::bad_alloc,
std::runtime_error)
{
std::ostream& m = create_file(member);
try {
m.write(&content[0], content.size());
if(!m)
throw std::runtime_error("Can't write ZIP file member");
close_file();
} catch(...) {
close_file();
throw;
}
}
namespace
{
#if defined(_WIN32) || defined(_WIN64) || defined(TEST_WIN32_CODE)