Preferred use byte_buffer as APIs

This commit is contained in:
halx99 2023-09-29 01:57:41 +08:00
parent 1fcb6abfc2
commit 4065b90039
11 changed files with 99 additions and 264 deletions

View File

@ -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;
}

View File

@ -446,11 +446,8 @@ void TMXMapInfo::startElement(void* /*ctx*/, const char* name, const char** atts
Vec2 layerSize = layer->_layerSize;
int tilesAmount = static_cast<int>(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<uint32_t*>(deflated);
layer->_tiles = reinterpret_cast<uint32_t*>(buffer.release_pointer());
}
else
{
layer->_tiles = reinterpret_cast<uint32_t*>(buffer);
layer->_tiles = reinterpret_cast<uint32_t*>(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<uint32_t*>(buffer);
axstd::byte_buffer buffer{gidTokens.size() * 4, std::true_type{}};
uint32_t* bufferPtr = reinterpret_cast<uint32_t*>(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<uint32_t*>(buffer);
layer->_tiles = reinterpret_cast<uint32_t*>(buffer.release_pointer());
tmxMapInfo->setCurrentString("");
}

View File

@ -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

View File

@ -31,6 +31,7 @@
#include <stdint.h> // for ssize_t on android
#include <string> // 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

View File

@ -427,7 +427,7 @@ signed char Properties::readChar()
{
if (eof())
return EOF;
return _data->_bytes[(*_dataIdx)++];
return static_cast<axstd::byte_buffer&>(*_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<axstd::byte_buffer&>(*_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()

View File

@ -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<uint8_t> 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)

View File

@ -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<uint8_t> 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.

View File

@ -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<unsigned int>(inLength);
d_stream.next_out = *out;
d_stream.avail_out = static_cast<unsigned int>(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<unsigned int>(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<int>(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<uLong>(bufferLen - sizeof(*header)));
int ret = uncompress(outBuffer.data(), &destlen, (Bytef*)source, static_cast<uLong>(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;
}

View File

@ -3,7 +3,9 @@
#include <type_traits>
#include <memory>
#include <string_view>
#include <span>
#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 <class _Ty, std::enable_if_t<!std::is_array_v<_Ty>, int> = 0>
inline std::unique_ptr<_Ty> make_unique_for_overwrite()

View File

@ -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<char*>(data.getBytes()),
static_cast<unsigned int>(data.getSize()));
const auto url = getDataURI(dataString, MIMEType);
const auto url = getDataURI(data, MIMEType);
_systemWebControl->loadURL(url, false);
}
}

View File

@ -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<const char*>(compData.data()), compData.size()});
auto pixels = utils::base64Encode(std::span{compData});
pages.push_back(std::move(pixels));
}