mirror of
https://github.com/AxioDL/LibCommon.git
synced 2026-03-30 11:47:23 -07:00
10a45dd4e9
Fixes cooking the majority of string tables, since some contain strings that consist of just a space.
169 lines
6.1 KiB
C++
169 lines
6.1 KiB
C++
#ifndef AXIO_CXMLWRITER_H
|
|
#define AXIO_CXMLWRITER_H
|
|
|
|
#include "Common/CFourCC.h"
|
|
#include "Common/Log.h"
|
|
#include "Common/Serialization/IArchive.h"
|
|
#include <tinyxml2.h>
|
|
|
|
class CXMLWriter : public IArchive
|
|
{
|
|
tinyxml2::XMLDocument mDoc;
|
|
tinyxml2::XMLElement *mpCurElem = nullptr;
|
|
TString mOutFilename;
|
|
const char* mpAttributeName = nullptr;
|
|
bool mSaved = false;
|
|
|
|
public:
|
|
explicit CXMLWriter(const TString& rkFileName, const TString& rkRootName, uint16_t FileVersion = 0, EGame Game = EGame::Invalid)
|
|
: mDoc(true, tinyxml2::PEDANTIC_WHITESPACE), mOutFilename(rkFileName)
|
|
{
|
|
mArchiveFlags = AF_Writer | AF_Text;
|
|
SetVersion(skCurrentArchiveVersion, FileVersion, Game);
|
|
|
|
// Create declaration and root node
|
|
tinyxml2::XMLDeclaration *pDecl = mDoc.NewDeclaration();
|
|
mDoc.LinkEndChild(pDecl);
|
|
|
|
mpCurElem = mDoc.NewElement(rkRootName.CString());
|
|
mDoc.LinkEndChild(mpCurElem);
|
|
|
|
// Write version data
|
|
SerializeVersion();
|
|
}
|
|
|
|
~CXMLWriter() override
|
|
{
|
|
if (!mSaved)
|
|
{
|
|
[[maybe_unused]] bool SaveSuccess = Save();
|
|
ASSERT(SaveSuccess);
|
|
}
|
|
}
|
|
|
|
bool Save()
|
|
{
|
|
if (mSaved)
|
|
{
|
|
NLog::Error("Attempted to save XML twice!");
|
|
return false;
|
|
}
|
|
|
|
tinyxml2::XMLError Error = mDoc.SaveFile(mOutFilename.CString());
|
|
mSaved = true;
|
|
|
|
if (Error != tinyxml2::XML_SUCCESS)
|
|
{
|
|
NLog::Error("Failed to save XML file: {}", mOutFilename);
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool IsValid() const
|
|
{
|
|
return mpCurElem != nullptr && !mSaved;
|
|
}
|
|
|
|
// Interface
|
|
bool ParamBegin(const char *pkName, uint32_t Flags) override
|
|
{
|
|
ASSERT(IsValid());
|
|
ASSERT(!mpAttributeName); // Attributes cannot have sub-children
|
|
|
|
// Read as attribute if needed
|
|
if (Flags & SH_Attribute)
|
|
{
|
|
mpAttributeName = pkName;
|
|
}
|
|
else
|
|
{
|
|
tinyxml2::XMLElement *pElem = mDoc.NewElement(pkName);
|
|
mpCurElem->LinkEndChild(pElem);
|
|
mpCurElem = pElem;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void ParamEnd() override
|
|
{
|
|
if (mpAttributeName)
|
|
{
|
|
mpAttributeName = nullptr;
|
|
}
|
|
else
|
|
{
|
|
// If we didn't save any sub parameters, remove the element.
|
|
tinyxml2::XMLElement* pParent = mpCurElem->Parent()->ToElement();
|
|
|
|
if ( mpCurElem->FirstAttribute() == nullptr
|
|
&& mpCurElem->FirstChild() == nullptr
|
|
&& mpCurElem->GetText() == nullptr )
|
|
{
|
|
pParent->DeleteChild(mpCurElem);
|
|
}
|
|
|
|
mpCurElem = pParent;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
void WriteParam(const char *pkValue)
|
|
{
|
|
if (mpAttributeName)
|
|
mpCurElem->SetAttribute(mpAttributeName, pkValue);
|
|
else
|
|
mpCurElem->SetText(pkValue);
|
|
}
|
|
|
|
public:
|
|
bool PreSerializePointer(void*& Pointer, uint32_t Flags) override
|
|
{
|
|
if (!Pointer)
|
|
{
|
|
mpCurElem->SetText("NULL");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void SerializeArraySize(uint32_t& Value) override
|
|
{
|
|
// Do nothing. Reader obtains container size from number of child elements
|
|
}
|
|
|
|
void SerializePrimitive(bool& rValue, uint32_t Flags) override { WriteParam(rValue ? "true" : "false"); }
|
|
void SerializePrimitive(char& rValue, uint32_t Flags) override { WriteParam(TString(rValue).CString()); }
|
|
void SerializePrimitive(int8_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(uint8_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(int16_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(uint16_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(int32_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(uint32_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(int64_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(uint64_t& rValue, uint32_t Flags) override { WriteParam((Flags & SH_HexDisplay) ? fmt::format("0x{:X}", rValue).c_str() : fmt::format("{}", rValue).c_str()); }
|
|
void SerializePrimitive(float& rValue, uint32_t Flags) override { WriteParam(TString::FromFloat(rValue, 1, true).CString()); }
|
|
void SerializePrimitive(double& rValue, uint32_t Flags) override { WriteParam(TString::FromFloat((float)rValue, 1, true).CString()); }
|
|
void SerializePrimitive(TString& rValue, uint32_t Flags) override { WriteParam(rValue.CString()); }
|
|
void SerializePrimitive(CFourCC& rValue, uint32_t Flags) override { WriteParam(rValue.ToString().CString()); }
|
|
void SerializePrimitive(CAssetID& rValue, uint32_t Flags) override { WriteParam(rValue.ToString(CAssetID::GameIDLength(Game())).CString()); }
|
|
|
|
void SerializeBulkData(void* pData, uint32_t Size, uint32_t Flags) override
|
|
{
|
|
char* pCharData = (char*) pData;
|
|
TString OutString(Size*2);
|
|
|
|
for (uint32_t ByteIdx = 0; ByteIdx < Size; ByteIdx++)
|
|
{
|
|
//@todo: sloooooow. maybe replace with a LUT?
|
|
sprintf(&OutString[ByteIdx*2], "%02X", pCharData[ByteIdx]);
|
|
}
|
|
|
|
WriteParam(OutString.CString());
|
|
}
|
|
};
|
|
|
|
#endif // AXIO_CXMLWRITER_H
|