chenjunfu2-nbt-cpp v2.1.3
一个基于CPP20的NBT(Named Binary Tag)库
载入中...
搜索中...
未找到
NBT_IO.hpp
浏览该文件的文档.
1#pragma once
2
3#include <stdio.h>
4#include <stdint.h>
5#include <stddef.h>//size_t
6#include <string.h>//memcpy
7#include <fstream>
8#include <vector>
9#include <filesystem>
10
11#include "NBT_Print.hpp"//打印输出
12
13#include "vcpkg_config.h"//包含vcpkg生成的配置以确认库安装情况
14
15#ifdef CJF2_NBT_CPP_USE_ZLIB
16
17/*zlib*/
18#define ZLIB_CONST
19#include <zlib.h>
20/*zlib*/
21
22#endif
23
26
28class NBT_IO
29{
31 NBT_IO(void) = delete;
33 ~NBT_IO(void) = delete;
34
35public:
43 template <typename T = std::vector<uint8_t>>
45 {
46 private:
47 const T &tData = {};
48 size_t szIndex = 0;
49
50 public:
52 using StreamType = T;
54 using ValueType = typename T::value_type;
55
56 //静态断言确保字节流与可平凡拷贝
57 static_assert(sizeof(ValueType) == 1, "Error ValueType Size");
58 static_assert(std::is_trivially_copyable_v<ValueType>, "ValueType Must Be Trivially Copyable");
59
61 DefaultInputStream(const T &&_tData, size_t szStartIdx = 0) = delete;
62
67 DefaultInputStream(const T &_tData, size_t szStartIdx = 0) :tData(_tData), szIndex(szStartIdx)
68 {}
69
71 ~DefaultInputStream(void) = default;
80
85 const ValueType &operator[](size_t szIndex) const noexcept
86 {
87 return tData[szIndex];
88 }
89
93 const ValueType &GetNext() noexcept
94 {
95 return tData[szIndex++];
96 }
97
102 void GetRange(void *pDest, size_t szSize) noexcept
103 {
104 memcpy(pDest, &tData[szIndex], szSize);
105 szIndex += szSize;
106 }
107
110 void UnGet() noexcept
111 {
112 --szIndex;
113 }
114
119 size_t SkipData(size_t szSize) noexcept
120 {
121 return szIndex += szSize;
122 }
123
128 size_t RewindData(size_t szSize) noexcept
129 {
130 return szIndex -= szSize;
131 }
132
135 bool IsEnd() const noexcept
136 {
137 return szIndex >= tData.size();
138 }
139
142 size_t Size() const noexcept
143 {
144 return tData.size();
145 }
146
150 bool HasAvailData(size_t szSize) const noexcept
151 {
152 return (tData.size() - szIndex) >= szSize;
153 }
154
156 void Reset() noexcept
157 {
158 szIndex = 0;
159 }
160
163 const size_t &Index() const noexcept
164 {
165 return szIndex;
166 }
167
171 size_t &Index() noexcept
172 {
173 return szIndex;
174 }
175 };
176
184 template <typename T = std::vector<uint8_t>>
186 {
187 private:
188 T &tData;
189
190 public:
192 using StreamType = T;
194 using ValueType = typename T::value_type;
195
196 //静态断言确保字节流与可平凡拷贝
197 static_assert(sizeof(ValueType) == 1, "Error ValueType Size");
198 static_assert(std::is_trivially_copyable_v<ValueType>, "ValueType Must Be Trivially Copyable");
199
204 DefaultOutputStream(T &_tData, size_t szStartIdx = 0) :tData(_tData)//引用天生无法使用临时值构造,无需担心临时值构造导致的悬空引用
205 {
206 tData.resize(szStartIdx);
207 }
208
210 ~DefaultOutputStream(void) = default;
219
224 const ValueType &operator[](size_t szIndex) const noexcept
225 {
226 return tData[szIndex];
227 }
228
233 template<typename V>
234 requires(std::is_constructible_v<ValueType, V &&>)
235 void PutOnce(V &&c)
236 {
237 tData.push_back(std::forward<V>(c));
238 }
239
244 void PutRange(const ValueType *pData, size_t szSize)
245 {
246 //tData.insert(tData.end(), &pData[0], &pData[szSize]);
247
248 //使用更高效的实现,而不是迭代器写入
249 size_t szCurSize = tData.size();
250 tData.resize(szCurSize + szSize);
251 memcpy(&tData.data()[szCurSize], &pData[0], szSize);
252 }
253
258 void AddReserve(size_t szAddSize)
259 {
260 tData.reserve(tData.size() + szAddSize);
261 }
262
265 void UnPut(void) noexcept
266 {
267 tData.pop_back();
268 }
269
274 size_t RemoveData(size_t szSize) noexcept
275 {
276 tData.resize(tData.size() - szSize);
277 return tData.size();
278 }
279
282 size_t Size(void) const noexcept
283 {
284 return tData.size();
285 }
286
288 void Reset(void) noexcept
289 {
290 tData.clear();
291 }
292 };
293
294
295public:
305 template<typename T = std::vector<uint8_t>, typename InfoFunc = NBT_Print>
306 requires (sizeof(typename T::value_type) == 1 && std::is_trivially_copyable_v<typename T::value_type>)
307 static bool WriteFile(const std::filesystem::path &pathFileName, const T &tData, InfoFunc funcInfo = InfoFunc{}) noexcept
308 {
309 try
310 {
311 std::error_code ec;
312
313 //存在性检查
314 bool bExists = std::filesystem::exists(pathFileName, ec);
315 if (ec || bExists)
316 {
317 if (ec)
318 {
319 funcInfo(NBT_Print_Level::Err, "Error: Failed to check existence of [{}]: {}\n", pathFileName.string(), ec.message());
320 return false;
321 }
322 else
323 {
324 //已存在,必须为普通文件
325 bool bRegularFile = std::filesystem::is_regular_file(pathFileName, ec);
326 if (ec)
327 {
328 funcInfo(NBT_Print_Level::Err, "Error: Failed to check file type of [{}]: {}\n", pathFileName.string(), ec.message());
329 return false;
330 }
331
332 //不是普通文件,出错
333 if (!bRegularFile)
334 {
335 funcInfo(NBT_Print_Level::Err, "Error: [{}] exists but is not a regular file.\n", pathFileName.string());
336 return false;
337 }
338 }
339 }
340
341 //检查通过,继续写入
342 std::fstream fWrite;
343 fWrite.open(pathFileName, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
344 if (!fWrite)
345 {
346 funcInfo(NBT_Print_Level::Err, "Error: Cannot open file [{}] for writing.\n", pathFileName.string());
347 return false;
348 }
349
350 //获取文件大小并写出
351 uint64_t qwFileSize = tData.size();
352 if (!fWrite.write((const char *)tData.data(), sizeof(tData[0]) * qwFileSize))
353 {
354 funcInfo(NBT_Print_Level::Err, "Error: Failed to write data to file [{}].\n", pathFileName.string());
355 return false;
356 }
357
358 //完成,关闭文件
359 fWrite.close();
360
361 return true;
362 }
363 catch (const std::bad_alloc &e)
364 {
365 funcInfo(NBT_Print_Level::Err, "std::bad_alloc:[{}]\n", e.what());
366 return false;
367 }
368 catch (const std::exception &e)
369 {
370 funcInfo(NBT_Print_Level::Err, "std::exception:[{}]\n", e.what());
371 return false;
372 }
373 catch (...)
374 {
375 funcInfo(NBT_Print_Level::Err, "Unknown Error\n");
376 return false;
377 }
378 }
379
389 template<typename T = std::vector<uint8_t>, typename InfoFunc = NBT_Print>
390 requires (sizeof(typename T::value_type) == 1 && std::is_trivially_copyable_v<typename T::value_type>)
391 static bool ReadFile(const std::filesystem::path &pathFileName, T &tData, InfoFunc funcInfo = InfoFunc{}) noexcept
392 {
393 try
394 {
395 std::error_code ec;
396
397 bool bRegularFile = std::filesystem::is_regular_file(pathFileName, ec);
398 if (ec || !bRegularFile)//必须是普通文件
399 {
400 if (ec)
401 {
402 funcInfo(NBT_Print_Level::Err, "Error: Failed to check file type of [{}]: {}.\n", pathFileName.string(), ec.message());
403 }
404 else
405 {
406 funcInfo(NBT_Print_Level::Err, "Error: [{}] is not a regular file.\n", pathFileName.string());
407 }
408 return false;
409 }
410
411 //获取文件大小
412 uintmax_t umFileSize = std::filesystem::file_size(pathFileName, ec);
413 if (ec || umFileSize > (uintmax_t)std::numeric_limits<size_t>::max())//大小超过size_t范围,无法读取
414 {
415 if (ec)
416 {
417 funcInfo(NBT_Print_Level::Err, "Error: Cannot get file size of [{}]: {}\n", pathFileName.string(), ec.message());
418 }
419 else
420 {
421 funcInfo(NBT_Print_Level::Err, "Error: File [{}](size: [{}] bytes) is too large to fit into memory(max: [{}] bytes).\n", pathFileName.string(), umFileSize, std::numeric_limits<size_t>::max());
422 }
423 return false;
424 }
425
426 //转换为size_t
427 size_t szFileSize = (size_t)umFileSize;
428
429 //打开文件
430 std::fstream fRead;
431 fRead.open(pathFileName, std::ios_base::binary | std::ios_base::in);
432 if (!fRead)
433 {
434 funcInfo(NBT_Print_Level::Err, "Error: Cannot open file [{}] for reading.\n", pathFileName.string());
435 return false;
436 }
437
438 //直接给数据塞string里
439 tData.resize(szFileSize);//设置长度 c++23用resize_and_overwrite
440 if (!fRead.read((char *)tData.data(), sizeof(tData[0]) * szFileSize))//直接读入data
441 {
442 funcInfo(NBT_Print_Level::Err, "Error: Failed to read data from file [{}].\n", pathFileName.string());
443 return false;
444 }
445
446 //完成,关闭文件
447 fRead.close();
448
449 return true;
450 }
451 catch (const std::bad_alloc &e)
452 {
453 funcInfo(NBT_Print_Level::Err, "std::bad_alloc:[{}]\n", e.what());
454 return false;
455 }
456 catch (const std::exception &e)
457 {
458 funcInfo(NBT_Print_Level::Err, "std::exception:[{}]\n", e.what());
459 return false;
460 }
461 catch (...)
462 {
463 funcInfo(NBT_Print_Level::Err, "Unknown Error\n");
464 return false;
465 }
466 }
467
473 static bool IsFileExist(const std::filesystem::path &pathFileName)
474 {
475 std::error_code ec;//判断这东西是不是true确定有没有error
476 bool bExists = std::filesystem::exists(pathFileName, ec);
477
478 return !ec && bExists;//没有错误并且存在
479 }
480
481#ifdef CJF2_NBT_CPP_USE_ZLIB
482
488 static bool IsZlib(uint8_t u8DataFirst, uint8_t u8DataSecond)
489 {
490 return u8DataFirst == (uint8_t)0x78 &&
491 (
492 u8DataSecond == (uint8_t)0x9C ||
493 u8DataSecond == (uint8_t)0x01 ||
494 u8DataSecond == (uint8_t)0xDA ||
495 u8DataSecond == (uint8_t)0x5E
496 );
497 }
498
504 static bool IsGzip(uint8_t u8DataFirst, uint8_t u8DataSecond)
505 {
506 return u8DataFirst == (uint8_t)0x1F && u8DataSecond == (uint8_t)0x8B;
507 }
508
515 template<typename T>
516 requires (sizeof(typename T::value_type) == 1 && std::is_trivially_copyable_v<typename T::value_type>)
517 static bool IsDataZipped(const T &tData)
518 {
519 if (tData.size() <= 2)
520 {
521 return false;
522 }
523
524 uint8_t u8DataFirst = (uint8_t)tData[0];
525 uint8_t u8DataSecond = (uint8_t)tData[1];
526
527 return IsZlib(u8DataFirst, u8DataSecond) || IsGzip(u8DataFirst, u8DataSecond);
528 }
529
537 template<typename I, typename O>
538 requires (sizeof(typename I::value_type) == 1 && std::is_trivially_copyable_v<typename I::value_type> &&
539 sizeof(typename O::value_type) == 1 && std::is_trivially_copyable_v<typename O::value_type>)
540 static void DecompressData(O &oData, const I &iData)
541 {
542 if (std::addressof(oData) == std::addressof(iData))
543 {
544 throw std::runtime_error("The oData object cannot be the iData object");
545 }
546
547 if (iData.empty())
548 {
549 oData.clear();
550 return;
551 }
552
553 z_stream zs
554 {
555 .next_in = Z_NULL,
556 .avail_in = 0,
557 .total_in = 0,
558
559 .next_out = Z_NULL,
560 .avail_out = 0,
561 .total_out = 0,
562
563 .msg = Z_NULL,
564 .state = Z_NULL,
565
566 .zalloc = (alloc_func)Z_NULL,
567 .zfree = (free_func)Z_NULL,
568 .opaque = (voidpf)Z_NULL,
569
570 .data_type = Z_BINARY,
571
572 .adler = 0,
573 .reserved = {},
574 };
575
576 if (inflateInit2(&zs, 32 + 15) != Z_OK)//32+15自动判断是gzip还是zlib
577 {
578 throw std::runtime_error("Failed to initialize zlib decompression");
579 }
580
581 //对于大于uint_max的数据来说,切分为多个uint_max的块作为流依次输入
582 //注意zlib在实现内会移动指针,所以对于大于一定字节的情况下,只需要更新
583 //avail_in,而无须更新next_in。这里的容器保证不变,所以地址不会失效
584 zs.next_in = (z_const Bytef *)iData.data();
585
586 //默认解压大小为压缩大小,后续扩容
587 oData.resize(iData.size());
588
589 //两个变量用于记录已经压缩的大小和剩余数据大小
590 size_t szDecompressedSize = 0;
591 size_t szRemainingSize = iData.size();
592 int iRet = Z_OK;
593 do
594 {
595 //首先计算剩余可用空间,然后决定是否扩容
596 size_t szOut = oData.size() - szDecompressedSize;
597 if (szOut == 0)
598 {
599 oData.resize(oData.size() * 2);
600 szOut = oData.size() - szDecompressedSize;
601 }
602
603 //虽然next_out也会在内部实现被移动,但是oData是容器,会被扩容
604 //一旦扩容触发,那么实际上的地址就可能会改变,所以必须每次重新获取
605 //切记上面与这里的代码顺序不可改变,必须在上面计算并扩容完成后获取地址
606 zs.next_out = (Bytef *)(&oData.data()[szDecompressedSize]);
607
608 //如果输入被消耗完,重新赋值
609 if (zs.avail_in == 0)
610 {
611 constexpr uInt uIntMax = (uInt)-1;
612 zs.avail_in = szRemainingSize > (size_t)uIntMax ? uIntMax : (uInt)szRemainingSize;
613 szRemainingSize -= zs.avail_in;//缩小剩余待处理大小
614 }
615
616 //如果输出大小耗尽,重新赋值
617 if (zs.avail_out == 0)
618 {
619 constexpr uInt uIntMax = (uInt)-1;
620 zs.avail_out = szOut > (size_t)uIntMax ? uIntMax : (uInt)szOut;
621 //这里不对szOut处理,因为会在开头与结尾计算
622 }
623
624 //解压,如果剩余不为0则代表分块了,使用Z_NO_FLUSH,否则Z_FINISH
625 iRet = inflate(&zs, szRemainingSize != 0 ? Z_NO_FLUSH : Z_FINISH);
626
627 //计算本次解压的大小
628 szDecompressedSize += szOut - zs.avail_out;
629 } while (iRet == Z_OK || iRet == Z_BUF_ERROR);//只要没错误(缓冲区不够大除外)或者没到结尾就继续运行
630
631 inflateEnd(&zs);//结束解压
632 oData.resize(szDecompressedSize);//设置解压大小
633
634 //错误处理
635 if (iRet != Z_STREAM_END)
636 {
637 if (zs.msg != NULL)//错误消息不为null则抛出带消息异常
638 {
639 throw std::runtime_error(std::string("Zlib decompression failed with error message: ") + std::string(zs.msg));
640 }
641 else//如果为null直接使用错误码
642 {
643 throw std::runtime_error(std::string("Zlib decompression failed with error code: ") + std::to_string(iRet));
644 }
645 }
646 }
647
656 template<typename I, typename O>
657 requires (sizeof(typename I::value_type) == 1 && std::is_trivially_copyable_v<typename I::value_type> &&
658 sizeof(typename O::value_type) == 1 && std::is_trivially_copyable_v<typename O::value_type>)
659 static void CompressData(O &oData, const I &iData, int iLevel = Z_DEFAULT_COMPRESSION)
660 {
661 if (std::addressof(oData) == std::addressof(iData))
662 {
663 throw std::runtime_error("The oData object cannot be the iData object");
664 }
665
666 if (iData.empty())
667 {
668 oData.clear();
669 return;
670 }
671
672 z_stream zs
673 {
674 .next_in = Z_NULL,
675 .avail_in = 0,
676 .total_in = 0,
677
678 .next_out = Z_NULL,
679 .avail_out = 0,
680 .total_out = 0,
681
682 .msg = Z_NULL,
683 .state = Z_NULL,
684
685 .zalloc = (alloc_func)Z_NULL,
686 .zfree = (free_func)Z_NULL,
687 .opaque = (voidpf)Z_NULL,
688
689 .data_type = Z_BINARY,
690
691 .adler = 0,
692 .reserved = {},
693 };
694
695 if (deflateInit2(&zs, iLevel, Z_DEFLATED, 16 + 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)//16+15使用gzip(mojang默认格式)
696 {
697 throw std::runtime_error("Failed to initialize zlib compression");
698 }
699
700 //与上方解压例程相同,不做重复解释
701 zs.next_in = (z_const Bytef *)iData.data();
702
703 /*
704 如果范围溢出,则设置为比原始数据的大小加12字节大0.1%的一半
705 这样做的目的是为了尽可能缩小一开始的体积
706 比如实际上压缩率非常低的情况下可能根本用不到一半
707 但是如果实际上压缩率很高,那么下面二倍扩容一次后刚好就是最坏情况
708 这样基本上性能较优,下面zlib文档说明的最坏情况:
709
710 Upon entry, destLen is the total size of the
711 destination buffer, which must be at least 0.1%
712 larger than sourceLen plus 12 bytes.
713 */
714
715 constexpr uLong uLongMax = (uLong)-1;
716 if (iData.size() > (size_t)uLongMax)
717 {
718 size_t szNeedSize = iData.size() + 12;//先比原始数据大12byte
719 //注意这里使用了向上取整的整数除法
720 //加等于自身的0.1%相当于比原先的自己大0.1%,这里的1/1000就是0.1/100
721 szNeedSize += (szNeedSize + (1000 - 1)) / 1000;
722 //设置目标大小
723 oData.resize((szNeedSize + (2 - 1)) / 2);//向上取整除以二
724 }
725 else
726 {
727 //在范围未溢出的情况下,进行预测
728 //把压缩大小设置为预测的压缩大小
729 oData.resize(deflateBound(&zs, (uLong)iData.size()));
730 }
731
732 //设置压缩后大小与待处理大小
733 size_t szCompressedSize = 0;
734 size_t szRemainingSize = iData.size();
735 int iRet = Z_OK;
736 do
737 {
738 //计算剩余大小并在不足时扩容
739 size_t szOut = oData.size() - szCompressedSize;
740 if (szOut == 0)
741 {
742 oData.resize(oData.size() * 2);
743 szOut = oData.size() - szCompressedSize;
744 }
745
746 //获取新的地址
747 zs.next_out = (Bytef *)(&oData.data()[szCompressedSize]);
748
749 //如果输入被消耗完,重新赋值
750 if (zs.avail_in == 0)
751 {
752 constexpr uInt uIntMax = (uInt)-1;
753 zs.avail_in = szRemainingSize > (size_t)uIntMax ? uIntMax : (uInt)szRemainingSize;
754 szRemainingSize -= zs.avail_in;//缩小剩余待处理大小
755 }
756
757 //如果输出大小耗尽,重新赋值
758 if (zs.avail_out == 0)
759 {
760 constexpr uInt uIntMax = (uInt)-1;
761 zs.avail_out = szOut > (size_t)uIntMax ? uIntMax : (uInt)szOut;
762 //这里不对szOut处理,因为会在开头与结尾计算
763 }
764
765 //压缩,如果剩余不为0则代表分块了,使用Z_NO_FLUSH,否则Z_FINISH
766 iRet = deflate(&zs, szRemainingSize != 0 ? Z_NO_FLUSH : Z_FINISH);
767
768 //计算本次压缩的大小
769 szCompressedSize += szOut - zs.avail_out;
770 } while (iRet == Z_OK || iRet == Z_BUF_ERROR);//只要没错误(缓冲区不够大除外)或者没到结尾就继续运行
771
772 //结束并设置大小
773 deflateEnd(&zs);
774 oData.resize(szCompressedSize);
775
776 //错误处理
777 if (iRet != Z_STREAM_END)
778 {
779 if (zs.msg != NULL)
780 {
781 throw std::runtime_error(std::string("Zlib compression failed with error message: ") + std::string(zs.msg));
782 }
783 else
784 {
785 throw std::runtime_error(std::string("Zlib compression failed with error code: ") + std::to_string(iRet));
786 }
787 }
788 }
789
801 template<typename I, typename O, typename InfoFunc = NBT_Print>
802 requires (sizeof(typename I::value_type) == 1 && std::is_trivially_copyable_v<typename I::value_type> &&
803 sizeof(typename O::value_type) == 1 && std::is_trivially_copyable_v<typename O::value_type>)
804 static bool DecompressDataNoThrow(O &oData, const I &iData, InfoFunc funcInfo = InfoFunc{}) noexcept
805 {
806 try
807 {
808 DecompressData(oData, iData);
809 return true;
810 }
811 catch (const std::bad_alloc &e)
812 {
813 funcInfo(NBT_Print_Level::Err, "std::bad_alloc:[{}]\n", e.what());
814 return false;
815 }
816 catch (const std::exception &e)
817 {
818 funcInfo(NBT_Print_Level::Err, "std::exception:[{}]\n", e.what());
819 return false;
820 }
821 catch (...)
822 {
823 funcInfo(NBT_Print_Level::Err, "Unknown Error\n");
824 return false;
825 }
826 }
827
840 template<typename I, typename O, typename InfoFunc = NBT_Print>
841 requires (sizeof(typename I::value_type) == 1 && std::is_trivially_copyable_v<typename I::value_type> &&
842 sizeof(typename O::value_type) == 1 && std::is_trivially_copyable_v<typename O::value_type>)
843 static bool CompressDataNoThrow(O &oData, const I &iData, int iLevel = Z_DEFAULT_COMPRESSION, InfoFunc funcInfo = InfoFunc{}) noexcept
844 {
845 try
846 {
847 CompressData(oData, iData, iLevel);
848 return true;
849 }
850 catch (const std::bad_alloc &e)
851 {
852 funcInfo(NBT_Print_Level::Err, "std::bad_alloc:[{}]\n", e.what());
853 return false;
854 }
855 catch (const std::exception &e)
856 {
857 funcInfo(NBT_Print_Level::Err, "std::exception:[{}]\n", e.what());
858 return false;
859 }
860 catch (...)
861 {
862 funcInfo(NBT_Print_Level::Err, "Unknown Error\n");
863 return false;
864 }
865 }
866#endif
867
868};
用于处理NBT信息打印的默认实现
@ Err
错误信息
定义 NBT_Print.hpp:14
DefaultInputStream(DefaultInputStream &&)=delete
禁止移动构造
DefaultInputStream(const T &&_tData, size_t szStartIdx=0)=delete
禁止使用临时对象构造
size_t RewindData(size_t szSize) noexcept
回退一段数据
定义 NBT_IO.hpp:128
void UnGet() noexcept
回退一个字节的读取
定义 NBT_IO.hpp:110
DefaultInputStream & operator=(const DefaultInputStream &)=delete
禁止拷贝赋值
~DefaultInputStream(void)=default
默认析构函数
typename T::value_type ValueType
容器值类型
定义 NBT_IO.hpp:54
size_t Size() const noexcept
获取流的总大小
定义 NBT_IO.hpp:142
T StreamType
容器类型
定义 NBT_IO.hpp:52
DefaultInputStream(const DefaultInputStream &)=delete
禁止拷贝构造
void Reset() noexcept
重置流读取位置到起始处
定义 NBT_IO.hpp:156
const size_t & Index() const noexcept
获取当前读取位置(只读)
定义 NBT_IO.hpp:163
const ValueType & operator[](size_t szIndex) const noexcept
下标访问运算符
定义 NBT_IO.hpp:85
size_t & Index() noexcept
获取当前读取位置(可写)
定义 NBT_IO.hpp:171
DefaultInputStream & operator=(DefaultInputStream &&)=delete
禁止移动赋值
size_t SkipData(size_t szSize) noexcept
跳过一段数据
定义 NBT_IO.hpp:119
bool HasAvailData(size_t szSize) const noexcept
检查是否还有足够的数据可供读取
定义 NBT_IO.hpp:150
DefaultInputStream(const T &_tData, size_t szStartIdx=0)
构造函数
定义 NBT_IO.hpp:67
bool IsEnd() const noexcept
检查是否已到达流末尾
定义 NBT_IO.hpp:135
void GetRange(void *pDest, size_t szSize) noexcept
从流中读取一段数据
定义 NBT_IO.hpp:102
const ValueType & GetNext() noexcept
获取下一个字节并推进读取位置
定义 NBT_IO.hpp:93
DefaultOutputStream & operator=(DefaultOutputStream &&)=delete
禁止移动赋值
void PutRange(const ValueType *pData, size_t szSize)
向流中写入一段数据
定义 NBT_IO.hpp:244
void UnPut(void) noexcept
删除(撤销)最后一个写入的字节
定义 NBT_IO.hpp:265
typename T::value_type ValueType
容器值类型
定义 NBT_IO.hpp:194
T StreamType
容器类型
定义 NBT_IO.hpp:192
DefaultOutputStream(DefaultOutputStream &&)=delete
禁止移动构造
size_t Size(void) const noexcept
获取当前字节流中已有的数据大小
定义 NBT_IO.hpp:282
DefaultOutputStream(T &_tData, size_t szStartIdx=0)
构造函数
定义 NBT_IO.hpp:204
DefaultOutputStream & operator=(const DefaultOutputStream &)=delete
禁止拷贝赋值
const ValueType & operator[](size_t szIndex) const noexcept
下标访问运算符
定义 NBT_IO.hpp:224
DefaultOutputStream(const DefaultOutputStream &)=delete
禁止拷贝构造
void AddReserve(size_t szAddSize)
预分配额外容量
定义 NBT_IO.hpp:258
size_t RemoveData(size_t szSize) noexcept
删除(撤销)最后szSize个写入的字节
定义 NBT_IO.hpp:274
~DefaultOutputStream(void)=default
默认析构函数
void Reset(void) noexcept
重置流,清空所有数据
定义 NBT_IO.hpp:288
void PutOnce(V &&c)
向流中写入写入单个值
定义 NBT_IO.hpp:235
static bool DecompressDataNoThrow(O &oData, const I &iData, InfoFunc funcInfo=InfoFunc{}) noexcept
解压数据,但是不抛出异常,而是通过funcInfo打印异常信息并返回成功与否
定义 NBT_IO.hpp:804
static void CompressData(O &oData, const I &iData, int iLevel=Z_DEFAULT_COMPRESSION)
压缩数据,默认压缩为Gzip,也就是NBT格式的标准压缩类型,如果失败则抛出异常
定义 NBT_IO.hpp:659
static bool IsFileExist(const std::filesystem::path &pathFileName)
判断指定文件名的文件是否存在
定义 NBT_IO.hpp:473
static bool ReadFile(const std::filesystem::path &pathFileName, T &tData, InfoFunc funcInfo=InfoFunc{}) noexcept
从指定文件名的文件中读取字节流数据到任意顺序容器中
定义 NBT_IO.hpp:391
static bool IsDataZipped(const T &tData)
判断一个顺序容器存储的字节流是否可能存在压缩
定义 NBT_IO.hpp:517
static bool IsGzip(uint8_t u8DataFirst, uint8_t u8DataSecond)
通过字节流开始的两个字节判断是否可能是Gzip压缩
定义 NBT_IO.hpp:504
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
static void DecompressData(O &oData, const I &iData)
解压数据,自动判断Zlib或Gzip并解压,如果失败则抛出异常
定义 NBT_IO.hpp:540
static bool IsZlib(uint8_t u8DataFirst, uint8_t u8DataSecond)
通过字节流开始的两个字节判断是否可能是Zlib压缩
定义 NBT_IO.hpp:488
根据已安装的可选依赖提供定义