chenjunfu2-nbt-cpp v2.1.0
一个基于CPP20的NBT(Named Binary Tag)库
载入中...
搜索中...
未找到
NBT_Writer.hpp
浏览该文件的文档.
1#pragma once
2
3#include <new>//std::bad_alloc
4#include <bit>//std::bit_cast
5#include <vector>//字节流
6#include <stdint.h>//类型定义
7#include <stddef.h>//size_t
8#include <stdlib.h>//byte swap
9#include <utility>//std::move
10#include <type_traits>//类型约束
11#include <algorithm>//std::sort
12
13#include "NBT_Print.hpp"//打印输出
14#include "NBT_Node.hpp"//nbt类型
15#include "NBT_Endian.hpp"//字节序
16
19
21class NBT_Writer
22{
24 NBT_Writer(void) = delete;
26 ~NBT_Writer(void) = delete;
27
28protected:
30 enum ErrCode : uint8_t
31 {
32 AllOk = 0,//没有问题
33
34 UnknownError,//其他错误(代码问题)
35 StdException,//标准异常(代码问题)
36 OutOfMemoryError,//内存不足错误(代码问题)
37 StackDepthExceeded,//调用栈深度过深(代码问题)
38 StringTooLongError,//字符串过长错误(代码问题)
39 ArrayTooLongError,//数组过长错误(代码问题)
40 ListTooLongError,//列表过长错误(代码问题)
41 NbtTypeTagError,//NBT标签类型错误(代码问题)
42
43 ERRCODE_END,//结束标记
44 };
45
46 constexpr static inline const char *const errReason[] =
47 {
48 "AllOk",
49
50 "UnknownError",
51 "StdException",
52 "OutOfMemoryError",
53 "StackDepthExceeded",
54 "StringTooLongError",
55 "ArrayTooLongError",
56 "ListTooLongError",
57 "NbtTypeTagError",
58 };
59
60 //记得同步数组!
61 static_assert(sizeof(errReason) / sizeof(errReason[0]) == (ERRCODE_END), "errReason array out sync");
62
63 enum WarnCode : uint8_t
64 {
65 NoWarn = 0,
66
67 EndElementIgnoreWarn,
68
69 WARNCODE_END,
70 };
71
72 constexpr static inline const char *const warnReason[] =//正常数组,直接用WarnCode访问
73 {
74 "NoWarn",
75
76 "EndElementIgnoreWarn",
77 };
78
79 //记得同步数组!
80 static_assert(sizeof(warnReason) / sizeof(warnReason[0]) == WARNCODE_END, "warnReason array out sync");
81
82 //error处理
83 //使用变参形参表+vprintf代理复杂输出,给出更多扩展信息
84 //主动检查引发的错误,主动调用eRet = Error报告,然后触发STACK_TRACEBACK,最后返回eRet到上一级
85 //上一级返回的错误通过if (eRet != AllOk)判断的,直接触发STACK_TRACEBACK后返回eRet到上一级
86 //如果是警告值,则不返回值
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
90 (
91 const T &code,
92 const OutputStream &tData,
93 InfoFunc &funcInfo,
94 const std::format_string<Args...> fmt,
95 Args&&... args
96 ) noexcept
97 {
99
100 //打印错误原因
101 if constexpr (std::is_same_v<T, ErrCode>)
102 {
104 if (code >= ERRCODE_END)
105 {
106 return code;
107 }
108 //上方if保证code不会溢出
109 funcInfo(lvl, "Read Err[{}]: {}\n", (uint8_t)code, errReason[code]);
110 }
111 else if constexpr (std::is_same_v<T, WarnCode>)
112 {
114 if (code >= WARNCODE_END)
115 {
116 return;
117 }
118 //上方if保证code不会溢出
119 funcInfo(lvl, "Read Warn[{}]: {}\n", (uint8_t)code, warnReason[code]);
120 }
121 else
122 {
123 static_assert(false, "Unknown [T code] Type!");
124 }
125
126 //打印扩展信息
127 funcInfo(lvl, "Extra Info: \"");
128 funcInfo(lvl, std::move(fmt), std::forward<Args>(args)...);
129 funcInfo(lvl, "\"\n\n");
130
131 //如果可以,预览szCurrent前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();//下边界裁切
135#undef VIEW_PRE
136 //输出信息
137 funcInfo
138 (
139 lvl,
140 "Data Review:\n"\
141 "Data Size: 0x{:02X}({})\n"\
142 "Data Range: [0x{:02X}({}),0x{:02X}({})):\n",
143
144 (uint64_t)tData.Size(), tData.Size(),
145 (uint64_t)rangeBeg, rangeBeg,
146 (uint64_t)rangeEnd, rangeEnd
147 );
148
149 //打数据
150 for (size_t i = rangeBeg; i < rangeEnd; ++i)
151 {
152 if ((i - rangeBeg) % 8 == 0)//输出地址
153 {
154 if (i != rangeBeg)//除去第一个每8个换行
155 {
156 funcInfo(lvl, "\n");
157 }
158 funcInfo(lvl, "0x{:02X}: ", (uint64_t)i);
159 }
160
161 funcInfo(lvl, " {:02X} ", (uint8_t)tData[i]);
162 }
163
164 //输出提示信息
165 if constexpr (std::is_same_v<T, ErrCode>)
166 {
167 funcInfo(lvl, "\nSkip err and return...\n\n");
168 }
169 else if constexpr (std::is_same_v<T, WarnCode>)
170 {
171 funcInfo(lvl, "\nSkip warn and continue...\n\n");
172 }
173 else
174 {
175 static_assert(false, "Unknown [T code] Type!");
176 }
177
178 //警告不返回值
179 if constexpr (std::is_same_v<T, ErrCode>)
180 {
181 return code;
182 }
183 }
184
185#define _RP___FUNCTION__ __FUNCTION__//用于编译过程二次替换达到函数内部
186
187#define _RP___LINE__ _RP_STRLING(__LINE__)
188#define _RP_STRLING(l) STRLING(l)
189#define STRLING(l) #l
190
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) \
193if((Depth) <= 0)\
194{\
195 eRet = Error(StackDepthExceeded, tData, funcInfo, "{}: NBT nesting depth exceeded maximum call stack limit", _RP___FUNCTION__);\
196 STACK_TRACEBACK("(Depth) <= 0");\
197 return eRet;\
198}\
199
200#define MYTRY \
201try\
202{
203
204#define MYCATCH \
205}\
206catch(const std::bad_alloc &e)\
207{\
208 ErrCode eRet = Error(OutOfMemoryError, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
209 STACK_TRACEBACK("catch(std::bad_alloc)");\
210 return eRet;\
211}\
212catch(const std::exception &e)\
213{\
214 ErrCode eRet = Error(StdException, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
215 STACK_TRACEBACK("catch(std::exception)");\
216 return eRet;\
217}\
218catch(...)\
219{\
220 ErrCode eRet = Error(UnknownError, tData, funcInfo, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);\
221 STACK_TRACEBACK("catch(...)");\
222 return eRet;\
223}
224
225 template<typename OutputStream, typename InfoFunc>
226 static inline ErrCode CheckReserve(OutputStream &tData, size_t szAddSize, InfoFunc &funcInfo) noexcept
227 {
228 MYTRY;
229 tData.AddReserve(szAddSize);
230 return AllOk;
231 MYCATCH;
232 }
233
234 //写出大端序值
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
238 {
239 MYTRY;
240 auto BigEndianVal = NBT_Endian::NativeToBigAny(tVal);
241 tData.PutRange((const uint8_t *)&BigEndianVal, sizeof(BigEndianVal));
242 return AllOk;
243 MYCATCH;
244 }
245
246 template<typename OutputStream, typename InfoFunc>
247 static ErrCode PutName(OutputStream &tData, const NBT_Type::String &sName, InfoFunc &funcInfo) noexcept
248 {
249 MYTRY;
250 ErrCode eRet = AllOk;
251
252 //获取string长度
253 size_t szStringLength = sName.size();
254
255 //检查大小是否符合上限
256 if (szStringLength > (size_t)NBT_Type::StringLength_Max)
257 {
258 eRet = Error(StringTooLongError, tData, funcInfo, "{}:\nszStringLength[{}] > StringLength_Max[{}]", __FUNCTION__,
259 szStringLength, (size_t)NBT_Type::StringLength_Max);
260 STACK_TRACEBACK("szStringLength Test");
261 return eRet;
262 }
263
264 //输出名称长度
265 NBT_Type::StringLength wNameLength = (uint16_t)szStringLength;
266 eRet = WriteBigEndian(tData, wNameLength, funcInfo);
267 if (eRet != AllOk)
268 {
269 STACK_TRACEBACK("wNameLength Write");
270 return eRet;
271 }
272
273 //输出名称
274 eRet = CheckReserve(tData, szStringLength * sizeof(sName[0]), funcInfo);//提前分配
275 if (eRet != AllOk)
276 {
277 STACK_TRACEBACK("CheckReserve Fail, Check Size: [{}]", szStringLength * sizeof(sName[0]));
278 return eRet;
279 }
280 //范围写入
281 tData.PutRange((const typename OutputStream::ValueType *)sName.data(), szStringLength);
282
283 return eRet;
284 MYCATCH;
285 }
286
287 template<typename T, typename OutputStream, typename InfoFunc>
288 static ErrCode PutbuiltInType(OutputStream &tData, const T &tBuiltIn, InfoFunc &funcInfo) noexcept
289 {
290 ErrCode eRet = AllOk;
291
292 //获取原始类型,然后转换到raw类型准备写出
293 using RAW_DATA_T = NBT_Type::BuiltinRawType_T<T>;//原始类型映射
294 RAW_DATA_T tTmpRawData = std::bit_cast<RAW_DATA_T>(tBuiltIn);
295
296 eRet = WriteBigEndian(tData, tTmpRawData, funcInfo);
297 if (eRet != AllOk)
298 {
299 STACK_TRACEBACK("tTmpRawData Write");
300 return eRet;
301 }
302
303 return eRet;
304 }
305
306 template<typename T, typename OutputStream, typename InfoFunc>
307 static ErrCode PutArrayType(OutputStream &tData, const T &tArray, InfoFunc &funcInfo) noexcept
308 {
309 ErrCode eRet = AllOk;
310
311 //获取数组大小判断是否超过要求上限
312 //也就是4字节有符号整数上限
313 size_t szArrayLength = tArray.size();
314 if (szArrayLength > (size_t)NBT_Type::ArrayLength_Max)
315 {
316 eRet = Error(ArrayTooLongError, tData, funcInfo, "{}:\nszArrayLength[{}] > ArrayLength_Max[{}]", __FUNCTION__,
317 szArrayLength, (size_t)NBT_Type::ArrayLength_Max);
318 STACK_TRACEBACK("szArrayLength Test");
319 return eRet;
320 }
321
322 //获取实际写出大小
323 NBT_Type::ArrayLength iArrayLength = (NBT_Type::ArrayLength)szArrayLength;
324 eRet = WriteBigEndian(tData, iArrayLength, funcInfo);
325 if (eRet != AllOk)
326 {
327 STACK_TRACEBACK("iArrayLength Write");
328 return eRet;
329 }
330
331 //写出元素
332 eRet = CheckReserve(tData, iArrayLength * sizeof(tArray[0]), funcInfo);//提前分配
333 if (eRet != AllOk)
334 {
335 STACK_TRACEBACK("CheckReserve Fail, Check Size: [{}]", iArrayLength * sizeof(tArray[0]));
336 return eRet;
337 }
338
339 for (NBT_Type::ArrayLength i = 0; i < iArrayLength; ++i)
340 {
341 eRet = WriteBigEndian(tData, tArray[i], funcInfo);
342 if (eRet != AllOk)
343 {
344 STACK_TRACEBACK("tTmpData Write");
345 return eRet;
346 }
347 }
348
349 return eRet;
350 }
351
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)//它不是noexcept的
354 {
355 ErrCode eRet = AllOk;
356
357 //获取类型
358 NBT_TAG curTag = nodeNbt.GetTag();
359
360 //集合中如果存在nbt end类型的元素,删除而不输出
361 if (curTag == NBT_TAG::End)
362 {
363 //End元素被忽略警告(警告不返回错误码)
364 Error(EndElementIgnoreWarn, tData, funcInfo, "{}:\nName: \"{}\", type is [NBT_Type::End], ignored!", __FUNCTION__,
365 sName.ToCharTypeUTF8());//此处ToCharTypeUTF8可能抛异常
366 return eRet;
367 }
368
369 //先写出tag
370 eRet = WriteBigEndian(tData, (NBT_TAG_RAW_TYPE)curTag, funcInfo);
371 if (eRet != AllOk)
372 {
373 STACK_TRACEBACK("curTag Write");
374 return eRet;
375 }
376
377 //然后写出name
378 eRet = PutName(tData, sName, funcInfo);
379 if (eRet != AllOk)
380 {
381 STACK_TRACEBACK("PutName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(curTag));
382 return eRet;
383 }
384
385 //最后根据tag类型写出数据
386 eRet = PutSwitch<bSortCompound>(tData, nodeNbt, curTag, szStackDepth - 1, funcInfo);
387 if (eRet != AllOk)
388 {
389 STACK_TRACEBACK("PutSwitch Fail, Name: \"{}\", Type: [NBT_Type::{}]",
390 sName.ToCharTypeUTF8(), NBT_Type::GetTypeName(curTag));//此处ToCharTypeUTF8可能抛异常
391 return eRet;
392 }
393
394 return eRet;
395 }
396
397 template<typename OutputStream, typename InfoFunc>
398 static ErrCode PutCompoundEnd(OutputStream &tData, InfoFunc &funcInfo) noexcept
399 {
400 ErrCode eRet = AllOk;
401
402 //注意Compound类型有一个NBT_TAG::End结尾
403 eRet = WriteBigEndian(tData, (NBT_TAG_RAW_TYPE)NBT_TAG::End, funcInfo);
404 if (eRet != AllOk)
405 {
406 STACK_TRACEBACK("NBT_TAG::End[0x00(0)] Write");
407 return eRet;
408 }
409
410 return eRet;
411 }
412
413 //如果是非根部,则会输出额外的Compound_End
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
416 {
417 MYTRY;
418 ErrCode eRet = AllOk;
419 CHECK_STACK_DEPTH(szStackDepth);
420
421 using IterableRangeType = typename std::conditional_t<bSortCompound, std::vector<NBT_Type::Compound::const_iterator>, const NBT_Type::Compound &>;
422
423 //通过模板bSortCompound指定是否执行排序输出(nbt中仅compound是无序结构)
424 IterableRangeType tmpIterableRange =//注意此处如果内部抛出异常,返回空vector的情况下还有可能二次异常,所以外部还需另一个try catch
425 [&](void) noexcept -> IterableRangeType
426 {
427 if constexpr (bSortCompound)
428 {
429 try//筛掉标准库异常
430 {
431 return tCompound.KeySortIt();
432 }
433 catch (const std::bad_alloc &e)
434 {
435 eRet = Error(OutOfMemoryError, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());
436 STACK_TRACEBACK("catch(std::bad_alloc)");
437 return {};
438 }
439 catch (const std::exception &e)
440 {
441 eRet = Error(StdException, tData, funcInfo, "{}: Info:[{}]", _RP___FUNCTION__, e.what());
442 STACK_TRACEBACK("catch(std::exception)");
443 return {};
444 }
445 catch (...)
446 {
447 eRet = Error(UnknownError, tData, funcInfo, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);
448 STACK_TRACEBACK("catch(...)");
449 return {};
450 }
451 }
452 else
453 {
454 return tCompound;
455 }
456 }();
457
458 //判断错误码是否被设置
459 if constexpr (bSortCompound)
460 {
461 if (eRet != AllOk)
462 {
463 STACK_TRACEBACK("Lambda: GetIterableRange Error!");
464 return eRet;
465 }
466 }
467
468 //注意compound是为数不多的没有元素数量限制的结构
469 //此处无需检查大小,且无需写出大小
470 for (const auto &it: tmpIterableRange)
471 {
472 const auto &[sName, nodeNbt] = [&](void) -> const auto &
473 {
474 if constexpr (bSortCompound)
475 {
476 return *it;
477 }
478 else
479 {
480 return it;
481 }
482 }();
483
484 eRet = PutCompoundEntry<bSortCompound>(tData, sName, nodeNbt, szStackDepth, funcInfo);
485 if (eRet != AllOk)
486 {
487 STACK_TRACEBACK("PutCompoundEntry");
488 return eRet;
489 }
490 }
491
492 if constexpr (!bRoot)
493 {
494 eRet = PutCompoundEnd(tData, funcInfo);
495 if (eRet != AllOk)
496 {
497 STACK_TRACEBACK("PutCompoundEnd");
498 return eRet;
499 }
500 }
501
502 return eRet;
503 MYCATCH;
504 }
505
506 template<typename OutputStream, typename InfoFunc>
507 static ErrCode PutStringType(OutputStream &tData, const NBT_Type::String &tString, InfoFunc &funcInfo) noexcept
508 {
509 ErrCode eRet = AllOk;
510
511 eRet = PutName(tData, tString, funcInfo);//借用PutName实现,因为string走的name相同操作
512 if (eRet != AllOk)
513 {
514 STACK_TRACEBACK("PutString");//因为是借用实现,所以这里小小的改个名,防止报错Name误导人
515 return eRet;
516 }
517
518 return eRet;
519 }
520
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
523 {
524 ErrCode eRet = AllOk;
525 CHECK_STACK_DEPTH(szStackDepth);
526
527 //检查
528 size_t szListLength = tList.size();
529 if (szListLength > (size_t)NBT_Type::ListLength_Max)//大于的情况下强制赋值会导致严重问题,只能返回错误
530 {
531 eRet = Error(ListTooLongError, tData, funcInfo, "{}:\nszListLength[{}] > ListLength_Max[{}]", __FUNCTION__,
532 szListLength, (size_t)NBT_Type::ListLength_Max);
533 STACK_TRACEBACK("szListLength Test");
534 return eRet;
535 }
536
537 //转换为写入大小
538 NBT_Type::ListLength iListLength = (NBT_Type::ListLength)szListLength;
539 NBT_Type::ListLength iListEmptyEntryLength = 0;//统计空元素数量
540
541 //获取列表标签
542 bool bNeedWarp = false;
543 NBT_TAG enListElementTag = NBT_TAG::End;
544
545 //判断列表元素一致性,不一致则使用Compound封装
546 for (const auto &it : tList)
547 {
548 auto curTag = it.GetTag();
549 if (curTag == NBT_TAG::End)
550 {
551 ++iListEmptyEntryLength;//统计空元素数量
552 continue;//空元素没有后续判断必要性,跳过
553 }
554
555 //如果已经确定需要进行替换,则跳过
556 if (bNeedWarp == true)
557 {
558 continue;
559 }
560
561 //如果列表元素值为End,那么替换为当前类型
562 if (enListElementTag == NBT_TAG::End)
563 {
564 enListElementTag = curTag;
565 continue;
566 }
567
568 //类型不同则设为替换类型
569 if (enListElementTag != curTag)
570 {
571 bNeedWarp = true;
572 enListElementTag = NBT_TAG::Compound;//修改为Compound封装
573 }
574 }
575
576 //执行到这里:如果tList为空,那么enListElementTag恰好为End,符合0长度且为End的情况
577 //如果List不为空:
578 //元素不同:bNeedWarp为true且enListElementTag为Compound
579 //元素相同:bNeedWarp为false且enListElementTag为列表元素类型
580
581 //写出标签
582 eRet = WriteBigEndian(tData, (NBT_TAG_RAW_TYPE)enListElementTag, funcInfo);
583 if (eRet != AllOk)
584 {
585 STACK_TRACEBACK("enListElementTag Write");
586 return eRet;
587 }
588
589 //写出长度,不包含空元素,所以减去iListEmptyEntryLength
590 eRet = WriteBigEndian(tData, iListLength - iListEmptyEntryLength, funcInfo);
591 if (eRet != AllOk)
592 {
593 STACK_TRACEBACK("iListLength Write");
594 return eRet;
595 }
596
597 //写出列表(递归)
598 for (NBT_Type::ListLength i = 0; i < iListLength; ++i)//注意遍历仍然需要遍历整个列表,而不是iListLength - iListEmptyEntryLength
599 {
600 //获取元素与类型
601 const NBT_Node &tmpNode = tList[i];
602 auto curTag = tmpNode.GetTag();
603
604 if (curTag == NBT_TAG::End)//空元素跳过
605 {
606 //End元素被忽略警告(警告不返回错误码)
607 Error(EndElementIgnoreWarn, tData, funcInfo, "{}:\ntList[{}] type is [NBT_Type::End], ignored!", __FUNCTION__, i);
608 continue;//跳过
609 }
610
611 if (!bNeedWarp)//不需要封装,直接写出
612 {
613 //列表无名字,无需重复tag,只需输出数据
614 eRet = PutSwitch<bSortCompound>(tData, tmpNode, enListElementTag, szStackDepth - 1, funcInfo);//同一元素类型List
615
616 if (eRet != AllOk)
617 {
618 STACK_TRACEBACK("PutSwitch Error, Size: [{}] Index: [{}]", iListLength, i);
619 return eRet;
620 }
621 }
622 else//需要封装,添加Compound
623 {
624 //如果元素本身就是Compound,那么检测是否和封装模式匹配,是的话再套一层防止丢失语义
625
626 if (curTag == NBT_TAG::Compound)
627 {
628 const auto &cpdNode = tmpNode.GetCompound();
629 if (cpdNode.Size() != 1 || !cpdNode.Contains(MU8STR("")))//直接写出为Compound
630 {
631 eRet = PutCompoundType<false, bSortCompound>(tData, cpdNode, szStackDepth - 1, funcInfo);
632 continue;
633 }
634 }
635
636 //是Compound但是需要再套一层或者不是Compound
637 MYTRY;
638 eRet = PutCompoundEntry<bSortCompound>(tData, MU8STR(""), tmpNode, szStackDepth - 1, funcInfo);
639 MYCATCH;
640 if (eRet != AllOk)
641 {
642 STACK_TRACEBACK("PutCompoundEntry");
643 return eRet;
644 }
645
646 eRet = PutCompoundEnd(tData, funcInfo);
647 if (eRet != AllOk)
648 {
649 STACK_TRACEBACK("PutCompoundEnd");
650 return eRet;
651 }
652 }
653 }
654
655 return eRet;
656 }
657
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
660 {
661 ErrCode eRet = AllOk;
662
663 switch (tagNbt)
664 {
665 case NBT_TAG::Byte:
666 {
668 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
669 }
670 break;
671 case NBT_TAG::Short:
672 {
674 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
675 }
676 break;
677 case NBT_TAG::Int:
678 {
680 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
681 }
682 break;
683 case NBT_TAG::Long:
684 {
686 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
687 }
688 break;
689 case NBT_TAG::Float:
690 {
692 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
693 }
694 break;
695 case NBT_TAG::Double:
696 {
698 eRet = PutbuiltInType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
699 }
700 break;
702 {
704 eRet = PutArrayType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
705 }
706 break;
707 case NBT_TAG::String://类型唯一,非模板函数
708 {
710 eRet = PutStringType(tData, nodeNbt.Get<CurType>(), funcInfo);
711 }
712 break;
713 case NBT_TAG::List://可能递归,需要处理szStackDepth
714 {
716 eRet = PutListType<bSortCompound>(tData, nodeNbt.Get<CurType>(), szStackDepth, funcInfo);
717 }
718 break;
719 case NBT_TAG::Compound://可能递归,需要处理szStackDepth
720 {
722 eRet = PutCompoundType<false, bSortCompound>(tData, nodeNbt.Get<CurType>(), szStackDepth, funcInfo);
723 }
724 break;
726 {
728 eRet = PutArrayType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
729 }
730 break;
732 {
734 eRet = PutArrayType<CurType>(tData, nodeNbt.Get<CurType>(), funcInfo);
735 }
736 break;
737 case NBT_TAG::End://注意end标签绝对不可以进来
738 {
739 eRet = Error(NbtTypeTagError, tData, funcInfo, "{}:\nNBT Tag switch error: Unexpected Type Tag NBT_TAG::End[0x00(0)]", __FUNCTION__);
740 }
741 break;
742 default://数据出错
743 {
744 eRet = Error(NbtTypeTagError, tData, funcInfo, "{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
745 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);//此处不进行提前返回,往后默认返回处理
746 }
747 break;
748 }
749
750 if (eRet != AllOk)//如果出错,打一下栈回溯
751 {
752 STACK_TRACEBACK("Tag[0x{:02X}({})] write error!",
753 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);
754 }
755
756 return eRet;
757 }
759
760public:
761 //输出到tData中,部分功能和原理参照ReadNBT处的注释,szDataStartIndex在此处可以对一个tData通过不同的tCompound和szStartIdx = tData.size()
762 //来调用以达到把多个不同的nbt输出到同一个tData内的功能
763
774 template<bool bSortCompound = true, typename OutputStream, typename InfoFunc = NBT_Print>
775 static bool WriteNBT(OutputStream &OptStream, const NBT_Type::Compound &tCompound, size_t szStackDepth = 512, InfoFunc funcInfo = NBT_Print{}) noexcept
776 {
777 return PutCompoundType<true, bSortCompound>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
778 }
779
793 template<bool bSortCompound = true, typename DataType = std::vector<uint8_t>, typename InfoFunc = NBT_Print>
794 static bool WriteNBT(DataType &tDataOutput, size_t szStartIdx, const NBT_Type::Compound &tCompound, size_t szStackDepth = 512, InfoFunc funcInfo = NBT_Print{}) noexcept
795 {
796 NBT_IO::DefaultOutputStream<DataType> OptStream(tDataOutput, szStartIdx);
797 return PutCompoundType<true, bSortCompound>(OptStream, tCompound, szStackDepth, funcInfo) == AllOk;
798 }
799
800
801#undef MYTRY
802#undef MYCATCH
803#undef CHECK_STACK_DEPTH
804#undef STACK_TRACEBACK
805#undef STRLING
806#undef _RP_STRLING
807#undef _RP___LINE__
808#undef _RP___FUNCTION__
809};
端序工具集
NBT节点类型,支持存储所有NBT类型的变体
#define MU8STR(charLiteralString)
从C风格字符串获取M-UTF-8的字符串
定义 NBT_Node.hpp:21
用于处理NBT信息打印的默认实现
NBT_Print_Level
用于指示信息打印等级的枚举
定义 NBT_Print.hpp:11
@ Warn
警告信息
定义 NBT_Print.hpp:13
@ Err
错误信息
定义 NBT_Print.hpp:14
uint8_t NBT_TAG_RAW_TYPE
NBT_TAG的原始类型,用于二进制读写或判断等
定义 NBT_TAG.hpp:12
NBT_TAG
枚举NBT类型对应的类型标签值
定义 NBT_TAG.hpp:17
@ Int
对应NBT_Type::Int
定义 NBT_TAG.hpp:21
@ Float
对应NBT_Type::Float
定义 NBT_TAG.hpp:23
@ Compound
对应NBT_Type::Compound
定义 NBT_TAG.hpp:28
@ String
对应NBT_Type::String
定义 NBT_TAG.hpp:26
@ ByteArray
对应NBT_Type::ByteArray
定义 NBT_TAG.hpp:25
@ Short
对应NBT_Type::Short
定义 NBT_TAG.hpp:20
@ List
对应NBT_Type::List
定义 NBT_TAG.hpp:27
@ Long
对应NBT_Type::Long
定义 NBT_TAG.hpp:22
@ End
对应NBT_Type::End
定义 NBT_TAG.hpp:18
@ LongArray
对应NBT_Type::LongArray
定义 NBT_TAG.hpp:30
@ Byte
对应NBT_Type::Byte
定义 NBT_TAG.hpp:19
@ IntArray
对应NBT_Type::IntArray
定义 NBT_TAG.hpp:29
@ Double
对应NBT_Type::Double
定义 NBT_TAG.hpp:24
std::vector< typename Compound::iterator > KeySortIt(void)
获取按键名排序的迭代器向量(非常量版本)
定义 NBT_Compound.hpp:216
static T NativeToBigAny(T data) noexcept
从当前平台字节序转换到大端字节序,自动匹配位数
定义 NBT_Endian.hpp:173
默认输出流类,用于将数据写入到标准库容器中
定义 NBT_IO.hpp:204
NBT节点,用于存储NBT格式的各种数据类型
定义 NBT_Node.hpp:37
NBT_TAG GetTag() const noexcept
获取当前存储的NBT类型的枚举值
定义 NBT_Node.hpp:189
const NBT_Type::Compound & GetCompound() const
获取当前对象中存储的 Compound 类型的数据
定义 NBT_Node.hpp:285
const T & Get() const
通过指定类型获取当前存储的数据对象
定义 NBT_Node.hpp:200
一个用于打印信息到指定的C文件对象的工具类,作为库内大部分存在信息输出接口的默认实现。 实际可被使用此类为默认值参数的函数的调用方,以类似此类的仿函数参数重写的其它类型替换, 比如调用方实现了一个My_...
定义 NBT_Print.hpp:24
auto ToCharTypeUTF8(void) const
转换到UTF-8字符编码,但是返回为char类型而非char8_t类型
定义 NBT_String.hpp:283
typename TagToType< Tag >::type TagToType_T
从NBT_TAG获取对应的类型:编译期从NBT_TAG的enum值获取类型
定义 NBT_Type.hpp:250
int32_t ArrayLength
数组长度类型
定义 NBT_Type.hpp:136
static constexpr StringLength StringLength_Max
字符串长度类型最大值
定义 NBT_Type.hpp:146
NBT_String< std::basic_string< uint8_t >, std::basic_string_view< uint8_t > > String
字符串类型,存储Java M-UTF-8字符串
定义 NBT_Type.hpp:64
NBT_List< std::vector< NBT_Node > > List
列表类型,可顺序存储任意相同的NBT类型
定义 NBT_Type.hpp:68
NBT_Compound< std::unordered_map< String, NBT_Node > > Compound
集合类型,可存储任意不同的NBT类型,通过名称映射值
定义 NBT_Type.hpp:72
typename BuiltinRawType< T >::Type BuiltinRawType_T
映射内建类型到方便读写的raw类型:编译期获得内建类型到可以进行二进制读写的原始类型
定义 NBT_Type.hpp:341
int32_t ListLength
列表长度类型
定义 NBT_Type.hpp:138
uint16_t StringLength
字符串长度类型
定义 NBT_Type.hpp:137
static constexpr ListLength ListLength_Max
列表长度类型最大值
定义 NBT_Type.hpp:149
static constexpr ArrayLength ArrayLength_Max
数组长度类型最大值
定义 NBT_Type.hpp:143
static constexpr const char * GetTypeName(NBT_TAG tag) noexcept
通过类型标签获取类型名称
定义 NBT_Type.hpp:123
static bool WriteNBT(OutputStream &OptStream, const NBT_Type::Compound &tCompound, size_t szStackDepth=512, InfoFunc funcInfo=NBT_Print{}) noexcept
将NBT_Type::Compound对象写入到输出流中
定义 NBT_Writer.hpp:775
static bool WriteNBT(DataType &tDataOutput, size_t szStartIdx, const NBT_Type::Compound &tCompound, size_t szStackDepth=512, InfoFunc funcInfo=NBT_Print{}) noexcept
将NBT_Type::Compound对象写入到数据容器中
定义 NBT_Writer.hpp:794