2012-09-23 18:11:08 +00:00
|
|
|
#ifndef OPENMW_ESM_WRITER_H
|
|
|
|
#define OPENMW_ESM_WRITER_H
|
2012-04-06 19:04:30 +00:00
|
|
|
|
2013-03-12 08:16:03 +00:00
|
|
|
#include <iosfwd>
|
2012-04-08 15:04:52 +00:00
|
|
|
#include <list>
|
2022-01-30 13:04:12 +00:00
|
|
|
#include <type_traits>
|
2012-04-06 19:04:30 +00:00
|
|
|
|
2022-01-22 14:58:41 +00:00
|
|
|
#include "components/esm/esmcommon.hpp"
|
2023-02-12 18:36:56 +00:00
|
|
|
#include "components/esm/refid.hpp"
|
|
|
|
|
2013-03-12 08:16:03 +00:00
|
|
|
#include "loadtes3.hpp"
|
|
|
|
|
2015-01-25 00:53:20 +00:00
|
|
|
namespace ToUTF8
|
|
|
|
{
|
|
|
|
class Utf8Encoder;
|
|
|
|
}
|
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
namespace ESM
|
|
|
|
{
|
2012-04-06 19:04:30 +00:00
|
|
|
|
|
|
|
class ESMWriter
|
|
|
|
{
|
2013-09-15 12:55:40 +00:00
|
|
|
struct RecordData
|
|
|
|
{
|
2022-04-11 22:18:39 +00:00
|
|
|
NAME name;
|
2013-09-15 12:55:40 +00:00
|
|
|
std::streampos position;
|
2014-02-22 16:31:44 +00:00
|
|
|
uint32_t size;
|
2013-09-15 12:55:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
ESMWriter();
|
|
|
|
|
|
|
|
unsigned int getVersion() const;
|
2014-06-24 22:11:25 +00:00
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
// Set various header data (Header::Data). All of the below functions must be called before writing,
|
2014-06-24 22:11:25 +00:00
|
|
|
// otherwise this data will be left uninitialized.
|
2013-09-15 12:55:40 +00:00
|
|
|
void setVersion(unsigned int ver = 0x3fa66666);
|
2014-06-24 22:11:25 +00:00
|
|
|
void setType(int type);
|
2013-09-15 12:55:40 +00:00
|
|
|
void setEncoder(ToUTF8::Utf8Encoder* encoding);
|
|
|
|
void setAuthor(const std::string& author);
|
|
|
|
void setDescription(const std::string& desc);
|
2022-05-01 12:46:47 +00:00
|
|
|
void setHeader(const Header& value) { mHeader = value; }
|
2014-06-24 22:11:25 +00:00
|
|
|
|
2014-04-28 09:29:57 +00:00
|
|
|
// Set the record count for writing it in the file header
|
2013-09-15 12:55:40 +00:00
|
|
|
void setRecordCount(int count);
|
2014-04-28 09:29:57 +00:00
|
|
|
// Counts how many records we have actually written.
|
|
|
|
// It is a good idea to compare this with the value you wrote into the header (setRecordCount)
|
|
|
|
// It should be the record count you set + 1 (1 additional record for the TES3 header)
|
2023-02-12 16:04:06 +00:00
|
|
|
int getRecordCount() const { return mRecordCount; }
|
2023-02-12 15:27:23 +00:00
|
|
|
|
|
|
|
FormatVersion getFormatVersion() const { return mHeader.mFormatVersion; }
|
2023-02-10 12:16:52 +00:00
|
|
|
void setFormatVersion(FormatVersion value);
|
2013-09-15 12:55:40 +00:00
|
|
|
|
2013-09-27 09:36:06 +00:00
|
|
|
void clearMaster();
|
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
void addMaster(const std::string& name, uint64_t size);
|
|
|
|
|
|
|
|
void save(std::ostream& file);
|
|
|
|
///< Start saving a file by writing the TES3 header.
|
|
|
|
|
|
|
|
void close();
|
|
|
|
///< \note Does not close the stream.
|
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNString(NAME name, const std::string& data);
|
|
|
|
void writeHNString(NAME name, const std::string& data, size_t size);
|
|
|
|
void writeHNCString(NAME name, const std::string& data)
|
2013-09-15 12:55:40 +00:00
|
|
|
{
|
|
|
|
startSubRecord(name);
|
|
|
|
writeHCString(data);
|
|
|
|
endRecord(name);
|
|
|
|
}
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNOString(NAME name, const std::string& data)
|
2013-09-15 12:55:40 +00:00
|
|
|
{
|
|
|
|
if (!data.empty())
|
|
|
|
writeHNString(name, data);
|
|
|
|
}
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNOCString(NAME name, const std::string& data)
|
2013-09-15 12:55:40 +00:00
|
|
|
{
|
|
|
|
if (!data.empty())
|
|
|
|
writeHNCString(name, data);
|
|
|
|
}
|
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHNRefId(NAME name, RefId value);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHNRefId(NAME name, RefId value, std::size_t size);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHNCRefId(NAME name, RefId value)
|
2023-02-12 18:36:56 +00:00
|
|
|
{
|
|
|
|
startSubRecord(name);
|
|
|
|
writeHCRefId(value);
|
|
|
|
endRecord(name);
|
|
|
|
}
|
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHNORefId(NAME name, RefId value)
|
2023-02-12 18:36:56 +00:00
|
|
|
{
|
|
|
|
if (!value.empty())
|
|
|
|
writeHNRefId(name, value);
|
|
|
|
}
|
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHNOCRefId(NAME name, RefId value)
|
2023-02-12 18:36:56 +00:00
|
|
|
{
|
|
|
|
if (!value.empty())
|
|
|
|
writeHNCRefId(name, value);
|
|
|
|
}
|
|
|
|
|
2023-02-21 22:26:40 +00:00
|
|
|
void writeCellId(const ESM::RefId& cellId);
|
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
template <typename T>
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNT(NAME name, const T& data)
|
2013-09-15 12:55:40 +00:00
|
|
|
{
|
|
|
|
startSubRecord(name);
|
|
|
|
writeT(data);
|
|
|
|
endRecord(name);
|
|
|
|
}
|
|
|
|
|
2019-10-06 11:19:55 +00:00
|
|
|
template <typename T, std::size_t size>
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNT(NAME name, const T (&data)[size])
|
2019-10-06 11:19:55 +00:00
|
|
|
{
|
|
|
|
startSubRecord(name);
|
|
|
|
writeT(data);
|
|
|
|
endRecord(name);
|
|
|
|
}
|
|
|
|
|
2014-05-14 07:17:30 +00:00
|
|
|
// Prevent using writeHNT with strings. This already happened by accident and results in
|
|
|
|
// state being discarded without any error on writing or reading it. :(
|
|
|
|
// writeHNString and friends must be used instead.
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNT(NAME name, const std::string& data) = delete;
|
2019-10-06 11:19:55 +00:00
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeT(NAME data) = delete;
|
2019-10-06 11:19:55 +00:00
|
|
|
|
|
|
|
template <typename T, std::size_t size>
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNT(NAME name, const T (&data)[size], int) = delete;
|
2014-05-14 07:17:30 +00:00
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
template <typename T>
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeHNT(NAME name, const T& data, int size)
|
2013-09-15 12:55:40 +00:00
|
|
|
{
|
|
|
|
startSubRecord(name);
|
|
|
|
writeT(data, size);
|
|
|
|
endRecord(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
void writeT(const T& data)
|
|
|
|
{
|
2022-01-30 13:04:12 +00:00
|
|
|
static_assert(!std::is_pointer_v<T>);
|
2022-07-03 11:36:32 +00:00
|
|
|
write(reinterpret_cast<const char*>(&data), sizeof(T));
|
2013-09-15 12:55:40 +00:00
|
|
|
}
|
|
|
|
|
2019-10-06 11:19:55 +00:00
|
|
|
template <typename T, std::size_t size>
|
|
|
|
void writeT(const T (&data)[size])
|
|
|
|
{
|
|
|
|
write(reinterpret_cast<const char*>(data), size * sizeof(T));
|
|
|
|
}
|
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
template <typename T>
|
|
|
|
void writeT(const T& data, size_t size)
|
|
|
|
{
|
2022-01-30 13:04:12 +00:00
|
|
|
static_assert(!std::is_pointer_v<T>);
|
2013-09-15 12:55:40 +00:00
|
|
|
write((char*)&data, size);
|
|
|
|
}
|
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
void startRecord(NAME name, uint32_t flags = 0);
|
2013-12-01 12:32:11 +00:00
|
|
|
void startRecord(uint32_t name, uint32_t flags = 0);
|
2014-05-12 19:04:02 +00:00
|
|
|
/// @note Sub-record hierarchies are not properly supported in ESMReader. This should be fixed later.
|
2022-04-11 22:18:39 +00:00
|
|
|
void startSubRecord(NAME name);
|
|
|
|
void endRecord(NAME name);
|
2013-12-01 12:32:11 +00:00
|
|
|
void endRecord(uint32_t name);
|
2023-02-12 16:03:01 +00:00
|
|
|
void writeMaybeFixedSizeString(const std::string& data, std::size_t size);
|
2013-09-15 12:55:40 +00:00
|
|
|
void writeHString(const std::string& data);
|
|
|
|
void writeHCString(const std::string& data);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeMaybeFixedSizeRefId(RefId value, std::size_t size);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHRefId(RefId refId);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2023-02-12 15:27:23 +00:00
|
|
|
void writeHCRefId(RefId refId);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2022-04-11 22:18:39 +00:00
|
|
|
void writeName(NAME data);
|
2023-02-12 18:36:56 +00:00
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
void write(const char* data, size_t size);
|
|
|
|
|
2023-04-07 00:14:32 +00:00
|
|
|
void writeFormId(const ESM::FormId&, bool wide = false, NAME tag = "FRMR");
|
|
|
|
|
2013-09-15 12:55:40 +00:00
|
|
|
private:
|
|
|
|
std::list<RecordData> mRecords;
|
|
|
|
std::ostream* mStream;
|
|
|
|
std::streampos mHeaderPos;
|
|
|
|
ToUTF8::Utf8Encoder* mEncoder;
|
|
|
|
int mRecordCount;
|
|
|
|
bool mCounting;
|
|
|
|
|
|
|
|
Header mHeader;
|
2023-02-12 15:27:23 +00:00
|
|
|
|
|
|
|
void writeRefId(RefId value);
|
2012-04-08 09:51:52 +00:00
|
|
|
};
|
2012-04-06 19:04:30 +00:00
|
|
|
}
|
2013-09-15 12:55:40 +00:00
|
|
|
|
2012-04-06 19:04:30 +00:00
|
|
|
#endif
|