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