25 NBT_Reader(
void) =
delete;
27 ~NBT_Reader(
void) =
delete;
31 enum ErrCode : uint8_t
46 constexpr static inline const char *
const errReason[] =
51 "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((
void *)&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 using ValueType = NBT_Type::String::value_type;
277 size_t szStringLength = (size_t)wStringLength;
278 size_t szStringSize = szStringLength *
sizeof(ValueType);
281 if (!tData.HasAvailData(szStringSize))
283 ErrCode eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\n(Index[{}] + szStringLength[{}])[{}] > DataSize[{}]", __FUNCTION__,
284 tData.Index(), szStringLength, tData.Index() + szStringLength, tData.Size());
285 STACK_TRACEBACK(
"HasAvailData Test");
290 tName.resize(szStringLength);
291 tData.GetRange((
void *)tName.data(), szStringSize);
297 template<
typename T,
typename InputStream,
typename InfoFunc>
298 static ErrCode GetBuiltInType(InputStream &tData, T &tBuiltIn, InfoFunc &funcInfo)
noexcept
300 ErrCode eRet = AllOk;
306 RAW_DATA_T tTmpRawData = 0;
307 eRet = ReadBigEndian(tData, tTmpRawData, funcInfo);
310 STACK_TRACEBACK(
"tTmpRawData Read");
315 tBuiltIn = std::move(std::bit_cast<T>(tTmpRawData));
319 template<
typename T,
typename InputStream,
typename InfoFunc>
320 static ErrCode GetArrayType(InputStream &tData, T &tArray, InfoFunc &funcInfo)
noexcept
323 ErrCode eRet = AllOk;
327 eRet = ReadBigEndian(tData, iArrayLength, funcInfo);
330 STACK_TRACEBACK(
"iArrayLength Read");
335 if (iArrayLength < 0)
337 eRet = Error(OutOfRangeError, tData, funcInfo,
":\niArrayLength[{}] < 0", __FUNCTION__, iArrayLength);
338 STACK_TRACEBACK(
"iArrayLength Test");
343 using ValueType =
typename T::value_type;
344 size_t szArrayLength = (size_t)iArrayLength;
345 size_t szArraySize = szArrayLength *
sizeof(ValueType);
348 if (!tData.HasAvailData(szArraySize))
350 eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\n(Index[{}] + szArraySize[{}])[{}] > DataSize[{}]", __FUNCTION__,
351 tData.Index(), szArrayLength, tData.Index() + szArraySize, tData.Size());
352 STACK_TRACEBACK(
"HasAvailData Test");
357 tArray.reserve(szArrayLength);
360 for (
size_t i = 0; i < szArrayLength; ++i)
362 ValueType tTmpData{};
363 ReadBigEndian<true>(tData, tTmpData, funcInfo);
364 tArray.emplace_back(std::move(tTmpData));
372 template<
bool bRoot,
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
373 static ErrCode GetCompoundType(InputStream &tData,
NBT_Type::Compound &tCompound,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
376 ErrCode eRet = AllOk;
377 CHECK_STACK_DEPTH(szStackDepth);
385 if constexpr (!bRoot)
387 eRet = Error(OutOfRangeError, tData, funcInfo,
"{}:\nIndex[{}] >= DataSize()[{}]", __FUNCTION__,
388 tData.Index(), tData.Size());
389 STACK_TRACEBACK(
"HasAvailData Test");
404 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch default: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
405 u8CompoundEntryTag, u8CompoundEntryTag);
406 STACK_TRACEBACK(
"u8CompoundEntryTag Test");
415 eRet = GetName(tData, sName, funcInfo);
424 eRet = GetSwitch<bUnwrapMixedList>(tData, tmpNode, enCompoundEntryTag, szStackDepth - 1, funcInfo);
435 auto [it, bSuccess] = tCompound.try_emplace(std::move(sName), std::move(tmpNode));
439 it->second = std::move(tmpNode);
442 Error(ElementExistsWarn, tData, funcInfo,
"{}:\nName: \"{}\", Type: [NBT_Type::{}] data already exist!", __FUNCTION__,
449 STACK_TRACEBACK(
"While break with an error!");
458 template<
typename InputStream,
typename InfoFunc>
459 static ErrCode GetStringType(InputStream &tData,
NBT_Type::String &tString, InfoFunc &funcInfo)
noexcept
461 ErrCode eRet = AllOk;
464 eRet = GetName(tData, tString, funcInfo);
467 STACK_TRACEBACK(
"GetString");
474 template<
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
475 static ErrCode GetListType(InputStream &tData,
NBT_Type::List &tList,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
478 ErrCode eRet = AllOk;
479 CHECK_STACK_DEPTH(szStackDepth);
483 eRet = ReadBigEndian(tData, u8ListElementTag, funcInfo);
486 STACK_TRACEBACK(
"u8ListElementTag Read");
493 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nList NBT Type:Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
495 STACK_TRACEBACK(
"u8ListElementTag Test");
504 eRet = ReadBigEndian(tData, iListLength, funcInfo);
507 STACK_TRACEBACK(
"iListLength Read");
514 eRet = Error(OutOfRangeError, tData, funcInfo,
":\niListLength[{}] < 0", __FUNCTION__, iListLength);
515 STACK_TRACEBACK(
"iListLength Test");
520 size_t szListLength = (size_t)iListLength;
523 if (enListElementTag ==
NBT_TAG::End && szListLength != 0)
525 eRet = Error(ListElementTypeError, tData, funcInfo,
"{}:\nThe list with TAG_End[0x00] tag must be empty, but [{}] elements were found", __FUNCTION__,
527 STACK_TRACEBACK(
"enListElementTag And szListLength Test");
532 if (szListLength == 0 && enListElementTag !=
NBT_TAG::End)
538 tList.reserve(szListLength);
541 for (
size_t i = 0; i < szListLength; ++i)
544 eRet = GetSwitch<bUnwrapMixedList>(tData, tmpNode, enListElementTag, szStackDepth - 1, funcInfo);
547 STACK_TRACEBACK(
"GetSwitch Error, Size: [{}] Index: [{}]", szListLength, i);
552 if constexpr (!bUnwrapMixedList)
554 tList.emplace_back(std::move(tmpNode));
558 auto *pNode = &tmpNode;
568 if (cpdNode.Size() != 1)
582 tList.emplace_back(std::move(*pNode));
591 template<
bool bUnwrapMixedList,
typename InputStream,
typename InfoFunc>
592 static ErrCode GetSwitch(InputStream &tData,
NBT_Node &nodeNbt,
NBT_TAG tagNbt,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
594 ErrCode eRet = AllOk;
601 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
607 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
613 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
619 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
625 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
631 eRet = GetBuiltInType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
637 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
643 eRet = GetStringType(tData, nodeNbt.
Set<CurType>(), funcInfo);
649 eRet = GetListType<bUnwrapMixedList>(tData, nodeNbt.
Set<CurType>(), szStackDepth, funcInfo);
655 eRet = GetCompoundType<false, bUnwrapMixedList>(tData, nodeNbt.
Set<CurType>(), szStackDepth, funcInfo);
661 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
667 eRet = GetArrayType<CurType>(tData, nodeNbt.
Set<CurType>(), funcInfo);
672 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unexpected Type Tag NBT_TAG::End[0x00(0)]", __FUNCTION__);
677 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
685 STACK_TRACEBACK(
"Tag[0x{:02X}({})] read error!",
726 template<
bool bUnwrapMixedList = true,
typename InputStream,
typename InfoFunc = NBT_Pr
int>
727 static bool ReadNBT(InputStream &IptStream,
NBT_Type::Compound &tCompound,
size_t szStackDepth = 512, InfoFunc funcInfo = InfoFunc{})
noexcept
729 return GetCompoundType<true, bUnwrapMixedList>(IptStream, tCompound, szStackDepth, funcInfo) == AllOk;
743 template<
bool bUnwrapMixedList = true,
typename DataType = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
744 static bool ReadNBT(
const DataType &tDataInput,
size_t szStartIdx,
NBT_Type::Compound &tCompound,
size_t szStackDepth = 512, InfoFunc funcInfo = InfoFunc{})
noexcept
747 return GetCompoundType<true, bUnwrapMixedList>(IptStream, tCompound, szStackDepth, funcInfo) == AllOk;
750#ifdef CJF2_NBT_CPP_USE_ZLIB
760 template <
typename InfoFunc = NBT_Pr
int>
764 std::vector<uint8_t> vFileData;
772 std::vector<uint8_t> vNbtData;
776 vNbtData = std::move(vFileData);
781 vFileData.shrink_to_fit();
784 if (!
ReadNBT(vNbtData, 0, tCompound, 512, funcInfo))
797#undef CHECK_STACK_DEPTH
798#undef STACK_TRACEBACK
802#undef _RP___FUNCTION__