25 NBT_Writer(
void) =
delete;
27 ~NBT_Writer(
void) =
delete;
31 enum ErrCode : uint8_t
47 constexpr static inline const char *
const errReason[] =
62 static_assert(
sizeof(errReason) /
sizeof(errReason[0]) == (ERRCODE_END),
"errReason array out sync");
64 enum WarnCode : uint8_t
73 constexpr static inline const char *
const warnReason[] =
77 "EndElementIgnoreWarn",
81 static_assert(
sizeof(warnReason) /
sizeof(warnReason[0]) == WARNCODE_END,
"warnReason array out sync");
88 template <
typename T,
typename OutputStream,
typename InfoFunc,
typename... Args>
89 requires(std::is_same_v<T, ErrCode> || std::is_same_v<T, WarnCode>)
90 static std::conditional_t<std::is_same_v<T, ErrCode>, ErrCode,
void> Error
93 const OutputStream &tData,
95 const std::format_string<Args...> fmt,
102 if constexpr (std::is_same_v<T, ErrCode>)
105 if (code >= ERRCODE_END)
110 funcInfo(lvl,
"Write Err[{}]: {}\n", (uint8_t)code, errReason[code]);
112 else if constexpr (std::is_same_v<T, WarnCode>)
115 if (code >= WARNCODE_END)
120 funcInfo(lvl,
"Write Warn[{}]: {}\n", (uint8_t)code, warnReason[code]);
124 static_assert(
false,
"Unknown [T code] Type!");
128 funcInfo(lvl,
"Extra Info: \"");
129 funcInfo(lvl, std::move(fmt), std::forward<Args>(args)...);
130 funcInfo(lvl,
"\"\n\n");
133#define VIEW_PRE (8 * 8 + 8)
134 size_t rangeBeg = (tData.Size() > VIEW_PRE) ? (tData.Size() - VIEW_PRE) : (0);
135 size_t rangeEnd = tData.Size();
142 "Data Size: 0x{:02X}({})\n"\
143 "Data Range: [0x{:02X}({}),0x{:02X}({})):\n",
145 (uint64_t)tData.Size(), tData.Size(),
146 (uint64_t)rangeBeg, rangeBeg,
147 (uint64_t)rangeEnd, rangeEnd
151 for (
size_t i = rangeBeg; i < rangeEnd; ++i)
153 if ((i - rangeBeg) % 8 == 0)
159 funcInfo(lvl,
"0x{:02X}: ", (uint64_t)i);
162 funcInfo(lvl,
" {:02X} ", (uint8_t)tData[i]);
166 if constexpr (std::is_same_v<T, ErrCode>)
168 funcInfo(lvl,
"\nSkip err and return...\n\n");
170 else if constexpr (std::is_same_v<T, WarnCode>)
172 funcInfo(lvl,
"\nSkip warn and continue...\n\n");
176 static_assert(
false,
"Unknown [T code] Type!");
180 if constexpr (std::is_same_v<T, ErrCode>)
186#define _RP___FUNCTION__ __FUNCTION__
188#define _RP___LINE__ _RP_STRLING(__LINE__)
189#define _RP_STRLING(l) STRLING(l)
192#define STACK_TRACEBACK(fmt, ...) funcInfo(NBT_Print_Level::Err, "In [{}] Line:[" _RP___LINE__ "]: \n" fmt "\n\n", _RP___FUNCTION__ __VA_OPT__(,) __VA_ARGS__);
193#define CHECK_STACK_DEPTH(depth) \
196 eRet = Error(StackDepthExceeded, tData, funcInfo, "{}: NBT nesting depth exceeded maximum call stack limit", _RP___FUNCTION__);\
197 STACK_TRACEBACK(#depth " == 0");\
207catch(const std::bad_alloc &e)\
209 ErrCode eRet = Error(OutOfMemoryError, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
210 STACK_TRACEBACK("catch(std::bad_alloc)");\
213catch(const std::exception &e)\
215 ErrCode eRet = Error(StdException, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
216 STACK_TRACEBACK("catch(std::exception)");\
221 ErrCode eRet = Error(UnknownError, tData, funcInfo, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);\
222 STACK_TRACEBACK("catch(...)");\
226 template<
typename OutputStream,
typename InfoFunc>
227 static inline ErrCode CheckReserve(OutputStream &tData,
size_t szAddSize, InfoFunc &funcInfo)
noexcept
230 tData.AddReserve(szAddSize);
236 template<
typename T,
typename OutputStream,
typename InfoFunc>
237 requires std::integral<T>
238 static inline ErrCode WriteBigEndian(OutputStream &tData,
const T &tVal, InfoFunc &funcInfo)
noexcept
242 tData.PutRange((
const uint8_t *)&BigEndianVal,
sizeof(BigEndianVal));
247 template<
typename OutputStream,
typename InfoFunc>
248 static ErrCode PutName(OutputStream &tData,
const NBT_Type::String &sName, InfoFunc &funcInfo)
noexcept
251 ErrCode eRet = AllOk;
254 size_t szStringLength = sName.size();
259 eRet = Error(StringTooLongError, tData, funcInfo,
"{}:\nszStringLength[{}] > StringLength_Max[{}]", __FUNCTION__,
261 STACK_TRACEBACK(
"szStringLength Test");
267 eRet = WriteBigEndian(tData, wStringLength, funcInfo);
270 STACK_TRACEBACK(
"wStringLength Write");
274 using ValueType = NBT_Type::String::value_type;
275 size_t szStringSize = szStringLength *
sizeof(ValueType);
278 eRet = CheckReserve(tData, szStringSize, funcInfo);
281 STACK_TRACEBACK(
"CheckReserve Error, Check Size: [{}]", szStringSize);
285 tData.PutRange((
const typename OutputStream::ValueType *)sName.data(), szStringSize);
291 template<
typename T,
typename OutputStream,
typename InfoFunc>
292 static ErrCode PutbuiltInType(OutputStream &tData,
const T &tBuiltIn, InfoFunc &funcInfo)
noexcept
294 ErrCode eRet = AllOk;
298 RAW_DATA_T tTmpRawData = std::bit_cast<RAW_DATA_T>(tBuiltIn);
300 eRet = WriteBigEndian(tData, tTmpRawData, funcInfo);
303 STACK_TRACEBACK(
"tTmpRawData Write");
310 template<
typename T,
typename OutputStream,
typename InfoFunc>
311 static ErrCode PutArrayType(OutputStream &tData,
const T &tArray, InfoFunc &funcInfo)
noexcept
313 ErrCode eRet = AllOk;
317 size_t szArrayLength = tArray.size();
320 eRet = Error(ArrayTooLongError, tData, funcInfo,
"{}:\nszArrayLength[{}] > ArrayLength_Max[{}]", __FUNCTION__,
322 STACK_TRACEBACK(
"szArrayLength Test");
328 eRet = WriteBigEndian(tData, iArrayLength, funcInfo);
331 STACK_TRACEBACK(
"iArrayLength Write");
335 using ValueType =
typename T::value_type;
336 size_t szArraySize = szArrayLength *
sizeof(ValueType);
339 eRet = CheckReserve(tData, szArraySize, funcInfo);
342 STACK_TRACEBACK(
"CheckReserve Error, Check Size: [{}]", szArraySize);
346 for (
size_t i = 0; i < szArrayLength; ++i)
348 eRet = WriteBigEndian(tData, tArray[i], funcInfo);
351 STACK_TRACEBACK(
"tTmpData Write");
359 template<
typename SortPolicy,
typename OutputStream,
typename InfoFunc>
360 static ErrCode PutCompoundEntry(OutputStream &tData,
const NBT_Type::String &sName,
const NBT_Node &nodeNbt,
size_t szStackDepth, InfoFunc &funcInfo)
362 ErrCode eRet = AllOk;
371 Error(EndElementIgnoreWarn, tData, funcInfo,
"{}:\nName: \"{}\", type is [NBT_Type::End], ignored!", __FUNCTION__,
377 eRet = WriteBigEndian(tData, (
NBT_TAG_RAW_TYPE)enCompoundEntryTag, funcInfo);
380 STACK_TRACEBACK(
"enCompoundEntryTag Write");
385 eRet = PutName(tData, sName, funcInfo);
393 eRet = PutSwitch<SortPolicy>(tData, nodeNbt, enCompoundEntryTag, szStackDepth - 1, funcInfo);
396 STACK_TRACEBACK(
"PutSwitch Error, Name: \"{}\", Type: [NBT_Type::{}]",
404 template<
typename OutputStream,
typename InfoFunc>
405 static ErrCode PutCompoundEnd(OutputStream &tData, InfoFunc &funcInfo)
noexcept
407 ErrCode eRet = AllOk;
413 STACK_TRACEBACK(
"NBT_TAG::End[0x00(0)] Write");
421 template<
bool bRoot,
typename SortPolicy,
typename OutputStream,
typename InfoFunc>
422 static ErrCode PutCompoundType(OutputStream &tData,
const NBT_Type::Compound &tCompound,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
425 ErrCode eRet = AllOk;
426 CHECK_STACK_DEPTH(szStackDepth);
428 using IterableRangeType =
typename std::conditional_t<std::is_same_v<SortPolicy, NoSortCompound>,
const NBT_Type::Compound &, std::vector<NBT_Type::Compound::Const_Iterator>>;
431 IterableRangeType tmpIterableRange =
432 [&](void)
noexcept -> IterableRangeType
434 if constexpr (std::is_same_v<SortPolicy, NoSortCompound>)
442 return SortPolicy{}(tCompound);
444 catch (
const std::bad_alloc &e)
446 eRet = Error(OutOfMemoryError, tData, funcInfo,
"{}: Info:[{}]", _RP___FUNCTION__, e.what());
447 STACK_TRACEBACK(
"catch(std::bad_alloc)");
450 catch (
const std::exception &e)
452 eRet = Error(StdException, tData, funcInfo,
"{}: Info:[{}]", _RP___FUNCTION__, e.what());
453 STACK_TRACEBACK(
"catch(std::exception)");
458 eRet = Error(UnknownError, tData, funcInfo,
"{}: Info:[Unknown Exception]", _RP___FUNCTION__);
459 STACK_TRACEBACK(
"catch(...)");
466 if constexpr (!std::is_same_v<SortPolicy, NoSortCompound>)
470 STACK_TRACEBACK(
"Lambda: GetIterableRange Error!");
477 for (
const auto &it: tmpIterableRange)
479 const auto &[sName, nodeNbt] = [&](void) ->
const auto &
481 if constexpr (std::is_same_v<SortPolicy, NoSortCompound>)
491 eRet = PutCompoundEntry<SortPolicy>(tData, sName, nodeNbt, szStackDepth, funcInfo);
494 STACK_TRACEBACK(
"PutCompoundEntry");
499 if constexpr (!bRoot)
501 eRet = PutCompoundEnd(tData, funcInfo);
504 STACK_TRACEBACK(
"PutCompoundEnd");
513 template<
typename OutputStream,
typename InfoFunc>
514 static ErrCode PutStringType(OutputStream &tData,
const NBT_Type::String &tString, InfoFunc &funcInfo)
noexcept
516 ErrCode eRet = AllOk;
518 eRet = PutName(tData, tString, funcInfo);
521 STACK_TRACEBACK(
"PutString");
528 template<
typename SortPolicy,
typename OutputStream,
typename InfoFunc>
529 static ErrCode PutListType(OutputStream &tData,
const NBT_Type::List &tList,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
531 ErrCode eRet = AllOk;
532 CHECK_STACK_DEPTH(szStackDepth);
535 size_t szListEmptyEntryLength = 0;
538 bool bNeedWarp =
false;
542 for (
const auto &it : tList)
547 ++szListEmptyEntryLength;
552 if (bNeedWarp ==
true)
560 enListElementTag = curTag;
565 if (enListElementTag != curTag)
579 size_t szListLength = tList.size();
580 size_t szListNoEmptyEntryLength = szListLength - szListEmptyEntryLength;
583 eRet = Error(ListTooLongError, tData, funcInfo,
"{}:\nszListNoEmptyEntryLength[{}] > ListLength_Max[{}]", __FUNCTION__,
585 STACK_TRACEBACK(
"szListLength Test");
593 STACK_TRACEBACK(
"enListElementTag Write");
599 eRet = WriteBigEndian(tData, iListLength, funcInfo);
602 STACK_TRACEBACK(
"iListLength Write");
607 for (
size_t i = 0; i < szListLength; ++i)
616 Error(EndElementIgnoreWarn, tData, funcInfo,
"{}:\ntList[{}] type is [NBT_Type::End], ignored!", __FUNCTION__, i);
623 eRet = PutSwitch<SortPolicy>(tData, tmpNode, enListElementTag, szStackDepth - 1, funcInfo);
627 STACK_TRACEBACK(
"PutSwitch Error, Size: [{}] Index: [{}]", szListLength, i);
638 if (cpdNode.Size() != 1 || !cpdNode.Contains(
MU8STR(
"")))
640 eRet = PutCompoundType<false, SortPolicy>(tData, cpdNode, szStackDepth - 1, funcInfo);
647 eRet = PutCompoundEntry<SortPolicy>(tData,
MU8STR(
""), tmpNode, szStackDepth - 1, funcInfo);
651 STACK_TRACEBACK(
"PutCompoundEntry");
655 eRet = PutCompoundEnd(tData, funcInfo);
658 STACK_TRACEBACK(
"PutCompoundEnd");
667 template<
typename SortPolicy,
typename OutputStream,
typename InfoFunc>
668 static ErrCode PutSwitch(OutputStream &tData,
const NBT_Node &nodeNbt,
NBT_TAG tagNbt,
size_t szStackDepth, InfoFunc &funcInfo)
noexcept
670 ErrCode eRet = AllOk;
677 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
683 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
689 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
695 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
701 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
707 eRet = PutbuiltInType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
713 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
719 eRet = PutStringType(tData, nodeNbt.
Get<CurType>(), funcInfo);
725 eRet = PutListType<SortPolicy>(tData, nodeNbt.
Get<CurType>(), szStackDepth, funcInfo);
731 eRet = PutCompoundType<false, SortPolicy>(tData, nodeNbt.
Get<CurType>(), szStackDepth, funcInfo);
737 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
743 eRet = PutArrayType<CurType>(tData, nodeNbt.
Get<CurType>(), funcInfo);
748 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unexpected Type Tag NBT_TAG::End[0x00(0)]", __FUNCTION__);
753 eRet = Error(NbtTypeTagError, tData, funcInfo,
"{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
761 STACK_TRACEBACK(
"Tag[0x{:02X}({})] write error!",
777 template<
bool bAscending = true>
804 template<
typename SortPolicy = DefaultCompoundSort<true>,
typename OutputStream,
typename InfoFunc = NBT_Pr
int>
805 static bool WriteNBT(OutputStream &OptStream,
const NBT_Type::Compound &tCompound,
size_t szStackDepth = 512, InfoFunc funcInfo = InfoFunc{})
noexcept
807 return PutCompoundType<true, SortPolicy>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
823 template<
typename SortPolicy = DefaultCompoundSort<true>,
typename DataType = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
824 static bool WriteNBT(DataType &tDataOutput,
size_t szStartIdx,
const NBT_Type::Compound &tCompound,
size_t szStackDepth = 512, InfoFunc funcInfo = InfoFunc{})
noexcept
827 return PutCompoundType<true, SortPolicy>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
830#ifdef CJF2_NBT_CPP_USE_ZLIB
840 template <
typename InfoFunc = NBT_Pr
int>
844 std::vector<uint8_t> vNbtData;
845 if (!
WriteNBT(vNbtData, 0, tCompound, 512, funcInfo))
852 std::vector<uint8_t> vFileData;
856 vFileData = std::move(vNbtData);
861 vNbtData.shrink_to_fit();
877#undef CHECK_STACK_DEPTH
878#undef STACK_TRACEBACK
882#undef _RP___FUNCTION__