chenjunfu2-nbt-cpp v2.1.3
一个基于CPP20的NBT(Named Binary Tag)库
载入中...
搜索中...
未找到
NBT_Scanner.hpp
浏览该文件的文档.
1#pragma once
2
3#include "NBT_Node.hpp"//nbt类型
4#include "NBT_Visitor.hpp"//鸭子类与部分实现
5#include "NBT_Endian.hpp"//字节序
6#include "NBT_IO.hpp"//IO流对象
7
8#include <stdint.h>
9
12
17class NBT_Scanner
18{
20 NBT_Scanner(void) = delete;
22 ~NBT_Scanner(void) = delete;
23
24protected:
26 enum class Control : uint8_t
27 {
28 Continue,
29 Break,
30 Stop,
31 Error,
32 };
33
34 static Control ResultControlToControl(NBT_Visitor_ResultControl enResultControl)
35 {
36 switch (enResultControl)
37 {
38 case NBT_Visitor_ResultControl::Continue: return Control::Continue; break;
39 case NBT_Visitor_ResultControl::Break: return Control::Break; break;
40 case NBT_Visitor_ResultControl::Stop: return Control::Stop; break;
41 default: return Control::Error; break;
42 }
43 }
44
45protected:
46 enum ErrCode : uint8_t
47 {
48 AllOk = 0,//没有问题
49
50 UnknownError,//其他错误(代码问题)
51 StdException,//标准异常(代码问题)
52 UnknownControlCode,//未知的控制码(代码问题)
53 ListElementTypeError,//列表元素类型错误(NBT文件问题)
54 OutOfMemoryError,//内存不足错误(NBT文件问题)
55 StackDepthExceeded,//调用栈深度过深(NBT文件or代码设置问题)
56 NbtTypeTagError,//NBT标签类型错误(NBT文件问题)
57 OutOfRangeError,//(NBT内部长度错误溢出)(NBT文件问题)
58
59 ERRCODE_END,//结束标记,统计负数部分大小
60 };
61
62 constexpr static inline const char *const errReason[] =
63 {
64 "AllOk",
65
66 "UnknownError",
67 "StdException",
68 "UnknownControlCode",
69 "ListElementTypeError",
70 "OutOfMemoryError",
71 "StackDepthExceeded",
72 "NbtTypeTagError",
73 "OutOfRangeError",
74 };
75
76 //记得同步数组!
77 static_assert(sizeof(errReason) / sizeof(errReason[0]) == ERRCODE_END, "errReason array out sync");
78
79 template <typename InputStream, typename Visitor, typename... Args>
80 static ErrCode Error
81 (
82 const ErrCode errCode,
83 const InputStream &tData,
84 Visitor &tVisitor,
85 const std::format_string<Args...> fmt,
86 Args&&... args
87 ) noexcept
88 {
89 if (errCode >= ERRCODE_END)//保证errCode不会溢出
90 {
91 return errCode;
92 }
93
94 //打印错误原因
96 tVisitor.VisitError(lvl, "Scan Err[{}]: {}\n", (uint8_t)errCode, errReason[errCode]);
97
98 //打印扩展信息
99 tVisitor.VisitError(lvl, "Extra Info: \"");
100 tVisitor.VisitError(lvl, std::move(fmt), std::forward<Args>(args)...);
101 tVisitor.VisitError(lvl, "\"\n\n");
102
103 //如果可以,预览szCurrent前后n个字符,否则裁切到边界
104#define VIEW_PRE (4 * 8 + 3)//向前
105#define VIEW_SUF (4 * 8 + 5)//向后
106 size_t rangeBeg = (tData.Index() > VIEW_PRE) ? (tData.Index() - VIEW_PRE) : (0);//上边界裁切
107 size_t rangeEnd = ((tData.Index() + VIEW_SUF) < tData.Size()) ? (tData.Index() + VIEW_SUF) : (tData.Size());//下边界裁切
108#undef VIEW_SUF
109#undef VIEW_PRE
110 //输出信息
111 tVisitor.VisitError
112 (
113 lvl,
114 "Data Review:\n"\
115 "Current: 0x{:02X}({})\n"\
116 "Data Size: 0x{:02X}({})\n"\
117 "Data Range: [0x{:02X}({}),0x{:02X}({})):\n",
118
119 (uint64_t)tData.Index(), tData.Index(),
120 (uint64_t)tData.Size(), tData.Size(),
121 (uint64_t)rangeBeg, rangeBeg,
122 (uint64_t)rangeEnd, rangeEnd
123 );
124
125 //打数据
126 for (size_t i = rangeBeg; i < rangeEnd; ++i)
127 {
128 if ((i - rangeBeg) % 8 == 0)//输出地址
129 {
130 if (i != rangeBeg)//除去第一个每8个换行
131 {
132 tVisitor.VisitError(lvl, "\n");
133 }
134 tVisitor.VisitError(lvl, "0x{:02X}: ", (uint64_t)i);
135 }
136
137 if (i != tData.Index())
138 {
139 tVisitor.VisitError(lvl, " {:02X} ", (uint8_t)tData[i]);
140 }
141 else//如果是当前出错字节,加方括号框起
142 {
143 tVisitor.VisitError(lvl, "[{:02X}]", (uint8_t)tData[i]);
144 }
145 }
146
147 //输出提示信息
148 tVisitor.VisitError(lvl, "\nSkip err data and return...\n\n");
149
150 return errCode;
151 }
152
153#define _RP___FUNCTION__ __FUNCTION__//用于编译过程二次替换达到函数内部
154
155#define _RP___LINE__ _RP_STRLING(__LINE__)
156#define _RP_STRLING(l) STRLING(l)
157#define STRLING(l) #l
158
159#define STACK_TRACEBACK(fmt, ...) tVisitor.VisitError(NBT_Print_Level::Err, "In [{}] Line:[" _RP___LINE__ "]: \n" fmt "\n\n", _RP___FUNCTION__ __VA_OPT__(,) __VA_ARGS__);
160#define CHECK_STACK_DEPTH(depth, ret) \
161if((depth) == 0)\
162{\
163 Error(StackDepthExceeded, tData, tVisitor, "{}: NBT nesting depth exceeded maximum call stack limit", _RP___FUNCTION__);\
164 STACK_TRACEBACK(#depth " == 0");\
165 return ret;\
166}
167
168#define UNKNOWN_CONTROL_CODE(func, ret) \
169{\
170 Error(UnknownControlCode, tData, tVisitor, "Function [" #func "] return unknown control code");\
171 STACK_TRACEBACK("ControlCode Test");\
172 return ret;\
173}
174
175#define CALL_FUNC_RET_CONTROL(name, val) \
176do\
177{\
178 Control controlRet = ResultControlToControl(val);\
179 if (controlRet == Control::Error)\
180 {\
181 Error(UnknownControlCode, tData, tVisitor, "Function [" #name "] return unknown control code");\
182 STACK_TRACEBACK("ControlCode Test");\
183 }\
184 return controlRet;\
185}while(false)
186
187#define MYTRY \
188try\
189{
190
191#define MYCATCH(ret) \
192}\
193catch(const std::bad_alloc &e)\
194{\
195 Error(OutOfMemoryError, tData, tVisitor, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
196 STACK_TRACEBACK("catch(std::bad_alloc)");\
197 return ret;\
198}\
199catch(const std::exception &e)\
200{\
201 Error(StdException, tData, tVisitor, "{}: Info:[{}]", _RP___FUNCTION__, e.what());\
202 STACK_TRACEBACK("catch(std::exception)");\
203 return ret;\
204}\
205catch(...)\
206{\
207 Error(UnknownError, tData, tVisitor, "{}: Info:[Unknown Exception]", _RP___FUNCTION__);\
208 STACK_TRACEBACK("catch(...)");\
209 return ret;\
210}
211
212 template<bool bNoCheck = false, typename T, typename InputStream, typename Visitor>
213 requires std::integral<T>
214 static inline std::conditional_t<bNoCheck, void, bool> ReadBigEndian(InputStream &tData, T &tVal, Visitor &tVisitor) noexcept
215 {
216 if constexpr (!bNoCheck)
217 {
218 if (!tData.HasAvailData(sizeof(T)))
219 {
220 Error(OutOfRangeError, tData, tVisitor, "tData size [{}], current index [{}], remaining data size [{}], but try to read [{}]",
221 tData.Size(), tData.Index(), tData.Size() - tData.Index(), sizeof(T));
222 STACK_TRACEBACK("HasAvailData Test");
223 return false;
224 }
225 }
226
227 T BigEndianVal{};
228 tData.GetRange((void *)&BigEndianVal, sizeof(BigEndianVal));
229 tVal = NBT_Endian::BigToNativeAny(BigEndianVal);
230
231 if constexpr (!bNoCheck)
232 {
233 return true;
234 }
235 }
236
237 template<typename InputStream, typename Visitor>
238 static bool GetName(InputStream &tData, NBT_Type::String &tName, Visitor &tVisitor) noexcept
239 {
240 MYTRY;
241 //读取长度
242 NBT_Type::StringLength wStringLength = 0;//w->word=2*byte
243 if (!ReadBigEndian(tData, wStringLength, tVisitor))
244 {
245 STACK_TRACEBACK("wStringLength Read");
246 return false;
247 }
248
249 using ValueType = NBT_Type::String::value_type;
250 size_t szStringLength = (size_t)wStringLength;
251 size_t szStringSize = szStringLength * sizeof(ValueType);
252
253 //检查长度
254 if (!tData.HasAvailData(szStringSize))
255 {
256 Error(OutOfRangeError, tData, tVisitor, "{}:\n(Index[{}] + szStringLength[{}])[{}] > DataSize[{}]", __FUNCTION__,
257 tData.Index(), szStringLength, tData.Index() + szStringLength, tData.Size());
258 STACK_TRACEBACK("HasAvailData Test");
259 return false;
260 }
261
262 //解析出名称
263 tName.resize(szStringLength);//设置大小
264 tData.GetRange((void *)tName.data(), szStringSize);//构造string(如果长度为0则构造0长字符串,合法行为)
265
266 return true;
267 MYCATCH(false);
268 }
269
270 template<typename InputStream, typename Visitor>
271 static bool SkipName(InputStream &tData, Visitor &tVisitor) noexcept
272 {
273 //读取长度
274 NBT_Type::StringLength wStringLength = 0;//w->word=2*byte
275 if (!ReadBigEndian(tData, wStringLength, tVisitor))
276 {
277 STACK_TRACEBACK("wStringLength Read");
278 return false;
279 }
280
281 size_t szSkipSize = (size_t)wStringLength * sizeof(NBT_Type::String::value_type);
282
283 //检查长度
284 if (!tData.HasAvailData(szSkipSize))
285 {
286 Error(OutOfRangeError, tData, tVisitor, "{}:\n(Index[{}] + szSkipSize[{}])[{}] > DataSize[{}]", __FUNCTION__,
287 tData.Index(), szSkipSize, tData.Index() + szSkipSize, tData.Size());
288 STACK_TRACEBACK("HasAvailData Test");
289 return false;
290 }
291
292 //跳过数据
293 tData.SkipData(szSkipSize);
294 return true;
295 }
296
297 template<typename InputStream, typename Visitor>
298 static Control ScanEndType(InputStream &tData, Visitor &tVisitor) noexcept
299 {
300 MYTRY;
301 return ResultControlToControl(tVisitor.VisitListEnd());
302 MYCATCH(Control::Error);
303 }
304
305 template<typename InputStream, typename Visitor>
306 static bool SkipEndType(InputStream &tData, Visitor &tVisitor) noexcept
307 {
308 //EndType无数据负载
309 return true;
310 }
311
312 template<typename T, typename InputStream, typename Visitor>
313 static Control ScanBuiltInType(InputStream &tData, Visitor &tVisitor) noexcept
314 {
315 using RAW_DATA_T = NBT_Type::BuiltinRawType_T<T>;//类型映射
316 RAW_DATA_T tTmpRawData = 0;
317 if (!ReadBigEndian(tData, tTmpRawData, tVisitor))
318 {
319 STACK_TRACEBACK("tTmpRawData Read");
320 return Control::Error;
321 }
322
323 MYTRY;
324 CALL_FUNC_RET_CONTROL(tVisitor.VisitNumericResult<T>, tVisitor.template VisitNumericResult<T>(std::bit_cast<T>(tTmpRawData)));
325 MYCATCH(Control::Error);
326 }
327
328 template<typename T, typename InputStream, typename Visitor>
329 static bool SkipBuiltInType(InputStream &tData, Visitor &tVisitor) noexcept
330 {
331 using RAW_DATA_T = NBT_Type::BuiltinRawType_T<T>;//类型映射
332 size_t szSkipSize = sizeof(RAW_DATA_T);
333
334 if (!tData.HasAvailData(szSkipSize))
335 {
336 Error(OutOfRangeError, tData, tVisitor, "{}:\n(Index[{}] + szSkipSize[{}])[{}] > DataSize[{}]", __FUNCTION__,
337 tData.Index(), szSkipSize, tData.Index() + szSkipSize, tData.Size());
338 STACK_TRACEBACK("HasAvailData Test");
339 return false;
340 }
341
342 //跳过数据
343 tData.SkipData(szSkipSize);
344 return true;
345 }
346
347 template<typename T, typename InputStream, typename Visitor>
348 static Control ScanArrayType(InputStream &tData, Visitor &tVisitor) noexcept
349 {
350 MYTRY;
351 //获取4字节有符号数,代表数组元素个数
352 NBT_Type::ArrayLength iArrayLength = 0;//4byte
353 if (!ReadBigEndian(tData, iArrayLength, tVisitor))
354 {
355 STACK_TRACEBACK("iArrayLength Read");
356 return Control::Error;
357 }
358
359 //检查有符号数大小范围
360 if (iArrayLength < 0)
361 {
362 Error(OutOfRangeError, tData, tVisitor, ":\niArrayLength[{}] < 0", __FUNCTION__, iArrayLength);
363 STACK_TRACEBACK("iArrayLength Test");
364 return Control::Error;
365 }
366
367 //验证完成,类型转换
368 using ValueType = typename T::value_type;
369 size_t szArrayLength = (size_t)iArrayLength;
370 size_t szArraySize = szArrayLength * sizeof(ValueType);
371
372 //先进行合法性检查
373 if (!tData.HasAvailData(szArraySize))
374 {
375 Error(OutOfRangeError, tData, tVisitor, "{}:\n(Index[{}] + szArraySize[{}])[{}] > DataSize[{}]", __FUNCTION__,
376 tData.Index(), szArrayLength, tData.Index() + szArraySize, tData.Size());
377 STACK_TRACEBACK("HasAvailData Test");
378 return Control::Error;
379 }
380
381 //数组保存
382 T tArray{};
383 tArray.reserve(szArrayLength);
384
385 //读取dElementCount个元素
386 for (size_t i = 0; i < szArrayLength; ++i)
387 {
388 ValueType tTmpData{};
389 ReadBigEndian<true>(tData, tTmpData, tVisitor);//调用需要确保范围安全(已在前面检查)
390 tArray.emplace_back(std::move(tTmpData));//读取一个插入一个
391 }
392
393 CALL_FUNC_RET_CONTROL(tVisitor.VisitArrayResult<T>, tVisitor.template VisitArrayResult<T>(std::move(tArray)));
394 MYCATCH(Control::Error);
395 }
396
397 template<typename T, typename InputStream, typename Visitor>
398 static bool SkipArrayType(InputStream &tData, Visitor &tVisitor) noexcept
399 {
400 //获取4字节有符号数,代表数组元素个数
401 NBT_Type::ArrayLength iArrayLength = 0;//4byte
402 if (!ReadBigEndian(tData, iArrayLength, tVisitor))
403 {
404 STACK_TRACEBACK("iArrayLength Read");
405 return false;
406 }
407
408 //检查有符号数大小范围
409 if (iArrayLength < 0)
410 {
411 Error(OutOfRangeError, tData, tVisitor, ":\niArrayLength[{}] < 0", __FUNCTION__, iArrayLength);
412 STACK_TRACEBACK("iArrayLength Test");
413 return false;
414 }
415
416 size_t szSkipSize = (size_t)iArrayLength * sizeof(typename T::value_type);
417
418 if (!tData.HasAvailData(szSkipSize))
419 {
420 Error(OutOfRangeError, tData, tVisitor, "{}:\n(Index[{}] + szSkipSize[{}])[{}] > DataSize[{}]", __FUNCTION__,
421 tData.Index(), szSkipSize, tData.Index() + szSkipSize, tData.Size());
422 STACK_TRACEBACK("HasAvailData Test");
423 return false;
424 }
425
426 tData.SkipData(szSkipSize);//直接递增索引跳过
427 return true;
428 }
429
430 template<typename InputStream, typename Visitor>
431 static Control ScanStringType(InputStream &tData, Visitor &tVisitor) noexcept
432 {
433 NBT_Type::String tString;
434 if (!GetName(tData, tString, tVisitor))//转发调用
435 {
436 STACK_TRACEBACK("GetString");
437 return Control::Error;
438 }
439
440 MYTRY;
441 CALL_FUNC_RET_CONTROL(tVisitor.VisitStringResult, tVisitor.VisitStringResult(std::move(tString)));
442 MYCATCH(Control::Error);
443 }
444
445 template<typename InputStream, typename Visitor>
446 static bool SkipStringType(InputStream &tData, Visitor &tVisitor) noexcept
447 {
448 if (!SkipName(tData, tVisitor))//转发调用
449 {
450 STACK_TRACEBACK("SkipString");
451 return false;
452 }
453
454 return true;
455 }
456
457 template<typename InputStream, typename Visitor>
458 static Control ScanListType(InputStream &tData, Visitor &tVisitor, size_t szStackDepth) noexcept
459 {
460 MYTRY;
461 //栈深度检测
462 CHECK_STACK_DEPTH(szStackDepth, Control::Error);
463
464 //读取列表标签
465 NBT_TAG_RAW_TYPE u8ListElementTag = 0;//b=byte
466 if (!ReadBigEndian(tData, u8ListElementTag, tVisitor))
467 {
468 STACK_TRACEBACK("u8ListElementTag Read");
469 return Control::Error;
470 }
471
472 //标签验证
473 if (u8ListElementTag >= NBT_TAG::ENUM_END)
474 {
475 Error(NbtTypeTagError, tData, tVisitor, "{}:\nList NBT Type:Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
476 (NBT_TAG_RAW_TYPE)u8ListElementTag, (NBT_TAG_RAW_TYPE)u8ListElementTag);
477 STACK_TRACEBACK("u8ListElementTag Test");
478 return Control::Error;
479 }
480
481 //类型转换
482 NBT_TAG enListElementTag = (NBT_TAG)u8ListElementTag;
483
484 //读取列表长度
485 NBT_Type::ListLength iListLength = 0;//4byte
486 if (!ReadBigEndian(tData, iListLength, tVisitor))
487 {
488 STACK_TRACEBACK("iListLength Read");
489 return Control::Error;
490 }
491
492 //验证
493 if (iListLength < 0)
494 {
495 Error(OutOfRangeError, tData, tVisitor, ":\niListLength[{}] < 0", __FUNCTION__, iListLength);
496 STACK_TRACEBACK("iListLength Test");
497 return Control::Error;
498 }
499
500 //类型转换
501 size_t szListLength = (size_t)iListLength;
502
503 //大小&类型判断
504 if (enListElementTag == NBT_TAG::End && szListLength != 0)
505 {
506 Error(ListElementTypeError, tData, tVisitor, "{}:\nThe list with TAG_End[0x00] tag must be empty, but [{}] elements were found", __FUNCTION__,
507 szListLength);
508 STACK_TRACEBACK("enListElementTag And szListLength Test");
509 return Control::Error;
510 }
511
512 //类型设置
513 if (szListLength == 0 && enListElementTag != NBT_TAG::End)
514 {
515 enListElementTag = NBT_TAG::End;
516 }
517
518 //遍历索引
519 size_t i = 0;//声明在外面,用于跳过剩余的起始位置
520
521 //访问器开始回调
522 switch (tVisitor.VisitListBegin(enListElementTag, szListLength))
523 {
524 case NBT_Visitor_ResultControl::Continue: /*继续(什么也不做)*/ break;
525 case NBT_Visitor_ResultControl::Break: goto skip_any; break;//这时候索引从0开始,跳过所有
526 case NBT_Visitor_ResultControl::Stop: return Control::Stop; break;
527 default:
528 UNKNOWN_CONTROL_CODE(tVisitor.VisitListBegin, Control::Error);
529 break;
530 }
531
532 //遍历读取
533 for (; i < szListLength; ++i)
534 {
535 //访问器元素回调
536 switch (tVisitor.VisitListElementBegin(enListElementTag, i))
537 {
538 case NBT_Visitor_NestingControl::Enter: /*进入值(什么也不做)*/ break;
539 case NBT_Visitor_NestingControl::Skip: //跳过当前元素
540 {
541 if (!SkipSwitch(tData, enListElementTag, tVisitor, szStackDepth - 1))
542 {
543 STACK_TRACEBACK("SkipSwitch Error, Size: [{}] Index: [{}]", szListLength, i);
544 return Control::Error;
545 }
546 continue;//跳过当前并继续
547 }
548 break;
549 case NBT_Visitor_NestingControl::Break: goto skip_any; break;//跳过剩余所有列表元素,注意当前元素还未读取,所以下面依旧从i开始跳
550 case NBT_Visitor_NestingControl::Stop: return Control::Stop; break;
551 default:
552 UNKNOWN_CONTROL_CODE(tVisitor.VisitListElementBegin, Control::Error);
553 break;
554 }
555
556 //元素递归访问
557 switch (ScanSwitch(tData, enListElementTag, tVisitor, szStackDepth - 1))
558 {
559 case Control::Continue: /*继续(什么也不做)*/ break;
560 case Control::Break: goto skip_any; break;//跳过剩余所有
561 case Control::Stop: return Control::Stop; break;
562 case Control::Error:
563 STACK_TRACEBACK("ScanSwitch Error, Size: [{}] Index: [{}]", szListLength, i);
564 return Control::Error;
565 break;
566 default:
567 UNKNOWN_CONTROL_CODE(ScanSwitch, Control::Error);
568 break;
569 }
570
571 //元素结束回调
572 switch (tVisitor.VisitListElementEnd(enListElementTag, i))
573 {
574 case NBT_Visitor_ResultControl::Continue: /*继续(什么也不做)*/ break;
575 case NBT_Visitor_ResultControl::Break: goto skip_any; break;//跳过剩余所有
576 case NBT_Visitor_ResultControl::Stop: return Control::Stop; break;
577 default:
578 UNKNOWN_CONTROL_CODE(tVisitor.VisitListElementEnd, Control::Error);
579 break;
580 }
581 }
582
583 skip_any://跳过剩余,如果没有则不跳过
584 for (size_t j = i; j < szListLength; ++j)//从当前i开始跳到结束
585 {
586 if (!SkipSwitch(tData, enListElementTag, tVisitor, szStackDepth - 1))
587 {
588 STACK_TRACEBACK("SkipSwitch Error, Size: [{}] Index: [{}]", szListLength, j);
589 return Control::Error;
590 }
591 }
592
593 //返回控制标签
594 CALL_FUNC_RET_CONTROL(tVisitor.VisitListEnd, tVisitor.VisitListEnd());
595 MYCATCH(Control::Error);
596 }
597
598 template<typename InputStream, typename Visitor>
599 static bool SkipListType(InputStream &tData, Visitor &tVisitor, size_t szStackDepth) noexcept
600 {
601 //栈深度检测
602 CHECK_STACK_DEPTH(szStackDepth, false);
603
604 NBT_TAG_RAW_TYPE u8ListElementTag = 0;//b=byte
605 if (!ReadBigEndian(tData, u8ListElementTag, tVisitor))
606 {
607 STACK_TRACEBACK("u8ListElementTag Read");
608 return false;
609 }
610
611 if (u8ListElementTag >= NBT_TAG::ENUM_END)
612 {
613 Error(NbtTypeTagError, tData, tVisitor, "{}:\nList NBT Type:Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
614 (NBT_TAG_RAW_TYPE)u8ListElementTag, (NBT_TAG_RAW_TYPE)u8ListElementTag);
615 STACK_TRACEBACK("u8ListElementTag Test");
616 return false;
617 }
618
619 NBT_TAG enListElementTag = (NBT_TAG)u8ListElementTag;
620
621 NBT_Type::ListLength iListLength = 0;//4byte
622 if (!ReadBigEndian(tData, iListLength, tVisitor))
623 {
624 STACK_TRACEBACK("iListLength Read");
625 return false;
626 }
627
628 if (iListLength < 0)
629 {
630 Error(OutOfRangeError, tData, tVisitor, ":\niListLength[{}] < 0", __FUNCTION__, iListLength);
631 STACK_TRACEBACK("iListLength Test");
632 return false;
633 }
634
635 size_t szListLength = (size_t)iListLength;
636
637 if (enListElementTag == NBT_TAG::End && szListLength != 0)
638 {
639 Error(ListElementTypeError, tData, tVisitor, "{}:\nThe list with TAG_End[0x00] tag must be empty, but [{}] elements were found", __FUNCTION__,
640 szListLength);
641 STACK_TRACEBACK("enListElementTag And szListLength Test");
642 return false;
643 }
644
645 if (szListLength == 0 && enListElementTag != NBT_TAG::End)
646 {
647 enListElementTag = NBT_TAG::End;
648 }
649
650 size_t szSkipLength = szListLength;
651
652 for (size_t i = 0; i < szSkipLength; ++i)
653 {
654 if (!SkipSwitch(tData, enListElementTag, tVisitor, szStackDepth - 1))
655 {
656 STACK_TRACEBACK("SkipSwitch Error, Size: [{}] Index: [{}]", szListLength, i);
657 return false;
658 }
659 }
660
661 return true;
662 }
663
664 template<bool bRoot, typename InputStream, typename Visitor>
665 static Control ScanCompoundType(InputStream &tData, Visitor &tVisitor, size_t szStackDepth) noexcept
666 {
667 MYTRY;
668 //栈深度检测
669 CHECK_STACK_DEPTH(szStackDepth, Control::Error);
670
671 if constexpr (!bRoot)//非根部才进行compound调用
672 {
673 switch (tVisitor.VisitCompoundBegin())
674 {
675 case NBT_Visitor_ResultControl::Continue: /*继续(什么也不做)*/ break;
676 case NBT_Visitor_ResultControl::Break: goto skip_any; break;//跳过所有
677 case NBT_Visitor_ResultControl::Stop: return Control::Stop; break;
678 default:
679 UNKNOWN_CONTROL_CODE(tVisitor.VisitCompoundBegin, Control::Error);
680 break;
681 }
682 }
683 else//根部调用访问器起始回调
684 {
685 tVisitor.VisitBegin();
686 }
687
688 //循环直到内部退出
689 while (true)
690 {
691 //处理末尾情况
692 if (!tData.HasAvailData(sizeof(NBT_TAG_RAW_TYPE)))
693 {
694 if constexpr (!bRoot)//非根部情况遇到末尾,则报错
695 {
696 Error(OutOfRangeError, tData, tVisitor, "{}:\nIndex[{}] >= DataSize()[{}]", __FUNCTION__,
697 tData.Index(), tData.Size());
698 STACK_TRACEBACK("HasAvailData Test");
699 return Control::Error;
700 }
701 else//根部遇到末尾,正常结束
702 {
703 return Control::Stop;
704 }
705 }
706
707 //先读取一下类型
708 NBT_TAG_RAW_TYPE u8CompoundEntryTag = (NBT_TAG_RAW_TYPE)tData.GetNext();
709 if (u8CompoundEntryTag == NBT_TAG::End)//处理End情况
710 {
711 goto end_return;//遇到end tag,正常离开
712 }
713
714 //范围验证
715 if (u8CompoundEntryTag >= NBT_TAG::ENUM_END)
716 {
717 Error(NbtTypeTagError, tData, tVisitor, "{}:\nNBT Tag switch default: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
718 u8CompoundEntryTag, u8CompoundEntryTag);
719 STACK_TRACEBACK("u8CompoundEntryTag Test");
720 return Control::Error;
721 }
722
723 //验证完成,类型转换
724 NBT_TAG enCompoundEntryTag = (NBT_TAG)u8CompoundEntryTag;
725
726 //访问器条目回调(仅类型)
727 switch (tVisitor.VisitCompoundNextEntryType(enCompoundEntryTag))
728 {
729 case NBT_Visitor_NestingControl::Enter: /*进入(什么也不做)*/ break;
730 case NBT_Visitor_NestingControl::Skip: //跳过一个
731 {
732 //类型已被读取
733 //跳过名称
734 if (!SkipName(tData, tVisitor))
735 {
736 STACK_TRACEBACK("SkipName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
737 return Control::Error;
738 }
739
740 //跳过数据
741 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
742 {
743 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
744 return Control::Error;
745 }
746 }
747 break;
748 case NBT_Visitor_NestingControl::Break: //跳过所有(离开)
749 {
750 //类型已被读取
751 //跳过名称
752 if (!SkipName(tData, tVisitor))
753 {
754 STACK_TRACEBACK("SkipName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
755 return Control::Error;
756 }
757
758 //跳过数据
759 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
760 {
761 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
762 return Control::Error;
763 }
764
765 //前面跳过当前剩余未完成的部分,然后到尾部跳过所有
766 goto skip_any;
767 }
768 break;
769 case NBT_Visitor_NestingControl::Stop: return Control::Stop; break;
770 default:
771 UNKNOWN_CONTROL_CODE(tVisitor.VisitCompoundNextEntryType, Control::Error);
772 break;
773 }
774
775 //读取名称
776 NBT_Type::String sName{};
777 if (!GetName(tData, sName, tVisitor))
778 {
779 STACK_TRACEBACK("GetName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
780 return Control::Error;
781 }
782
783 //调用访问器(类型名称)
784 switch (tVisitor.VisitCompoundEntryBegin(enCompoundEntryTag, std::move(sName)))
785 {
786 case NBT_Visitor_NestingControl::Enter: /*进入(什么也不做)*/ break;
787 case NBT_Visitor_NestingControl::Skip: //跳过一个
788 {
789 //类型、名称已被读取
790 //跳过数据
791 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
792 {
793 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
794 return Control::Error;
795 }
796 continue;//继续上面的循环
797 }
798 break;
799 case NBT_Visitor_NestingControl::Break://跳过剩余
800 {
801 //类型、名称已被读取
802 //跳过数据
803 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))//先跳过当前
804 {
805 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
806 return Control::Error;
807 }
808
809 //前面跳过当前剩余未完成的部分,然后到尾部跳过所有
810 goto skip_any;
811 }
812 break;
813 case NBT_Visitor_NestingControl::Stop: return Control::Stop; break;
814 default:
815 UNKNOWN_CONTROL_CODE(tVisitor.VisitCompoundEntryBegin, Control::Error);
816 break;
817 }
818
819 //元素递归访问
820 switch (ScanSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
821 {
822 case Control::Continue: /*继续(什么也不做)*/ break;
823 case Control::Break: goto skip_any; break;//跳过剩余所有
824 case Control::Stop: return Control::Stop; break;
825 case Control::Error:
826 STACK_TRACEBACK("ScanSwitch Error, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
827 return Control::Error;
828 break;
829 default:
830 UNKNOWN_CONTROL_CODE(ScanSwitch, Control::Error);
831 break;
832 }
833
834 //元素访问结束回调
835 switch (tVisitor.VisitCompoundEntryEnd(enCompoundEntryTag, std::move(sName)))
836 {
837 case NBT_Visitor_ResultControl::Continue: /*继续(什么也不做)*/ break;
838 case NBT_Visitor_ResultControl::Break: goto skip_any; break;//跳过剩余所有
839 case NBT_Visitor_ResultControl::Stop: return Control::Stop; break;
840 default:
841 UNKNOWN_CONTROL_CODE(tVisitor.VisitCompoundEntryEnd, Control::Error);
842 break;
843 }
844 }
845
846 skip_any://跳过剩下所有数据
847 while (true)
848 {
849 //跳过剩余的compound值
850 //处理末尾情况
851 if (!tData.HasAvailData(sizeof(NBT_TAG_RAW_TYPE)))
852 {
853 if constexpr (!bRoot)//非根部情况遇到末尾,则报错
854 {
855 Error(OutOfRangeError, tData, tVisitor, "{}:\nIndex[{}] >= DataSize()[{}]", __FUNCTION__,
856 tData.Index(), tData.Size());
857 STACK_TRACEBACK("HasAvailData Test");
858 return Control::Error;
859 }
860 else
861 {
862 return Control::Stop;//结束
863 }
864 }
865
866 NBT_TAG_RAW_TYPE u8CompoundEntryTag = (NBT_TAG_RAW_TYPE)tData.GetNext();
867
868 if (u8CompoundEntryTag == NBT_TAG::End)
869 {
870 goto end_return;//遇到end tag,正常离开
871 }
872
873 if (u8CompoundEntryTag >= NBT_TAG::ENUM_END)
874 {
875 Error(NbtTypeTagError, tData, tVisitor, "{}:\nNBT Tag switch default: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
876 u8CompoundEntryTag, u8CompoundEntryTag);
877 STACK_TRACEBACK("u8CompoundEntryTag Test");
878 return Control::Error;
879 }
880
881 NBT_TAG enCompoundEntryTag = (NBT_TAG)u8CompoundEntryTag;
882
883 if (!SkipName(tData, tVisitor))
884 {
885 STACK_TRACEBACK("SkipName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
886 return Control::Error;
887 }
888
889 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
890 {
891 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
892 return Control::Error;
893 }
894 }
895
896 end_return://结束返回
897 if constexpr (!bRoot)
898 {
899 CALL_FUNC_RET_CONTROL(tVisitor.VisitCompoundEnd, tVisitor.VisitCompoundEnd());//返回
900 }
901 else
902 {
903 tVisitor.VisitEnd();//根部调用结束
904 return Control::Stop;//根部直接返回
905 }
906 MYCATCH(Control::Error);
907 }
908
909 template<typename InputStream, typename Visitor>
910 static bool SkipCompoundType(InputStream &tData, Visitor &tVisitor, size_t szStackDepth) noexcept
911 {
912 //栈深度检测
913 CHECK_STACK_DEPTH(szStackDepth, false);
914
915 while (true)
916 {
917 //跳过compound值
918 if (!tData.HasAvailData(sizeof(NBT_TAG_RAW_TYPE)))//处理末尾情况
919 {
920 Error(OutOfRangeError, tData, tVisitor, "{}:\nIndex[{}] >= DataSize()[{}]", __FUNCTION__,
921 tData.Index(), tData.Size());
922 STACK_TRACEBACK("HasAvailData Test");
923 return false;//跳过必然不可能是根部调用
924 }
925
926 NBT_TAG_RAW_TYPE u8CompoundEntryTag = (NBT_TAG_RAW_TYPE)tData.GetNext();
927
928 if (u8CompoundEntryTag == NBT_TAG::End)
929 {
930 return true;//正常结束
931 }
932
933 if (u8CompoundEntryTag >= NBT_TAG::ENUM_END)
934 {
935 Error(NbtTypeTagError, tData, tVisitor, "{}:\nNBT Tag switch default: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
936 u8CompoundEntryTag, u8CompoundEntryTag);
937 STACK_TRACEBACK("u8CompoundEntryTag Test");
938 return false;
939 }
940
941 NBT_TAG enCompoundEntryTag = (NBT_TAG)u8CompoundEntryTag;
942
943 if (!SkipName(tData, tVisitor))
944 {
945 STACK_TRACEBACK("SkipName Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
946 return false;
947 }
948
949 if (!SkipSwitch(tData, enCompoundEntryTag, tVisitor, szStackDepth - 1))
950 {
951 STACK_TRACEBACK("SkipSwitch Fail, Type: [NBT_Type::{}]", NBT_Type::GetTypeName(enCompoundEntryTag));
952 return false;
953 }
954 }
955
956 return true;
957 }
958
959 template<typename InputStream, typename Visitor>
960 static Control ScanSwitch(InputStream &tData, NBT_TAG tagNbt, Visitor &tVisitor, size_t szStackDepth) noexcept
961 {
962 Control retControl;
963 switch (tagNbt)
964 {
965 case NBT_TAG::End:
966 {
967 retControl = ScanEndType(tData, tVisitor);
968 }
969 break;
970 case NBT_TAG::Byte:
971 {
973 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
974 }
975 break;
976 case NBT_TAG::Short:
977 {
979 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
980 }
981 break;
982 case NBT_TAG::Int:
983 {
985 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
986 }
987 break;
988 case NBT_TAG::Long:
989 {
991 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
992 }
993 break;
994 case NBT_TAG::Float:
995 {
997 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
998 }
999 break;
1000 case NBT_TAG::Double:
1001 {
1003 retControl = ScanBuiltInType<CurType>(tData, tVisitor);
1004 }
1005 break;
1006 case NBT_TAG::ByteArray:
1007 {
1009 retControl = ScanArrayType<CurType>(tData, tVisitor);
1010 }
1011 break;
1012 case NBT_TAG::String:
1013 {
1014 retControl = ScanStringType(tData, tVisitor);
1015 }
1016 break;
1017 case NBT_TAG::List:
1018 {
1019 retControl = ScanListType(tData, tVisitor, szStackDepth);
1020 }
1021 break;
1022 case NBT_TAG::Compound:
1023 {
1024 retControl = ScanCompoundType<false>(tData, tVisitor, szStackDepth);
1025 }
1026 break;
1027 case NBT_TAG::IntArray:
1028 {
1030 retControl = ScanArrayType<CurType>(tData, tVisitor);
1031 }
1032 break;
1033 case NBT_TAG::LongArray:
1034 {
1036 retControl = ScanArrayType<CurType>(tData, tVisitor);
1037 }
1038 break;
1039 default:
1040 {
1041 Error(NbtTypeTagError, tData, tVisitor, "{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
1042 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);
1043 retControl = Control::Error;
1044 }
1045 break;
1046 }
1047
1048 if (retControl == Control::Error)//如果出错,打一下栈回溯
1049 {
1050 STACK_TRACEBACK("Tag[0x{:02X}({})] read error!",
1051 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);
1052 }
1053
1054 return retControl;
1055 }
1056
1057 template<typename InputStream, typename Visitor>
1058 static bool SkipSwitch(InputStream &tData, NBT_TAG tagNbt, Visitor &tVisitor, size_t szStackDepth) noexcept
1059 {
1060 bool bRet = false;
1061 switch (tagNbt)
1062 {
1063 case NBT_TAG::End:
1064 {
1065 bRet = SkipEndType(tData, tVisitor);
1066 }
1067 break;
1068 case NBT_TAG::Byte:
1069 {
1071 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1072 }
1073 break;
1074 case NBT_TAG::Short:
1075 {
1077 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1078 }
1079 break;
1080 case NBT_TAG::Int:
1081 {
1083 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1084 }
1085 break;
1086 case NBT_TAG::Long:
1087 {
1089 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1090 }
1091 break;
1092 case NBT_TAG::Float:
1093 {
1095 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1096 }
1097 break;
1098 case NBT_TAG::Double:
1099 {
1101 bRet = SkipBuiltInType<CurType>(tData, tVisitor);
1102 }
1103 break;
1104 case NBT_TAG::ByteArray:
1105 {
1107 bRet = SkipArrayType<CurType>(tData, tVisitor);
1108 }
1109 break;
1110 case NBT_TAG::String:
1111 {
1112 bRet = SkipStringType(tData, tVisitor);
1113 }
1114 break;
1115 case NBT_TAG::List:
1116 {
1117 bRet = SkipListType(tData, tVisitor, szStackDepth);
1118 }
1119 break;
1120 case NBT_TAG::Compound:
1121 {
1122 bRet = SkipCompoundType(tData, tVisitor, szStackDepth);
1123 }
1124 break;
1125 case NBT_TAG::IntArray:
1126 {
1128 bRet = SkipArrayType<CurType>(tData, tVisitor);
1129 }
1130 break;
1131 case NBT_TAG::LongArray:
1132 {
1134 bRet = SkipArrayType<CurType>(tData, tVisitor);
1135 }
1136 break;
1137 default:
1138 {
1139 Error(NbtTypeTagError, tData, tVisitor, "{}:\nNBT Tag switch error: Unknown Type Tag[0x{:02X}({})]", __FUNCTION__,
1140 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);
1141 bRet = false;
1142 }
1143 break;
1144 }
1145
1146 if (!bRet)//如果出错,打一下栈回溯
1147 {
1148 STACK_TRACEBACK("Tag[0x{:02X}({})] read error!",
1149 (NBT_TAG_RAW_TYPE)tagNbt, (NBT_TAG_RAW_TYPE)tagNbt);
1150 }
1151
1152 return bRet;
1153 }
1154
1156public:
1166 template<typename InputStream, typename Visitor>
1168 static bool ScanNBT(InputStream &IptStream, Visitor &tVisitor, size_t szStackDepth = 512) noexcept
1169 {
1170 return ScanCompoundType<true>(IptStream, tVisitor, szStackDepth) != Control::Error;
1171 }
1172
1182 template<typename DataType = std::vector<uint8_t>, typename Visitor>
1184 static bool ScanNBT(const DataType &tDataInput, size_t szStartIdx, Visitor &tVisitor, size_t szStackDepth = 512) noexcept
1185 {
1186 NBT_IO::DefaultInputStream<DataType> IptStream(tDataInput, szStartIdx);
1187 return ScanCompoundType<true>(IptStream, tVisitor, szStackDepth) != Control::Error;
1188 }
1189
1190#ifdef CJF2_NBT_CPP_USE_ZLIB
1191
1201 template <typename Visitor, typename InfoFunc = NBT_Print>
1203 static bool SimpleScanNbtFile(const std::filesystem::path &pathFileName, Visitor &tVisitor, InfoFunc funcInfo = InfoFunc{}) noexcept
1204 {
1205 // 读取文件
1206 std::vector<uint8_t> vFileData;
1207 if (!NBT_IO::ReadFile(pathFileName, vFileData, funcInfo))
1208 {
1209 funcInfo(NBT_Print_Level::Err, "Error: Cannot read file [{}].\n", pathFileName.string());
1210 return false;
1211 }
1212
1213 // 尝试解压,失败则视作未压缩数据
1214 std::vector<uint8_t> vNbtData;
1215 if (!NBT_IO::DecompressDataNoThrow(vNbtData, vFileData, funcInfo))
1216 {
1217 funcInfo(NBT_Print_Level::Warn, "Warning: Decompression failed, assuming uncompressed data.\n");
1218 vNbtData = std::move(vFileData);
1219 }
1220
1221 // 清理数据
1222 vFileData.clear();
1223 vFileData.shrink_to_fit();
1224
1225 // 扫描
1226 if (!ScanNBT(vNbtData, 0, tVisitor, 512))
1227 {
1228 funcInfo(NBT_Print_Level::Err, "Error: ScanNBT failed.\n");
1229 return false;
1230 }
1231
1232 return true;
1233 }
1234
1235#endif // CJF2_NBT_CPP_USE_ZLIB
1236
1237#undef MYTRY
1238#undef MYCATCH
1239#undef CALL_FUNC_RET_CONTROL
1240#undef UNKNOWN_CONTROL_CODE
1241#undef CHECK_STACK_DEPTH
1242#undef STACK_TRACEBACK
1243#undef STRLING
1244#undef _RP_STRLING
1245#undef _RP___LINE__
1246#undef _RP___FUNCTION__
1247};
端序工具集
IO工具集
NBT节点类型,支持存储所有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
@ ENUM_END
枚举结束标记,用于计算enum元素个数,范围判断等
定义 NBT_TAG.hpp:31
NBT类型二进制流访问器(作为扫描工具的回调)
NBT_Visitor_ResultControl
控制流返回码(用于普通回调)
定义 NBT_Visitor.hpp:15
@ Stop
停止处理(终止解析)
定义 NBT_Visitor.hpp:18
@ Continue
继续处理(继续迭代)
定义 NBT_Visitor.hpp:16
@ Break
跳过剩余值(离开当前结构层级回到父层级)
定义 NBT_Visitor.hpp:17
@ Stop
停止处理(终止解析)
定义 NBT_Visitor.hpp:27
@ Skip
跳过当前值(跳过递归进入嵌套结构或展开值)
定义 NBT_Visitor.hpp:25
@ Break
跳过剩余值(离开当前结构层级回到父层级)
定义 NBT_Visitor.hpp:26
@ Enter
进入当前值(递归进入嵌套结构或展开值)
定义 NBT_Visitor.hpp:24
static T BigToNativeAny(T data) noexcept
从大端字节序转换到当前平台字节序,自动匹配位数
定义 NBT_Endian.hpp:209
默认输入流类,用于从标准库容器中读取数据
定义 NBT_IO.hpp:45
static bool DecompressDataNoThrow(O &oData, const I &iData, InfoFunc funcInfo=InfoFunc{}) noexcept
解压数据,但是不抛出异常,而是通过funcInfo打印异常信息并返回成功与否
定义 NBT_IO.hpp:804
static bool ReadFile(const std::filesystem::path &pathFileName, T &tData, InfoFunc funcInfo=InfoFunc{}) noexcept
从指定文件名的文件中读取字节流数据到任意顺序容器中
定义 NBT_IO.hpp:391
static bool ScanNBT(InputStream &IptStream, Visitor &tVisitor, size_t szStackDepth=512) noexcept
从输入流中扫描NBT数据,并通过访问器回调处理每个节点
定义 NBT_Scanner.hpp:1168
static bool SimpleScanNbtFile(const std::filesystem::path &pathFileName, Visitor &tVisitor, InfoFunc funcInfo=InfoFunc{}) noexcept
从可能被压缩的文件中扫描 NBT 数据,并通过访问器回调处理每个节点
定义 NBT_Scanner.hpp:1203
static bool ScanNBT(const DataType &tDataInput, size_t szStartIdx, Visitor &tVisitor, size_t szStackDepth=512) noexcept
从数据容器中扫描NBT数据,并通过访问器回调处理每个节点
定义 NBT_Scanner.hpp:1184
typename TagToType< Tag >::type TagToType_T
从NBT_TAG获取对应的类型:编译期从NBT_TAG的enum值获取类型
定义 NBT_Type.hpp:251
int32_t ArrayLength
数组长度类型
定义 NBT_Type.hpp:137
NBT_String< MUTF8_String, MUTF8_String_View > String
字符串类型,存储Java M-UTF-8字符串
定义 NBT_Type.hpp:65
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 const char * GetTypeName(NBT_TAG tag) noexcept
通过类型标签获取类型名称
定义 NBT_Type.hpp:124
检查类型是否符合 NBT 访问器(Visitor)的接口要求
定义 NBT_Visitor.hpp:200