From 8fbb9dbf53105fc7379b5696baf2363777a29691 Mon Sep 17 00:00:00 2001 From: peterbell10 Date: Sun, 30 Jul 2017 17:55:19 +0100 Subject: cParsedNBT: Improved error reporting (#3876) * cParsedNBT: Improved error reporting * Fix typos --- src/WorldStorage/FastNBT.cpp | 172 +++++++++++++++++++++++++++++++------------ 1 file changed, 125 insertions(+), 47 deletions(-) (limited to 'src/WorldStorage/FastNBT.cpp') diff --git a/src/WorldStorage/FastNBT.cpp b/src/WorldStorage/FastNBT.cpp index 7d99b927a..b71169105 100644 --- a/src/WorldStorage/FastNBT.cpp +++ b/src/WorldStorage/FastNBT.cpp @@ -25,20 +25,100 @@ static const int MAX_LIST_ITEMS = 10000; #ifdef _MSC_VER // Dodge a C4127 (conditional expression is constant) for this specific macro usage - #define RETURN_FALSE_IF_FALSE(X) do { if (!X) return false; } while ((false, false)) + #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while ((false, false)) #else - #define RETURN_FALSE_IF_FALSE(X) do { if (!X) return false; } while (false) + #define PROPAGATE_ERROR(X) do { auto Err = (X); if (Err != eNBTParseError::npSuccess) return Err; } while (false) #endif +//////////////////////////////////////////////////////////////////////////////// +// cNBTParseErrorCategory: + +AString cNBTParseErrorCategory::message(int a_Condition) const +{ + switch (static_cast(a_Condition)) + { + case eNBTParseError::npSuccess: + { + return "Parsing succeded"; + } + case eNBTParseError::npNeedBytes: + { + return "Expected more data"; + } + case eNBTParseError::npNoTopLevelCompound: + { + return "No top level compound tag"; + } + case eNBTParseError::npStringMissingLength: + { + return "Expected a string length but had insufficient data"; + } + case eNBTParseError::npStringInvalidLength: + { + return "String length invalid"; + } + case eNBTParseError::npCompoundImbalancedTag: + { + return "Compound tag was unmatched at end of file"; + } + case eNBTParseError::npListMissingType: + { + return "Expected a list type but had insuffiecient data"; + } + case eNBTParseError::npListMissingLength: + { + return "Expected a list length but had insufficient data"; + } + case eNBTParseError::npListInvalidLength: + { + return "List length invalid"; + } + case eNBTParseError::npSimpleMissing: + { + return "Expected a numeric type but had insufficient data"; + } + case eNBTParseError::npArrayMissingLength: + { + return "Expected an array length but had insufficient data"; + } + case eNBTParseError::npArrayInvalidLength: + { + return "Array length invalid"; + } + case eNBTParseError::npUnknownTag: + { + return "Unknown tag"; + } + + #ifdef __clang__ + #pragma clang diagnostic push + #pragma clang diagnostic ignored "-Wcovered-switch-default" + #endif + + default: + { + return ""; + } + + #ifdef __clang__ + #pragma clang diagnostic pop + #endif + } +} + + + + + //////////////////////////////////////////////////////////////////////////////// // cParsedNBT: -#define NEEDBYTES(N) \ +#define NEEDBYTES(N, ERR) \ if (m_Length - m_Pos < static_cast(N)) \ { \ - return false; \ + return ERR; \ } @@ -50,57 +130,55 @@ cParsedNBT::cParsedNBT(const char * a_Data, size_t a_Length) : m_Length(a_Length), m_Pos(0) { - m_IsValid = Parse(); + m_Error = Parse(); } -bool cParsedNBT::Parse(void) +eNBTParseError cParsedNBT::Parse(void) { if (m_Length < 3) { // Data too short - return false; + return eNBTParseError::npNeedBytes; } if (m_Data[0] != TAG_Compound) { // The top-level tag must be a Compound - return false; + return eNBTParseError::npNoTopLevelCompound; } m_Tags.reserve(NBT_RESERVE_SIZE); - m_Tags.push_back(cFastNBTTag(TAG_Compound, -1)); + m_Tags.emplace_back(TAG_Compound, -1); m_Pos = 1; - RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); - RETURN_FALSE_IF_FALSE(ReadCompound()); - - return true; + PROPAGATE_ERROR(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); + return ReadCompound(); } -bool cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen) +eNBTParseError cParsedNBT::ReadString(size_t & a_StringStart, size_t & a_StringLen) { - NEEDBYTES(2); + NEEDBYTES(2, eNBTParseError::npStringMissingLength); a_StringStart = m_Pos + 2; a_StringLen = static_cast(GetBEShort(m_Data + m_Pos)); - NEEDBYTES(2 + a_StringLen); + NEEDBYTES(2 + a_StringLen, eNBTParseError::npStringInvalidLength); m_Pos += 2 + a_StringLen; - return true; + return eNBTParseError::npSuccess; } -bool cParsedNBT::ReadCompound(void) +eNBTParseError cParsedNBT::ReadCompound(void) { ASSERT(m_Tags.size() > 0); @@ -109,11 +187,11 @@ bool cParsedNBT::ReadCompound(void) int PrevSibling = -1; for (;;) { - NEEDBYTES(1); + NEEDBYTES(1, eNBTParseError::npCompoundImbalancedTag); const char TagTypeNum = m_Data[m_Pos]; if ((TagTypeNum < TAG_Min) || (TagTypeNum > TAG_Max)) { - return false; + return eNBTParseError::npUnknownTag; } eTagType TagType = static_cast(TagTypeNum); m_Pos++; @@ -121,7 +199,7 @@ bool cParsedNBT::ReadCompound(void) { break; } - m_Tags.push_back(cFastNBTTag(TagType, static_cast(ParentIdx), PrevSibling)); + m_Tags.emplace_back(TagType, static_cast(ParentIdx), PrevSibling); if (PrevSibling >= 0) { m_Tags[static_cast(PrevSibling)].m_NextSibling = static_cast(m_Tags.size()) - 1; @@ -131,28 +209,28 @@ bool cParsedNBT::ReadCompound(void) m_Tags[ParentIdx].m_FirstChild = static_cast(m_Tags.size()) - 1; } PrevSibling = static_cast(m_Tags.size()) - 1; - RETURN_FALSE_IF_FALSE(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); - RETURN_FALSE_IF_FALSE(ReadTag()); + PROPAGATE_ERROR(ReadString(m_Tags.back().m_NameStart, m_Tags.back().m_NameLength)); + PROPAGATE_ERROR(ReadTag()); } // while (true) m_Tags[ParentIdx].m_LastChild = PrevSibling; - return true; + return eNBTParseError::npSuccess; } -bool cParsedNBT::ReadList(eTagType a_ChildrenType) +eNBTParseError cParsedNBT::ReadList(eTagType a_ChildrenType) { // Reads the latest tag as a list of items of type a_ChildrenType // Read the count: - NEEDBYTES(4); + NEEDBYTES(4, eNBTParseError::npListMissingLength); int Count = GetBEInt(m_Data + m_Pos); m_Pos += 4; if ((Count < 0) || (Count > MAX_LIST_ITEMS)) { - return false; + return eNBTParseError::npListInvalidLength; } // Read items: @@ -161,7 +239,7 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) int PrevSibling = -1; for (int i = 0; i < Count; i++) { - m_Tags.push_back(cFastNBTTag(a_ChildrenType, static_cast(ParentIdx), PrevSibling)); + m_Tags.emplace_back(a_ChildrenType, static_cast(ParentIdx), PrevSibling); if (PrevSibling >= 0) { m_Tags[static_cast(PrevSibling)].m_NextSibling = static_cast(m_Tags.size()) - 1; @@ -171,10 +249,10 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) m_Tags[ParentIdx].m_FirstChild = static_cast(m_Tags.size()) - 1; } PrevSibling = static_cast(m_Tags.size()) - 1; - RETURN_FALSE_IF_FALSE(ReadTag()); + PROPAGATE_ERROR(ReadTag()); } // for (i) m_Tags[ParentIdx].m_LastChild = PrevSibling; - return true; + return eNBTParseError::npSuccess; } @@ -184,14 +262,14 @@ bool cParsedNBT::ReadList(eTagType a_ChildrenType) #define CASE_SIMPLE_TAG(TAGTYPE, LEN) \ case TAG_##TAGTYPE: \ { \ - NEEDBYTES(LEN); \ + NEEDBYTES(LEN, eNBTParseError::npSimpleMissing); \ Tag.m_DataStart = m_Pos; \ Tag.m_DataLength = LEN; \ m_Pos += LEN; \ - return true; \ + return eNBTParseError::npSuccess; \ } -bool cParsedNBT::ReadTag(void) +eNBTParseError cParsedNBT::ReadTag(void) { cFastNBTTag & Tag = m_Tags.back(); switch (Tag.m_Type) @@ -210,52 +288,52 @@ bool cParsedNBT::ReadTag(void) case TAG_ByteArray: { - NEEDBYTES(4); + NEEDBYTES(4, eNBTParseError::npArrayMissingLength); int len = GetBEInt(m_Data + m_Pos); m_Pos += 4; if (len < 0) { // Invalid length - return false; + return eNBTParseError::npArrayInvalidLength; } - NEEDBYTES(len); + NEEDBYTES(len, eNBTParseError::npArrayInvalidLength); Tag.m_DataLength = static_cast(len); Tag.m_DataStart = m_Pos; m_Pos += static_cast(len); - return true; + return eNBTParseError::npSuccess; } case TAG_List: { - NEEDBYTES(1); + NEEDBYTES(1, eNBTParseError::npListMissingType); eTagType ItemType = static_cast(m_Data[m_Pos]); m_Pos++; - RETURN_FALSE_IF_FALSE(ReadList(ItemType)); - return true; + PROPAGATE_ERROR(ReadList(ItemType)); + return eNBTParseError::npSuccess; } case TAG_Compound: { - RETURN_FALSE_IF_FALSE(ReadCompound()); - return true; + PROPAGATE_ERROR(ReadCompound()); + return eNBTParseError::npSuccess; } case TAG_IntArray: { - NEEDBYTES(4); + NEEDBYTES(4, eNBTParseError::npArrayMissingLength); int len = GetBEInt(m_Data + m_Pos); m_Pos += 4; if (len < 0) { // Invalid length - return false; + return eNBTParseError::npArrayInvalidLength; } len *= 4; - NEEDBYTES(len); + NEEDBYTES(len, eNBTParseError::npArrayInvalidLength); Tag.m_DataLength = static_cast(len); Tag.m_DataStart = m_Pos; m_Pos += static_cast(len); - return true; + return eNBTParseError::npSuccess; } #if !defined(__clang__) @@ -263,7 +341,7 @@ bool cParsedNBT::ReadTag(void) #endif case TAG_Min: { - return false; + return eNBTParseError::npUnknownTag; } } // switch (iType) } -- cgit v1.2.3