diff --git a/coding/coding.pro b/coding/coding.pro index f54e7ff550..ccdd44f9e7 100644 --- a/coding/coding.pro +++ b/coding/coding.pro @@ -13,6 +13,7 @@ SOURCES += \ file_reader.cpp \ file_writer.cpp \ lodepng.cpp \ + file_container.cpp \ HEADERS += \ @@ -59,3 +60,4 @@ HEADERS += \ streams.hpp \ streams_sink.hpp \ streams_common.hpp \ + file_container.hpp \ diff --git a/coding/file_container.cpp b/coding/file_container.cpp new file mode 100644 index 0000000000..0d9aab407a --- /dev/null +++ b/coding/file_container.cpp @@ -0,0 +1,91 @@ +#include "../base/SRC_FIRST.hpp" + +#include "file_container.hpp" +#include "varint.hpp" + + +FilesContainerR::FilesContainerR(string const & fName) +: m_source(fName) +{ + ReaderSource src(m_source); + + uint64_t const offset = ReadVarUint(src); + src.Skip(offset); + + uint32_t const count = ReadVarUint(src); + m_info.resize(count); + + for (uint32_t i = 0; i < count; ++i) + { + uint32_t const tagSize = ReadVarUint(src); + m_info[i].m_tag.resize(tagSize); + src.Read(&m_info[i].m_tag[0], tagSize); + + m_info[i].m_offset = ReadVarUint(src); + m_info[i].m_size = ReadVarUint(src); + } +} + +FileReader FilesContainerR::GetReader(Tag const & tag) +{ + info_cont_t::const_iterator i = + lower_bound(m_info.begin(), m_info.end(), tag, less_info()); + + if (i != m_info.end() && i->m_tag == tag) + return m_source.SubReader(i->m_offset, i->m_size); + else + MYTHROW(Reader::OpenException, (tag)); +} + +FilesContainerW::FilesContainerW(string const & fName) +: m_name(fName) +{ + FileWriter writer(fName); + uint64_t skip = 0; + writer.Write(&skip, sizeof(skip)); +} + +uint64_t FilesContainerW::SaveCurrentSize() +{ + uint64_t const curr = FileReader(m_name).Size(); + if (!m_info.empty()) + m_info.back().m_size = curr - m_info.back().m_offset; + return curr; +} + +FileWriter FilesContainerW::GetWriter(Tag const & tag) +{ + uint64_t const curr = SaveCurrentSize(); + + m_info.push_back(Info(tag, curr)); + + return FileWriter(m_name, FileWriter::OP_APPEND); +} + +void FilesContainerW::Finish() +{ + uint64_t const curr = SaveCurrentSize(); + + { + FileWriter writer(m_name, FileWriter::OP_WRITE_EXISTING); + writer.Write(&curr, sizeof(curr)); + } + + FileWriter writer(m_name, FileWriter::OP_APPEND); + writer.Write(&curr, sizeof(curr)); + + sort(m_info.begin(), m_info.end(), less_info()); + + uint32_t const count = m_info.size(); + WriteVarUint(writer, count); + + for (uint32_t i = 0; i < count; ++i) + { + size_t const tagSize = m_info[i].m_tag.size(); + WriteVarUint(writer, tagSize); + writer.Write(&m_info[i].m_tag[0], tagSize); + + WriteVarUint(writer, m_info[i].m_offset); + WriteVarUint(writer, m_info[i].m_size); + } +} diff --git a/coding/file_container.hpp b/coding/file_container.hpp new file mode 100644 index 0000000000..355517c767 --- /dev/null +++ b/coding/file_container.hpp @@ -0,0 +1,70 @@ +#pragma once +#include "file_reader.hpp" +#include "file_writer.hpp" + +#include "../std/vector.hpp" +#include "../std/string.hpp" + +class FilesContainerBase +{ +protected: + + typedef string Tag; + + struct Info + { + Tag m_tag; + uint64_t m_offset; + uint64_t m_size; + + Info() {} + Info(Tag const & tag, uint64_t offset) : m_tag(tag), m_offset(offset) {} + }; + + struct less_info + { + bool operator() (Info const & t1, Info const & t2) const + { + return (t1.m_tag < t2.m_tag); + } + bool operator() (Info const & t1, Tag const & t2) const + { + return (t1.m_tag < t2); + } + bool operator() (Tag const & t1, Info const & t2) const + { + return (t1 < t2.m_tag); + } + }; + + typedef vector info_cont_t; + info_cont_t m_info; +}; + +class FilesContainerR : public FilesContainerBase +{ + typedef public FilesContainerBase base_type; + + FileReader m_source; + +public: + FilesContainerR(string const & fName); + + FileReader GetReader(Tag const & tag); +}; + +class FilesContainerW : public FilesContainerBase +{ + typedef public FilesContainerBase base_type; + + string m_name; + + uint64_t SaveCurrentSize(); + +public: + FilesContainerW(string const & fName); + + FileWriter GetWriter(Tag const & tag); + + void Finish(); +};