15#ifdef CJF2_NBT_CPP_USE_ZLIB
31 NBT_IO(
void) =
delete;
33 ~NBT_IO(
void) =
delete;
43 template <
typename T = std::vector<u
int8_t>>
57 static_assert(
sizeof(
ValueType) == 1,
"Error ValueType Size");
58 static_assert(std::is_trivially_copyable_v<ValueType>,
"ValueType Must Be Trivially Copyable");
87 return tData[szIndex];
95 return tData[szIndex++];
104 memcpy(pDest, &tData[szIndex], szSize);
121 return szIndex += szSize;
130 return szIndex -= szSize;
137 return szIndex >= tData.size();
152 return (tData.size() - szIndex) >= szSize;
163 const size_t &
Index() const noexcept
184 template <
typename T = std::vector<u
int8_t>>
197 static_assert(
sizeof(
ValueType) == 1,
"Error ValueType Size");
198 static_assert(std::is_trivially_copyable_v<ValueType>,
"ValueType Must Be Trivially Copyable");
206 tData.resize(szStartIdx);
226 return tData[szIndex];
234 requires(std::is_constructible_v<ValueType, V &&>)
237 tData.push_back(std::forward<V>(c));
249 size_t szCurSize = tData.size();
250 tData.resize(szCurSize + szSize);
251 memcpy(&tData.data()[szCurSize], &pData[0], szSize);
260 tData.reserve(tData.size() + szAddSize);
276 tData.resize(tData.size() - szSize);
282 size_t Size(
void)
const noexcept
305 template<
typename T = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
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
314 bool bExists = std::filesystem::exists(pathFileName, ec);
319 funcInfo(
NBT_Print_Level::Err,
"Error: Failed to check existence of [{}]: {}\n", pathFileName.string(), ec.message());
325 bool bRegularFile = std::filesystem::is_regular_file(pathFileName, ec);
328 funcInfo(
NBT_Print_Level::Err,
"Error: Failed to check file type of [{}]: {}\n", pathFileName.string(), ec.message());
335 funcInfo(
NBT_Print_Level::Err,
"Error: [{}] exists but is not a regular file.\n", pathFileName.string());
343 fWrite.open(pathFileName, std::ios_base::binary | std::ios_base::out | std::ios_base::trunc);
346 funcInfo(
NBT_Print_Level::Err,
"Error: Cannot open file [{}] for writing.\n", pathFileName.string());
351 uint64_t qwFileSize = tData.size();
352 if (!fWrite.write((
const char *)tData.data(),
sizeof(tData[0]) * qwFileSize))
354 funcInfo(
NBT_Print_Level::Err,
"Error: Failed to write data to file [{}].\n", pathFileName.string());
363 catch (
const std::bad_alloc &e)
368 catch (
const std::exception &e)
389 template<
typename T = std::vector<u
int8_t>,
typename InfoFunc = NBT_Pr
int>
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
397 bool bRegularFile = std::filesystem::is_regular_file(pathFileName, ec);
398 if (ec || !bRegularFile)
402 funcInfo(
NBT_Print_Level::Err,
"Error: Failed to check file type of [{}]: {}.\n", pathFileName.string(), ec.message());
412 uintmax_t umFileSize = std::filesystem::file_size(pathFileName, ec);
413 if (ec || umFileSize > (uintmax_t)std::numeric_limits<size_t>::max())
417 funcInfo(
NBT_Print_Level::Err,
"Error: Cannot get file size of [{}]: {}\n", pathFileName.string(), ec.message());
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());
427 size_t szFileSize = (size_t)umFileSize;
431 fRead.open(pathFileName, std::ios_base::binary | std::ios_base::in);
434 funcInfo(
NBT_Print_Level::Err,
"Error: Cannot open file [{}] for reading.\n", pathFileName.string());
439 tData.resize(szFileSize);
440 if (!fRead.read((
char *)tData.data(),
sizeof(tData[0]) * szFileSize))
442 funcInfo(
NBT_Print_Level::Err,
"Error: Failed to read data from file [{}].\n", pathFileName.string());
451 catch (
const std::bad_alloc &e)
456 catch (
const std::exception &e)
473 static bool IsFileExist(
const std::filesystem::path &pathFileName)
476 bool bExists = std::filesystem::exists(pathFileName, ec);
478 return !ec && bExists;
481#ifdef CJF2_NBT_CPP_USE_ZLIB
488 static bool IsZlib(uint8_t u8DataFirst, uint8_t u8DataSecond)
490 return u8DataFirst == (uint8_t)0x78 &&
492 u8DataSecond == (uint8_t)0x9C ||
493 u8DataSecond == (uint8_t)0x01 ||
494 u8DataSecond == (uint8_t)0xDA ||
495 u8DataSecond == (uint8_t)0x5E
504 static bool IsGzip(uint8_t u8DataFirst, uint8_t u8DataSecond)
506 return u8DataFirst == (uint8_t)0x1F && u8DataSecond == (uint8_t)0x8B;
516 requires (
sizeof(
typename T::value_type) == 1 && std::is_trivially_copyable_v<typename T::value_type>)
519 if (tData.size() <= 2)
524 uint8_t u8DataFirst = (uint8_t)tData[0];
525 uint8_t u8DataSecond = (uint8_t)tData[1];
527 return IsZlib(u8DataFirst, u8DataSecond) ||
IsGzip(u8DataFirst, u8DataSecond);
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>)
542 if (std::addressof(oData) == std::addressof(iData))
544 throw std::runtime_error(
"The oData object cannot be the iData object");
566 .zalloc = (alloc_func)Z_NULL,
567 .zfree = (free_func)Z_NULL,
568 .opaque = (voidpf)Z_NULL,
570 .data_type = Z_BINARY,
576 if (inflateInit2(&zs, 32 + 15) != Z_OK)
578 throw std::runtime_error(
"Failed to initialize zlib decompression");
584 zs.next_in = (z_const Bytef *)iData.data();
587 oData.resize(iData.size());
590 size_t szDecompressedSize = 0;
591 size_t szRemainingSize = iData.size();
596 size_t szOut = oData.size() - szDecompressedSize;
599 oData.resize(oData.size() * 2);
600 szOut = oData.size() - szDecompressedSize;
606 zs.next_out = (Bytef *)(&oData.data()[szDecompressedSize]);
609 if (zs.avail_in == 0)
611 constexpr uInt uIntMax = (uInt)-1;
612 zs.avail_in = szRemainingSize > (size_t)uIntMax ? uIntMax : (uInt)szRemainingSize;
613 szRemainingSize -= zs.avail_in;
617 if (zs.avail_out == 0)
619 constexpr uInt uIntMax = (uInt)-1;
620 zs.avail_out = szOut > (size_t)uIntMax ? uIntMax : (uInt)szOut;
625 iRet = inflate(&zs, szRemainingSize != 0 ? Z_NO_FLUSH : Z_FINISH);
628 szDecompressedSize += szOut - zs.avail_out;
629 }
while (iRet == Z_OK || iRet == Z_BUF_ERROR);
632 oData.resize(szDecompressedSize);
635 if (iRet != Z_STREAM_END)
639 throw std::runtime_error(std::string(
"Zlib decompression failed with error message: ") + std::string(zs.msg));
643 throw std::runtime_error(std::string(
"Zlib decompression failed with error code: ") + std::to_string(iRet));
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)
661 if (std::addressof(oData) == std::addressof(iData))
663 throw std::runtime_error(
"The oData object cannot be the iData object");
685 .zalloc = (alloc_func)Z_NULL,
686 .zfree = (free_func)Z_NULL,
687 .opaque = (voidpf)Z_NULL,
689 .data_type = Z_BINARY,
695 if (deflateInit2(&zs, iLevel, Z_DEFLATED, 16 + 15, 8, Z_DEFAULT_STRATEGY) != Z_OK)
697 throw std::runtime_error(
"Failed to initialize zlib compression");
701 zs.next_in = (z_const Bytef *)iData.data();
715 constexpr uLong uLongMax = (uLong)-1;
716 if (iData.size() > (
size_t)uLongMax)
718 size_t szNeedSize = iData.size() + 12;
721 szNeedSize += (szNeedSize + (1000 - 1)) / 1000;
723 oData.resize((szNeedSize + (2 - 1)) / 2);
729 oData.resize(deflateBound(&zs, (uLong)iData.size()));
733 size_t szCompressedSize = 0;
734 size_t szRemainingSize = iData.size();
739 size_t szOut = oData.size() - szCompressedSize;
742 oData.resize(oData.size() * 2);
743 szOut = oData.size() - szCompressedSize;
747 zs.next_out = (Bytef *)(&oData.data()[szCompressedSize]);
750 if (zs.avail_in == 0)
752 constexpr uInt uIntMax = (uInt)-1;
753 zs.avail_in = szRemainingSize > (size_t)uIntMax ? uIntMax : (uInt)szRemainingSize;
754 szRemainingSize -= zs.avail_in;
758 if (zs.avail_out == 0)
760 constexpr uInt uIntMax = (uInt)-1;
761 zs.avail_out = szOut > (size_t)uIntMax ? uIntMax : (uInt)szOut;
766 iRet = deflate(&zs, szRemainingSize != 0 ? Z_NO_FLUSH : Z_FINISH);
769 szCompressedSize += szOut - zs.avail_out;
770 }
while (iRet == Z_OK || iRet == Z_BUF_ERROR);
774 oData.resize(szCompressedSize);
777 if (iRet != Z_STREAM_END)
781 throw std::runtime_error(std::string(
"Zlib compression failed with error message: ") + std::string(zs.msg));
785 throw std::runtime_error(std::string(
"Zlib compression failed with error code: ") + std::to_string(iRet));
801 template<
typename I,
typename O,
typename InfoFunc = NBT_Pr
int>
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>)
811 catch (
const std::bad_alloc &e)
816 catch (
const std::exception &e)
840 template<
typename I,
typename O,
typename InfoFunc = NBT_Pr
int>
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
850 catch (
const std::bad_alloc &e)
855 catch (
const std::exception &e)
@ Err
错误信息
定义 NBT_Print.hpp:14
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