mirror of https://github.com/axmolengine/axmol.git
Merge pull request #340 from rh101/vfs-support
Enhance FileStream support to allow usage of virtual file systems
This commit is contained in:
commit
dd69c21c0e
|
@ -68,8 +68,8 @@ static unsigned long ft_stream_read_callback(FT_Stream stream, unsigned long off
|
|||
}
|
||||
|
||||
static void ft_stream_close_callback(FT_Stream stream) {
|
||||
auto fd = (FileStream*)stream->descriptor.pointer;
|
||||
if (fd) delete fd;
|
||||
const auto* fd = (FileStream*)stream->descriptor.pointer;
|
||||
delete fd;
|
||||
stream->size = 0;
|
||||
stream->descriptor.pointer = nullptr;
|
||||
}
|
||||
|
@ -174,21 +174,23 @@ bool FontFreeType::createFontObject(const std::string &fontName, float fontSize)
|
|||
auto fullPath = FileUtils::getInstance()->fullPathForFilename(fontName);
|
||||
if (fullPath.empty()) return false;
|
||||
|
||||
FileStream fs;
|
||||
if (!fs.open(fullPath, FileStream::Mode::READ))
|
||||
FileStream* fs = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::READ);
|
||||
if (!fs)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::unique_ptr<FT_StreamRec> fts(new FT_StreamRec());
|
||||
fts->read = ft_stream_read_callback;
|
||||
fts->close = ft_stream_close_callback;
|
||||
fts->size = fs.seek(0, SEEK_END);
|
||||
fs.seek(0, SEEK_SET);
|
||||
fts->size = fs->seek(0, SEEK_END);
|
||||
fs->seek(0, SEEK_SET);
|
||||
|
||||
fts->descriptor.pointer = new FileStream(std::move(fs));
|
||||
fts->descriptor.pointer = fs;
|
||||
|
||||
FT_Open_Args args = { 0 };
|
||||
args.flags = FT_OPEN_STREAM;
|
||||
args.stream = fts.get();;
|
||||
args.stream = fts.get();
|
||||
|
||||
if (FT_Open_Face(getFTLibrary(), &args, 0, &face))
|
||||
return false;
|
||||
|
|
|
@ -80,7 +80,7 @@ protected:
|
|||
static bool lazyInit();
|
||||
static void destroy();
|
||||
|
||||
FileStream _fileStream;
|
||||
FileStream* _fileStream = nullptr;
|
||||
mp3dec_handle_t _handle;
|
||||
|
||||
friend class AudioDecoderManager;
|
||||
|
|
|
@ -68,7 +68,7 @@ protected:
|
|||
AudioDecoderOgg();
|
||||
~AudioDecoderOgg();
|
||||
|
||||
FileStream _fileStream;
|
||||
FileStream* _fileStream;
|
||||
OggVorbis_File _vf;
|
||||
|
||||
friend class AudioDecoderManager;
|
||||
|
|
|
@ -106,7 +106,7 @@ struct WAV_FILE
|
|||
WAV_FILE_HEADER FileHeader;
|
||||
AUDIO_SOURCE_FORMAT SourceFormat;
|
||||
uint32_t PcmDataOffset;
|
||||
cocos2d::FileStream Stream;
|
||||
cocos2d::FileStream* Stream = nullptr;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -128,7 +128,9 @@ namespace cocos2d {
|
|||
#if !CC_USE_MPG123
|
||||
do
|
||||
{
|
||||
if (!_fileStream.open(fullPath, FileStream::Mode::READ))
|
||||
delete _fileStream;
|
||||
_fileStream = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::READ);
|
||||
if (!_fileStream)
|
||||
{
|
||||
ALOGE("Trouble with minimp3(1): %s\n", strerror(errno));
|
||||
break;
|
||||
|
@ -138,7 +140,7 @@ namespace cocos2d {
|
|||
|
||||
handle->_decIO.read = minimp3_read_r;
|
||||
handle->_decIO.seek = minimp3_seek_r;
|
||||
handle->_decIO.read_data = handle->_decIO.seek_data = &_fileStream;
|
||||
handle->_decIO.read_data = handle->_decIO.seek_data = _fileStream;
|
||||
|
||||
if (mp3dec_ex_open_cb(&handle->_dec, &handle->_decIO, MP3D_SEEK_TO_SAMPLE) != 0)
|
||||
{
|
||||
|
@ -189,7 +191,7 @@ namespace cocos2d {
|
|||
|
||||
mpg123_replace_reader_handle(_handle, mpg123_read_r, mpg123_lseek_r, mpg123_close_r);
|
||||
|
||||
if (mpg123_open_handle(_handle, &_fileStream) != MPG123_OK
|
||||
if (mpg123_open_handle(_handle, _fileStream) != MPG123_OK
|
||||
|| mpg123_getformat(_handle, &rate, &channel, &mp3Encoding) != MPG123_OK)
|
||||
{
|
||||
ALOGE("Trouble with mpg123(2): %s\n", mpg123_strerror(_handle));
|
||||
|
@ -248,7 +250,8 @@ namespace cocos2d {
|
|||
delete _handle;
|
||||
_handle = nullptr;
|
||||
|
||||
_fileStream.close();
|
||||
delete _fileStream;
|
||||
_fileStream = nullptr;
|
||||
}
|
||||
#else
|
||||
if (_handle != nullptr)
|
||||
|
@ -256,6 +259,9 @@ namespace cocos2d {
|
|||
mpg123_close(_handle);
|
||||
mpg123_delete(_handle);
|
||||
_handle = nullptr;
|
||||
|
||||
delete _fileStream;
|
||||
_fileStream = nullptr;
|
||||
}
|
||||
#endif
|
||||
_isOpened = false;
|
||||
|
|
|
@ -69,7 +69,8 @@ namespace cocos2d {
|
|||
|
||||
bool AudioDecoderOgg::open(const std::string& fullPath)
|
||||
{
|
||||
if (!_fileStream.open(fullPath, FileStream::Mode::READ))
|
||||
_fileStream = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::READ);
|
||||
if (!_fileStream)
|
||||
{
|
||||
ALOGE("Trouble with ogg(1): %s\n", strerror(errno));
|
||||
return false;
|
||||
|
|
|
@ -52,23 +52,23 @@ namespace cocos2d {
|
|||
static bool wav_scan_chunk(WAV_FILE* wavf, uint32_t chunkID, void* header, void* body, uint32_t bodySize) {
|
||||
auto& fs = wavf->Stream;
|
||||
auto h = (WAV_CHUNK_HEADER*)header;
|
||||
for (; fs.read(h, WAV_HEADER_SIZE) == WAV_HEADER_SIZE; ) {
|
||||
for (; fs->read(h, WAV_HEADER_SIZE) == WAV_HEADER_SIZE; ) {
|
||||
wavf->PcmDataOffset += WAV_HEADER_SIZE;
|
||||
if (h->ChunkID == chunkID)
|
||||
{ // chunk found
|
||||
if (body)
|
||||
{ // require read body?
|
||||
auto readsize = (std::min)(bodySize, h->ChunkSize);
|
||||
fs.read(body, readsize);
|
||||
fs->read(body, readsize);
|
||||
if (h->ChunkSize > bodySize)
|
||||
fs.seek(h->ChunkSize - bodySize, SEEK_CUR);
|
||||
fs->seek(h->ChunkSize - bodySize, SEEK_CUR);
|
||||
wavf->PcmDataOffset += h->ChunkSize;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
// Skip other non specified chunk
|
||||
fs.seek(h->ChunkSize, SEEK_CUR);
|
||||
fs->seek(h->ChunkSize, SEEK_CUR);
|
||||
wavf->PcmDataOffset += h->ChunkSize;
|
||||
}
|
||||
}
|
||||
|
@ -76,15 +76,16 @@ namespace cocos2d {
|
|||
}
|
||||
static bool wav_open(const std::string& fullPath, WAV_FILE* wavf)
|
||||
{
|
||||
bool succeed = wavf->Stream.open(fullPath, FileStream::Mode::READ);
|
||||
if (!succeed)
|
||||
delete wavf->Stream;
|
||||
wavf->Stream = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::READ);
|
||||
if (!wavf->Stream)
|
||||
return false;
|
||||
|
||||
auto& fileStream = wavf->Stream;
|
||||
wavf->PcmDataOffset = 0;
|
||||
|
||||
// Parsing RIFF chunk
|
||||
fileStream.read(&wavf->FileHeader, WAV_RIFF_SIZE);
|
||||
fileStream->read(&wavf->FileHeader, WAV_RIFF_SIZE);
|
||||
wavf->PcmDataOffset += WAV_RIFF_SIZE;
|
||||
|
||||
if (wavf->FileHeader.Riff.Format != WAV_SIGN_ID)
|
||||
|
@ -132,13 +133,13 @@ namespace cocos2d {
|
|||
if (!IsEqualGUID(fmtInfo.ExtParams.SubFormat, WAV_SUBTYPE_PCM)
|
||||
&& !IsEqualGUID(fmtInfo.ExtParams.SubFormat, WAV_SUBTYPE_IEEE_FLOAT))
|
||||
{
|
||||
fileStream.close();
|
||||
fileStream->close();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ALOGW("The wav format %d doesn't supported currently!", (int)fmtInfo.AudioFormat);
|
||||
fileStream.close();
|
||||
fileStream->close();
|
||||
assert(false);
|
||||
return false;;
|
||||
}
|
||||
|
@ -148,18 +149,21 @@ namespace cocos2d {
|
|||
|
||||
static int wav_read(WAV_FILE* wavf, char* pcmBuf, uint32_t bytesToRead)
|
||||
{
|
||||
return wavf->Stream.read(pcmBuf, bytesToRead);
|
||||
return wavf->Stream->read(pcmBuf, bytesToRead);
|
||||
}
|
||||
|
||||
static int wav_seek(WAV_FILE* wavf, int offset)
|
||||
{
|
||||
auto newOffset = wavf->Stream.seek(wavf->PcmDataOffset + offset, SEEK_SET);
|
||||
auto newOffset = wavf->Stream->seek(wavf->PcmDataOffset + offset, SEEK_SET);
|
||||
return newOffset >= wavf->PcmDataOffset ? newOffset - wavf->PcmDataOffset : -1;
|
||||
}
|
||||
|
||||
static int wav_close(WAV_FILE* wavf)
|
||||
{
|
||||
return wavf->Stream.close();
|
||||
const auto result = wavf->Stream->close();
|
||||
delete wavf->Stream;
|
||||
wavf->Stream = nullptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
AudioDecoderWav::AudioDecoderWav()
|
||||
|
|
|
@ -35,6 +35,7 @@ THE SOFTWARE.
|
|||
#include <sys/stat.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sstream>
|
||||
|
||||
#include "openssl/aes.h"
|
||||
#include "openssl/modes.h"
|
||||
|
@ -51,7 +52,7 @@ THE SOFTWARE.
|
|||
#include "yasio/obstream.hpp"
|
||||
#include "yasio/detail/sz.hpp"
|
||||
|
||||
#include "CCFileStream.h"
|
||||
#include "CCPosixFileStream.h"
|
||||
|
||||
#define USER_DEFAULT_PLAIN_MODE 0
|
||||
|
||||
|
@ -132,10 +133,12 @@ UserDefault::UserDefault()
|
|||
void UserDefault::closeFileMapping()
|
||||
{
|
||||
_rwmmap.reset();
|
||||
#if !USER_DEFAULT_PLAIN_MODE
|
||||
if (_fd != -1) {
|
||||
posix_close(_fd);
|
||||
_fd = -1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool UserDefault::getBoolForKey(const char* pKey)
|
||||
|
@ -369,9 +372,9 @@ void UserDefault::lazyInit()
|
|||
{
|
||||
if (_initialized) return;
|
||||
|
||||
_filePath = FileUtils::getInstance()->getWritablePath() + USER_DEFAULT_FILENAME;
|
||||
|
||||
#if !USER_DEFAULT_PLAIN_MODE
|
||||
_filePath = FileUtils::getInstance()->getNativeWritableAbsolutePath() + USER_DEFAULT_FILENAME;
|
||||
|
||||
// construct file mapping
|
||||
_fd = posix_open(_filePath.c_str(), O_OVERLAP_FLAGS);
|
||||
if (_fd == -1) {
|
||||
|
@ -415,14 +418,22 @@ void UserDefault::lazyInit()
|
|||
}
|
||||
#else
|
||||
pugi::xml_document doc;
|
||||
pugi::xml_parse_result ret = doc.load_file(_filePath.c_str());
|
||||
if (ret) {
|
||||
for (auto& elem : doc.document_element())
|
||||
updateValueForKey(elem.name(), elem.text().as_string());
|
||||
}
|
||||
else {
|
||||
log("UserDefault::init load xml file: %s failed, %s", _filePath.c_str(), ret.description());
|
||||
|
||||
_filePath = FileUtils::getInstance()->getWritablePath() + USER_DEFAULT_FILENAME;
|
||||
|
||||
if (FileUtils::getInstance()->isFileExist(_filePath))
|
||||
{
|
||||
auto data = FileUtils::getInstance()->getDataFromFile(_filePath);
|
||||
pugi::xml_parse_result ret = doc.load_buffer_inplace(data.getBytes(), data.getSize());
|
||||
if (ret) {
|
||||
for (auto& elem : doc.document_element())
|
||||
updateValueForKey(elem.name(), elem.text().as_string());
|
||||
}
|
||||
else {
|
||||
log("UserDefault::init load xml file: %s failed, %s", _filePath.c_str(), ret.description());
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
_initialized = true;
|
||||
|
@ -474,7 +485,10 @@ void UserDefault::flush()
|
|||
r.append_child(kv.first.c_str())
|
||||
.append_child(pugi::xml_node_type::node_pcdata)
|
||||
.set_value(kv.second.c_str());
|
||||
doc.save_file(_filePath.c_str(), " ");
|
||||
|
||||
std::stringstream ss;
|
||||
doc.save(ss, " ");
|
||||
FileUtils::getInstance()->writeStringToFile(ss.str(), _filePath);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
#include "network/CCDownloader-curl.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <set>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
@ -38,7 +39,6 @@
|
|||
#include "platform/CCFileStream.h"
|
||||
#include "md5/md5.h"
|
||||
#include "yasio/xxsocket.hpp"
|
||||
#include <inttypes.h>
|
||||
|
||||
// **NOTE**
|
||||
// In the file:
|
||||
|
@ -87,11 +87,8 @@ namespace cocos2d { namespace network {
|
|||
}
|
||||
}
|
||||
|
||||
if (_fs)
|
||||
_fs.close();
|
||||
|
||||
if (_fsMd5)
|
||||
_fsMd5.close();
|
||||
delete _fs;
|
||||
delete _fsMd5;
|
||||
|
||||
if (_requestHeaders)
|
||||
curl_slist_free_all(_requestHeaders);
|
||||
|
@ -152,7 +149,7 @@ namespace cocos2d { namespace network {
|
|||
}
|
||||
}
|
||||
// open file
|
||||
_fs.open(_tempFileName, FileStream::Mode::APPEND);
|
||||
_fs = FileUtils::getInstance()->openFileStream(_tempFileName, FileStream::Mode::APPEND);
|
||||
if (!_fs)
|
||||
{
|
||||
_errCode = DownloadTask::ERROR_OPEN_FILE_FAILED;
|
||||
|
@ -164,13 +161,14 @@ namespace cocos2d { namespace network {
|
|||
|
||||
// init md5 state
|
||||
_checksumFileName = filename + ".chksum";
|
||||
_fsMd5.open(_checksumFileName.c_str(), FileStream::Mode::WRITE);
|
||||
if (_fsMd5.seek(0, SEEK_END) != sizeof(md5_state_s)) {
|
||||
|
||||
_fsMd5 = FileUtils::getInstance()->openFileStream(_checksumFileName, FileStream::Mode::WRITE);
|
||||
if (_fsMd5->seek(0, SEEK_END) != sizeof(md5_state_s)) {
|
||||
md5_init(&_md5State);
|
||||
}
|
||||
else {
|
||||
_fsMd5.seek(0, SEEK_SET);
|
||||
_fsMd5.read(&_md5State, sizeof(md5_state_s));
|
||||
_fsMd5->seek(0, SEEK_SET);
|
||||
_fsMd5->read(&_md5State, sizeof(md5_state_s));
|
||||
}
|
||||
ret = true;
|
||||
} while (0);
|
||||
|
@ -242,9 +240,9 @@ namespace cocos2d { namespace network {
|
|||
|
||||
auto bytes_transferred = size * count;
|
||||
|
||||
if (_fs)
|
||||
if (_fs->isOpen())
|
||||
{
|
||||
ret = _fs.write(buffer, bytes_transferred);// fwrite(buffer, size, count, _fp);
|
||||
ret = _fs->write(buffer, bytes_transferred);// fwrite(buffer, size, count, _fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -263,8 +261,8 @@ namespace cocos2d { namespace network {
|
|||
_totalBytesReceived += ret;
|
||||
|
||||
::md5_append(&_md5State, buffer, bytes_transferred);
|
||||
_fsMd5.seek(0, SEEK_SET);
|
||||
_fsMd5.write(&_md5State, sizeof(_md5State));
|
||||
_fsMd5->seek(0, SEEK_SET);
|
||||
_fsMd5->write(&_md5State, sizeof(_md5State));
|
||||
}
|
||||
|
||||
curl_easy_getinfo(_curl, CURLINFO_SPEED_DOWNLOAD, &_speed);
|
||||
|
@ -306,10 +304,10 @@ namespace cocos2d { namespace network {
|
|||
string _tempFileName;
|
||||
std::string _checksumFileName;
|
||||
vector<unsigned char> _buf;
|
||||
FileStream _fs;
|
||||
FileStream* _fs;
|
||||
|
||||
// calculate md5 in downloading time support
|
||||
FileStream _fsMd5; // store md5 state realtime
|
||||
FileStream* _fsMd5; // store md5 state realtime
|
||||
md5_state_s _md5State;
|
||||
|
||||
|
||||
|
@ -887,8 +885,7 @@ public:
|
|||
task.progressInfo.totalBytesReceived = coTask._totalBytesReceived;
|
||||
task.progressInfo.totalBytesExpected = coTask._totalBytesExpected;
|
||||
task.progressInfo.speedInBytes = coTask._speed;
|
||||
onTaskProgress(task,
|
||||
_transferDataToBuffer);
|
||||
onTaskProgress(task, _transferDataToBuffer);
|
||||
coTask._bytesReceived = 0;
|
||||
_currTask = nullptr;
|
||||
}
|
||||
|
@ -899,14 +896,14 @@ public:
|
|||
do
|
||||
{
|
||||
auto pFileUtils = FileUtils::getInstance();
|
||||
coTask._fs.close();
|
||||
coTask._fsMd5.close();
|
||||
coTask._fs->close();
|
||||
coTask._fsMd5->close();
|
||||
|
||||
if (checkState & kCheckSumStateSucceed) // No need download
|
||||
{
|
||||
FileStream fsOrigin;
|
||||
if (fsOrigin.open(coTask._fileName, FileStream::Mode::READ)) {
|
||||
task.progressInfo.totalBytesExpected = fsOrigin.seek(0, SEEK_END);
|
||||
FileStream* fsOrigin = FileUtils::getInstance()->openFileStream(coTask._fileName, FileStream::Mode::READ);
|
||||
if (fsOrigin) {
|
||||
task.progressInfo.totalBytesExpected = fsOrigin->seek(0, SEEK_END);
|
||||
task.progressInfo.bytesReceived = task.progressInfo.totalBytesExpected;
|
||||
task.progressInfo.totalBytesReceived = task.progressInfo.totalBytesExpected;
|
||||
task.progressInfo.speedInBytes = task.progressInfo.totalBytesExpected;
|
||||
|
@ -916,8 +913,10 @@ public:
|
|||
|
||||
pFileUtils->removeFile(coTask._tempFileName);
|
||||
|
||||
onTaskProgress(task,
|
||||
_transferDataToBuffer);
|
||||
onTaskProgress(task,_transferDataToBuffer);
|
||||
|
||||
delete fsOrigin;
|
||||
fsOrigin = nullptr;
|
||||
}
|
||||
else {
|
||||
coTask._errCode = DownloadTask::ERROR_ORIGIN_FILE_MISSING;
|
||||
|
@ -926,6 +925,7 @@ public:
|
|||
pFileUtils->removeFile(coTask._checksumFileName);
|
||||
pFileUtils->removeFile(coTask._tempFileName);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,199 +2,6 @@
|
|||
// Copyright (c) 2020 c4games.com
|
||||
#include "platform/CCFileStream.h"
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#include "base/ZipUtils.h"
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
struct PXIoF {
|
||||
int(*read)(PXFileHandle& handle, void*, unsigned int);
|
||||
long(*seek)(PXFileHandle& handle, long, int);
|
||||
int(*close)(PXFileHandle& handle);
|
||||
};
|
||||
|
||||
static int pfs_posix_open(const std::string& path, FileStream::Mode mode, PXFileHandle& handle)
|
||||
{
|
||||
switch (mode) {
|
||||
case FileStream::Mode::READ:
|
||||
handle._fd = posix_open(path.c_str(), O_READ_FLAGS);
|
||||
break;
|
||||
case FileStream::Mode::WRITE:
|
||||
handle._fd = posix_open(path.c_str(), O_WRITE_FLAGS);
|
||||
break;
|
||||
case FileStream::Mode::APPEND:
|
||||
handle._fd = posix_open(path.c_str(), O_APPEND_FLAGS);
|
||||
break;
|
||||
default:
|
||||
handle._fd = -1;
|
||||
}
|
||||
return handle._fd;
|
||||
}
|
||||
|
||||
// posix standard wrappers
|
||||
static int pfs_posix_read(PXFileHandle& handle, void* buf, unsigned int size) { return static_cast<int>(posix_read(handle._fd, buf, size)); }
|
||||
static long pfs_posix_seek(PXFileHandle& handle, long offst, int origin) { return posix_lseek(handle._fd, offst, origin); }
|
||||
static int pfs_posix_close(PXFileHandle& handle) {
|
||||
int fd = handle._fd;
|
||||
if (fd != -1) {
|
||||
handle._fd = -1;
|
||||
return posix_close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_posix_iof = {
|
||||
pfs_posix_read,
|
||||
pfs_posix_seek,
|
||||
pfs_posix_close
|
||||
};
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
// android AssetManager wrappers
|
||||
static int pfs_asset_read(PXFileHandle& handle, void* buf, unsigned int size) { return AAsset_read(handle._asset, buf, size); }
|
||||
static long pfs_asset_seek(PXFileHandle& handle, long offst, int origin) { return AAsset_seek(handle._asset, offst, origin); }
|
||||
static int pfs_asset_close(PXFileHandle& handle) {
|
||||
if (handle._asset != nullptr) {
|
||||
AAsset_close(handle._asset);
|
||||
handle._asset = nullptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_asset_iof = {
|
||||
pfs_asset_read,
|
||||
pfs_asset_seek,
|
||||
pfs_asset_close
|
||||
};
|
||||
|
||||
// android obb
|
||||
static int pfs_obb_read(PXFileHandle& handle, void* buf, unsigned int size) { return FileUtilsAndroid::getObbFile()->zfread(&handle._zfs, buf, size); }
|
||||
static long pfs_obb_seek(PXFileHandle& handle, long offset, int origin) { return FileUtilsAndroid::getObbFile()->zfseek(&handle._zfs, offset, origin); }
|
||||
static int pfs_obb_close(PXFileHandle& handle) {
|
||||
FileUtilsAndroid::getObbFile()->zfclose(&handle._zfs);
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_obb_iof = {
|
||||
pfs_obb_read,
|
||||
pfs_obb_seek,
|
||||
pfs_obb_close
|
||||
};
|
||||
#endif
|
||||
|
||||
FileStream::FileStream()
|
||||
{
|
||||
zeroset();
|
||||
}
|
||||
|
||||
FileStream::~FileStream()
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
|
||||
FileStream::FileStream(FileStream&& rhs)
|
||||
{
|
||||
zeroset();
|
||||
assign(std::forward<FileStream>(rhs));
|
||||
}
|
||||
|
||||
FileStream& FileStream::operator=(FileStream&& rhs)
|
||||
{
|
||||
assign(std::forward<FileStream>(rhs));
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FileStream::zeroset()
|
||||
{
|
||||
memset(this, 0, sizeof(FileStream));
|
||||
}
|
||||
|
||||
void FileStream::assign(FileStream&& rhs)
|
||||
{
|
||||
this->close();
|
||||
memcpy(this, &rhs, sizeof(FileStream));
|
||||
rhs.zeroset();
|
||||
}
|
||||
|
||||
bool FileStream::open(const std::string& path, FileStream::Mode mode)
|
||||
{
|
||||
bool ok = false;
|
||||
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
|
||||
ok = pfs_posix_open(path, mode, _handle) != -1;
|
||||
#else // Android
|
||||
if (path[0] != '/') { // from package, always readonly
|
||||
std::string relativePath;
|
||||
size_t position = path.find("assets/");
|
||||
if (0 == position)
|
||||
{
|
||||
// "assets/" is at the beginning of the path and we don't want it
|
||||
relativePath = path.substr(sizeof("assets/") - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
relativePath = path;
|
||||
}
|
||||
|
||||
auto obb = FileUtilsAndroid::getObbFile();
|
||||
ok = obb != nullptr && obb->zfopen(relativePath, &_handle._zfs);
|
||||
if (ok) {
|
||||
this->_iof = &pfs_obb_iof;
|
||||
}
|
||||
else {
|
||||
AAssetManager* asMgr = FileUtilsAndroid::getAssetManager();
|
||||
AAsset* asset = AAssetManager_open(asMgr, relativePath.c_str(), AASSET_MODE_UNKNOWN);
|
||||
ok = !!asset;
|
||||
if (ok) {
|
||||
_handle._asset = asset;
|
||||
// setup file read/seek/close at here
|
||||
this->_iof = &pfs_asset_iof;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // otherwise, as a absolutely path
|
||||
ok = pfs_posix_open(path, mode, _handle) != -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ok && !_iof)
|
||||
_iof = &pfs_posix_iof;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
FileStream::operator bool() const
|
||||
{
|
||||
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
|
||||
return _handle._fd != -1;
|
||||
#else
|
||||
return _handle._fd != -1 && _handle._asset != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
int FileStream::close()
|
||||
{
|
||||
if (_iof) {
|
||||
int ret = _iof->close(_handle);
|
||||
_iof = nullptr;
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FileStream::seek(long offset, int origin)
|
||||
{
|
||||
return static_cast<int>(_iof->seek(_handle, offset, origin));
|
||||
}
|
||||
|
||||
int FileStream::read(void* buf, unsigned int size)
|
||||
{
|
||||
return _iof->read(_handle, buf, size);
|
||||
}
|
||||
|
||||
int FileStream::write(const void* buf, unsigned int size)
|
||||
{
|
||||
return static_cast<int>(posix_write(_handle._fd, buf, size));
|
||||
}
|
||||
|
||||
NS_CC_END
|
||||
|
|
|
@ -2,78 +2,16 @@
|
|||
// Copyright (c) 2020 c4games.com
|
||||
#pragma once
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#include <string>
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#include "platform/CCPlatformMacros.h"
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#include "platform/android/CCFileUtils-android.h"
|
||||
#include <jni.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include "base/ZipUtils.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define O_READ_FLAGS O_BINARY | O_RDONLY, S_IREAD
|
||||
#define O_WRITE_FLAGS O_CREAT | O_RDWR | O_BINARY | O_TRUNC, S_IWRITE | S_IREAD
|
||||
#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD
|
||||
|
||||
#define O_OVERLAP_FLAGS O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD
|
||||
|
||||
#define posix_open ::_open
|
||||
#define posix_close ::_close
|
||||
#define posix_lseek ::_lseek
|
||||
#define posix_read ::_read
|
||||
#define posix_write ::_write
|
||||
#define posix_fd2fh(fd) reinterpret_cast<HANDLE>(_get_osfhandle(fd))
|
||||
#define posix_fsetsize(fd, size) ::_chsize(fd, size)
|
||||
#else
|
||||
#define O_READ_FLAGS O_RDONLY, S_IRUSR
|
||||
#define O_WRITE_FLAGS O_CREAT | O_RDWR | O_TRUNC, S_IRWXU
|
||||
#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR, S_IRWXU
|
||||
|
||||
#define O_OVERLAP_FLAGS O_CREAT | O_RDWR, S_IRWXU
|
||||
|
||||
#define posix_open ::open
|
||||
#define posix_close ::close
|
||||
#define posix_lseek ::lseek
|
||||
#define posix_read ::read
|
||||
#define posix_write ::write
|
||||
#define posix_fd2fh(fd) (fd)
|
||||
#define posix_fsetsize(fd, size) ::ftruncate(fd, size); ::lseek(fd, 0, SEEK_SET)
|
||||
#endif
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
struct UnzFileStream;
|
||||
union PXFileHandle {
|
||||
int _fd = -1;
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
AAsset* _asset;
|
||||
ZipFileStream _zfs;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct PXIoF;
|
||||
|
||||
class CC_DLL FileStream {
|
||||
public:
|
||||
FileStream();
|
||||
~FileStream();
|
||||
|
||||
FileStream(FileStream&& rhs);
|
||||
FileStream& operator=(FileStream&& rhs);
|
||||
virtual ~FileStream() = default;
|
||||
|
||||
enum class Mode {
|
||||
READ,
|
||||
|
@ -81,22 +19,20 @@ public:
|
|||
APPEND,
|
||||
};
|
||||
|
||||
bool open(const std::string& path, Mode mode);
|
||||
int close();
|
||||
virtual bool open(const std::string& path, FileStream::Mode mode) = 0;
|
||||
virtual int close() = 0;
|
||||
|
||||
int seek(long offset, int origin);
|
||||
int read(void* buf, unsigned int size);
|
||||
virtual int seek(long offset, int origin) = 0;
|
||||
virtual int read(void* buf, unsigned int size) = 0;
|
||||
|
||||
int write(const void* buf, unsigned int size);
|
||||
virtual int write(const void* buf, unsigned int size) = 0;
|
||||
virtual int tell() = 0;
|
||||
virtual bool isOpen() const = 0;
|
||||
|
||||
operator bool() const;
|
||||
virtual operator bool() const { return isOpen(); }
|
||||
|
||||
private:
|
||||
void zeroset();
|
||||
void assign(FileStream&& rhs);
|
||||
|
||||
PXFileHandle _handle;
|
||||
const PXIoF* _iof;
|
||||
protected:
|
||||
FileStream() = default;
|
||||
};
|
||||
|
||||
NS_CC_END
|
|
@ -27,12 +27,14 @@ THE SOFTWARE.
|
|||
#include "platform/CCFileUtils.h"
|
||||
|
||||
#include <stack>
|
||||
#include <sstream>
|
||||
|
||||
#include "base/CCData.h"
|
||||
#include "base/ccMacros.h"
|
||||
#include "base/CCDirector.h"
|
||||
#include "platform/CCSAXParser.h"
|
||||
//#include "base/ccUtils.h"
|
||||
#include "platform/CCPosixFileStream.h"
|
||||
|
||||
#ifdef MINIZIP_FROM_SYSTEM
|
||||
#include <minizip/unzip.h>
|
||||
|
@ -370,8 +372,9 @@ bool FileUtils::writeValueMapToFile(const ValueMap& dict, const std::string& ful
|
|||
auto rootEle = doc.document_element();
|
||||
|
||||
generateElementForDict(dict, rootEle);
|
||||
|
||||
return doc.save_file(fullPath.c_str());
|
||||
std::stringstream ss;
|
||||
doc.save(ss, " ");
|
||||
return writeStringToFile(ss.str(), fullPath);
|
||||
}
|
||||
|
||||
bool FileUtils::writeValueVectorToFile(const ValueVector& vecData, const std::string& fullPath) const
|
||||
|
@ -383,8 +386,9 @@ bool FileUtils::writeValueVectorToFile(const ValueVector& vecData, const std::st
|
|||
|
||||
auto rootEle = doc.document_element();
|
||||
generateElementForArray(vecData, rootEle);
|
||||
|
||||
return doc.save_file(fullPath.c_str());
|
||||
std::stringstream ss;
|
||||
doc.save(ss, " ");
|
||||
return writeStringToFile(ss.str(), fullPath);
|
||||
}
|
||||
|
||||
static void generateElementForObject(const Value& value, pugi::xml_node& parent)
|
||||
|
@ -1101,6 +1105,18 @@ void FileUtils::listFilesRecursivelyAsync(const std::string& dirPath, std::funct
|
|||
}, std::move(callback));
|
||||
}
|
||||
|
||||
FileStream* FileUtils::openFileStream(const std::string& filePath, FileStream::Mode mode)
|
||||
{
|
||||
PosixFileStream fs;
|
||||
|
||||
if (fs.open(filePath, mode))
|
||||
{
|
||||
return new PosixFileStream(std::move(fs)); // PosixFileStream is the default implementation
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32)
|
||||
// windows os implement should override in platform specific FileUtiles class
|
||||
bool FileUtils::isDirectoryExistInternal(const std::string& dirPath) const
|
||||
|
|
|
@ -32,6 +32,7 @@ THE SOFTWARE.
|
|||
#include <type_traits>
|
||||
#include <mutex>
|
||||
|
||||
#include "platform/CCFileStream.h"
|
||||
#include "platform/CCPlatformMacros.h"
|
||||
#include "base/ccTypes.h"
|
||||
#include "base/CCValue.h"
|
||||
|
@ -449,11 +450,19 @@ public:
|
|||
virtual const std::vector<std::string> getOriginalSearchPaths() const;
|
||||
|
||||
/**
|
||||
* Gets the writable path.
|
||||
* Gets the writable path that may not be in the format of an absolute path
|
||||
* @return The path that can be write/read a file in
|
||||
* @note This may return the same value as getNativeWritableAbsolutePath(). If you require the absolute path
|
||||
* to the underlying file system, then call getNativeWritableAbsolutePath() instead.
|
||||
*/
|
||||
virtual std::string getWritablePath() const = 0;
|
||||
|
||||
/**
|
||||
* Gets the writable path in the native file-system format
|
||||
* @return The path that can be write/read a file in
|
||||
*/
|
||||
virtual std::string getNativeWritableAbsolutePath() const = 0;
|
||||
|
||||
/**
|
||||
* Sets writable path.
|
||||
*/
|
||||
|
@ -839,6 +848,14 @@ public:
|
|||
*/
|
||||
virtual bool isDirectoryExistInternal(const std::string& dirPath) const;
|
||||
|
||||
/**
|
||||
* Open a FileStream based on the implementation provided in openFileStream or its overrides
|
||||
* @param filePath The path to the file
|
||||
* @param mode The mode to open the file in, being READ | WRITE | APPEND
|
||||
* @return Returns a pointer to the file stream
|
||||
*/
|
||||
virtual FileStream* openFileStream(const std::string& filePath, FileStream::Mode mode);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* The default constructor.
|
||||
|
|
|
@ -471,6 +471,19 @@ namespace
|
|||
}tImageSource;
|
||||
|
||||
#if CC_USE_PNG
|
||||
void pngWriteCallback(png_structp png_ptr, png_bytep data, size_t length)
|
||||
{
|
||||
if (png_ptr == NULL)
|
||||
return;
|
||||
|
||||
FileStream* fileStream = (FileStream*)png_get_io_ptr(png_ptr);
|
||||
|
||||
const auto check = fileStream->write(data, length);
|
||||
|
||||
if (check != length)
|
||||
png_error(png_ptr, "Write Error");
|
||||
}
|
||||
|
||||
static void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
tImageSource* isource = (tImageSource*)png_get_io_ptr(png_ptr);
|
||||
|
@ -2161,36 +2174,38 @@ bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB)
|
|||
bool ret = false;
|
||||
do
|
||||
{
|
||||
FILE *fp;
|
||||
png_structp png_ptr;
|
||||
png_infop info_ptr;
|
||||
png_bytep *row_pointers;
|
||||
|
||||
auto* outStream = FileUtils::getInstance()->openFileStream(filePath, FileStream::Mode::WRITE);
|
||||
|
||||
fp = fopen(filePath.c_str(), "wb");
|
||||
CC_BREAK_IF(nullptr == fp);
|
||||
CC_BREAK_IF(nullptr == outStream);
|
||||
|
||||
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
|
||||
if (nullptr == png_ptr)
|
||||
{
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
break;
|
||||
}
|
||||
|
||||
info_ptr = png_create_info_struct(png_ptr);
|
||||
if (nullptr == info_ptr)
|
||||
{
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
png_destroy_write_struct(&png_ptr, nullptr);
|
||||
break;
|
||||
}
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
break;
|
||||
}
|
||||
png_init_io(png_ptr, fp);
|
||||
|
||||
//png_init_io(png_ptr, outStream);
|
||||
png_set_write_fn(png_ptr, outStream, pngWriteCallback, nullptr);
|
||||
|
||||
if (!isToRGB && hasAlpha())
|
||||
{
|
||||
|
@ -2210,7 +2225,7 @@ bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB)
|
|||
row_pointers = (png_bytep *)malloc(_height * sizeof(png_bytep));
|
||||
if(row_pointers == nullptr)
|
||||
{
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
break;
|
||||
}
|
||||
|
@ -2234,7 +2249,7 @@ bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB)
|
|||
uint8_t *tempData = static_cast<uint8_t*>(malloc(_width * _height * 3));
|
||||
if (nullptr == tempData)
|
||||
{
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
free(row_pointers);
|
||||
|
@ -2285,7 +2300,7 @@ bool Image::saveImageToPNG(const std::string& filePath, bool isToRGB)
|
|||
|
||||
png_destroy_write_struct(&png_ptr, &info_ptr);
|
||||
|
||||
fclose(fp);
|
||||
delete outStream;
|
||||
|
||||
ret = true;
|
||||
} while (0);
|
||||
|
@ -2304,7 +2319,7 @@ bool Image::saveImageToJPG(const std::string& filePath)
|
|||
{
|
||||
struct jpeg_compress_struct cinfo;
|
||||
struct jpeg_error_mgr jerr;
|
||||
FILE * outfile; /* target file */
|
||||
FileStream * outfile; /* target file */
|
||||
JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */
|
||||
int row_stride; /* physical row width in image buffer */
|
||||
|
||||
|
@ -2312,9 +2327,12 @@ bool Image::saveImageToJPG(const std::string& filePath)
|
|||
/* Now we can initialize the JPEG compression object. */
|
||||
jpeg_create_compress(&cinfo);
|
||||
|
||||
CC_BREAK_IF((outfile = fopen(filePath.c_str(), "wb")) == nullptr);
|
||||
|
||||
jpeg_stdio_dest(&cinfo, outfile);
|
||||
outfile = FileUtils::getInstance()->openFileStream(filePath, FileStream::Mode::WRITE);
|
||||
CC_BREAK_IF(nullptr == outfile);
|
||||
|
||||
unsigned char* outputBuffer = nullptr;
|
||||
unsigned long outputSize = 0;
|
||||
jpeg_mem_dest(&cinfo, &outputBuffer, &outputSize);
|
||||
|
||||
cinfo.image_width = _width; /* image width and height, in pixels */
|
||||
cinfo.image_height = _height;
|
||||
|
@ -2335,7 +2353,14 @@ bool Image::saveImageToJPG(const std::string& filePath)
|
|||
{
|
||||
jpeg_finish_compress(&cinfo);
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
fclose(outfile);
|
||||
|
||||
delete outfile;
|
||||
outfile = nullptr;
|
||||
if (outputBuffer)
|
||||
{
|
||||
free(outputBuffer);
|
||||
outputBuffer = nullptr;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2370,7 +2395,16 @@ bool Image::saveImageToJPG(const std::string& filePath)
|
|||
}
|
||||
|
||||
jpeg_finish_compress(&cinfo);
|
||||
fclose(outfile);
|
||||
|
||||
outfile->write(outputBuffer, outputSize);
|
||||
delete outfile; // closes FileStream automatically
|
||||
outfile = nullptr;
|
||||
if (outputBuffer)
|
||||
{
|
||||
free(outputBuffer);
|
||||
outputBuffer = nullptr;
|
||||
}
|
||||
|
||||
jpeg_destroy_compress(&cinfo);
|
||||
|
||||
ret = true;
|
||||
|
|
|
@ -0,0 +1,188 @@
|
|||
// Copyright (c) 2018-2019 HALX99.
|
||||
// Copyright (c) 2020 c4games.com
|
||||
#include "platform/CCPosixFileStream.h"
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#include "base/ZipUtils.h"
|
||||
#endif
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
struct PXIoF {
|
||||
int(*read)(PXFileHandle& handle, void*, unsigned int);
|
||||
long(*seek)(PXFileHandle& handle, long, int);
|
||||
int(*close)(PXFileHandle& handle);
|
||||
};
|
||||
|
||||
static int pfs_posix_open(const std::string& path, FileStream::Mode mode, PXFileHandle& handle)
|
||||
{
|
||||
switch (mode) {
|
||||
case FileStream::Mode::READ:
|
||||
handle._fd = posix_open(path.c_str(), O_READ_FLAGS);
|
||||
break;
|
||||
case FileStream::Mode::WRITE:
|
||||
handle._fd = posix_open(path.c_str(), O_WRITE_FLAGS);
|
||||
break;
|
||||
case FileStream::Mode::APPEND:
|
||||
handle._fd = posix_open(path.c_str(), O_APPEND_FLAGS);
|
||||
break;
|
||||
default:
|
||||
handle._fd = -1;
|
||||
}
|
||||
return handle._fd;
|
||||
}
|
||||
|
||||
// posix standard wrappers
|
||||
static int pfs_posix_read(PXFileHandle& handle, void* buf, unsigned int size) { return static_cast<int>(posix_read(handle._fd, buf, size)); }
|
||||
static long pfs_posix_seek(PXFileHandle& handle, long offst, int origin) { return posix_lseek(handle._fd, offst, origin); }
|
||||
static int pfs_posix_close(PXFileHandle& handle) {
|
||||
int fd = handle._fd;
|
||||
if (fd != -1) {
|
||||
handle._fd = -1;
|
||||
return posix_close(fd);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_posix_iof = {
|
||||
pfs_posix_read,
|
||||
pfs_posix_seek,
|
||||
pfs_posix_close
|
||||
};
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
// android AssetManager wrappers
|
||||
static int pfs_asset_read(PXFileHandle& handle, void* buf, unsigned int size) { return AAsset_read(handle._asset, buf, size); }
|
||||
static long pfs_asset_seek(PXFileHandle& handle, long offst, int origin) { return AAsset_seek(handle._asset, offst, origin); }
|
||||
static int pfs_asset_close(PXFileHandle& handle) {
|
||||
if (handle._asset != nullptr) {
|
||||
AAsset_close(handle._asset);
|
||||
handle._asset = nullptr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_asset_iof = {
|
||||
pfs_asset_read,
|
||||
pfs_asset_seek,
|
||||
pfs_asset_close
|
||||
};
|
||||
|
||||
// android obb
|
||||
static int pfs_obb_read(PXFileHandle& handle, void* buf, unsigned int size) { return FileUtilsAndroid::getObbFile()->zfread(&handle._zfs, buf, size); }
|
||||
static long pfs_obb_seek(PXFileHandle& handle, long offset, int origin) { return FileUtilsAndroid::getObbFile()->zfseek(&handle._zfs, offset, origin); }
|
||||
static int pfs_obb_close(PXFileHandle& handle) {
|
||||
FileUtilsAndroid::getObbFile()->zfclose(&handle._zfs);
|
||||
return 0;
|
||||
}
|
||||
static PXIoF pfs_obb_iof = {
|
||||
pfs_obb_read,
|
||||
pfs_obb_seek,
|
||||
pfs_obb_close
|
||||
};
|
||||
#endif
|
||||
|
||||
PosixFileStream::~PosixFileStream()
|
||||
{
|
||||
internalClose();
|
||||
}
|
||||
|
||||
bool PosixFileStream::open(const std::string& path, FileStream::Mode mode)
|
||||
{
|
||||
bool ok = false;
|
||||
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
|
||||
ok = pfs_posix_open(path, mode, _handle) != -1;
|
||||
#else // Android
|
||||
if (path[0] != '/') { // from package, always readonly
|
||||
std::string relativePath;
|
||||
size_t position = path.find("assets/");
|
||||
if (0 == position)
|
||||
{
|
||||
// "assets/" is at the beginning of the path and we don't want it
|
||||
relativePath = path.substr(sizeof("assets/") - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
relativePath = path;
|
||||
}
|
||||
|
||||
auto obb = FileUtilsAndroid::getObbFile();
|
||||
ok = obb != nullptr && obb->zfopen(relativePath, &_handle._zfs);
|
||||
if (ok) {
|
||||
this->_iof = &pfs_obb_iof;
|
||||
}
|
||||
else {
|
||||
AAssetManager* asMgr = FileUtilsAndroid::getAssetManager();
|
||||
AAsset* asset = AAssetManager_open(asMgr, relativePath.c_str(), AASSET_MODE_UNKNOWN);
|
||||
ok = !!asset;
|
||||
if (ok) {
|
||||
_handle._asset = asset;
|
||||
// setup file read/seek/close at here
|
||||
this->_iof = &pfs_asset_iof;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { // otherwise, as a absolutely path
|
||||
ok = pfs_posix_open(path, mode, _handle) != -1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (ok && !_iof)
|
||||
_iof = &pfs_posix_iof;
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
int PosixFileStream::internalClose()
|
||||
{
|
||||
if (_iof) {
|
||||
int ret = _iof->close(_handle);
|
||||
reset();
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int PosixFileStream::close()
|
||||
{
|
||||
return internalClose();
|
||||
}
|
||||
|
||||
int PosixFileStream::seek(long offset, int origin)
|
||||
{
|
||||
return static_cast<int>(_iof->seek(_handle, offset, origin));
|
||||
}
|
||||
|
||||
int PosixFileStream::read(void* buf, unsigned int size)
|
||||
{
|
||||
return _iof->read(_handle, buf, size);
|
||||
}
|
||||
|
||||
int PosixFileStream::write(const void* buf, unsigned int size)
|
||||
{
|
||||
return static_cast<int>(posix_write(_handle._fd, buf, size));
|
||||
}
|
||||
|
||||
int PosixFileStream::tell()
|
||||
{
|
||||
return static_cast<int>(_iof->seek(_handle, 0, SEEK_CUR));
|
||||
}
|
||||
|
||||
bool PosixFileStream::isOpen() const
|
||||
{
|
||||
#if CC_TARGET_PLATFORM != CC_PLATFORM_ANDROID
|
||||
return _handle._fd != -1;
|
||||
#else
|
||||
return _handle._fd != -1 && _handle._asset != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
void PosixFileStream::reset()
|
||||
{
|
||||
memset(&_handle, 0, sizeof(_handle));
|
||||
_handle._fd = -1;
|
||||
_iof = nullptr;
|
||||
}
|
||||
|
||||
NS_CC_END
|
|
@ -0,0 +1,125 @@
|
|||
// Copyright (c) 2018-2019 HALX99
|
||||
// Copyright (c) 2020 c4games.com
|
||||
#pragma once
|
||||
|
||||
#include "platform/CCFileStream.h"
|
||||
#include "platform/CCPlatformConfig.h"
|
||||
#include <string>
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_WIN32
|
||||
#include <io.h>
|
||||
#include <direct.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <functional>
|
||||
|
||||
#include "platform/CCPlatformMacros.h"
|
||||
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
#include "platform/android/CCFileUtils-android.h"
|
||||
#include <jni.h>
|
||||
#include <android/asset_manager.h>
|
||||
#include <android/asset_manager_jni.h>
|
||||
#include "base/ZipUtils.h"
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#define O_READ_FLAGS O_BINARY | O_RDONLY, S_IREAD
|
||||
#define O_WRITE_FLAGS O_CREAT | O_RDWR | O_BINARY | O_TRUNC, S_IWRITE | S_IREAD
|
||||
#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD
|
||||
|
||||
#define O_OVERLAP_FLAGS O_CREAT | O_RDWR | O_BINARY, S_IWRITE | S_IREAD
|
||||
|
||||
#define posix_open ::_open
|
||||
#define posix_close ::_close
|
||||
#define posix_lseek ::_lseek
|
||||
#define posix_read ::_read
|
||||
#define posix_write ::_write
|
||||
#define posix_fd2fh(fd) reinterpret_cast<HANDLE>(_get_osfhandle(fd))
|
||||
#define posix_fsetsize(fd, size) ::_chsize(fd, size)
|
||||
#else
|
||||
#define O_READ_FLAGS O_RDONLY, S_IRUSR
|
||||
#define O_WRITE_FLAGS O_CREAT | O_RDWR | O_TRUNC, S_IRWXU
|
||||
#define O_APPEND_FLAGS O_APPEND | O_CREAT | O_RDWR, S_IRWXU
|
||||
|
||||
#define O_OVERLAP_FLAGS O_CREAT | O_RDWR, S_IRWXU
|
||||
|
||||
#define posix_open ::open
|
||||
#define posix_close ::close
|
||||
#define posix_lseek ::lseek
|
||||
#define posix_read ::read
|
||||
#define posix_write ::write
|
||||
#define posix_fd2fh(fd) (fd)
|
||||
#define posix_fsetsize(fd, size) ::ftruncate(fd, size); ::lseek(fd, 0, SEEK_SET)
|
||||
#endif
|
||||
|
||||
NS_CC_BEGIN
|
||||
|
||||
struct UnzFileStream;
|
||||
union PXFileHandle {
|
||||
int _fd = -1;
|
||||
#if CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
|
||||
AAsset* _asset;
|
||||
ZipFileStream _zfs;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct PXIoF;
|
||||
|
||||
class CC_DLL PosixFileStream : public FileStream
|
||||
{
|
||||
public:
|
||||
PosixFileStream() = default;
|
||||
virtual ~PosixFileStream();
|
||||
|
||||
PosixFileStream(const PosixFileStream& other) = delete;
|
||||
|
||||
PosixFileStream(PosixFileStream&& other) noexcept
|
||||
: FileStream(std::move(other)),
|
||||
_handle(std::move(other._handle)),
|
||||
_iof(other._iof)
|
||||
{
|
||||
other.reset();
|
||||
}
|
||||
|
||||
PosixFileStream& operator=(const PosixFileStream& other) = delete;
|
||||
|
||||
PosixFileStream& operator=(PosixFileStream&& other) noexcept
|
||||
{
|
||||
if (this == &other)
|
||||
return *this;
|
||||
FileStream::operator =(std::move(other));
|
||||
_handle = std::move(other._handle);
|
||||
_iof = other._iof;
|
||||
|
||||
other.reset();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
enum class Mode {
|
||||
READ,
|
||||
WRITE,
|
||||
APPEND,
|
||||
};
|
||||
|
||||
bool open(const std::string& path, FileStream::Mode mode) override;
|
||||
int close() override;
|
||||
|
||||
int seek(long offset, int origin) override;
|
||||
int read(void* buf, unsigned int size) override;
|
||||
int write(const void* buf, unsigned int size) override;
|
||||
int tell() override;
|
||||
bool isOpen() const override;
|
||||
|
||||
private:
|
||||
int internalClose();
|
||||
void reset();
|
||||
|
||||
PXFileHandle _handle;
|
||||
const PXIoF* _iof;
|
||||
};
|
||||
|
||||
NS_CC_END
|
|
@ -160,6 +160,7 @@ set(COCOS_PLATFORM_HEADER
|
|||
platform/CCSAXParser.h
|
||||
platform/CCStdC.h
|
||||
platform/CCFileStream.h
|
||||
platform/CCPosixFileStream.h
|
||||
)
|
||||
|
||||
set(COCOS_PLATFORM_SRC
|
||||
|
@ -169,4 +170,5 @@ set(COCOS_PLATFORM_SRC
|
|||
platform/CCFileUtils.cpp
|
||||
platform/CCImage.cpp
|
||||
platform/CCFileStream.cpp
|
||||
platform/CCPosixFileStream.cpp
|
||||
)
|
||||
|
|
|
@ -388,13 +388,18 @@ FileUtils::Status FileUtilsAndroid::getContents(const std::string& filename, Res
|
|||
}
|
||||
|
||||
std::string FileUtilsAndroid::getWritablePath() const
|
||||
{
|
||||
return getNativeWritableAbsolutePath();
|
||||
}
|
||||
|
||||
std::string FileUtilsAndroid::getNativeWritableAbsolutePath() const
|
||||
{
|
||||
// Fix for Nexus 10 (Android 4.2 multi-user environment)
|
||||
// the path is retrieved through Java Context.getCacheDir() method
|
||||
std::string path = JniHelper::callStaticStringMethod("org.cocos2dx.lib.Cocos2dxHelper", "getCocos2dxWritablePath");
|
||||
if (!path.empty())
|
||||
path.append("/");
|
||||
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ public:
|
|||
virtual FileUtils::Status getContents(const std::string& filename, ResizableBuffer* buffer) const override;
|
||||
|
||||
virtual std::string getWritablePath() const override;
|
||||
std::string getNativeWritableAbsolutePath() const override;
|
||||
virtual bool isAbsolutePath(const std::string& strPath) const override;
|
||||
|
||||
virtual int64_t getFileSize(const std::string& filepath) const override;
|
||||
|
|
|
@ -50,6 +50,7 @@ public:
|
|||
virtual ~FileUtilsApple();
|
||||
/* override functions */
|
||||
virtual std::string getWritablePath() const override;
|
||||
virtual std::string getNativeWritableAbsolutePath() const override;
|
||||
virtual std::string getFullPathForFilenameWithinDirectory(const std::string& directory, const std::string& filename) const override;
|
||||
|
||||
#if CC_FILEUTILS_APPLE_ENABLE_OBJC
|
||||
|
|
|
@ -84,6 +84,12 @@ FileUtils* FileUtils::getInstance()
|
|||
|
||||
|
||||
std::string FileUtilsApple::getWritablePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
return getNativeWritableAbsolutePath();
|
||||
}
|
||||
|
||||
std::string FileUtilsApple::getNativeWritableAbsolutePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
if (_writablePath.length())
|
||||
|
|
|
@ -94,6 +94,12 @@ bool FileUtilsLinux::init()
|
|||
}
|
||||
|
||||
string FileUtilsLinux::getWritablePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
return getNativeWritableAbsolutePath();
|
||||
}
|
||||
|
||||
std::string FileUtilsLinux::getNativeWritableAbsolutePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
struct stat st;
|
||||
|
|
|
@ -50,6 +50,8 @@ public:
|
|||
/* override functions */
|
||||
bool init() override;
|
||||
virtual std::string getWritablePath() const override;
|
||||
std::string getNativeWritableAbsolutePath() const override;
|
||||
|
||||
private:
|
||||
virtual bool isFileExistInternal(const std::string& strFilePath) const override;
|
||||
};
|
||||
|
|
|
@ -299,6 +299,12 @@ std::vector<std::string> FileUtilsWin32::listFiles(const std::string& dirPath) c
|
|||
}
|
||||
|
||||
string FileUtilsWin32::getWritablePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
return getNativeWritableAbsolutePath();
|
||||
}
|
||||
|
||||
std::string FileUtilsWin32::getNativeWritableAbsolutePath() const
|
||||
{
|
||||
DECLARE_GUARD;
|
||||
if (_writablePath.length())
|
||||
|
@ -313,9 +319,9 @@ string FileUtilsWin32::getWritablePath() const
|
|||
// Debug app uses executable directory; Non-debug app uses local app data directory
|
||||
//#ifndef _DEBUG
|
||||
// Get filename of executable only, e.g. MyGame.exe
|
||||
WCHAR *base_name = wcsrchr(full_path, '\\');
|
||||
WCHAR* base_name = wcsrchr(full_path, '\\');
|
||||
wstring retPath;
|
||||
if(base_name)
|
||||
if (base_name)
|
||||
{
|
||||
WCHAR app_data_path[CC_MAX_PATH + 1];
|
||||
|
||||
|
|
|
@ -46,8 +46,9 @@ protected:
|
|||
FileUtilsWin32();
|
||||
public:
|
||||
/* override functions */
|
||||
bool init();
|
||||
bool init() override;
|
||||
virtual std::string getWritablePath() const override;
|
||||
virtual std::string getNativeWritableAbsolutePath() const override;
|
||||
virtual bool isAbsolutePath(const std::string& strPath) const override;
|
||||
protected:
|
||||
|
||||
|
|
Loading…
Reference in New Issue