diff --git a/apps/esmtool/tes4.cpp b/apps/esmtool/tes4.cpp index 3f213ff0b7..815eb6dd34 100644 --- a/apps/esmtool/tes4.cpp +++ b/apps/esmtool/tes4.cpp @@ -9,6 +9,7 @@ #include #include #include +#include namespace EsmTool { diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index cbfcece2c2..af4b8c7f14 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -80,7 +80,7 @@ add_component_dir (to_utf8 to_utf8 ) -add_component_dir(esm attr common defs esmcommon reader records util luascripts format) +add_component_dir(esm attr common defs esmcommon records util luascripts format) add_component_dir(fx pass technique lexer widgets stateupdater) diff --git a/components/esm/reader.cpp b/components/esm/reader.cpp deleted file mode 100644 index 5fafbb45ee..0000000000 --- a/components/esm/reader.cpp +++ /dev/null @@ -1,86 +0,0 @@ -#include "reader.hpp" - -//#ifdef NDEBUG -//#undef NDEBUG -//#endif - -#include -#include - -#include - -#include "components/esm3/esmreader.hpp" -#include "components/esm4/reader.hpp" - -namespace ESM -{ - Reader* Reader::getReader(const std::string &filename) - { - Files::IStreamPtr esmStream(Files::openConstrainedFileStream(filename)); - - std::uint32_t modVer = 0; // get the first 4 bytes of the record header only - esmStream->read((char*)&modVer, sizeof(modVer)); - if (esmStream->gcount() == sizeof(modVer)) - { - esmStream->seekg(0); - - if (modVer == ESM4::REC_TES4) - { - return new ESM4::Reader(std::move(esmStream), filename); - } - else - { - //return new ESM3::ESMReader(esmStream, filename); - } - } - - throw std::runtime_error("Unknown file format"); - } - - bool Reader::getStringImpl(std::string& str, std::size_t size, - std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull) - { - std::size_t newSize = size; - - if (encoder) - { - std::string input(size, '\0'); - stream.read(input.data(), size); - if (stream.gcount() == static_cast(size)) - { - encoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::FitToRequiredSize, str); - return true; - } - } - else - { - if (hasNull) - newSize -= 1; // don't read the null terminator yet - - str.resize(newSize); // assumed C++11 - stream.read(str.data(), newSize); - if (static_cast(stream.gcount()) == newSize) - { - if (hasNull) - { - char ch; - stream.read(&ch, 1); // read the null terminator - assert (ch == '\0' - && "ESM4::Reader::getString string is not terminated with a null"); - } -#if 0 - else - { - // NOTE: normal ESMs don't but omwsave has locals or spells with null terminator - assert (str[newSize - 1] != '\0' - && "ESM4::Reader::getString string is unexpectedly terminated with a null"); - } -#endif - return true; - } - } - - str.clear(); - return false; // FIXME: throw instead? - } -} diff --git a/components/esm/reader.hpp b/components/esm/reader.hpp deleted file mode 100644 index a1ddf35641..0000000000 --- a/components/esm/reader.hpp +++ /dev/null @@ -1,59 +0,0 @@ -#ifndef COMPONENT_ESM_READER_H -#define COMPONENT_ESM_READER_H - -#include - -#include - -#include "common.hpp" // MasterData - -namespace ToUTF8 -{ - class Utf8Encoder; -} - -namespace ESM -{ - class Reader - { - std::vector* mGlobalReaderList; - - public: - virtual ~Reader() {} - - static Reader* getReader(const std::string& filename); - - void setGlobalReaderList(std::vector *list) {mGlobalReaderList = list;} - std::vector *getGlobalReaderList() {return mGlobalReaderList;} - - virtual inline bool isEsm4() const = 0; - - virtual inline bool hasMoreRecs() const = 0; - - virtual inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) = 0; - - // used to check for dependencies e.g. CS::Editor::run() - virtual inline const std::vector& getGameFiles() const = 0; - - // used by ContentSelector::ContentModel::addFiles() - virtual inline const std::string getAuthor() const = 0; - virtual inline const std::string getDesc() const = 0; - virtual inline int getFormat() const = 0; - - virtual inline std::string getFileName() const = 0; - - // used by CSMWorld::Data::startLoading() and getTotalRecords() for loading progress bar - virtual inline int getRecordCount() const = 0; - - virtual void setModIndex(std::uint32_t index) = 0; - - // used by CSMWorld::Data::getTotalRecords() - virtual void close() = 0; - - protected: - bool getStringImpl(std::string& str, std::size_t size, - std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false); - }; -} - -#endif // COMPONENT_ESM_READER_H diff --git a/components/esm4/loadbptd.cpp b/components/esm4/loadbptd.cpp index 33229edd07..da40df0de9 100644 --- a/components/esm4/loadbptd.cpp +++ b/components/esm4/loadbptd.cpp @@ -28,6 +28,7 @@ #include #include // FIXME: testing only +#include #include "reader.hpp" //#include "writer.hpp" diff --git a/components/esm4/reader.cpp b/components/esm4/reader.cpp index f33fb0aed1..b7179ef125 100644 --- a/components/esm4/reader.cpp +++ b/components/esm4/reader.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include "formid.hpp" @@ -646,4 +647,51 @@ void Reader::adjustGRUPFormId() throw std::runtime_error(ss.str()); } +bool Reader::getStringImpl(std::string& str, std::size_t size, + std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull) +{ + std::size_t newSize = size; + + if (encoder) + { + std::string input(size, '\0'); + stream.read(input.data(), size); + if (stream.gcount() == static_cast(size)) + { + encoder->getUtf8(input, ToUTF8::BufferAllocationPolicy::FitToRequiredSize, str); + return true; + } + } + else + { + if (hasNull) + newSize -= 1; // don't read the null terminator yet + + str.resize(newSize); // assumed C++11 + stream.read(str.data(), newSize); + if (static_cast(stream.gcount()) == newSize) + { + if (hasNull) + { + char ch; + stream.read(&ch, 1); // read the null terminator + assert (ch == '\0' + && "ESM4::Reader::getString string is not terminated with a null"); + } +#if 0 + else + { + // NOTE: normal ESMs don't but omwsave has locals or spells with null terminator + assert (str[newSize - 1] != '\0' + && "ESM4::Reader::getString string is unexpectedly terminated with a null"); + } +#endif + return true; + } + } + + str.clear(); + return false; // FIXME: throw instead? +} + } diff --git a/components/esm4/reader.hpp b/components/esm4/reader.hpp index d4979d034a..e620cae932 100644 --- a/components/esm4/reader.hpp +++ b/components/esm4/reader.hpp @@ -30,10 +30,14 @@ #include "common.hpp" #include "loadtes4.hpp" -#include "../esm/reader.hpp" #include +namespace ToUTF8 +{ + class StatelessUtf8Encoder; +} + namespace ESM4 { // bytes read from group, updated by // getRecordHeader() in advance @@ -75,7 +79,7 @@ namespace ESM4 { ReaderContext(); }; - class Reader : public ESM::Reader + class Reader { Header mHeader; // ESM4 header @@ -107,6 +111,8 @@ namespace ESM4 { std::map mLStringIndex; + std::vector* mGlobalReaderList = nullptr; + void buildLStringIndex(const std::string& stringFile, LocalizedStringType stringType); inline bool hasLocalizedStrings() const { return (mHeader.mFlags & Rec_Localized) != 0; } @@ -126,6 +132,9 @@ namespace ESM4 { Reader() = default; + bool getStringImpl(std::string& str, std::size_t size, + std::istream& stream, const ToUTF8::StatelessUtf8Encoder* encoder, bool hasNull = false); + public: Reader(Files::IStreamPtr&& esmStream, const std::string& filename); @@ -136,22 +145,22 @@ namespace ESM4 { void open(const std::string& filename); - void close() final; + void close(); - inline bool isEsm4() const final { return true; } + inline bool isEsm4() const { return true; } - inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) final { mEncoder = encoder; }; + inline void setEncoder(const ToUTF8::StatelessUtf8Encoder* encoder) { mEncoder = encoder; }; - const std::vector& getGameFiles() const final { return mHeader.mMaster; } + const std::vector& getGameFiles() const { return mHeader.mMaster; } - inline int getRecordCount() const final { return mHeader.mData.records; } - inline const std::string getAuthor() const final { return mHeader.mAuthor; } - inline int getFormat() const final { return 0; }; // prob. not relevant for ESM4 - inline const std::string getDesc() const final { return mHeader.mDesc; } + inline int getRecordCount() const { return mHeader.mData.records; } + inline const std::string getAuthor() const { return mHeader.mAuthor; } + inline int getFormat() const { return 0; }; // prob. not relevant for ESM4 + inline const std::string getDesc() const { return mHeader.mDesc; } - inline std::string getFileName() const final { return mCtx.filename; }; // not used + inline std::string getFileName() const { return mCtx.filename; }; // not used - inline bool hasMoreRecs() const final { return (mFileSize - mCtx.fileRead) > 0; } + inline bool hasMoreRecs() const { return (mFileSize - mCtx.fileRead) > 0; } // Methods added for updating loading progress bars inline std::size_t getFileSize() const { return mFileSize; } @@ -195,7 +204,7 @@ namespace ESM4 { // The object setting up this reader needs to supply the file's load order index // so that the formId's in this file can be adjusted with the file (i.e. mod) index. - void setModIndex(std::uint32_t index) final { mCtx.modIndex = (index << 24) & 0xff000000; } + void setModIndex(std::uint32_t index) { mCtx.modIndex = (index << 24) & 0xff000000; } void updateModIndices(const std::vector& files); // Maybe should throw an exception if called when not valid? @@ -292,6 +301,10 @@ namespace ESM4 { // Used for error handling [[noreturn]] void fail(const std::string& msg); + + void setGlobalReaderList(std::vector *list) { mGlobalReaderList = list; } + + std::vector *getGlobalReaderList() { return mGlobalReaderList; } }; }