2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
// FastNBT.h
|
|
|
|
|
|
|
|
// Interfaces to the fast NBT parser and writer
|
|
|
|
|
|
|
|
/*
|
|
|
|
The fast parser parses the data into a vector of cFastNBTTag structures. These structures describe the NBT tree,
|
2014-07-17 16:50:58 -04:00
|
|
|
but themselves are allocated in a vector, thus minimizing reallocation.
|
2012-06-14 09:06:06 -04:00
|
|
|
The structures have a minimal constructor, setting all member "pointers" to "invalid".
|
|
|
|
|
|
|
|
The fast writer doesn't need a NBT tree structure built beforehand, it is commanded to open, append and close tags
|
2014-07-17 16:50:58 -04:00
|
|
|
(just like XML); it keeps the internal tag stack and reports errors in usage.
|
2012-06-14 09:06:06 -04:00
|
|
|
It directly outputs a string containing the serialized NBT data.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
2017-07-30 12:55:19 -04:00
|
|
|
#include <system_error>
|
2012-09-23 16:22:46 -04:00
|
|
|
#include "../Endianness.h"
|
2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
enum eTagType
|
|
|
|
{
|
|
|
|
TAG_Min = 0, // The minimum value for a tag type
|
|
|
|
TAG_End = 0,
|
|
|
|
TAG_Byte = 1,
|
|
|
|
TAG_Short = 2,
|
|
|
|
TAG_Int = 3,
|
|
|
|
TAG_Long = 4,
|
|
|
|
TAG_Float = 5,
|
|
|
|
TAG_Double = 6,
|
|
|
|
TAG_ByteArray = 7,
|
|
|
|
TAG_String = 8,
|
|
|
|
TAG_List = 9,
|
|
|
|
TAG_Compound = 10,
|
|
|
|
TAG_IntArray = 11,
|
|
|
|
TAG_Max = 11, // The maximum value for a tag type
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** This structure is used for all NBT tags.
|
|
|
|
It contains indices to the parent array of tags, building the NBT tree this way.
|
|
|
|
Also contains indices into the data stream being parsed, used for values;
|
|
|
|
NO dynamically allocated memory is used!
|
|
|
|
Structure (all with the tree structure it describes) supports moving in memory (std::vector reallocation)
|
|
|
|
*/
|
|
|
|
struct cFastNBTTag
|
|
|
|
{
|
|
|
|
public:
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
eTagType m_Type;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
// The following members are indices into the data stream. m_DataLength == 0 if no data available
|
|
|
|
// They must not be pointers, because the datastream may be copied into another AString object in the meantime.
|
2014-05-09 13:33:22 -04:00
|
|
|
size_t m_NameStart;
|
|
|
|
size_t m_NameLength;
|
|
|
|
size_t m_DataStart;
|
|
|
|
size_t m_DataLength;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
// The following members are indices into the array returned; -1 if not valid
|
|
|
|
// They must not be pointers, because pointers would not survive std::vector reallocation
|
|
|
|
int m_Parent;
|
|
|
|
int m_PrevSibling;
|
|
|
|
int m_NextSibling;
|
|
|
|
int m_FirstChild;
|
|
|
|
int m_LastChild;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
cFastNBTTag(eTagType a_Type, int a_Parent) :
|
|
|
|
m_Type(a_Type),
|
2014-08-21 16:39:53 -04:00
|
|
|
m_NameStart(0),
|
2012-06-14 09:06:06 -04:00
|
|
|
m_NameLength(0),
|
2014-08-21 16:39:53 -04:00
|
|
|
m_DataStart(0),
|
2012-06-14 09:06:06 -04:00
|
|
|
m_DataLength(0),
|
|
|
|
m_Parent(a_Parent),
|
|
|
|
m_PrevSibling(-1),
|
|
|
|
m_NextSibling(-1),
|
|
|
|
m_FirstChild(-1),
|
|
|
|
m_LastChild(-1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
cFastNBTTag(eTagType a_Type, int a_Parent, int a_PrevSibling) :
|
|
|
|
m_Type(a_Type),
|
2014-08-21 16:39:53 -04:00
|
|
|
m_NameStart(0),
|
2012-06-14 09:06:06 -04:00
|
|
|
m_NameLength(0),
|
2014-08-21 16:39:53 -04:00
|
|
|
m_DataStart(0),
|
2012-06-14 09:06:06 -04:00
|
|
|
m_DataLength(0),
|
|
|
|
m_Parent(a_Parent),
|
|
|
|
m_PrevSibling(a_PrevSibling),
|
|
|
|
m_NextSibling(-1),
|
|
|
|
m_FirstChild(-1),
|
|
|
|
m_LastChild(-1)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-07-30 12:55:19 -04:00
|
|
|
enum class eNBTParseError
|
|
|
|
{
|
|
|
|
npSuccess = 0,
|
|
|
|
npNeedBytes,
|
|
|
|
npNoTopLevelCompound,
|
|
|
|
npCompoundImbalancedTag,
|
|
|
|
npStringMissingLength,
|
|
|
|
npStringInvalidLength,
|
|
|
|
npListMissingType,
|
|
|
|
npListMissingLength,
|
|
|
|
npListInvalidLength,
|
|
|
|
npSimpleMissing,
|
|
|
|
npArrayMissingLength,
|
|
|
|
npArrayInvalidLength,
|
|
|
|
npUnknownTag,
|
|
|
|
};
|
|
|
|
|
|
|
|
// The following is required to make an error_code constructible from an eNBTParseError
|
2020-05-10 12:16:38 -04:00
|
|
|
std::error_code make_error_code(eNBTParseError a_Err) noexcept;
|
2017-07-30 12:55:19 -04:00
|
|
|
|
|
|
|
namespace std
|
|
|
|
{
|
|
|
|
template <>
|
|
|
|
struct is_error_code_enum<eNBTParseError>:
|
|
|
|
public std::true_type
|
|
|
|
{
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
/** Parses and contains the parsed data
|
|
|
|
Also implements data accessor functions for tree traversal and value getters
|
|
|
|
The data pointer passed in the constructor is assumed to be valid throughout the object's life. Care must be taken not to initialize from a temporary.
|
2014-03-02 02:22:27 -05:00
|
|
|
The parser decomposes the input data into a tree of tags that is stored as an array of cFastNBTTag items,
|
|
|
|
and accessing the tree is done by using the array indices for tags. Each tag stores the indices for its parent,
|
|
|
|
first child, last child, prev sibling and next sibling, a value of -1 indicates that the indice is not valid.
|
|
|
|
Each primitive tag also stores the length of the contained data, in bytes.
|
2012-06-14 09:06:06 -04:00
|
|
|
*/
|
|
|
|
class cParsedNBT
|
|
|
|
{
|
|
|
|
public:
|
2021-01-11 11:39:43 -05:00
|
|
|
cParsedNBT(ContiguousByteBufferView a_Data);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2017-07-30 12:55:19 -04:00
|
|
|
bool IsValid(void) const { return (m_Error == eNBTParseError::npSuccess); }
|
|
|
|
|
|
|
|
/** Returns the error code for the parsing of the NBT data. */
|
|
|
|
std::error_code GetErrorCode() const { return m_Error; }
|
|
|
|
|
|
|
|
/** Returns the position where an error occurred while parsing. */
|
|
|
|
size_t GetErrorPos() const { return m_Pos; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the root tag of the hierarchy. */
|
2017-07-30 12:55:19 -04:00
|
|
|
int GetRoot(void) const { return 0; }
|
2014-03-02 02:22:27 -05:00
|
|
|
|
|
|
|
/** Returns the first child of the specified tag, or -1 if none / not applicable. */
|
2015-07-09 13:15:37 -04:00
|
|
|
int GetFirstChild (int a_Tag) const { return m_Tags[static_cast<size_t>(a_Tag)].m_FirstChild; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the last child of the specified tag, or -1 if none / not applicable. */
|
2015-07-09 13:15:37 -04:00
|
|
|
int GetLastChild (int a_Tag) const { return m_Tags[static_cast<size_t>(a_Tag)].m_LastChild; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the next sibling of the specified tag, or -1 if none. */
|
2015-07-09 13:15:37 -04:00
|
|
|
int GetNextSibling(int a_Tag) const { return m_Tags[static_cast<size_t>(a_Tag)].m_NextSibling; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the previous sibling of the specified tag, or -1 if none. */
|
2015-07-09 13:15:37 -04:00
|
|
|
int GetPrevSibling(int a_Tag) const { return m_Tags[static_cast<size_t>(a_Tag)].m_PrevSibling; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the length of the tag's data, in bytes.
|
|
|
|
Not valid for Compound or List tags! */
|
2021-01-11 11:39:43 -05:00
|
|
|
size_t GetDataLength(int a_Tag) const
|
2014-03-02 02:22:27 -05:00
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type != TAG_List);
|
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type != TAG_Compound);
|
|
|
|
return m_Tags[static_cast<size_t>(a_Tag)].m_DataLength;
|
2014-03-02 02:22:27 -05:00
|
|
|
}
|
2012-06-14 09:06:06 -04:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the data stored in this tag.
|
|
|
|
Not valid for Compound or List tags! */
|
2021-01-11 11:39:43 -05:00
|
|
|
const std::byte * GetData(int a_Tag) const
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type != TAG_List);
|
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type != TAG_Compound);
|
2021-01-11 11:39:43 -05:00
|
|
|
return m_Data.data() + m_Tags[static_cast<size_t>(a_Tag)].m_DataStart;
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the direct child tag of the specified name, or -1 if no such tag. */
|
2012-06-14 09:06:06 -04:00
|
|
|
int FindChildByName(int a_Tag, const AString & a_Name) const
|
|
|
|
{
|
|
|
|
return FindChildByName(a_Tag, a_Name.c_str(), a_Name.length());
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the direct child tag of the specified name, or -1 if no such tag. */
|
2012-06-14 09:06:06 -04:00
|
|
|
int FindChildByName(int a_Tag, const char * a_Name, size_t a_NameLength = 0) const;
|
2014-03-02 02:22:27 -05:00
|
|
|
|
2015-05-09 03:25:09 -04:00
|
|
|
/** Returns the child tag of the specified path (Name1 / Name2 / Name3...), or -1 if no such tag. */
|
2014-03-02 02:22:27 -05:00
|
|
|
int FindTagByPath(int a_Tag, const AString & a_Path) const;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2015-07-09 13:15:37 -04:00
|
|
|
eTagType GetType(int a_Tag) const { return m_Tags[static_cast<size_t>(a_Tag)].m_Type; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the children type for a List tag; undefined on other tags. If list empty, returns TAG_End. */
|
2012-06-14 09:06:06 -04:00
|
|
|
eTagType GetChildrenType(int a_Tag) const
|
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_List);
|
|
|
|
return (m_Tags[static_cast<size_t>(a_Tag)].m_FirstChild < 0) ? TAG_End : m_Tags[static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_FirstChild)].m_Type;
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a Byte tag. Not valid for any other tag type. */
|
2014-07-17 16:50:58 -04:00
|
|
|
inline unsigned char GetByte(int a_Tag) const
|
2012-06-14 09:06:06 -04:00
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Byte);
|
|
|
|
return static_cast<unsigned char>(m_Data[static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_DataStart)]);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a Short tag. Not valid for any other tag type. */
|
2012-06-14 09:06:06 -04:00
|
|
|
inline Int16 GetShort(int a_Tag) const
|
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Short);
|
2021-01-11 11:39:43 -05:00
|
|
|
return GetBEShort(GetData(a_Tag));
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in an Int tag. Not valid for any other tag type. */
|
2012-06-14 09:06:06 -04:00
|
|
|
inline Int32 GetInt(int a_Tag) const
|
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Int);
|
2021-01-11 11:39:43 -05:00
|
|
|
return GetBEInt(GetData(a_Tag));
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a Long tag. Not valid for any other tag type. */
|
2012-06-14 09:06:06 -04:00
|
|
|
inline Int64 GetLong(int a_Tag) const
|
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Long);
|
2021-01-11 11:39:43 -05:00
|
|
|
return NetworkToHostLong8(GetData(a_Tag));
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a Float tag. Not valid for any other tag type. */
|
2012-06-14 09:06:06 -04:00
|
|
|
inline float GetFloat(int a_Tag) const
|
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Float);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-28 02:31:35 -05:00
|
|
|
// Cause a compile-time error if sizeof(float) != 4
|
|
|
|
// If your platform produces a compiler error here, you'll need to add code that manually decodes 32-bit floats
|
2014-02-28 20:43:35 -05:00
|
|
|
char Check1[5 - sizeof(float)]; // Fails if sizeof(float) > 4
|
|
|
|
char Check2[sizeof(float) - 3]; // Fails if sizeof(float) < 4
|
2014-09-26 16:53:11 -04:00
|
|
|
UNUSED_VAR(Check1);
|
|
|
|
UNUSED_VAR(Check2);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2021-01-11 11:39:43 -05:00
|
|
|
Int32 i = GetBEInt(GetData(a_Tag));
|
2014-02-26 16:17:28 -05:00
|
|
|
float f;
|
|
|
|
memcpy(&f, &i, sizeof(f));
|
|
|
|
return f;
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a Double tag. Not valid for any other tag type. */
|
2012-06-14 09:06:06 -04:00
|
|
|
inline double GetDouble(int a_Tag) const
|
|
|
|
{
|
2014-03-02 02:22:27 -05:00
|
|
|
// Cause a compile-time error if sizeof(double) != 8
|
|
|
|
// If your platform produces a compiler error here, you'll need to add code that manually decodes 64-bit doubles
|
|
|
|
char Check1[9 - sizeof(double)]; // Fails if sizeof(double) > 8
|
|
|
|
char Check2[sizeof(double) - 7]; // Fails if sizeof(double) < 8
|
2014-09-26 16:53:11 -04:00
|
|
|
UNUSED_VAR(Check1);
|
|
|
|
UNUSED_VAR(Check2);
|
2014-03-02 02:22:27 -05:00
|
|
|
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_Double);
|
2021-01-11 11:39:43 -05:00
|
|
|
return NetworkToHostDouble8(GetData(a_Tag));
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the value stored in a String tag. Not valid for any other tag type. */
|
2012-06-15 16:58:52 -04:00
|
|
|
inline AString GetString(int a_Tag) const
|
2021-01-11 11:39:43 -05:00
|
|
|
{
|
|
|
|
return AString(GetStringView(a_Tag));
|
|
|
|
}
|
|
|
|
|
|
|
|
/** Returns the value stored in a String tag. Not valid for any other tag type. */
|
|
|
|
inline std::string_view GetStringView(int a_Tag) const
|
2012-06-15 16:58:52 -04:00
|
|
|
{
|
2015-07-09 13:15:37 -04:00
|
|
|
ASSERT(m_Tags[static_cast<size_t>(a_Tag)].m_Type == TAG_String);
|
2021-01-11 11:39:43 -05:00
|
|
|
return { reinterpret_cast<const char *>(GetData(a_Tag)), GetDataLength(a_Tag) };
|
2012-06-15 16:58:52 -04:00
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-03-02 02:22:27 -05:00
|
|
|
/** Returns the tag's name. For tags that are not named, returns an empty string. */
|
2013-05-01 13:00:05 -04:00
|
|
|
inline AString GetName(int a_Tag) const
|
|
|
|
{
|
|
|
|
AString res;
|
2021-01-11 11:39:43 -05:00
|
|
|
res.assign(reinterpret_cast<const char *>(m_Data.data()) + m_Tags[static_cast<size_t>(a_Tag)].m_NameStart, static_cast<size_t>(m_Tags[static_cast<size_t>(a_Tag)].m_NameLength));
|
2013-05-01 13:00:05 -04:00
|
|
|
return res;
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
protected:
|
2021-01-11 11:39:43 -05:00
|
|
|
|
|
|
|
ContiguousByteBufferView m_Data;
|
2012-06-14 09:06:06 -04:00
|
|
|
std::vector<cFastNBTTag> m_Tags;
|
2017-07-30 12:55:19 -04:00
|
|
|
eNBTParseError m_Error; // npSuccess if parsing succeeded
|
2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
// Used while parsing:
|
2014-05-09 13:33:22 -04:00
|
|
|
size_t m_Pos;
|
2012-06-14 09:06:06 -04:00
|
|
|
|
2017-07-30 12:55:19 -04:00
|
|
|
eNBTParseError Parse(void);
|
|
|
|
eNBTParseError ReadString(size_t & a_StringStart, size_t & a_StringLen); // Reads a simple string (2 bytes length + data), sets the string descriptors
|
|
|
|
eNBTParseError ReadCompound(void); // Reads the latest tag as a compound
|
|
|
|
eNBTParseError ReadList(eTagType a_ChildrenType); // Reads the latest tag as a list of items of type a_ChildrenType
|
|
|
|
eNBTParseError ReadTag(void); // Reads the latest tag, depending on its m_Type setting
|
2020-04-30 02:44:49 -04:00
|
|
|
|
|
|
|
/** Returns the minimum size, in bytes, of the specified tag type.
|
|
|
|
Used for sanity-checking. */
|
|
|
|
static size_t GetMinTagSize(eTagType a_TagType);
|
2012-06-14 09:06:06 -04:00
|
|
|
} ;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class cFastNBTWriter
|
|
|
|
{
|
|
|
|
public:
|
2013-02-07 05:09:42 -05:00
|
|
|
cFastNBTWriter(const AString & a_RootTagName = "");
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
void BeginCompound(const AString & a_Name);
|
|
|
|
void EndCompound(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
void BeginList(const AString & a_Name, eTagType a_ChildrenType);
|
|
|
|
void EndList(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
void AddByte (const AString & a_Name, unsigned char a_Value);
|
|
|
|
void AddShort (const AString & a_Name, Int16 a_Value);
|
|
|
|
void AddInt (const AString & a_Name, Int32 a_Value);
|
|
|
|
void AddLong (const AString & a_Name, Int64 a_Value);
|
|
|
|
void AddFloat (const AString & a_Name, float a_Value);
|
|
|
|
void AddDouble (const AString & a_Name, double a_Value);
|
2020-08-28 16:42:18 -04:00
|
|
|
void AddString (const AString & a_Name, std::string_view a_Value);
|
2012-06-14 09:06:06 -04:00
|
|
|
void AddByteArray(const AString & a_Name, const char * a_Value, size_t a_NumElements);
|
2021-03-05 08:03:55 -05:00
|
|
|
void AddByteArray(const AString & a_Name, size_t a_NumElements, unsigned char a_Value);
|
2020-07-20 04:56:27 -04:00
|
|
|
void AddIntArray (const AString & a_Name, const Int32 * a_Value, size_t a_NumElements);
|
2012-06-14 09:06:06 -04:00
|
|
|
|
|
|
|
void AddByteArray(const AString & a_Name, const AString & a_Value)
|
|
|
|
{
|
|
|
|
AddByteArray(a_Name, a_Value.data(), a_Value.size());
|
|
|
|
}
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2021-01-11 11:39:43 -05:00
|
|
|
ContiguousByteBufferView GetResult(void) const { return m_Result; }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
void Finish(void);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
protected:
|
|
|
|
|
|
|
|
struct sParent
|
|
|
|
{
|
|
|
|
int m_Type; // TAG_Compound or TAG_List
|
|
|
|
int m_Pos; // for TAG_List, the position of the list count
|
|
|
|
int m_Count; // for TAG_List, the element count
|
2013-03-09 09:35:43 -05:00
|
|
|
eTagType m_ItemType; // for TAG_List, the element type
|
2012-06-14 09:06:06 -04:00
|
|
|
} ;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2014-02-26 18:29:14 -05:00
|
|
|
static const int MAX_STACK = 50; // Highly doubtful that an NBT would be constructed this many levels deep
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
// These two fields emulate a stack. A raw array is used due to speed issues - no reallocations are allowed.
|
|
|
|
sParent m_Stack[MAX_STACK];
|
|
|
|
int m_CurrentStack;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2021-01-11 11:39:43 -05:00
|
|
|
ContiguousByteBuffer m_Result;
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
bool IsStackTopCompound(void) const { return (m_Stack[m_CurrentStack].m_Type == TAG_Compound); }
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2021-01-11 11:39:43 -05:00
|
|
|
void WriteString(std::string_view a_Data);
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
inline void TagCommon(const AString & a_Name, eTagType a_Type)
|
|
|
|
{
|
2013-03-09 09:35:43 -05:00
|
|
|
// If we're directly inside a list, check that the list is of the correct type:
|
|
|
|
ASSERT((m_Stack[m_CurrentStack].m_Type != TAG_List) || (m_Stack[m_CurrentStack].m_ItemType == a_Type));
|
2016-02-05 16:45:45 -05:00
|
|
|
|
2012-06-14 09:06:06 -04:00
|
|
|
if (IsStackTopCompound())
|
|
|
|
{
|
|
|
|
// Compound: add the type and name:
|
2021-01-11 11:39:43 -05:00
|
|
|
m_Result.push_back(std::byte(a_Type));
|
|
|
|
WriteString(a_Name);
|
2012-06-14 09:06:06 -04:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// List: add to the counter
|
|
|
|
m_Stack[m_CurrentStack].m_Count++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} ;
|