diff --git a/apps/openmw_test_suite/CMakeLists.txt b/apps/openmw_test_suite/CMakeLists.txt index 0a487e1022..4fe4cde9d0 100644 --- a/apps/openmw_test_suite/CMakeLists.txt +++ b/apps/openmw_test_suite/CMakeLists.txt @@ -91,6 +91,7 @@ file(GLOB UNITTEST_SRC_FILES esm3/readerscache.cpp esm3/testsaveload.cpp + esm3/testesmwriter.cpp nifosg/testnifloader.cpp ) diff --git a/apps/openmw_test_suite/esm3/testesmwriter.cpp b/apps/openmw_test_suite/esm3/testesmwriter.cpp new file mode 100644 index 0000000000..7ab727bf01 --- /dev/null +++ b/apps/openmw_test_suite/esm3/testesmwriter.cpp @@ -0,0 +1,54 @@ +#include + +#include +#include + +#include +#include +#include + +namespace ESM +{ + namespace + { + using namespace ::testing; + + struct Esm3EsmWriterTest : public Test + { + std::minstd_rand mRandom; + std::uniform_int_distribution mRefIdDistribution{ 'a', 'z' }; + + std::string generateRandomString(std::size_t size) + { + std::string result; + std::generate_n( + std::back_inserter(result), size, [&] { return static_cast(mRefIdDistribution(mRandom)); }); + return result; + } + }; + + TEST_F(Esm3EsmWriterTest, saveShouldThrowExceptionOnWhenTruncatingHeaderStrings) + { + const std::string author = generateRandomString(33); + const std::string description = generateRandomString(257); + + std::stringstream stream; + + ESMWriter writer; + writer.setAuthor(author); + writer.setDescription(description); + writer.setFormatVersion(CurrentSaveGameFormatVersion); + EXPECT_THROW(writer.save(stream), std::runtime_error); + } + + TEST_F(Esm3EsmWriterTest, writeFixedStringShouldThrowExceptionOnTruncate) + { + std::stringstream stream; + + ESMWriter writer; + writer.setFormatVersion(CurrentSaveGameFormatVersion); + writer.save(stream); + EXPECT_THROW(writer.writeFixedSizeString(generateRandomString(33), 32), std::runtime_error); + } + } +} diff --git a/components/esm3/esmwriter.cpp b/components/esm3/esmwriter.cpp index b03b5bceb3..32fd2b0c86 100644 --- a/components/esm3/esmwriter.cpp +++ b/components/esm3/esmwriter.cpp @@ -167,11 +167,14 @@ namespace ESM endRecord(name); } - void ESMWriter::writeFixedSizeString(const std::string& data, int size) + void ESMWriter::writeFixedSizeString(const std::string& data, std::size_t size) { std::string string; if (!data.empty()) string = mEncoder ? mEncoder->getLegacyEnc(data) : data; + if (string.size() > size) + throw std::runtime_error("Fixed string data is too long: \"" + string + "\" (" + + std::to_string(string.size()) + " > " + std::to_string(size) + ")"); string.resize(size); write(string.c_str(), string.size()); } diff --git a/components/esm3/esmwriter.hpp b/components/esm3/esmwriter.hpp index c629685eba..d6b3a630ad 100644 --- a/components/esm3/esmwriter.hpp +++ b/components/esm3/esmwriter.hpp @@ -136,7 +136,7 @@ namespace ESM void startSubRecord(NAME name); void endRecord(NAME name); void endRecord(uint32_t name); - void writeFixedSizeString(const std::string& data, int size); + void writeFixedSizeString(const std::string& data, std::size_t size); void writeHString(const std::string& data); void writeHCString(const std::string& data); void writeName(NAME data);