24 NBT_Writer(
void) =
delete;
26 ~NBT_Writer(
void) =
delete;
30 enum ErrCode : uint8_t
46 constexpr static inline const char *
const errReason[] =
61 static_assert(
sizeof(errReason) /
sizeof(errReason[0]) == (ERRCODE_END),
"errReason array out sync");
63 enum WarnCode : uint8_t
72 constexpr static inline const char *
const warnReason[] =
76 "EndElementIgnoreWarn",
80 static_assert(
sizeof(warnReason) /
sizeof(warnReason[0]) == WARNCODE_END,
"warnReason array out sync");
87 template <
typename T,
typename OutputStream,
typename InfoFunc,
typename... Args>
88 requires(std::is_same_v<T, ErrCode> || std::is_same_v<T, WarnCode>)
89 static std::conditional_t<std::is_same_v<T, ErrCode>, ErrCode,
void> Error
92 const OutputStream &tData,
94 const std::format_string<Args...> fmt,
101 if constexpr (std::is_same_v<T, ErrCode>)
104 if (code >= ERRCODE_END)
109 funcInfo(lvl,
"Read Err[{}]: {}\n", (uint8_t)code, errReason[code]);
111 else if constexpr (std::is_same_v<T, WarnCode>)
114 if (code >= WARNCODE_END)
119 funcInfo(lvl,
"Read Warn[{}]: {}\n", (uint8_t)code, warnReason[code]);
123 static_assert(
false,
"Unknown [T code] Type!");
127 funcInfo(lvl,
"Extra Info: \"");
128 funcInfo(lvl, std::move(fmt), std::forward<Args>(args)...);
129 funcInfo(lvl,
"\"\n\n");
132#define VIEW_PRE (8 * 8 + 8)
133 size_t rangeBeg = (tData.Size() > VIEW_PRE) ? (tData.Size() - VIEW_PRE) : (0);
134 size_t rangeEnd = tData.Size();
141 "Data Size: 0x{:02X}({})\n"\
142 "Data Range: [0x{:02X}({}),0x{:02X}({})):\n",
144 (uint64_t)tData.Size(), tData.Size(),
145 (uint64_t)rangeBeg, rangeBeg,
146 (uint64_t)rangeEnd, rangeEnd
150 for (
size_t i = rangeBeg; i < rangeEnd; ++i)
152 if ((i - rangeBeg) % 8 == 0)
158 funcInfo(lvl,
"0x{:02X}: ", (uint64_t)i);
161 funcInfo(lvl,
" {:02X} ", (uint8_t)tData[i]);
165 if constexpr (std::is_same_v<T, ErrCode>)
167 funcInfo(lvl,
"\nSkip err and return...\n\n");
169 else if constexpr (std::is_same_v<T, WarnCode>)
171 funcInfo(lvl,
"\nSkip warn and continue...\n\n");
175 static_assert(
false,
"Unknown [T code] Type!");
179 if constexpr (std::is_same_v<T, ErrCode>)
185#define _RP___FUNCTION__ __FUNCTION__
187#define _RP___LINE__ _RP_STRLING(__LINE__)
188#define _RP_STRLING(l) STRLING(l)
191#define STACK_TRACEBACK(fmt, ...) funcInfo(NBT_Print_Level::Err, "In [{}] Line:[" _RP___LINE__ "]: \n" fmt "\n\n", _RP___FUNCTION__ __VA_OPT__(,) __VA_ARGS__);
192#define CHECK_STACK_DEPTH(Depth) \
195 eRet = Error(StackDepthExceeded, tData, funcInfo, "{}: NBT nesting depth exceeded maximum call stack limit", _RP___FUNCTION__);\
196 STACK_TRACEBACK("(Depth) <= 0");\
206catch(const std::bad_alloc &e)\
208 ErrCode eRet = Error(OutOfMemoryError, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
209 STACK_TRACEBACK("catch(std::bad_alloc)");\
212catch(const std::exception &e)\
214 ErrCode eRet = Error(StdException, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
215 STACK_TRACEBACK("catch(std::exception)");\
220 ErrCode eRet = Error(UnknownError, tData, funcInfo, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);\
221 STACK_TRACEBACK("catch(...)");\
225 template<
typename OutputStream,
typename InfoFunc>
226 static inline ErrCode CheckReserve(OutputStream &tData,
size_t szAddSize, InfoFunc &funcInfo)
noexcept
229 tData.AddReserve(szAddSize);
235 template<
typename T,
typename OutputStream,
typename InfoFunc>
236 requires std::integral<T>
237 static inline ErrCode WriteBigEndian(OutputStream &tData,
const T &tVal, InfoFunc &funcInfo)
noexcept
241 tData.PutRange((
const uint8_t *)&BigEndianVal,
sizeof(BigEndianVal));
246 template<
typename OutputStream,
typename InfoFunc>
247 static ErrCode PutName(OutputStream &tData,
const NBT_Type::String &sName, InfoFunc &funcInfo)
noexcept
250 ErrCode eRet = AllOk;
253 size_t szStringLength = sName.size();
258 eRet = Error(StringTooLongError, tData, funcInfo,
"{}:\nszStringLength[{}] > StringLength_Max[{}]", __FUNCTION__,
260 STACK_TRACEBACK(
"szStringLength Test");
266 eRet = WriteBigEndian(tData, wNameLength, funcInfo);
269 STACK_TRACEBACK(
"wNameLength Write");
274 eRet = CheckReserve(tData, szStringLength *
sizeof(sName[0]), funcInfo);
277 STACK_TRACEBACK(
"CheckReserve Fail, Check Size: [{}]", szStringLength *
sizeof(sName[0]));
281 tData.PutRange((
const typename OutputStream::ValueType *)sName.data(), szStringLength);
287 template<
typename T,
typename OutputStream,
typename InfoFunc>
288 static ErrCode PutbuiltInType(OutputStream &tData,
const T &tBuiltIn, InfoFunc &funcInfo)
noexcept
290 ErrCode eRet = AllOk;
294 RAW_DATA_T tTmpRawData = std::bit_cast<RAW_DATA_T>(tBuiltIn);
296 eRet = WriteBigEndian(tData, tTmpRawData, funcInfo);
299 STACK_TRACEBACK(
"tTmpRawData Write");
306 template<
typename T,
typename OutputStream,
typename InfoFunc>
307 static ErrCode PutArrayType(OutputStream &tData,
const T &tArray, InfoFunc &funcInfo)
noexcept
309 ErrCode eRet = AllOk;
313 size_t szArrayLength = tArray.size();
316 eRet = Error(ArrayTooLongError, tData, funcInfo,
"{}:\nszArrayLength[{}] > ArrayLength_Max[{}]", __FUNCTION__,
318 STACK_TRACEBACK(
"szArrayLength Test");
324 eRet = WriteBigEndian(tData, iArrayLength, funcInfo);
327 STACK_TRACEBACK(
"iArrayLength Write");
332 eRet = CheckReserve(tData, iArrayLength *
sizeof(tArray[0]), funcInfo);
335 STACK_TRACEBACK(
"CheckReserve Fail, Check Size: [{}]", iArrayLength *
sizeof(tArray[0]));
341 eRet = WriteBigEndian(tData, tArray[i], funcInfo);
344 STACK_TRACEBACK(
"tTmpData Write");
352 template<
bool bSortCompound,
typename OutputStream,
typename InfoFunc>
353 static ErrCode PutCompoundEntry(OutputStream &tData,
const NBT_Type::String &sName,
const NBT_Node &nodeNbt,
size_t szStackDepth, InfoFunc &funcInfo)
355 ErrCode eRet = AllOk;
364 Error(EndElementIgnoreWarn, tData, funcInfo,
"{}:\nName: \"{}\", type is [NBT_Type::End], ignored!", __FUNCTION__,
373 STACK_TRACEBACK(
"curTag Write");
378 eRet = PutName(tData, sName, funcInfo);
386 eRet = PutSwitch<bSortCompound>(tData, nodeNbt, curTag, szStackDepth - 1, funcInfo);
389 STACK_TRACEBACK(
"PutSwitch Fail, Name: \"{}\", Type: [NBT_Type::{}]",
397 template<
typename OutputStream,
typename InfoFunc>
398 static ErrCode PutCompoundEnd(OutputStream &tData, InfoFunc &funcInfo)
noexcept
400 ErrCode eRet = AllOk;
406 STACK_TRACEBACK(
"NBT_TAG::End[0x00(0)] Write");
414 template<
bool bRoot,
bool bSortCompound,
typename OutputStream,
typename InfoFunc>
415 static ErrCode PutCompoundType(OutputStream &tData,
const NBT_Type::Compound &tCompound,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
418 ErrCode eRet = AllOk;
419 CHECK_STACK_DEPTH(szStackDepth);
421 using IterableRangeType =
typename std::conditional_t<bSortCompound, std::vector<NBT_Type::Compound::const_iterator>,
const NBT_Type::Compound &>;
424 IterableRangeType tmpIterableRange =
425 [&](void)
noexcept -> IterableRangeType
427 if constexpr (bSortCompound)
433 catch (
const std::bad_alloc &e)
435 eRet = Error(OutOfMemoryError, tData, funcInfo,
"{}: Info:[{}]", _RP___FUNCTION__, e.what());
436 STACK_TRACEBACK(
"catch(std::bad_alloc)");
439 catch (
const std::exception &e)
441 eRet = Error(StdException, tData, funcInfo,
"{}: Info:[{}]", _RP___FUNCTION__, e.what());
442 STACK_TRACEBACK(
"catch(std::exception)");
447 eRet = Error(UnknownError, tData, funcInfo,
"{}: Info:[Unknown Exception]", _RP___FUNCTION__);
448 STACK_TRACEBACK(
"catch(...)");
459 if constexpr (bSortCompound)
463 STACK_TRACEBACK(
"Lambda: GetIterableRange Error!");
470 for (
const auto &it: tmpIterableRange)
472 const auto &[sName, nodeNbt] = [&](void) ->
const auto &
474 if constexpr (bSortCompound)
484 eRet = PutCompoundEntry<bSortCompound>(tData, sName, nodeNbt, szStackDepth, funcInfo);
487 STACK_TRACEBACK(
"PutCompoundEntry");
492 if constexpr (!bRoot)
494 eRet = PutCompoundEnd(tData, funcInfo);
497 STACK_TRACEBACK(
"PutCompoundEnd");
506 template<
typename OutputStream,
typename InfoFunc>
507 static ErrCode PutStringType(OutputStream &tData,
const NBT_Type::String &tString, InfoFunc &funcInfo)
noexcept
509 ErrCode eRet = AllOk;
511 eRet = PutName(tData, tString, funcInfo);
514 STACK_TRACEBACK(
"PutString");
521 template<
bool bSortCompound,
typename OutputStream,
typename InfoFunc>
522 static ErrCode PutListType(OutputStream &tData,
const NBT_Type::List &tList,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
524 ErrCode eRet = AllOk;
525 CHECK_STACK_DEPTH(szStackDepth);
528 size_t szListLength = tList.size();
531 eRet = Error(ListTooLongError, tData, funcInfo,
"{}:\nszListLength[{}] > ListLength_Max[{}]", __FUNCTION__,
533 STACK_TRACEBACK(
"szListLength Test");
542 bool bNeedWarp =
false;
546 for (
const auto &it : tList)
548 auto curTag = it.GetTag();
551 ++iListEmptyEntryLength;
556 if (bNeedWarp ==
true)
564 enListElementTag = curTag;
569 if (enListElementTag != curTag)
585 STACK_TRACEBACK(
"enListElementTag Write");
590 eRet = WriteBigEndian(tData, iListLength - iListEmptyEntryLength, funcInfo);
593 STACK_TRACEBACK(
"iListLength Write");
602 auto curTag = tmpNode.
GetTag();
607 Error(EndElementIgnoreWarn, tData, funcInfo,
"{}:\ntList[{}] type is [NBT_Type::End], ignored!", __FUNCTION__, i);
614 eRet = PutSwitch<bSortCompound>(tData, tmpNode, enListElementTag, szStackDepth - 1, funcInfo);
618 STACK_TRACEBACK(
"PutSwitch Error, Size: [{}] Index: [{}]", iListLength, i);
629 if (cpdNode.Size() != 1 || !cpdNode.Contains(
MU8STR(
"")))
631 eRet = PutCompoundType<false, bSortCompound>(tData, cpdNode, szStackDepth - 1, funcInfo);
638 eRet = PutCompoundEntry<bSortCompound>(tData,
MU8STR(
""), tmpNode, szStackDepth - 1, funcInfo);
642 STACK_TRACEBACK(
"PutCompoundEntry");
646 eRet = PutCompoundEnd(tData, funcInfo);
649 STACK_TRACEBACK(
"PutCompoundEnd");
658 template<
bool bSortCompound,
typename OutputStream,
typename InfoFunc>
659 static ErrCode PutSwitch(OutputStream &tData,
const NBT_Node &nodeNbt,
NBT_TAG tagNbt,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
661 ErrCode eRet = AllOk;
668 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
674 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
680 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
686 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
692 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
698 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
704 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
710 eRet = PutStringType(tData, nodeNbt.
Get<CurType>(), funcInfo);
716 eRet = PutListType<bSortCompound>(tData, nodeNbt.
Get<CurType>(), szStackDepth, funcInfo);
722 eRet = PutCompoundType<false, bSortCompound>(tData, nodeNbt.
Get<CurType>(), szStackDepth, funcInfo);
728 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
734 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
739 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unexpected Type Tag NBT_TAG::End[0x00(0)]", __FUNCTION__);
744 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
752 STACK_TRACEBACK(
"Tag[0x{:02X}({})] write error!",
774 template<
bool bSortCompound = true,
typename OutputStream,
typename InfoFunc = NBT_Pr
int>
777 return PutCompoundType<true, bSortCompound>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
793 template<
bool bSortCompound = true,
typename DataType = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
797 return PutCompoundType<true, bSortCompound>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
803#undef CHECK_STACK_DEPTH
804#undef STACK_TRACEBACK
808#undef _RP___FUNCTION__