Merge pull request #342 from rh101/vfs-support

Ensure FileStream is used for file access where possible
This commit is contained in:
HALX99 2021-04-25 18:55:10 -07:00 committed by GitHub
commit 5664291631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 353 additions and 75 deletions

View File

@ -183,7 +183,8 @@ bool FontFreeType::createFontObject(const std::string &fontName, float fontSize)
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_END);
fts->size = fs->tell();
fs->seek(0, SEEK_SET);
fts->descriptor.pointer = fs;

View File

@ -68,7 +68,7 @@ protected:
AudioDecoderOgg();
~AudioDecoderOgg();
FileStream* _fileStream;
FileStream* _fileStream = nullptr;
OggVorbis_File _vf;
friend class AudioDecoderManager;

View File

@ -61,7 +61,7 @@ namespace cocos2d {
static int minimp3_seek_r(uint64_t position, void* user_data)
{
return ((FileStream*)user_data)->seek(position, SEEK_SET) >= 0 ? 0 : -1;
return ((FileStream*)user_data)->seek(position, SEEK_SET) < 0 ? -1 : 0;
}
#else
static bool __mp3Inited = false;

View File

@ -44,8 +44,7 @@ namespace cocos2d {
static int ov_fseek_r(void * handle, ogg_int64_t offset, int whence)
{
auto n = ((FileStream*)handle)->seek(offset, whence);
return n >= 0 ? 0 : -1;
return ((FileStream*)handle)->seek(offset, whence) < 0 ? -1 : 0;
}
static long ov_ftell_r(void * handle)

View File

@ -141,7 +141,7 @@ namespace cocos2d {
ALOGW("The wav format %d doesn't supported currently!", (int)fmtInfo.AudioFormat);
fileStream->close();
assert(false);
return false;;
return false;
}
return wav_scan_chunk(wavf, WAV_DATA_ID, &h->PcmData, nullptr, 0);
@ -154,7 +154,8 @@ namespace cocos2d {
static int wav_seek(WAV_FILE* wavf, int offset)
{
auto newOffset = wavf->Stream->seek(wavf->PcmDataOffset + offset, SEEK_SET);
wavf->Stream->seek(wavf->PcmDataOffset + offset, SEEK_SET);
const auto newOffset = wavf->Stream->tell();
return newOffset >= wavf->PcmDataOffset ? newOffset - wavf->PcmDataOffset : -1;
}

View File

@ -1491,8 +1491,8 @@ void Console::commandUpload(int fd)
static std::string writablePath = FileUtils::getInstance()->getWritablePath();
std::string filepath = writablePath + std::string(buf);
FILE* fp = fopen(filepath.c_str(), "wb");
if(!fp)
auto* fs = FileUtils::getInstance()->openFileStream(filepath, FileStream::Mode::WRITE);
if(!fs)
{
const char err[] = "can't create file!\n";
Console::Utility::sendToConsole(fd, err, strlen(err));
@ -1517,11 +1517,12 @@ void Console::commandUpload(int fd)
int dt = base64Decode(in, 4, &decode);
if (dt > 0)
{
fwrite(decode, dt, 1, fp);
fs->write(decode, dt);
}
free(decode);
}
fclose(fp);
fs->close();
delete fs;
}
void Console::commandVersion(int fd, const std::string& /*args*/)

View File

@ -154,7 +154,8 @@ public:
_checksumFileName = filename + ".chksum";
_fsMd5 = FileUtils::getInstance()->openFileStream(_checksumFileName, FileStream::Mode::WRITE);
if (_fsMd5->seek(0, SEEK_END) != sizeof(md5_state_s)) {
_fsMd5->seek(0, SEEK_END);
if (_fsMd5->tell() != sizeof(md5_state_s)) {
md5_init(&_md5State);
} else {
_fsMd5->seek(0, SEEK_SET);
@ -819,10 +820,10 @@ void DownloaderCURL::_onDownloadFinished(TaskWrapper&& wrapper, int checkState)
if (checkState & kCheckSumStateSucceed) // No need download
{
FileStream* fsOrigin =
FileUtils::getInstance()->openFileStream(coTask._fileName, FileStream::Mode::READ);
auto* fsOrigin = pFileUtils->openFileStream(coTask._fileName, FileStream::Mode::READ);
if (fsOrigin) {
task.progressInfo.totalBytesExpected = fsOrigin->seek(0, SEEK_END);
fsOrigin->seek(0, SEEK_END);
task.progressInfo.totalBytesExpected = fsOrigin->tell();
task.progressInfo.bytesReceived = task.progressInfo.totalBytesExpected;
task.progressInfo.totalBytesReceived = task.progressInfo.totalBytesExpected;
task.progressInfo.speedInBytes = task.progressInfo.totalBytesExpected;

View File

@ -409,7 +409,7 @@ void HttpClient::enableCookies(const char* cookieFile)
}
else
{
_cookieFilename = (FileUtils::getInstance()->getWritablePath() + "cookieFile.txt");
_cookieFilename = (FileUtils::getInstance()->getNativeWritableAbsolutePath() + "cookieFile.txt");
}
}

View File

@ -497,20 +497,17 @@ void FileUtils::writeDataToFile(Data data, const std::string& fullPath, std::fun
bool FileUtils::writeBinaryToFile(const void* data, size_t dataSize, const std::string& fullPath)
{
const char* mode = "wb";
CCASSERT(!fullPath.empty() && dataSize > 0, "Invalid parameters.");
auto fileutils = FileUtils::getInstance();
auto* fileUtils = FileUtils::getInstance();
do
{
auto* fileStream = fileUtils->openFileStream(fullPath, FileStream::Mode::WRITE);
// Read the file from hardware
FILE* fp = fopen(fullPath.c_str(), mode);
CC_BREAK_IF(!fp);
fwrite(data, dataSize, 1, fp);
fclose(fp);
CC_BREAK_IF(!fileStream);
fileStream->write(data, dataSize);
delete fileStream;
return true;
} while (0);
@ -571,40 +568,51 @@ FileUtils::Status FileUtils::getContents(const std::string& filename, ResizableB
if (filename.empty())
return Status::NotExists;
auto fs = FileUtils::getInstance();
auto fileUtils = FileUtils::getInstance();
std::string fullPath = fs->fullPathForFilename(filename);
if (fullPath.empty())
return Status::NotExists;
const auto fullPath = fileUtils->fullPathForFilename(filename);
FILE *fp = fopen(fullPath.c_str(), "rb");
if (!fp)
auto* fileStream = fileUtils->openFileStream(fullPath, FileStream::Mode::READ);
if (!fileStream)
return Status::OpenFailed;
struct AutoFileHandle {
void operator()(FILE* fp) {
fclose(fp);
}
};
std::unique_ptr<FILE, AutoFileHandle> autohandle(fp);
if (fileStream->seek(0, SEEK_END) != 0)
{
delete fileStream;
return Status::ObtainSizeFailed;
}
struct stat statBuf;
if (fstat(fileno(fp), &statBuf) == -1)
return Status::ReadFailed;
const auto size = fileStream->tell();
if (size == 0)
{
delete fileStream;
return Status::OK;
}
if (!(statBuf.st_mode & S_IFREG))
return Status::NotRegularFileType;
if (size < 0)
{
delete fileStream;
return Status::ObtainSizeFailed;
}
size_t size = statBuf.st_size;
if (size > ULONG_MAX)
{
delete fileStream;
return Status::TooLarge;
}
buffer->resize(size);
size_t readsize = fread(buffer->buffer(), 1, statBuf.st_size, fp);
if (readsize < size) {
buffer->resize(readsize);
fileStream->seek(0, SEEK_SET);
const auto sizeRead = fileStream->read(buffer->buffer(), size);
if (sizeRead < size) {
buffer->resize(sizeRead);
delete fileStream;
return Status::ReadFailed;
}
delete fileStream;
return Status::OK;
}

View File

@ -151,7 +151,8 @@ int PosixFileStream::close()
int PosixFileStream::seek(long offset, int origin)
{
return static_cast<int>(_iof->seek(_handle, offset, origin));
const auto result = _iof->seek(_handle, offset, origin); // this returns -1 for error, and resulting offset on success
return result < 0 ? -1 : 0; // return 0 for success
}
int PosixFileStream::read(void* buf, unsigned int size)

View File

@ -345,11 +345,10 @@ public:
std::string lowerCasePath = fontPath;
std::transform(lowerCasePath.begin(), lowerCasePath.end(), lowerCasePath.begin(), ::tolower);
if ( lowerCasePath.find(".ttf") != std::string::npos ) {
fontPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fontPath.c_str());
FILE *f = fopen(fontPath.c_str(), "r");
if ( f ) {
fclose(f);
fontPath = cocos2d::FileUtils::getInstance()->fullPathForFilename(fontPath);
auto* fileStream = cocos2d::FileUtils::getInstance()->openFileStream(fontPath, FileStream::Mode::READ);
if ( fileStream ) {
delete fileStream;
fontCache.insert(std::pair<std::string, std::string>(family_name, fontPath));
return fontPath;
}

View File

@ -50,6 +50,116 @@ using namespace cocos2d::network;
#define BUFFER_SIZE 8192
#define MAX_FILENAME 512
class AssetManagerZipFileInfo
{
public:
std::string zipFileName{};
};
// unzip overrides to support FileStream
long AssetManager_tell_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->tell();
}
long AssetManager_seek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->seek((long)offset, origin); // must return 0 for success or -1 for error
}
voidpf AssetManager_open_file_func(voidpf opaque, const char* filename, int mode)
{
FileStream::Mode fsMode;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
fsMode = FileStream::Mode::READ;
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
fsMode = FileStream::Mode::APPEND;
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
fsMode = FileStream::Mode::WRITE;
else
return nullptr;
return FileUtils::getInstance()->openFileStream(filename, fsMode);
}
voidpf AssetManager_opendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
{
if (stream == nullptr)
return nullptr;
const auto zipFileInfo = static_cast<AssetManagerZipFileInfo*>(opaque);
std::string diskFilename = zipFileInfo->zipFileName;
const auto pos = diskFilename.rfind('.', std::string::npos);
if (pos != std::string::npos && pos != 0)
{
const size_t bufferSize = 5;
char extensionBuffer[bufferSize];
snprintf(&extensionBuffer[0], bufferSize, ".z%02u", number_disk + 1);
diskFilename.replace(pos, std::min((size_t)4, zipFileInfo->zipFileName.size() - pos), extensionBuffer);
return AssetManager_open_file_func(opaque, diskFilename.c_str(), mode);
}
return nullptr;
}
uint32_t AssetManager_read_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
{
if (stream == nullptr)
return (uint32_t)-1;
auto* fs = (FileStream*)stream;
return fs->read(buf, size);
}
uint32_t AssetManager_write_file_func(voidpf opaque, voidpf stream, const void* buf, uint32_t size)
{
if (stream == nullptr)
return (uint32_t)-1;
auto* fs = (FileStream*)stream;
return fs->write(buf, size);
}
int AssetManager_close_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->close(); // 0 for success, -1 for error
}
// THis isn't supported by FileStream, so just check if the stream is null and open
int AssetManager_error_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
{
return -1;
}
auto* fs = (FileStream*)stream;
if (fs->isOpen())
{
return 0;
}
return -1;
}
// End of Overrides
// Implementation of AssetsManager
AssetsManager::AssetsManager(const char* packageUrl/* =nullptr */, const char* versionFileUrl/* =nullptr */, const char* storagePath/* =nullptr */)
@ -259,7 +369,17 @@ bool AssetsManager::uncompress()
{
// Open the zip file
string outFileName = _storagePath + TEMP_PACKAGE_FILE_NAME;
unzFile zipfile = unzOpen(outFileName.c_str());
zlib_filefunc_def zipFunctionOverrides;
fillZipFunctionOverrides(zipFunctionOverrides);
AssetManagerZipFileInfo zipFileInfo;
zipFileInfo.zipFileName = outFileName;
zipFunctionOverrides.opaque = &zipFileInfo;
// Open the zip file
unzFile zipfile = unzOpen2(outFileName.c_str(), &zipFunctionOverrides);
if (! zipfile)
{
CCLOG("can not open downloaded zip file %s", outFileName.c_str());
@ -330,10 +450,9 @@ bool AssetsManager::uncompress()
while(index != std::string::npos)
{
const string dir=_storagePath+fileNameStr.substr(0,index);
FILE *out = fopen(dir.c_str(), "r");
if(!out)
auto* fsOut = FileUtils::getInstance()->openFileStream(dir, FileStream::Mode::READ);
if (!fsOut)
{
if (!FileUtils::getInstance()->createDirectory(dir))
{
@ -348,13 +467,12 @@ bool AssetsManager::uncompress()
}
else
{
fclose(out);
delete fsOut;
}
startIndex=index+1;
index=fileNameStr.find('/',startIndex);
}
// Entry is a file, so extract it.
@ -368,8 +486,8 @@ bool AssetsManager::uncompress()
}
// Create a file to store current file.
FILE *out = fopen(fullPath.c_str(), "wb");
if (! out)
auto* fsOut = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::WRITE);
if (!fsOut)
{
CCLOG("can not open destination file %s", fullPath.c_str());
unzCloseCurrentFile(zipfile);
@ -387,16 +505,17 @@ bool AssetsManager::uncompress()
CCLOG("can not read zip file %s, error code is %d", fileName, error);
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
delete fsOut;
return false;
}
if (error > 0)
{
fwrite(readBuffer, error, 1, out);
fsOut->write(readBuffer, error);
}
} while(error > 0);
fclose(out);
delete fsOut;
}
unzCloseCurrentFile(zipfile);
@ -510,4 +629,17 @@ AssetsManager* AssetsManager::create(const char* packageUrl, const char* version
return manager;
}
void AssetsManager::fillZipFunctionOverrides(zlib_filefunc_def& zipFunctionOverrides)
{
zipFunctionOverrides.zopen_file = AssetManager_open_file_func;
zipFunctionOverrides.zopendisk_file = AssetManager_opendisk_file_func;
zipFunctionOverrides.zread_file = AssetManager_read_file_func;
zipFunctionOverrides.zwrite_file = AssetManager_write_file_func;
zipFunctionOverrides.ztell_file = AssetManager_tell_file_func;
zipFunctionOverrides.zseek_file = AssetManager_seek_file_func;
zipFunctionOverrides.zclose_file = AssetManager_close_file_func;
zipFunctionOverrides.zerror_file = AssetManager_error_file_func;
zipFunctionOverrides.opaque = nullptr;
}
NS_CC_EXT_END

View File

@ -26,6 +26,7 @@
#ifndef __AssetsManager__
#define __AssetsManager__
#include <ioapi.h>
#include <string>
#include <mutex>
@ -169,6 +170,7 @@ protected:
bool uncompress();
void setSearchPath();
void downloadAndUncompress();
void fillZipFunctionOverrides(zlib_filefunc_def& zipFunctionOverrides);
private:
//! The path to store downloaded resources.

View File

@ -53,6 +53,116 @@ NS_CC_EXT_BEGIN
const std::string AssetsManagerEx::VERSION_ID = "@version";
const std::string AssetsManagerEx::MANIFEST_ID = "@manifest";
class AssetManagerExZipFileInfo
{
public:
std::string zipFileName{};
};
// unzip overrides to support FileStream
long AssetManagerEx_tell_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->tell();
}
long AssetManagerEx_seek_file_func(voidpf opaque, voidpf stream, uint32_t offset, int origin)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->seek((long)offset, origin); // must return 0 for success or -1 for error
}
voidpf AssetManagerEx_open_file_func(voidpf opaque, const char* filename, int mode)
{
FileStream::Mode fsMode;
if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER) == ZLIB_FILEFUNC_MODE_READ)
fsMode = FileStream::Mode::READ;
else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
fsMode = FileStream::Mode::APPEND;
else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
fsMode = FileStream::Mode::WRITE;
else
return nullptr;
return FileUtils::getInstance()->openFileStream(filename, fsMode);
}
voidpf AssetManagerEx_opendisk_file_func(voidpf opaque, voidpf stream, uint32_t number_disk, int mode)
{
if (stream == nullptr)
return nullptr;
const auto zipFileInfo = static_cast<AssetManagerExZipFileInfo*>(opaque);
std::string diskFilename = zipFileInfo->zipFileName;
const auto pos = diskFilename.rfind('.', std::string::npos);
if (pos != std::string::npos && pos != 0)
{
const size_t bufferSize = 5;
char extensionBuffer[bufferSize];
snprintf(&extensionBuffer[0], bufferSize, ".z%02u", number_disk + 1);
diskFilename.replace(pos, std::min((size_t)4, zipFileInfo->zipFileName.size() - pos), extensionBuffer);
return AssetManagerEx_open_file_func(opaque, diskFilename.c_str(), mode);
}
return nullptr;
}
uint32_t AssetManagerEx_read_file_func(voidpf opaque, voidpf stream, void* buf, uint32_t size)
{
if (stream == nullptr)
return (uint32_t)-1;
auto* fs = (FileStream*)stream;
return fs->read(buf, size);
}
uint32_t AssetManagerEx_write_file_func(voidpf opaque, voidpf stream, const void* buf, uint32_t size)
{
if (stream == nullptr)
return (uint32_t)-1;
auto* fs = (FileStream*)stream;
return fs->write(buf, size);
}
int AssetManagerEx_close_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
return -1;
auto* fs = (FileStream*)stream;
return fs->close(); // 0 for success, -1 for error
}
// THis isn't supported by FileStream, so just check if the stream is null and open
int AssetManagerEx_error_file_func(voidpf opaque, voidpf stream)
{
if (stream == nullptr)
{
return -1;
}
auto* fs = (FileStream*)stream;
if (fs->isOpen())
{
return 0;
}
return -1;
}
// End of Overrides
// Implementation of AssetsManagerEx
AssetsManagerEx::AssetsManagerEx(const std::string& manifestUrl, const std::string& storagePath)
@ -314,9 +424,17 @@ bool AssetsManagerEx::decompress(const std::string &zip)
return false;
}
const std::string rootPath = zip.substr(0, pos+1);
zlib_filefunc_def zipFunctionOverrides;
fillZipFunctionOverrides(zipFunctionOverrides);
AssetManagerExZipFileInfo zipFileInfo;
zipFileInfo.zipFileName = zip;
zipFunctionOverrides.opaque = &zipFileInfo;
// Open the zip file
unzFile zipfile = unzOpen(zip.c_str());
unzFile zipfile = unzOpen2(zip.c_str(), &zipFunctionOverrides);
if (! zipfile)
{
CCLOG("AssetsManagerEx : can not open downloaded zip file %s\n", zip.c_str());
@ -392,8 +510,8 @@ bool AssetsManagerEx::decompress(const std::string &zip)
}
// Create a file to store current file.
FILE *out = fopen(fullPath.c_str(), "wb");
if (!out)
auto* fsOut = FileUtils::getInstance()->openFileStream(fullPath, FileStream::Mode::WRITE);
if (!fsOut)
{
CCLOG("AssetsManagerEx : can not create decompress destination file %s (errno: %d)\n", fullPath.c_str(), errno);
unzCloseCurrentFile(zipfile);
@ -409,7 +527,7 @@ bool AssetsManagerEx::decompress(const std::string &zip)
if (error < 0)
{
CCLOG("AssetsManagerEx : can not read zip file %s, error code is %d\n", fileName, error);
fclose(out);
delete fsOut;
unzCloseCurrentFile(zipfile);
unzClose(zipfile);
return false;
@ -417,11 +535,11 @@ bool AssetsManagerEx::decompress(const std::string &zip)
if (error > 0)
{
fwrite(readBuffer, error, 1, out);
fsOut->write(readBuffer, error);
}
} while(error > 0);
fclose(out);
delete fsOut;
}
unzCloseCurrentFile(zipfile);
@ -530,7 +648,7 @@ void AssetsManagerEx::downloadVersion()
{
_updateState = State::DOWNLOADING_VERSION;
// Download version file asynchronously
_downloader->createDownloadFileTask(versionUrl, _tempVersionPath, VERSION_ID);
_downloader->createDownloadFileTask(versionUrl, _tempVersionPath, "", VERSION_ID);
}
// No version file found
else
@ -598,7 +716,7 @@ void AssetsManagerEx::downloadManifest()
{
_updateState = State::DOWNLOADING_MANIFEST;
// Download version file asynchronously
_downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, MANIFEST_ID);
_downloader->createDownloadFileTask(manifestUrl, _tempManifestPath, "", MANIFEST_ID);
}
// No manifest file found
else
@ -1147,7 +1265,7 @@ void AssetsManagerEx::queueDowload()
_currConcurrentTask++;
DownloadUnit& unit = _downloadUnits[key];
_fileUtils->createDirectory(basename(unit.storagePath));
_downloader->createDownloadFileTask(unit.srcUrl, unit.storagePath, unit.customId);
_downloader->createDownloadFileTask(unit.srcUrl, unit.storagePath, "", unit.customId);
_tempManifest->setAssetDownloadState(key, Manifest::DownloadState::DOWNLOADING);
}
@ -1176,4 +1294,17 @@ void AssetsManagerEx::onDownloadUnitsFinished()
}
}
void AssetsManagerEx::fillZipFunctionOverrides(zlib_filefunc_def& zipFunctionOverrides)
{
zipFunctionOverrides.zopen_file = AssetManagerEx_open_file_func;
zipFunctionOverrides.zopendisk_file = AssetManagerEx_opendisk_file_func;
zipFunctionOverrides.zread_file = AssetManagerEx_read_file_func;
zipFunctionOverrides.zwrite_file = AssetManagerEx_write_file_func;
zipFunctionOverrides.ztell_file = AssetManagerEx_tell_file_func;
zipFunctionOverrides.zseek_file = AssetManagerEx_seek_file_func;
zipFunctionOverrides.zclose_file = AssetManagerEx_close_file_func;
zipFunctionOverrides.zerror_file = AssetManagerEx_error_file_func;
zipFunctionOverrides.opaque = nullptr;
}
NS_CC_EXT_END

View File

@ -26,6 +26,7 @@
#ifndef __AssetsManagerEx__
#define __AssetsManagerEx__
#include <ioapi.h>
#include <string>
#include <unordered_map>
#include <vector>
@ -219,7 +220,8 @@ private:
// Called when one DownloadUnits finished
void onDownloadUnitsFinished();
void fillZipFunctionOverrides(zlib_filefunc_def &zipFunctionOverrides);
//! The event of the current AssetsManagerEx in event dispatcher
std::string _eventName;
@ -263,7 +265,7 @@ private:
//! Remote manifest
Manifest *_remoteManifest = nullptr;
//! Whether user have requested to update
enum class UpdateEntry : char
{