15 #ifndef NBT_RESERVE_SIZE
16 #define NBT_RESERVE_SIZE 200
21 #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while ((false, false))
23 #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while (false)
34 class cNBTParseErrorCategory final :
35 public std::error_category
37 cNBTParseErrorCategory() =
default;
40 virtual const char * name()
const noexcept
override
42 return "NBT parse error";
46 virtual AString message(
int a_Condition)
const override;
49 static const cNBTParseErrorCategory & Get() noexcept
51 static cNBTParseErrorCategory Category;
60 AString cNBTParseErrorCategory::message(
int a_Condition)
const
66 return "Parsing succeded";
70 return "Expected more data";
74 return "No top level compound tag";
78 return "Expected a string length but had insufficient data";
82 return "String length invalid";
86 return "Compound tag was unmatched at end of file";
90 return "Expected a list type but had insuffiecient data";
94 return "Expected a list length but had insufficient data";
98 return "List length invalid";
102 return "Expected a numeric type but had insufficient data";
106 return "Expected an array length but had insufficient data";
110 return "Array length invalid";
114 return "Unknown tag";
128 return {
static_cast<int>(a_Err), cNBTParseErrorCategory::Get() };
138 #define NEEDBYTES(N, ERR) \
140 if (m_Data.size() - m_Pos < static_cast<size_t>(N)) \
191 a_StringStart =
m_Pos + 2;
194 m_Pos += 2 + a_StringLen;
207 size_t ParentIdx =
m_Tags.size() - 1;
208 int PrevSibling = -1;
213 if ((TagTypeNum < std::byte(
TAG_Min)) || (TagTypeNum > std::byte(
TAG_Max)))
223 m_Tags.emplace_back(TagType,
static_cast<int>(ParentIdx), PrevSibling);
224 if (PrevSibling >= 0)
226 m_Tags[
static_cast<size_t>(PrevSibling)].m_NextSibling =
static_cast<int>(
m_Tags.size()) - 1;
230 m_Tags[ParentIdx].m_FirstChild =
static_cast<int>(
m_Tags.size()) - 1;
232 PrevSibling =
static_cast<int>(
m_Tags.size()) - 1;
236 m_Tags[ParentIdx].m_LastChild = PrevSibling;
253 if ((Count < 0) || (Count >
static_cast<int>((
m_Data.size() -
m_Pos) / MinChildSize)))
260 size_t ParentIdx =
m_Tags.size() - 1;
261 int PrevSibling = -1;
262 for (
int i = 0; i < Count; i++)
264 m_Tags.emplace_back(a_ChildrenType,
static_cast<int>(ParentIdx), PrevSibling);
265 if (PrevSibling >= 0)
267 m_Tags[
static_cast<size_t>(PrevSibling)].m_NextSibling =
static_cast<int>(
m_Tags.size()) - 1;
271 m_Tags[ParentIdx].m_FirstChild =
static_cast<int>(
m_Tags.size()) - 1;
273 PrevSibling =
static_cast<int>(
m_Tags.size()) - 1;
276 m_Tags[ParentIdx].m_LastChild = PrevSibling;
284 #define CASE_SIMPLE_TAG(TAGTYPE, LEN) \
285 case TAG_##TAGTYPE: \
287 NEEDBYTES(LEN, eNBTParseError::npSimpleMissing); \
288 Tag.m_DataStart = m_Pos; \
289 Tag.m_DataLength = LEN; \
291 return eNBTParseError::npSuccess; \
324 m_Pos +=
static_cast<size_t>(len);
357 m_Pos +=
static_cast<size_t>(len);
369 #undef CASE_SIMPLE_TAG
386 if (a_NameLength == 0)
388 a_NameLength = strlen(a_Name);
390 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)
393 (
m_Tags[
static_cast<size_t>(Child)].m_NameLength == a_NameLength) &&
394 (memcmp(
m_Data.data() +
m_Tags[
static_cast<size_t>(Child)].m_NameStart, a_Name, a_NameLength) == 0)
414 size_t Length = a_Path.length();
416 for (
size_t i = 0; i < Length; i++)
418 if (a_Path[i] !=
'\\')
485 ASSERT(!
"Stack overflow");
516 ASSERT(!
"Stack overflow");
522 m_Result.push_back(std::byte(a_ChildrenType));
554 m_Result.push_back(std::byte(a_Value));
565 m_Result.append(
reinterpret_cast<const std::byte *
>(&Value), 2);
576 m_Result.append(
reinterpret_cast<const std::byte *
>(&Value), 4);
587 m_Result.append(
reinterpret_cast<const std::byte *
>(&Value), 8);
598 m_Result.append(
reinterpret_cast<const std::byte *
>(&Value), 4);
609 m_Result.append(
reinterpret_cast<const std::byte *
>(&Value), 8);
619 const UInt16 Length = htons(
static_cast<UInt16>(a_Value.size()));
620 m_Result.append(
reinterpret_cast<const std::byte *
>(&Length),
sizeof(Length));
621 m_Result.append({
reinterpret_cast<const std::byte *
>(a_Value.data()), a_Value.size() });
632 m_Result.append(
reinterpret_cast<const std::byte *
>(&len), 4);
633 m_Result.append(
reinterpret_cast<const std::byte *
>(a_Value), a_NumElements);
644 m_Result.append(
reinterpret_cast<const std::byte *
>(&len), 4);
645 m_Result.append(a_NumElements, std::byte(a_Value));
658 if ((cap - size) < (4 + a_NumElements * 4))
660 m_Result.reserve(size + 4 + (a_NumElements * 4));
662 m_Result.append(
reinterpret_cast<const std::byte *
>(&len),
sizeof(len));
663 for (
size_t i = 0; i < a_NumElements; i++)
665 UInt32 Element = htonl(
static_cast<UInt32>(a_Value[i]));
666 m_Result.append(
reinterpret_cast<const std::byte *
>(&Element),
sizeof(Element));
687 UInt16 Len = htons(
static_cast<unsigned short>(a_Data.size()));
688 m_Result.append(
reinterpret_cast<const std::byte *
>(&Len),
sizeof(Len));
689 m_Result.append(
reinterpret_cast<const std::byte *
>(a_Data.data()), a_Data.size());
UInt32 HostToNetwork4(const void *a_Value)
UInt64 HostToNetwork8(const void *a_Value)
std::basic_string_view< std::byte > ContiguousByteBufferView
unsigned long long UInt64
#define KiB
Allows arithmetic expressions like "32 KiB" (but consider using parenthesis around it,...
short GetBEShort(const std::byte *const a_Mem)
Reads two bytes from the specified memory location and interprets them as BigEndian short.
int GetBEInt(const std::byte *const a_Mem)
Reads four bytes from the specified memory location and interprets them as BigEndian int.
void SetBEInt(std::byte *a_Mem, Int32 a_Value)
Writes four bytes to the specified memory location so that they interpret as BigEndian int.
#define PROPAGATE_ERROR(X)
#define CASE_SIMPLE_TAG(TAGTYPE, LEN)
#define NEEDBYTES(N, ERR)
std::error_code make_error_code(eNBTParseError a_Err) noexcept
@ npCompoundImbalancedTag
bool Short(const BlockState Block)
This structure is used for all NBT tags.
eNBTParseError Parse(void)
std::vector< cFastNBTTag > m_Tags
eNBTParseError ReadList(eTagType a_ChildrenType)
eNBTParseError ReadString(size_t &a_StringStart, size_t &a_StringLen)
cParsedNBT(ContiguousByteBufferView a_Data)
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.
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.
eNBTParseError ReadTag(void)
ContiguousByteBufferView m_Data
static size_t GetMinTagSize(eTagType a_TagType)
Returns the minimum size, in bytes, of the specified tag type.
eNBTParseError ReadCompound(void)
void AddByteArray(const AString &a_Name, const char *a_Value, size_t a_NumElements)
void AddByte(const AString &a_Name, unsigned char a_Value)
void AddDouble(const AString &a_Name, double a_Value)
void AddShort(const AString &a_Name, Int16 a_Value)
void AddInt(const AString &a_Name, Int32 a_Value)
void AddString(const AString &a_Name, std::string_view a_Value)
ContiguousByteBuffer m_Result
void BeginList(const AString &a_Name, eTagType a_ChildrenType)
void AddFloat(const AString &a_Name, float a_Value)
void AddIntArray(const AString &a_Name, const Int32 *a_Value, size_t a_NumElements)
cFastNBTWriter(const AString &a_RootTagName="")
bool IsStackTopCompound(void) const
void BeginCompound(const AString &a_Name)
static const int MAX_STACK
void WriteString(std::string_view a_Data)
void AddLong(const AString &a_Name, Int64 a_Value)
void TagCommon(const AString &a_Name, eTagType a_Type)
sParent m_Stack[MAX_STACK]