Zip: Allow output to arbitrary ostream
This commit is contained in:
parent
3ab4db9aeb
commit
1ac35c2773
4 changed files with 53 additions and 23 deletions
|
@ -8,7 +8,7 @@
|
||||||
#include "core/controllerframe.hpp"
|
#include "core/controllerframe.hpp"
|
||||||
#include "core/rom.hpp"
|
#include "core/rom.hpp"
|
||||||
#include "core/subtitles.hpp"
|
#include "core/subtitles.hpp"
|
||||||
|
#include "library/zip.hpp"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This structure gives parsed representationg of movie file, as result of decoding or for encoding.
|
* This structure gives parsed representationg of movie file, as result of decoding or for encoding.
|
||||||
|
@ -61,7 +61,10 @@ struct moviefile
|
||||||
*/
|
*/
|
||||||
void save(const std::string& filename, unsigned compression, bool binary) throw(std::bad_alloc,
|
void save(const std::string& filename, unsigned compression, bool binary) throw(std::bad_alloc,
|
||||||
std::runtime_error);
|
std::runtime_error);
|
||||||
|
/**
|
||||||
|
* Reads this movie structure and saves it to stream (uncompressed ZIP).
|
||||||
|
*/
|
||||||
|
void save(std::ostream& outstream) throw(std::bad_alloc, std::runtime_error);
|
||||||
/**
|
/**
|
||||||
* Force loading as corrupt.
|
* Force loading as corrupt.
|
||||||
*/
|
*/
|
||||||
|
@ -213,6 +216,7 @@ struct moviefile
|
||||||
private:
|
private:
|
||||||
void binary_io(std::ostream& stream) throw(std::bad_alloc, std::runtime_error);
|
void binary_io(std::ostream& stream) throw(std::bad_alloc, std::runtime_error);
|
||||||
void binary_io(std::istream& stream, struct core_type& romtype) throw(std::bad_alloc, std::runtime_error);
|
void binary_io(std::istream& stream, struct core_type& romtype) throw(std::bad_alloc, std::runtime_error);
|
||||||
|
void save(zip_writer& w) throw(std::bad_alloc, std::runtime_error);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -297,12 +298,13 @@ public:
|
||||||
* Creates new empty ZIP archive. The members will be compressed according to specified compression.
|
* Creates new empty ZIP archive. The members will be compressed according to specified compression.
|
||||||
*
|
*
|
||||||
* parameter zipfile: The zipfile to create.
|
* parameter zipfile: The zipfile to create.
|
||||||
|
* parameter stream: The stream to write the ZIP to.
|
||||||
* parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
|
* parameter _compression: Compression. 0 is uncompressed, 1-9 are deflate compression levels.
|
||||||
* throws std::bad_alloc: Not enough memory.
|
* throws std::bad_alloc: Not enough memory.
|
||||||
* throws std::runtime_error: Can't open archive or invalid argument.
|
* throws std::runtime_error: Can't open archive or invalid argument.
|
||||||
*/
|
*/
|
||||||
zip_writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
|
zip_writer(const std::string& zipfile, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
|
||||||
|
zip_writer(std::ostream& stream, unsigned _compression) throw(std::bad_alloc, std::runtime_error);
|
||||||
/**
|
/**
|
||||||
* Destroys ZIP writer, aborting the transaction (unless commit() has been called).
|
* Destroys ZIP writer, aborting the transaction (unless commit() has been called).
|
||||||
*/
|
*/
|
||||||
|
@ -347,7 +349,8 @@ private:
|
||||||
|
|
||||||
zip_writer(zip_writer&);
|
zip_writer(zip_writer&);
|
||||||
zip_writer& operator=(zip_writer&);
|
zip_writer& operator=(zip_writer&);
|
||||||
std::ofstream zipstream;
|
std::ostream* zipstream;
|
||||||
|
bool system_stream;
|
||||||
std::string temp_path;
|
std::string temp_path;
|
||||||
std::string zipfile_path;
|
std::string zipfile_path;
|
||||||
std::string open_file;
|
std::string open_file;
|
||||||
|
|
|
@ -703,6 +703,17 @@ void moviefile::save(const std::string& movie, unsigned compression, bool binary
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
zip_writer w(movie, compression);
|
zip_writer w(movie, compression);
|
||||||
|
save(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moviefile::save(std::ostream& stream) throw(std::bad_alloc, std::runtime_error)
|
||||||
|
{
|
||||||
|
zip_writer w(stream, 0);
|
||||||
|
save(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
void moviefile::save(zip_writer& w) throw(std::bad_alloc, std::runtime_error)
|
||||||
|
{
|
||||||
write_linefile(w, "gametype", gametype->get_name());
|
write_linefile(w, "gametype", gametype->get_name());
|
||||||
write_settings<zip_writer>(w, settings, gametype->get_type().get_settings(), [](zip_writer& w,
|
write_settings<zip_writer>(w, settings, gametype->get_type().get_settings(), [](zip_writer& w,
|
||||||
const std::string& name, const std::string& value) -> void {
|
const std::string& name, const std::string& value) -> void {
|
||||||
|
@ -754,7 +765,6 @@ void moviefile::save(const std::string& movie, unsigned compression, bool binary
|
||||||
write_raw_file(w, "initram." + i.first, i.second);
|
write_raw_file(w, "initram." + i.first, i.second);
|
||||||
write_authors_file(w, authors);
|
write_authors_file(w, authors);
|
||||||
write_input(w, input);
|
write_input(w, input);
|
||||||
|
|
||||||
w.commit();
|
w.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -414,16 +414,27 @@ zip_writer::zip_writer(const std::string& zipfile, unsigned _compression) throw(
|
||||||
compression = _compression;
|
compression = _compression;
|
||||||
zipfile_path = zipfile;
|
zipfile_path = zipfile;
|
||||||
temp_path = zipfile + ".tmp";
|
temp_path = zipfile + ".tmp";
|
||||||
zipstream.open(temp_path.c_str(), std::ios::binary);
|
zipstream = new std::ofstream(temp_path.c_str(), std::ios::binary);
|
||||||
if(!zipstream)
|
if(!*zipstream)
|
||||||
throw std::runtime_error("Can't open zipfile '" + temp_path + "' for writing");
|
throw std::runtime_error("Can't open zipfile '" + temp_path + "' for writing");
|
||||||
committed = false;
|
committed = false;
|
||||||
|
system_stream = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
zip_writer::zip_writer(std::ostream& stream, unsigned _compression) throw(std::bad_alloc, std::runtime_error)
|
||||||
|
{
|
||||||
|
compression = _compression;
|
||||||
|
zipstream = &stream;
|
||||||
|
committed = false;
|
||||||
|
system_stream = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
zip_writer::~zip_writer() throw()
|
zip_writer::~zip_writer() throw()
|
||||||
{
|
{
|
||||||
if(!committed)
|
if(!committed && system_stream)
|
||||||
remove(temp_path.c_str());
|
remove(temp_path.c_str());
|
||||||
|
if(system_stream)
|
||||||
|
delete zipstream;
|
||||||
}
|
}
|
||||||
|
|
||||||
void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_error)
|
void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_error)
|
||||||
|
@ -434,7 +445,7 @@ void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_e
|
||||||
throw std::logic_error("Can't commit with file open");
|
throw std::logic_error("Can't commit with file open");
|
||||||
std::vector<unsigned char> directory_entry;
|
std::vector<unsigned char> directory_entry;
|
||||||
uint32_t cdirsize = 0;
|
uint32_t cdirsize = 0;
|
||||||
uint32_t cdiroff = zipstream.tellp();
|
uint32_t cdiroff = zipstream->tellp();
|
||||||
if(cdiroff == (uint32_t)-1)
|
if(cdiroff == (uint32_t)-1)
|
||||||
throw std::runtime_error("Can't read current ZIP stream position");
|
throw std::runtime_error("Can't read current ZIP stream position");
|
||||||
for(auto i : files) {
|
for(auto i : files) {
|
||||||
|
@ -458,8 +469,8 @@ void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_e
|
||||||
write32(&directory_entry[38], 0);
|
write32(&directory_entry[38], 0);
|
||||||
write32(&directory_entry[42], i.second.offset);
|
write32(&directory_entry[42], i.second.offset);
|
||||||
memcpy(&directory_entry[46], i.first.c_str(), i.first.length());
|
memcpy(&directory_entry[46], i.first.c_str(), i.first.length());
|
||||||
zipstream.write(reinterpret_cast<char*>(&directory_entry[0]), directory_entry.size());
|
zipstream->write(reinterpret_cast<char*>(&directory_entry[0]), directory_entry.size());
|
||||||
if(!zipstream)
|
if(!*zipstream)
|
||||||
throw std::runtime_error("Failed to write central directory entry to output file");
|
throw std::runtime_error("Failed to write central directory entry to output file");
|
||||||
}
|
}
|
||||||
directory_entry.resize(22);
|
directory_entry.resize(22);
|
||||||
|
@ -471,14 +482,16 @@ void zip_writer::commit() throw(std::bad_alloc, std::logic_error, std::runtime_e
|
||||||
write32(&directory_entry[12], cdirsize);
|
write32(&directory_entry[12], cdirsize);
|
||||||
write32(&directory_entry[16], cdiroff);
|
write32(&directory_entry[16], cdiroff);
|
||||||
write16(&directory_entry[20], 0);
|
write16(&directory_entry[20], 0);
|
||||||
zipstream.write(reinterpret_cast<char*>(&directory_entry[0]), directory_entry.size());
|
zipstream->write(reinterpret_cast<char*>(&directory_entry[0]), directory_entry.size());
|
||||||
if(!zipstream)
|
if(!*zipstream)
|
||||||
throw std::runtime_error("Failed to write central directory end marker to output file");
|
throw std::runtime_error("Failed to write central directory end marker to output file");
|
||||||
zipstream.close();
|
if(system_stream) {
|
||||||
std::string backup = zipfile_path + ".backup";
|
dynamic_cast<std::ofstream*>(zipstream)->close();
|
||||||
rename_file_overwrite(zipfile_path.c_str(), backup.c_str());
|
std::string backup = zipfile_path + ".backup";
|
||||||
if(rename_file_overwrite(temp_path.c_str(), zipfile_path.c_str()) < 0)
|
rename_file_overwrite(zipfile_path.c_str(), backup.c_str());
|
||||||
throw std::runtime_error("Can't rename '" + temp_path + "' -> '" + zipfile_path + "'");
|
if(rename_file_overwrite(temp_path.c_str(), zipfile_path.c_str()) < 0)
|
||||||
|
throw std::runtime_error("Can't rename '" + temp_path + "' -> '" + zipfile_path + "'");
|
||||||
|
}
|
||||||
committed = true;
|
committed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -514,7 +527,7 @@ void zip_writer::close_file() throw(std::bad_alloc, std::logic_error, std::runti
|
||||||
crc32 = f.crc32();
|
crc32 = f.crc32();
|
||||||
delete s;
|
delete s;
|
||||||
|
|
||||||
base_offset = zipstream.tellp();
|
base_offset = zipstream->tellp();
|
||||||
if(base_offset == (uint32_t)-1)
|
if(base_offset == (uint32_t)-1)
|
||||||
throw std::runtime_error("Can't read current ZIP stream position");
|
throw std::runtime_error("Can't read current ZIP stream position");
|
||||||
unsigned char header[30];
|
unsigned char header[30];
|
||||||
|
@ -529,10 +542,10 @@ void zip_writer::close_file() throw(std::bad_alloc, std::logic_error, std::runti
|
||||||
write32(header + 18, cs);
|
write32(header + 18, cs);
|
||||||
write32(header + 22, ucs);
|
write32(header + 22, ucs);
|
||||||
write16(header + 26, open_file.length());
|
write16(header + 26, open_file.length());
|
||||||
zipstream.write(reinterpret_cast<char*>(header), 30);
|
zipstream->write(reinterpret_cast<char*>(header), 30);
|
||||||
zipstream.write(open_file.c_str(), open_file.length());
|
zipstream->write(open_file.c_str(), open_file.length());
|
||||||
zipstream.write(¤t_compressed_file[0], current_compressed_file.size());
|
zipstream->write(¤t_compressed_file[0], current_compressed_file.size());
|
||||||
if(!zipstream)
|
if(!*zipstream)
|
||||||
throw std::runtime_error("Can't write member to ZIP file");
|
throw std::runtime_error("Can't write member to ZIP file");
|
||||||
current_compressed_file.resize(0);
|
current_compressed_file.resize(0);
|
||||||
zip_file_info info;
|
zip_file_info info;
|
||||||
|
|
Loading…
Add table
Reference in a new issue