25 NBT_Reader(
void) =
delete;
27 ~NBT_Reader(
void) =
delete;
31 enum ErrCode : uint8_t
46 constexpr static inline const char *
const errReason[] =
49 "ListElementTypeError",
59 static_assert(
sizeof(errReason) /
sizeof(errReason[0]) == ERRCODE_END,
"errReason array out sync");
61 enum WarnCode : uint8_t
70 constexpr static inline const char *
const warnReason[] =
78 static_assert(
sizeof(warnReason) /
sizeof(warnReason[0]) == WARNCODE_END,
"warnReason array out sync");
85 template <
typename T,
typename InputStream,
typename InfoFunc,
typename... Args>
86 requires(std::is_same_v<T, ErrCode> || std::is_same_v<T, WarnCode>)
87 static std::conditional_t<std::is_same_v<T, ErrCode>, ErrCode,
void> Error
90 const InputStream &tData,
92 const std::format_string<Args...> fmt,
99 if constexpr (std::is_same_v<T, ErrCode>)
102 if (code >= ERRCODE_END)
107 funcInfo(lvl,
"Read Err[{}]: {}\n", (uint8_t)code, errReason[code]);
109 else if constexpr (std::is_same_v<T, WarnCode>)
112 if (code >= WARNCODE_END)
117 funcInfo(lvl,
"Read Warn[{}]: {}\n", (uint8_t)code, warnReason[code]);
121 static_assert(
false,
"Unknown [T code] Type!");
125 funcInfo(lvl,
"Extra Info: \"");
126 funcInfo(lvl, std::move(fmt), std::forward<Args>(args)...);
127 funcInfo(lvl,
"\"\n\n");
130#define VIEW_PRE (4 * 8 + 3)
131#define VIEW_SUF (4 * 8 + 5)
132 size_t rangeBeg = (tData.Index() > VIEW_PRE) ? (tData.Index() - VIEW_PRE) : (0);
133 size_t rangeEnd = ((tData.Index() + VIEW_SUF) < tData.Size()) ? (tData.Index() + VIEW_SUF) : (tData.Size());
141 "Current: 0x{:02X}({})\n"\
142 "Data Size: 0x{:02X}({})\n"\
143 "Data Range: [0x{:02X}({}),0x{:02X}({})):\n",
145 (uint64_t)tData.Index(), tData.Index(),
146 (uint64_t)tData.Size(), tData.Size(),
147 (uint64_t)rangeBeg, rangeBeg,
148 (uint64_t)rangeEnd, rangeEnd
152 for (
size_t i = rangeBeg; i < rangeEnd; ++i)
154 if ((i - rangeBeg) % 8 == 0)
160 funcInfo(lvl,
"0x{:02X}: ", (uint64_t)i);
163 if (i != tData.Index())
165 funcInfo(lvl,
" {:02X} ", (uint8_t)tData[i]);
169 funcInfo(lvl,
"[{:02X}]", (uint8_t)tData[i]);
174 if constexpr (std::is_same_v<T, ErrCode>)
176 funcInfo(lvl,
"\nSkip err data and return...\n\n");
178 else if constexpr (std::is_same_v<T, WarnCode>)
180 funcInfo(lvl,
"\nSkip warn data and continue...\n\n");
184 static_assert(
false,
"Unknown [T code] Type!");
188 if constexpr (std::is_same_v<T, ErrCode>)
195#define _RP___FUNCTION__ __FUNCTION__
197#define _RP___LINE__ _RP_STRLING(__LINE__)
198#define _RP_STRLING(l) STRLING(l)
201#define STACK_TRACEBACK(fmt, ...) funcInfo(NBT_Print_Level::Err, "In [{}] Line:[" _RP___LINE__ "]: \n" fmt "\n\n", _RP___FUNCTION__ __VA_OPT__(,) __VA_ARGS__);
202#define CHECK_STACK_DEPTH(Depth) \
205 eRet = Error(StackDepthExceeded, tData, funcInfo, "{}: NBT nesting depth exceeded maximum call stack limit", _RP___FUNCTION__);\
206 STACK_TRACEBACK("(Depth) <= 0");\
216catch(const std::bad_alloc &e)\
218 ErrCode eRet = Error(OutOfMemoryError, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
219 STACK_TRACEBACK("catch(std::bad_alloc)");\
222catch(const std::exception &e)\
224 ErrCode eRet = Error(StdException, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
225 STACK_TRACEBACK("catch(std::exception)");\
230 ErrCode eRet = Error(UnknownError, tData, funcInfo, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);\
231 STACK_TRACEBACK("catch(...)");\
236 template<
bool bNoCheck = false,
typename T,
typename InputStream,
typename InfoFunc>
237 requires std::integral<T>
238 static inline std::conditional_t<bNoCheck, void, ErrCode> ReadBigEndian(InputStream &tData, T &tVal, InfoFunc &funcInfo)
noexcept
240 if constexpr (!bNoCheck)
242 if (!tData.HasAvailData(
sizeof(T)))
244 ErrCode eRet = Error(OutOfRangeError, tData, funcInfo,
"tData size [{}], current index [{}], remaining data size [{}], but try to read [{}]",
245 tData.Size(), tData.Index(), tData.Size() - tData.Index(),
sizeof(T));
246 STACK_TRACEBACK(
"HasAvailData Test");
252 tData.GetRange((uint8_t *)&BigEndianVal,
sizeof(BigEndianVal));
255 if constexpr (!bNoCheck)
261 template<
typename InputStream,
typename InfoFunc>
262 static ErrCode GetName(InputStream &tData,
NBT_Type::String &tName, InfoFunc &funcInfo)
noexcept
265 ErrCode eRet = AllOk;
268 eRet = ReadBigEndian(tData, wStringLength, funcInfo);
271 STACK_TRACEBACK(
"wStringLength Read");
276 if (!tData.HasAvailData(wStringLength))
278 ErrCode eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\n(Index[{}] + wStringLength[{}])[{}] > DataSize[{}]", __FUNCTION__,
279 tData.Index(), (
size_t)wStringLength, tData.Index() + (
size_t)wStringLength, tData.Size());
280 STACK_TRACEBACK(
"HasAvailData Test");
286 tName.reserve(wStringLength);
287 tName.assign((
const NBT_Type::String::value_type *)tData.CurData(), wStringLength);
288 tData.AddIndex(wStringLength);
294 template<
typename T,
typename InputStream,
typename InfoFunc>
295 static ErrCode GetBuiltInType(InputStream &tData, T &tBuiltIn, InfoFunc &funcInfo)
noexcept
297 ErrCode eRet = AllOk;
303 RAW_DATA_T tTmpRawData = 0;
304 eRet = ReadBigEndian(tData, tTmpRawData, funcInfo);
307 STACK_TRACEBACK(
"tTmpRawData Read");
312 tBuiltIn = std::move(std::bit_cast<T>(tTmpRawData));
316 template<
typename T,
typename InputStream,
typename InfoFunc>
317 static ErrCode GetArrayType(InputStream &tData, T &tArray, InfoFunc &funcInfo)
noexcept
320 ErrCode eRet = AllOk;
324 eRet = ReadBigEndian(tData, iElementCount, funcInfo);
327 STACK_TRACEBACK(
"iElementCount Read");
331 using ValueType =
typename T::value_type;
334 if (!tData.HasAvailData(iElementCount *
sizeof(ValueType)))
336 eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\n(Index[{}] + iElementCount[{}] * sizeof(T::value_type)[{}])[{}] > DataSize[{}]", __FUNCTION__,
337 tData.Index(), (
size_t)iElementCount,
sizeof(ValueType), tData.Index() + (
size_t)iElementCount *
sizeof(
typename T::value_type), tData.Size());
338 STACK_TRACEBACK(
"HasAvailData Test");
343 tArray.reserve(iElementCount);
347 ValueType tTmpData{};
348 ReadBigEndian<true>(tData, tTmpData, funcInfo);
349 tArray.emplace_back(std::move(tTmpData));
357 template<
bool bRoot,
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
358 static ErrCode GetCompoundType(InputStream &tData,
NBT_Type::Compound &tCompound,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
361 ErrCode eRet = AllOk;
362 CHECK_STACK_DEPTH(szStackDepth);
370 if constexpr (!bRoot)
372 eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\nIndex[{}] >= DataSize()[{}]", __FUNCTION__,
373 tData.Index(), tData.Size());
388 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch default: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
390 STACK_TRACEBACK(
"tagNbt Test");
396 eRet = GetName(tData, sName, funcInfo);
405 eRet = GetSwitch<bUnwrapMixedList>(tData, tmpNode, tagNbt, szStackDepth - 1, funcInfo);
416 auto [it, bSuccess] = tCompound.try_emplace(std::move(sName), std::move(tmpNode));
420 it->second = std::move(tmpNode);
423 Error(ElementExistsWarn, tData, funcInfo,
"{}:\nName: \"{}\", Type: [NBT_Type::{}] data already exist!", __FUNCTION__,
430 STACK_TRACEBACK(
"While break with an error!");
439 template<
typename InputStream,
typename InfoFunc>
440 static ErrCode GetStringType(InputStream &tData,
NBT_Type::String &tString, InfoFunc &funcInfo)
noexcept
442 ErrCode eRet = AllOk;
445 eRet = GetName(tData, tString, funcInfo);
448 STACK_TRACEBACK(
"GetString");
455 template<
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
456 static ErrCode GetListType(InputStream &tData,
NBT_Type::List &tList,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
459 ErrCode eRet = AllOk;
460 CHECK_STACK_DEPTH(szStackDepth);
464 eRet = ReadBigEndian(tData, enListElementTag, funcInfo);
467 STACK_TRACEBACK(
"enListElementTag Read");
474 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nList NBT Type:Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
476 STACK_TRACEBACK(
"enListElementTag Test");
482 eRet = ReadBigEndian(tData, iListLength, funcInfo);
485 STACK_TRACEBACK(
"iListLength Read");
492 eRet = Error(OutOfRangeError, tData, funcInfo,
":\niListLength[{}] < 0", __FUNCTION__, iListLength);
493 STACK_TRACEBACK(
"iListLength Test");
498 if (enListElementTag ==
NBT_TAG::End && iListLength != 0)
500 eRet = Error(ListElementTypeError, tData, funcInfo,
"{}:\nThe list with TAG_End[0x00] tag must be empty, but [{}] elements were found", __FUNCTION__,
502 STACK_TRACEBACK(
"enListElementTag And iListLength Test");
507 if (iListLength == 0 && enListElementTag !=
NBT_TAG::End)
513 tList.reserve(iListLength);
519 eRet = GetSwitch<bUnwrapMixedList>(tData, tmpNode, (
NBT_TAG)enListElementTag, szStackDepth - 1, funcInfo);
522 STACK_TRACEBACK(
"GetSwitch Error, Size: [{}] Index: [{}]", iListLength, i);
527 if constexpr (!bUnwrapMixedList)
529 tList.emplace_back(std::move(tmpNode));
533 auto *pNode = &tmpNode;
543 if (cpdNode.Size() != 1)
557 tList.emplace_back(std::move(*pNode));
566 template<
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
567 static ErrCode GetSwitch(InputStream &tData,
NBT_Node &nodeNbt,
NBT_TAG tagNbt,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
569 ErrCode eRet = AllOk;
576 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
582 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
588 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
594 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
600 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
606 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
612 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
618 eRet = GetStringType(tData, nodeNbt.
Set<CurType>(), funcInfo);
624 eRet = GetListType<bUnwrapMixedList>(tData, nodeNbt.
Set<CurType>(), szStackDepth, funcInfo);
630 eRet = GetCompoundType<false, bUnwrapMixedList>(tData, nodeNbt.
Set<CurType>(), szStackDepth, funcInfo);
636 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
642 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
647 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unexpected Type Tag NBT_TAG::End[0x00(0)]", __FUNCTION__);
652 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
660 STACK_TRACEBACK(
"Tag[0x{:02X}({})] read error!",
701 template<
bool bUnwrapMixedList = true,
typename InputStream,
typename InfoFunc = NBT_Pr
int>
704 return GetCompoundType<true, bUnwrapMixedList>(IptStream, tCompound, szStackDepth, funcInfo) == AllOk;
718 template<
bool bUnwrapMixedList = true,
typename DataType = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
722 return GetCompoundType<true, bUnwrapMixedList>(IptStream, tCompound, szStackDepth, funcInfo) == AllOk;
728#undef CHECK_STACK_DEPTH
729#undef STACK_TRACEBACK
733#undef _RP___FUNCTION__