diff --git a/core/2d/ParticleSystem.cpp b/core/2d/ParticleSystem.cpp index e588bcab2a..c28c6a1d00 100644 --- a/core/2d/ParticleSystem.cpp +++ b/core/2d/ParticleSystem.cpp @@ -436,7 +436,6 @@ bool ParticleSystem::initWithDictionary(const ValueMap& dictionary) bool ParticleSystem::initWithDictionary(const ValueMap& dictionary, std::string_view dirname) { bool ret = false; - unsigned char* buffer = nullptr; Image* image = nullptr; do { @@ -635,20 +634,18 @@ bool ParticleSystem::initWithDictionary(const ValueMap& dictionary, std::string_ if (dataLen != 0) { // if it fails, try to get it from the base64-gzipped data - int decodeLen = - utils::base64Decode((unsigned char*)textureData.c_str(), (unsigned int)dataLen, &buffer); - AXASSERT(buffer != nullptr, "CCParticleSystem: error decoding textureImageData"); - AX_BREAK_IF(!buffer); + yasio::byte_buffer buffer = utils::base64Decode(textureData); + AXASSERT(!buffer.empty(), "CCParticleSystem: error decoding textureImageData"); + AX_BREAK_IF(buffer.empty()); - unsigned char* deflated = nullptr; - ssize_t deflatedLen = ZipUtils::inflateMemory(buffer, decodeLen, &deflated); - AXASSERT(deflated != nullptr, "CCParticleSystem: error ungzipping textureImageData"); - AX_BREAK_IF(!deflated); + auto deflated = ZipUtils::decompressGZ(std::span{buffer}); + AXASSERT(!deflated.empty(), "CCParticleSystem: error ungzipping textureImageData"); + AX_BREAK_IF(deflated.empty()); // For android, we should retain it in VolatileTexture::addImage which invoked in // Director::getInstance()->getTextureCache()->addUIImage() image = new Image(); - bool isOK = image->initWithImageData(deflated, deflatedLen, true); + bool isOK = image->initWithImageData(deflated.release_pointer(), deflated.size(), true); AXASSERT(isOK, "CCParticleSystem: error init image with Data"); AX_BREAK_IF(!isOK); @@ -666,7 +663,6 @@ bool ParticleSystem::initWithDictionary(const ValueMap& dictionary, std::string_ ret = true; } } while (0); - free(buffer); return ret; } diff --git a/core/2d/TMXXMLParser.cpp b/core/2d/TMXXMLParser.cpp index 30ce89fca0..43e5241caa 100644 --- a/core/2d/TMXXMLParser.cpp +++ b/core/2d/TMXXMLParser.cpp @@ -446,11 +446,8 @@ void TMXMapInfo::startElement(void* /*ctx*/, const char* name, const char** atts Vec2 layerSize = layer->_layerSize; int tilesAmount = static_cast(layerSize.width * layerSize.height); - uint32_t* tiles = (uint32_t*)malloc(tilesAmount * sizeof(uint32_t)); - // set all value to 0 - memset(tiles, 0, tilesAmount * sizeof(int)); - - layer->_tiles = tiles; + layer->_tiles = + (uint32_t*)axstd::byte_buffer{tilesAmount * sizeof(uint32_t), 0, std::true_type{}}.release_pointer(); } else if (encoding == "base64") { @@ -690,10 +687,8 @@ void TMXMapInfo::endElement(void* /*ctx*/, const char* name) TMXLayerInfo* layer = tmxMapInfo->getLayers().back(); auto currentString = tmxMapInfo->getCurrentString(); - unsigned char* buffer; - auto len = utils::base64Decode((unsigned char*)currentString.data(), (unsigned int)currentString.length(), - &buffer); - if (!buffer) + auto buffer = utils::base64Decode(currentString); + if (buffer.empty()) { AXLOG("axmol: TiledMap: decode data error"); return; @@ -701,36 +696,30 @@ void TMXMapInfo::endElement(void* /*ctx*/, const char* name) if (tmxMapInfo->getLayerAttribs() & (TMXLayerAttribGzip | TMXLayerAttribZlib)) { - unsigned char* deflated = nullptr; Vec2 s = layer->_layerSize; // int sizeHint = s.width * s.height * sizeof(uint32_t); ssize_t sizeHint = s.width * s.height * sizeof(unsigned int); - ssize_t AX_UNUSED inflatedLen = ZipUtils::inflateMemoryWithHint(buffer, len, &deflated, sizeHint); - AXASSERT(inflatedLen == sizeHint, "inflatedLen should be equal to sizeHint!"); + buffer = ZipUtils::decompressGZ(std::span{buffer}, sizeHint); + AXASSERT(buffer.size() == sizeHint, "inflatedLen should be equal to sizeHint!"); - free(buffer); - buffer = nullptr; - - if (!deflated) + if (buffer.empty()) { AXLOG("axmol: TiledMap: inflate data error"); return; } - layer->_tiles = reinterpret_cast(deflated); + layer->_tiles = reinterpret_cast(buffer.release_pointer()); } else { - layer->_tiles = reinterpret_cast(buffer); + layer->_tiles = reinterpret_cast(buffer.release_pointer()); } tmxMapInfo->setCurrentString(""); } else if (tmxMapInfo->getLayerAttribs() & TMXLayerAttribCSV) { - unsigned char* buffer; - TMXLayerInfo* layer = tmxMapInfo->getLayers().back(); tmxMapInfo->setStoringCharacters(false); @@ -751,14 +740,8 @@ void TMXMapInfo::endElement(void* /*ctx*/, const char* name) } // 32-bits per gid - buffer = (unsigned char*)malloc(gidTokens.size() * 4); - if (!buffer) - { - AXLOG("axmol: TiledMap: CSV buffer not allocated."); - return; - } - - uint32_t* bufferPtr = reinterpret_cast(buffer); + axstd::byte_buffer buffer{gidTokens.size() * 4, std::true_type{}}; + uint32_t* bufferPtr = reinterpret_cast(buffer.data()); for (const auto& gidToken : gidTokens) { auto tileGid = (uint32_t)strtoul(gidToken.c_str(), nullptr, 10); @@ -766,7 +749,7 @@ void TMXMapInfo::endElement(void* /*ctx*/, const char* name) bufferPtr++; } - layer->_tiles = reinterpret_cast(buffer); + layer->_tiles = reinterpret_cast(buffer.release_pointer()); tmxMapInfo->setCurrentString(""); } diff --git a/core/base/Data.cpp b/core/base/Data.cpp index 287176630a..d4efb1003c 100644 --- a/core/base/Data.cpp +++ b/core/base/Data.cpp @@ -31,24 +31,19 @@ NS_AX_BEGIN const Data Data::Null; -Data::Data() : _bytes(nullptr), _size(0) +Data::Data() { AXLOGINFO("In the empty constructor of Data."); } -Data::Data(Data&& other) : _bytes(nullptr), _size(0) +Data::Data(Data&& other) : _impl(std::move(other)) { AXLOGINFO("In the move constructor of Data."); - move(other); } -Data::Data(const Data& other) : _bytes(nullptr), _size(0) +Data::Data(const Data& other) : _impl(other._impl) { AXLOGINFO("In the copy constructor of Data."); - if (other._bytes && other._size) - { - copy(other._bytes, other._size); - } } Data::~Data() @@ -62,7 +57,7 @@ Data& Data::operator=(const Data& other) if (this != &other) { AXLOGINFO("In the copy assignment of Data."); - copy(other._bytes, other._size); + _impl = other._impl; } return *this; } @@ -79,29 +74,22 @@ Data& Data::operator=(Data&& other) void Data::move(Data& other) { - if (_bytes != other._bytes) - clear(); - - _bytes = other._bytes; - _size = other._size; - - other._bytes = nullptr; - other._size = 0; + this->_impl = std::move(other._impl); } bool Data::isNull() const { - return (_bytes == nullptr || _size == 0); + return _impl.empty(); } uint8_t* Data::getBytes() const { - return _bytes; + return _impl.data(); } ssize_t Data::getSize() const { - return _size; + return _impl.size(); } ssize_t Data::copy(const unsigned char* bytes, const ssize_t size) @@ -109,47 +97,27 @@ ssize_t Data::copy(const unsigned char* bytes, const ssize_t size) AXASSERT(size >= 0, "copy size should be non-negative"); AXASSERT(bytes, "bytes should not be nullptr"); - if (size <= 0) - return 0; - - if (bytes != _bytes) - { - clear(); - _bytes = (unsigned char*)malloc(sizeof(unsigned char) * size); - memcpy(_bytes, bytes, size); - } - - _size = size; - return _size; + _impl.assign(bytes, bytes + size); + return size; } uint8_t* Data::resize(ssize_t size) { - if (_size < size) - { - auto newmb = (uint8_t*)realloc(_bytes, size); - if (!newmb) - return _bytes; - _bytes = newmb; - } - _size = size; - return _bytes; + _impl.resize_fit(size); + return this->data(); } void Data::fastSet(uint8_t* bytes, const ssize_t size) { AXASSERT(size >= 0, "fastSet size should be non-negative"); // AXASSERT(bytes, "bytes should not be nullptr"); - _bytes = bytes; - _size = size; + _impl.attach(bytes, size); } void Data::clear() { - if (_bytes) - free(_bytes); - _bytes = nullptr; - _size = 0; + _impl.clear(); + _impl.shrink_to_fit(); } uint8_t* Data::takeBuffer(ssize_t* size) @@ -157,8 +125,7 @@ uint8_t* Data::takeBuffer(ssize_t* size) auto buffer = getBytes(); if (size) *size = getSize(); - fastSet(nullptr, 0); - return buffer; + return _impl.release_pointer(); } NS_AX_END diff --git a/core/base/Data.h b/core/base/Data.h index 1057606c49..92201c431e 100644 --- a/core/base/Data.h +++ b/core/base/Data.h @@ -31,6 +31,7 @@ #include // for ssize_t on android #include // for ssize_t on linux #include "platform/StdC.h" // for ssize_t on window +#include "base/axstd.h" /** * @addtogroup base @@ -47,8 +48,11 @@ public: /* stl compatible */ using value_type = uint8_t; - size_t size() const { return _size; } - uint8_t* data() const { return _bytes; } + size_t size() const { return _impl.size(); } + const uint8_t* data() const { return _impl.data(); } + uint8_t* data() { return _impl.data(); } + + operator yasio::byte_buffer&(){ return _impl; } /** * This parameter is defined for convenient reference if a null Data object is needed. @@ -155,9 +159,7 @@ public: private: void move(Data& other); -private: - uint8_t* _bytes; - ssize_t _size; + mutable axstd::byte_buffer _impl; }; NS_AX_END diff --git a/core/base/Properties.cpp b/core/base/Properties.cpp index a4b9d88c83..91dbd7f3bf 100644 --- a/core/base/Properties.cpp +++ b/core/base/Properties.cpp @@ -427,7 +427,7 @@ signed char Properties::readChar() { if (eof()) return EOF; - return _data->_bytes[(*_dataIdx)++]; + return static_cast(*_data)[(*_dataIdx)++]; } char* Properties::readLine(char* output, int num) @@ -439,9 +439,9 @@ char* Properties::readLine(char* output, int num) const ssize_t dataIdx = *_dataIdx; int i; - for (i = 0; i < num && dataIdx + i < _data->_size; i++) + for (i = 0; i < num && dataIdx + i < _data->size(); i++) { - auto c = _data->_bytes[dataIdx + i]; + auto c = static_cast(*_data)[dataIdx + i]; if (c == '\n') break; output[i] = c; @@ -464,7 +464,7 @@ bool Properties::seekFromCurrent(int offset) bool Properties::eof() { - return (*_dataIdx >= _data->_size); + return (*_dataIdx >= _data->size()); } void Properties::skipWhiteSpace() diff --git a/core/base/Utils.cpp b/core/base/Utils.cpp index 8cfe8b3f69..58c1c78d98 100644 --- a/core/base/Utils.cpp +++ b/core/base/Utils.cpp @@ -791,9 +791,9 @@ std::string urlDecode(std::string_view st) return decoded; } -AX_DLL std::string base64Encode(std::string_view s) +AX_DLL std::string base64Encode(std::span s) { - size_t n = ax::base64::encoded_size(s.length()); + size_t n = ax::base64::encoded_size(s.size()); if (n > 0) { std::string ret; @@ -809,7 +809,7 @@ AX_DLL std::string base64Encode(std::string_view s) ret.resize_and_overwrite(n, [&](char* p, size_t) { return ax::base64::encode(p, s.data(), s.length()); }); #else ret.resize(n); - ret.resize(ax::base64::encode(&ret.front(), s.data(), s.length())); + ret.resize(ax::base64::encode(&ret.front(), s.data(), s.size())); #endif return ret; @@ -817,23 +817,16 @@ AX_DLL std::string base64Encode(std::string_view s) return std::string{}; } -AX_DLL std::string base64Decode(std::string_view s) +AX_DLL yasio::byte_buffer base64Decode(std::string_view s) { size_t n = ax::base64::decoded_size(s.length()); if (n > 0) { - std::string ret; - -#if _AX_HAS_CXX23 - ret.resize_and_overwrite(n, [&](char* p, size_t) { return ax::base64::decode(p, s.data(), s.length()); }); -#else - ret.resize(n); - ret.resize(ax::base64::decode(&ret.front(), s.data(), s.length())); -#endif - + axstd::byte_buffer ret{n, std::true_type{}}; + ret.resize_fit(ax::base64::decode(&ret.front(), s.data(), s.size())); return ret; } - return std::string{}; + return yasio::byte_buffer{}; } int base64Encode(const unsigned char* in, unsigned int inLength, char** out) diff --git a/core/base/Utils.h b/core/base/Utils.h index d80c3a019c..093e9dcc7e 100644 --- a/core/base/Utils.h +++ b/core/base/Utils.h @@ -37,6 +37,7 @@ THE SOFTWARE. #include "renderer/backend/Types.h" #include "math/Mat4.h" #include "math/Mat3.h" +#include "base/axstd.h" /** @file ccUtils.h Misc free functions @@ -412,7 +413,7 @@ AX_DLL std::string urlDecode(std::string_view st); * @since axmol-1.0.0 */ -AX_DLL std::string base64Encode(std::string_view s); +AX_DLL std::string base64Encode(std::span s); /** * Decodes a 64base encoded buffer @@ -420,7 +421,7 @@ AX_DLL std::string base64Encode(std::string_view s); * @since axmol-1.0.0 */ -AX_DLL std::string base64Decode(std::string_view s); +AX_DLL yasio::byte_buffer base64Decode(std::string_view s); /** * Encodes bytes into a 64base encoded memory with terminating '\0' character. diff --git a/core/base/ZipUtils.cpp b/core/base/ZipUtils.cpp index faf085a26b..a021991f35 100644 --- a/core/base/ZipUtils.cpp +++ b/core/base/ZipUtils.cpp @@ -175,7 +175,22 @@ _L_end: inflateEnd(&d_stream); if (err != Z_STREAM_END) { + switch (err) + { + case Z_MEM_ERROR: + AXLOG("axmol: ZipUtils: Out of memory while decompressing map data!"); + break; + case Z_VERSION_ERROR: + AXLOG("axmol: ZipUtils: Incompatible zlib version!"); + break; + case Z_DATA_ERROR: + AXLOG("axmol: ZipUtils: Incorrect zlib compressed data!"); + break; + default: + AXLOG("axmol: ZipUtils: Unknown error while decompressing map data!"); + } output.clear(); + output.shrink_to_fit(); } return output; @@ -273,112 +288,13 @@ inline unsigned int ZipUtils::checksumPvr(const unsigned int* data, ssize_t len) return cs; } -// memory in iPhone is precious -// Should buffer factor be 1.5 instead of 2 ? -#define BUFFER_INC_FACTOR (2) - -int ZipUtils::inflateMemoryWithHint(unsigned char* in, - ssize_t inLength, - unsigned char** out, - ssize_t* outLength, - ssize_t outLengthHint) -{ - /* ret value */ - int err = Z_OK; - - ssize_t bufferSize = outLengthHint; - *out = (unsigned char*)malloc(bufferSize); - - z_stream d_stream; /* decompression stream */ - d_stream.zalloc = (alloc_func)0; - d_stream.zfree = (free_func)0; - d_stream.opaque = (voidpf)0; - - d_stream.next_in = in; - d_stream.avail_in = static_cast(inLength); - d_stream.next_out = *out; - d_stream.avail_out = static_cast(bufferSize); - - /* window size to hold 256k */ - if ((err = inflateInit2(&d_stream, 15 + 32)) != Z_OK) - return err; - - for (;;) - { - err = inflate(&d_stream, Z_NO_FLUSH); - - if (err == Z_STREAM_END) - { - break; - } - - switch (err) - { - case Z_NEED_DICT: - err = Z_DATA_ERROR; - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&d_stream); - return err; - } - - // not enough memory ? - if (err != Z_STREAM_END) - { - *out = (unsigned char*)realloc(*out, bufferSize * BUFFER_INC_FACTOR); - - /* not enough memory, ouch */ - if (!*out) - { - AXLOG("axmol: ZipUtils: realloc failed"); - inflateEnd(&d_stream); - return Z_MEM_ERROR; - } - - d_stream.next_out = *out + bufferSize; - d_stream.avail_out = static_cast(bufferSize); - bufferSize *= BUFFER_INC_FACTOR; - } - } - - *outLength = bufferSize - d_stream.avail_out; - err = inflateEnd(&d_stream); - return err; -} - ssize_t ZipUtils::inflateMemoryWithHint(unsigned char* in, ssize_t inLength, unsigned char** out, ssize_t outLengthHint) { - ssize_t outLength = 0; - int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint); - - if (err != Z_OK || *out == nullptr) - { - if (err == Z_MEM_ERROR) - { - AXLOG("axmol: ZipUtils: Out of memory while decompressing map data!"); - } - else if (err == Z_VERSION_ERROR) - { - AXLOG("axmol: ZipUtils: Incompatible zlib version!"); - } - else if (err == Z_DATA_ERROR) - { - AXLOG("axmol: ZipUtils: Incorrect zlib compressed data!"); - } - else - { - AXLOG("axmol: ZipUtils: Unknown error while decompressing map data!"); - } - - if (*out) - { - free(*out); - *out = nullptr; - } - outLength = 0; - } - - return outLength; + auto outBuffer = decompressGZ(std::span{in, in + inLength}, static_cast(outLengthHint)); + auto outLen = outBuffer.size(); + if (out) + *out = outBuffer.release_pointer(); + return outLen; } ssize_t ZipUtils::inflateMemory(unsigned char* in, ssize_t inLength, unsigned char** out) @@ -403,24 +319,16 @@ int ZipUtils::inflateGZipFile(const char* path, unsigned char** out) } /* 512k initial decompress buffer */ - unsigned int bufferSize = 512 * 1024; - unsigned int totalBufferSize = bufferSize; + yasio::byte_buffer buffer{512}; - *out = (unsigned char*)malloc(bufferSize); - if (*out == NULL) - { - AXLOG("axmol: ZipUtils: out of memory"); - return -1; - } + uint8_t readBuffer[512]; for (;;) { - len = gzread(inFile, *out + offset, bufferSize); + len = gzread(inFile, readBuffer, sizeof(readBuffer)); if (len < 0) { AXLOG("axmol: ZipUtils: error in gzread"); - free(*out); - *out = nullptr; return -1; } if (len == 0) @@ -428,27 +336,7 @@ int ZipUtils::inflateGZipFile(const char* path, unsigned char** out) break; } - offset += len; - - // finish reading the file - if ((unsigned int)len < bufferSize) - { - break; - } - - bufferSize *= BUFFER_INC_FACTOR; - totalBufferSize += bufferSize; - unsigned char* tmp = (unsigned char*)realloc(*out, totalBufferSize); - - if (!tmp) - { - AXLOG("axmol: ZipUtils: out of memory"); - free(*out); - *out = nullptr; - return -1; - } - - *out = tmp; + buffer.append(readBuffer, readBuffer + 512); } if (gzclose(inFile) != Z_OK) @@ -456,7 +344,11 @@ int ZipUtils::inflateGZipFile(const char* path, unsigned char** out) AXLOG("axmol: ZipUtils: gzclose failed"); } - return offset; + + auto totalSize = buffer.size(); + if (out) + *out = buffer.release_pointer(); + return totalSize; } bool ZipUtils::isCCZFile(const char* path) @@ -576,26 +468,24 @@ int ZipUtils::inflateCCZBuffer(const unsigned char* buffer, ssize_t bufferLen, u } unsigned int len = AX_SWAP_INT32_BIG_TO_HOST(header->len); - - *out = (unsigned char*)malloc(len); - if (!*out) + if (!len) { AXLOG("axmol: CCZ: Failed to allocate memory for texture"); return -1; } + axstd::byte_buffer outBuffer{len, std::true_type{}}; + unsigned long destlen = len; size_t source = (size_t)buffer + sizeof(*header); - int ret = uncompress(*out, &destlen, (Bytef*)source, static_cast(bufferLen - sizeof(*header))); + int ret = uncompress(outBuffer.data(), &destlen, (Bytef*)source, static_cast(bufferLen - sizeof(*header))); if (ret != Z_OK) { AXLOG("axmol: CCZ: Failed to uncompress data"); - free(*out); - *out = nullptr; return -1; } - + *out = outBuffer.release_pointer(); return len; } diff --git a/core/base/axstd.h b/core/base/axstd.h index 6ac615a4f8..9fc78dec6f 100644 --- a/core/base/axstd.h +++ b/core/base/axstd.h @@ -3,7 +3,9 @@ #include #include #include +#include #include "pod_vector.h" +#include "yasio/byte_buffer.hpp" // Tests whether compiler has c++23 support #if (defined(__cplusplus) && __cplusplus > 202002L) || \ @@ -19,6 +21,9 @@ namespace axstd { +using byte_buffer = yasio::byte_buffer; +using sbyte_buffer = yasio::sbyte_buffer; + /* make_unique_for_overwrite since c++20, but not all platformm support */ template , int> = 0> inline std::unique_ptr<_Ty> make_unique_for_overwrite() diff --git a/core/ui/UIWebView/UIWebViewImpl-win32.cpp b/core/ui/UIWebView/UIWebViewImpl-win32.cpp index 5955b0309f..edc5261595 100644 --- a/core/ui/UIWebView/UIWebViewImpl-win32.cpp +++ b/core/ui/UIWebView/UIWebViewImpl-win32.cpp @@ -216,9 +216,9 @@ static std::string getUriStringFromArgs(ArgType* args) return {}; } -static std::string getDataURI(std::string_view data, std::string_view mime_type) +static std::string getDataURI(const ax::Data& data, std::string_view mime_type) { - auto encodedData = utils::base64Encode(data); + auto encodedData = utils::base64Encode(std::span{data.getBytes(), data.getBytes() + data.getSize()}); return std::string{"data:"}.append(mime_type).append(";base64,").append(utils::urlEncode(encodedData)); } @@ -669,9 +669,7 @@ void WebViewImpl::loadData(const Data& data, { if (_createSucceeded) { - const std::string dataString(reinterpret_cast(data.getBytes()), - static_cast(data.getSize())); - const auto url = getDataURI(dataString, MIMEType); + const auto url = getDataURI(data, MIMEType); _systemWebControl->loadURL(url, false); } } diff --git a/extensions/SDFGen/SDFGen.cpp b/extensions/SDFGen/SDFGen.cpp index 2fda0d00cc..47996547f3 100644 --- a/extensions/SDFGen/SDFGen.cpp +++ b/extensions/SDFGen/SDFGen.cpp @@ -133,7 +133,7 @@ public: for (auto& data : _pageDatas) { auto compData = ZipUtils::compressGZ(std::span{data}); - auto pixels = utils::base64Encode(std::string_view{reinterpret_cast(compData.data()), compData.size()}); + auto pixels = utils::base64Encode(std::span{compData}); pages.push_back(std::move(pixels)); }