#pragma once #include "coding/endianness.hpp" #include "base/assert.hpp" #include "base/exception.hpp" #include "std/cstring.hpp" #include "std/shared_array.hpp" #include "std/shared_ptr.hpp" #include "std/string.hpp" #include "std/unique_ptr.hpp" #include "std/vector.hpp" // Base class for random-access Reader. Not thread-safe. class Reader { public: DECLARE_EXCEPTION(Exception, RootException); DECLARE_EXCEPTION(OpenException, Exception); DECLARE_EXCEPTION(SizeException, Exception); DECLARE_EXCEPTION(ReadException, Exception); DECLARE_EXCEPTION(TooManyFilesException, Exception); virtual ~Reader() {} virtual uint64_t Size() const = 0; virtual void Read(uint64_t pos, void * p, size_t size) const = 0; virtual unique_ptr CreateSubReader(uint64_t pos, uint64_t size) const = 0; void ReadAsString(string & s) const; static bool IsEqual(string const & name1, string const & name2); }; // Reader from memory. template class MemReaderTemplate : public Reader { public: // Construct from block of memory. MemReaderTemplate(void const * pData, size_t size) : m_pData(static_cast(pData)), m_size(size) { } inline uint64_t Size() const override { return m_size; } inline void Read(uint64_t pos, void * p, size_t size) const override { AssertPosAndSize(pos, size); memcpy(p, m_pData + pos, size); } inline MemReaderTemplate SubReader(uint64_t pos, uint64_t size) const { AssertPosAndSize(pos, size); return MemReaderTemplate(m_pData + pos, static_cast(size)); } inline unique_ptr CreateSubReader(uint64_t pos, uint64_t size) const override { AssertPosAndSize(pos, size); return make_unique(m_pData + pos, static_cast(size)); } private: bool GoodPosAndSize(uint64_t pos, uint64_t size) const { uint64_t const readerSize = Size(); bool const ret1 = (pos + size <= readerSize); bool const ret2 = (size <= static_cast(-1)); return ret1 && ret2; } void AssertPosAndSize(uint64_t pos, uint64_t size) const { if (WithExceptions) { if (!GoodPosAndSize(pos, size)) MYTHROW(Reader::SizeException, (pos, size, Size())); } else { ASSERT(GoodPosAndSize(pos, size), (pos, size, Size())); } } char const * m_pData; size_t m_size; }; using MemReader = MemReaderTemplate; using MemReaderWithExceptions = MemReaderTemplate; // Reader wrapper to hold the pointer to a polymorfic reader. // Common use: ReaderSource >. // Note! It takes the ownership of Reader. template class ReaderPtr { protected: shared_ptr m_p; public: template ReaderPtr(unique_ptr p) : m_p(move(p)) {} uint64_t Size() const { return m_p->Size(); } void Read(uint64_t pos, void * p, size_t size) const { m_p->Read(pos, p, size); } void ReadAsString(string & s) const { m_p->ReadAsString(s); } TReader * GetPtr() const { return m_p.get(); } }; // Model reader store file id as string. class ModelReader : public Reader { string m_name; public: ModelReader(string const & name) : m_name(name) {} virtual unique_ptr CreateSubReader(uint64_t pos, uint64_t size) const override = 0; inline string const & GetName() const { return m_name; } }; // Reader pointer class for data files. class ModelReaderPtr : public ReaderPtr { using TBase = ReaderPtr; public: template ModelReaderPtr(unique_ptr p) : TBase(move(p)) {} inline ModelReaderPtr SubReader(uint64_t pos, uint64_t size) const { return unique_ptr(static_cast(m_p->CreateSubReader(pos, size).release())); } inline string const & GetName() const { return m_p->GetName(); } }; // Source that reads from a reader. class NonOwningReaderSource { public: NonOwningReaderSource(Reader const & reader) : m_reader(reader), m_pos(0) {} void Read(void * p, size_t size) { m_reader.Read(m_pos, p, size); m_pos += size; CheckPosition(); } void Skip(uint64_t size) { m_pos += size; CheckPosition(); } uint64_t Pos() const { return m_pos; } uint64_t Size() const { CheckPosition(); return (m_reader.Size() - m_pos); } private: void CheckPosition() const { ASSERT_LESS_OR_EQUAL(m_pos, m_reader.Size(), (m_pos, m_reader.Size())); } Reader const & m_reader; uint64_t m_pos; }; // Source that reads from a reader. template class ReaderSource { public: using ReaderType = TReader; ReaderSource(TReader const & reader) : m_reader(reader), m_pos(0) {} void Read(void * p, size_t size) { m_reader.Read(m_pos, p, size); m_pos += size; } void Skip(uint64_t size) { m_pos += size; ASSERT ( AssertPosition(), () ); } uint64_t Pos() const { return m_pos; } uint64_t Size() const { ASSERT ( AssertPosition(), () ); return (m_reader.Size() - m_pos); } TReader SubReader(uint64_t size) { uint64_t const pos = m_pos; Skip(size); return m_reader.SubReader(pos, size); } TReader SubReader() { return SubReader(Size()); } private: bool AssertPosition() const { bool const ret = (m_pos <= m_reader.Size()); ASSERT ( ret, (m_pos, m_reader.Size()) ); return ret; } TReader m_reader; uint64_t m_pos; }; template inline void ReadFromPos(TReader const & reader, uint64_t pos, void * p, size_t size) { reader.Read(pos, p, size); } template inline TPrimitive ReadPrimitiveFromPos(TReader const & reader, uint64_t pos) { #ifndef OMIM_OS_LINUX static_assert(is_trivially_copyable::value, ""); #endif TPrimitive primitive; ReadFromPos(reader, pos, &primitive, sizeof(primitive)); return SwapIfBigEndian(primitive); } template TPrimitive ReadPrimitiveFromSource(TSource & source) { #ifndef OMIM_OS_LINUX static_assert(is_trivially_copyable::value, ""); #endif TPrimitive primitive; source.Read(&primitive, sizeof(primitive)); return SwapIfBigEndian(primitive); }