22 #ifndef NBT_RESERVE_SIZE 23 #define NBT_RESERVE_SIZE 200 24 #endif // NBT_RESERVE_SIZE 28 #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while ((false, false)) 30 #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while (false) 41 class cNBTParseErrorCategory final :
42 public std::error_category
44 cNBTParseErrorCategory() =
default;
47 virtual const char * name()
const NOEXCEPT
override 49 return "NBT parse error";
53 virtual AString message(
int a_Condition)
const override;
56 static const cNBTParseErrorCategory & Get() NOEXCEPT
58 static cNBTParseErrorCategory Category;
67 AString cNBTParseErrorCategory::message(
int a_Condition)
const 69 switch (static_cast<eNBTParseError>(a_Condition))
73 return "Parsing succeded";
77 return "Expected more data";
81 return "No top level compound tag";
85 return "Expected a string length but had insufficient data";
89 return "String length invalid";
93 return "Compound tag was unmatched at end of file";
97 return "Expected a list type but had insuffiecient data";
101 return "Expected a list length but had insufficient data";
105 return "List length invalid";
109 return "Expected a numeric type but had insufficient data";
113 return "Expected an array length but had insufficient data";
117 return "Array length invalid";
121 return "Unknown tag";
135 return {
static_cast<int>(a_Err), cNBTParseErrorCategory::Get() };
145 #define NEEDBYTES(N, ERR) \ 147 if (m_Length - m_Pos < static_cast<size_t>(N)) \ 199 a_StringStart =
m_Pos + 2;
202 m_Pos += 2 + a_StringLen;
215 size_t ParentIdx =
m_Tags.size() - 1;
216 int PrevSibling = -1;
231 m_Tags.emplace_back(TagType, static_cast<int>(ParentIdx), PrevSibling);
232 if (PrevSibling >= 0)
234 m_Tags[
static_cast<size_t>(PrevSibling)].m_NextSibling = static_cast<int>(
m_Tags.size()) - 1;
238 m_Tags[ParentIdx].m_FirstChild =
static_cast<int>(
m_Tags.size()) - 1;
240 PrevSibling =
static_cast<int>(
m_Tags.size()) - 1;
244 m_Tags[ParentIdx].m_LastChild = PrevSibling;
267 size_t ParentIdx =
m_Tags.size() - 1;
268 int PrevSibling = -1;
269 for (
int i = 0; i < Count; i++)
271 m_Tags.emplace_back(a_ChildrenType, static_cast<int>(ParentIdx), PrevSibling);
272 if (PrevSibling >= 0)
274 m_Tags[
static_cast<size_t>(PrevSibling)].m_NextSibling = static_cast<int>(
m_Tags.size()) - 1;
278 m_Tags[ParentIdx].m_FirstChild =
static_cast<int>(
m_Tags.size()) - 1;
280 PrevSibling =
static_cast<int>(
m_Tags.size()) - 1;
283 m_Tags[ParentIdx].m_LastChild = PrevSibling;
291 #define CASE_SIMPLE_TAG(TAGTYPE, LEN) \ 292 case TAG_##TAGTYPE: \ 294 NEEDBYTES(LEN, eNBTParseError::npSimpleMissing); \ 295 Tag.m_DataStart = m_Pos; \ 296 Tag.m_DataLength = LEN; \ 298 return eNBTParseError::npSuccess; \ 331 m_Pos +=
static_cast<size_t>(len);
364 m_Pos +=
static_cast<size_t>(len);
376 #undef CASE_SIMPLE_TAG 393 if (a_NameLength == 0)
395 a_NameLength = strlen(a_Name);
397 for (
int Child =
m_Tags[static_cast<size_t>(a_Tag)].m_FirstChild; Child != -1; Child =
m_Tags[
static_cast<size_t>(Child)].m_NextSibling)
400 (
m_Tags[static_cast<size_t>(Child)].m_NameLength == a_NameLength) &&
401 (memcmp(
m_Data +
m_Tags[static_cast<size_t>(Child)].m_NameStart, a_Name, a_NameLength) == 0)
421 size_t Length = a_Path.length();
423 for (
size_t i = 0; i < Length; i++)
425 if (a_Path[i] !=
'\\')
468 ASSERT(!
"Stack overflow");
499 ASSERT(!
"Stack overflow");
505 m_Result.push_back(static_cast<char>(a_ChildrenType));
506 m_Result.append(4, static_cast<char>(0));
537 m_Result.push_back(static_cast<char>(a_Value));
547 UInt16 Value = htons(static_cast<UInt16>(a_Value));
548 m_Result.append(reinterpret_cast<const char *>(&Value), 2);
558 UInt32 Value = htonl(static_cast<UInt32>(a_Value));
559 m_Result.append(reinterpret_cast<const char *>(&Value), 4);
570 m_Result.append(reinterpret_cast<const char *>(&Value), 8);
581 m_Result.append(reinterpret_cast<const char *>(&Value), 4);
592 m_Result.append(reinterpret_cast<const char *>(&Value), 8);
602 UInt16 len = htons(static_cast<UInt16>(a_Value.size()));
603 m_Result.append(reinterpret_cast<const char *>(&len), 2);
604 m_Result.append(a_Value.c_str(), a_Value.size());
614 UInt32 len = htonl(static_cast<UInt32>(a_NumElements));
615 m_Result.append(reinterpret_cast<const char *>(&len), 4);
616 m_Result.append(a_Value, a_NumElements);
626 UInt32 len = htonl(static_cast<UInt32>(a_NumElements));
629 if ((cap - size) < (4 + a_NumElements * 4))
631 m_Result.reserve(size + 4 + (a_NumElements * 4));
633 m_Result.append(reinterpret_cast<const char *>(&len), 4);
634 for (
size_t i = 0; i < a_NumElements; i++)
636 UInt32 Element = htonl(static_cast<UInt32>(a_Value[i]));
637 m_Result.append(reinterpret_cast<const char *>(&Element), 4);
657 UInt16 Len = htons(a_Length);
658 m_Result.append(reinterpret_cast<const char *>(&Len), 2);
void TagCommon(const AString &a_Name, eTagType a_Type)
UInt64 HostToNetwork8(const void *a_Value)
eNBTParseError ReadCompound(void)
void AddFloat(const AString &a_Name, float a_Value)
This structure is used for all NBT tags.
cFastNBTWriter(const AString &a_RootTagName="")
void AddByteArray(const AString &a_Name, const char *a_Value, size_t a_NumElements)
void AddShort(const AString &a_Name, Int16 a_Value)
void WriteString(const char *a_Data, UInt16 a_Length)
cParsedNBT(const char *a_Data, size_t a_Length)
void AddByte(const AString &a_Name, unsigned char a_Value)
#define CASE_SIMPLE_TAG(TAGTYPE, LEN)
std::vector< cFastNBTTag > m_Tags
eNBTParseError ReadString(size_t &a_StringStart, size_t &a_StringLen)
void SetBEInt(char *a_Mem, Int32 a_Value)
Writes four bytes to the specified memory location so that they interpret as BigEndian int...
eNBTParseError ReadTag(void)
unsigned long long UInt64
short GetBEShort(const char *a_Mem)
Reads two bytes from the specified memory location and interprets them as BigEndian short...
void AddIntArray(const AString &a_Name, const int *a_Value, size_t a_NumElements)
#define NEEDBYTES(N, ERR)
bool IsStackTopCompound(void) const
int FindChildByName(int a_Tag, const AString &a_Name) const
Returns the direct child tag of the specified name, or -1 if no such tag.
void AddLong(const AString &a_Name, Int64 a_Value)
void AddString(const AString &a_Name, const AString &a_Value)
#define PROPAGATE_ERROR(X)
void AddInt(const AString &a_Name, Int32 a_Value)
static const int MAX_STACK
std::error_code make_error_code(eNBTParseError a_Err) NOEXCEPT
int FindTagByPath(int a_Tag, const AString &a_Path) const
Returns the child tag of the specified path (Name1 / Name2 / Name3...), or -1 if no such tag...
void AddDouble(const AString &a_Name, double a_Value)
void BeginList(const AString &a_Name, eTagType a_ChildrenType)
int GetBEInt(const char *a_Mem)
Reads four bytes from the specified memory location and interprets them as BigEndian int...
void BeginCompound(const AString &a_Name)
static const int MAX_LIST_ITEMS
If a list being loaded has more than this number of items, it's considered corrupted.
#define UNREACHABLE(x)
Use to mark code that should be impossible to reach.
UInt32 HostToNetwork4(const void *a_Value)
eNBTParseError Parse(void)
sParent m_Stack[MAX_STACK]
eNBTParseError ReadList(eTagType a_ChildrenType)