X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=tool%2Fpacker.cpp;fp=tool%2Fpacker.cpp;h=51b7d8f2c433e136a53d27ca2ccba3415ca047f9;hb=57d8b8c6f07808efdd1b9647d12447c177ce1e7d;hp=0000000000000000000000000000000000000000;hpb=348a6d9ca1a9b3838ff8c6da5050f61b2c74d010;p=libs%2Fdatafile.git diff --git a/tool/packer.cpp b/tool/packer.cpp new file mode 100644 index 0000000..51b7d8f --- /dev/null +++ b/tool/packer.cpp @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include "packer.h" +#include "tool.h" + +using namespace std; +using namespace Msp; + +Packer::Packer(DataTool &t): + tool(t), + tmp_file(tempfile()), + tmp_buf(new IO::Buffered(*tmp_file)), + dir_alloc(0) +{ } + +IO::File *Packer::tempfile() +{ + for(unsigned i=0;; ++i) + { + try + { + std::string filename = format("/tmp/mspdatatool.%d", i); + /*filename.reserve(25); + filename.append("/tmp/mspdatatool."); + for(unsigned i=0; i<8; ++i) + filename.append(rand());*/ + IO::File *file = new IO::File(filename, IO::M_RDWR, IO::File::C_NEW); + FS::unlink(filename); + return file; + } + catch(const IO::file_already_exists &) + { + continue; + } + } +} + +Packer::~Packer() +{ + delete tmp_buf; + delete tmp_file; +} + +void Packer::pack_file(const string &fn) +{ + if(!tmp_file) + throw logic_error("Packer::pack_file"); + + unsigned offset = tmp_file->tell(); + + IO::BufferedFile in(fn); + DataFile::Parser parser(in, fn); + + DataFile::Writer *writer = tool.create_writer(*tmp_buf); + + bool collection = FS::extpart(fn)==".mdc"; + std::list objects; + while(parser) + { + DataFile::Statement st = parser.parse(true); + if(st.valid) + { + bool sys = !st.keyword.compare(0, 2, "__"); + if(collection && !sys) + { + if(st.get_signature()=="s") + { + Object obj; + obj.name = st.args[0].get(); + obj.keyword = st.keyword; + objects.push_back(obj); + } + else + collection = false; + } + if(!sys || st.keyword=="__src") + writer->write(st); + } + } + writer->write(DataFile::Statement("__end")); + delete writer; + + tmp_buf->flush(); + unsigned length = tmp_file->tell()-offset; + + DataFile::Statement st("file"); + st.append(FS::basename(fn)); + st.sub.push_back((DataFile::Statement("slice"), offset, length)); + if(collection) + { + for(list::const_iterator i=objects.begin(); i!=objects.end(); ++i) + st.sub.push_back((DataFile::Statement("object"), i->name, i->keyword)); + dir_alloc += objects.size()*100; + } + directory.push_back(st); + dir_alloc += 100; +} + +void Packer::create_pack(const string &fn) +{ + vector dir_buffer(dir_alloc); + IO::Memory mem(&dir_buffer[0], dir_buffer.size(), IO::M_WRITE); + + unsigned base_offset = 0; + while(1) + { + mem.seek(0, IO::S_BEG); + + DataFile::Writer *writer = tool.create_writer(mem); + + for(list::const_iterator i=directory.begin(); i!=directory.end(); ++i) + writer->write(*i); + if(base_offset==0) + base_offset = mem.tell(); + writer->write((DataFile::Statement("base_offset"), base_offset)); + writer->write(DataFile::Statement("__end")); + delete writer; + + unsigned dir_size = mem.tell(); + if(dir_size<=base_offset) + break; + base_offset = dir_size; + } + + IO::File out(fn, IO::M_WRITE); + out.write(&dir_buffer[0], base_offset); + tmp_file->seek(0, IO::S_BEG); + while(!tmp_file->eof()) + { + char buf[16384]; + unsigned len = tmp_file->read(buf, sizeof(buf)); + if(!len) + break; + out.write(buf, len); + } +}