ApkAssetCache now fully works. Unlike AssetCache, it does not build a cache by traversing the directory hierarchy - this is due to limits of how the Android assets archive works -, but rather adds to the cache on get/load requests. This is more inefficient, but it shouldn't be much of a consideration. Fixed preprocessor conditionals around loops to stop vi from exploding. Some minor code cleanup to remove warnings.
parent
977af72999
commit
6e0a0b3226
|
@ -11,6 +11,9 @@ Our basic Asset class. This class exists as a container for data, but does not d
|
|||
class Asset {
|
||||
friend class AssetManager;
|
||||
friend class AssetCache;
|
||||
#ifdef __ANDROID__
|
||||
friend class ApkAssetCache;
|
||||
#endif
|
||||
public:
|
||||
Asset();
|
||||
~Asset();
|
||||
|
@ -30,4 +33,4 @@ class Asset {
|
|||
char *data; // Our data, NULL if IS_LOADED is not set
|
||||
off_t data_length; // Our data's length, in bytes
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,6 @@ AssetCache::AssetCache(const char *cache_file) {
|
|||
}
|
||||
AssetCache::~AssetCache() {
|
||||
HashEntry<Asset*> *entry;
|
||||
int i = 0;
|
||||
while ((entry = assets->iterate()) != NULL) {
|
||||
Asset *asset = (Asset*)(entry->data);
|
||||
assets->del(asset->filename.c_str());
|
||||
|
@ -43,23 +42,25 @@ int AssetCache::fromFile(const char *cache_file) {
|
|||
}
|
||||
char fpath[1024];
|
||||
uint32_t fsum = 0;
|
||||
size_t fsize = 0;
|
||||
off_t fsize = 0;
|
||||
#ifdef _WIN32
|
||||
while ((ret = fscanf_s(file, "%s %u %u\n", fpath, 1024, &fsum, &fsize)) != EOF) {
|
||||
while ((ret = fscanf_s(file, "%s %u %jd\n", fpath, 1024, &fsum, (intmax_t*)&fsize)) != EOF)
|
||||
#else
|
||||
while ((ret = fscanf(file, "%s %u %u\n", fpath, &fsum, &fsize)) != EOF) {
|
||||
while ((ret = fscanf(file, "%s %u %jd\n", fpath, &fsum, (intmax_t*)&fsize)) != EOF)
|
||||
#endif
|
||||
{
|
||||
char fullpath[1024];
|
||||
snprintf(fullpath, 1024, "%s/%s", directory.c_str(), fpath);
|
||||
// only add the asset if it exists.
|
||||
#ifdef _WIN32
|
||||
DWORD file_attrib = GetFileAttributes(fullpath);
|
||||
if (file_attrib != INVALID_FILE_ATTRIBUTES) {
|
||||
if (file_attrib != INVALID_FILE_ATTRIBUTES)
|
||||
#else
|
||||
// NOTE: TOCTOU/race vulnerability exists here, but I don't think it matters.
|
||||
struct stat fstat;
|
||||
if (stat(fullpath, &fstat) == 0) {
|
||||
if (stat(fullpath, &fstat) == 0)
|
||||
#endif
|
||||
{
|
||||
Asset *asset = new Asset();
|
||||
asset->filename.assign(fpath);
|
||||
asset->flags &= ~Asset::IS_NULL;
|
||||
|
@ -105,7 +106,6 @@ int AssetCache::fromDir(const char *dir) {
|
|||
int AssetCache::traverseDir_r(const char *dir) {
|
||||
char full_dir[1024]; // "full" dir path, e.g, "<appdata>/data/models"
|
||||
snprintf(full_dir, 1024, "%s/%s", directory.c_str(), dir);
|
||||
size_t dir_len = strlen(dir)+1;
|
||||
#if _WIN32
|
||||
WIN32_FIND_DATA ffd;
|
||||
HANDLE h_find = INVALID_HANDLE_VALUE;
|
||||
|
@ -150,7 +150,6 @@ int AssetCache::traverseDir_r(const char *dir) {
|
|||
struct dirent **files;
|
||||
struct stat file_stat;
|
||||
int n, i;
|
||||
char udir[1024];
|
||||
char fpath[1024]; // "full" file path, e.g., "<appdir>/data/models/cube.obj"
|
||||
char lpath[1024]; // "local" file path, e.g., "data/models/cube.obj"
|
||||
Asset *asset;
|
||||
|
@ -218,10 +217,9 @@ int AssetCache::toFile(const char *cache_file) {
|
|||
return 1;
|
||||
}
|
||||
HashEntry<Asset*> *entry;
|
||||
int i = 0;
|
||||
while ((entry = assets->iterate()) != NULL) {
|
||||
Asset *asset = (Asset*)(entry->data);
|
||||
fprintf(file, "%s %u %u\n", asset->filename.c_str(), asset->data_checksum, asset->data_length);
|
||||
fprintf(file, "%s %u %jd\n", asset->filename.c_str(), asset->data_checksum, (intmax_t)asset->data_length);
|
||||
LOG(LOG_DEBUG) << ": saving " << asset->filename.c_str() << " bytes " << asset->data_length;
|
||||
}
|
||||
fclose(file);
|
||||
|
@ -278,3 +276,69 @@ This function attempts to create a new Asset using some provided data
|
|||
Asset* AssetCache::createAsset(const char *filename, const char *data, size_t data_len) {
|
||||
return NULL;
|
||||
}
|
||||
/* ================================================================
|
||||
ApkAssetCache
|
||||
----------------
|
||||
Android-only Extended class of AssetCache that accessed the APK's asset archive. Access is read-only.
|
||||
|
||||
Unlike the standard AssetCache, ApkAssetCache does not build a cache by traversing the asset directory hierarchy, but rather adds to the cache during get/load requests. This is due to, AFAIK, the lack of directory traversal in the AAsset_* functions. getNextFileName only steps through files, not directories - this is probably due to the files not existing in a directory structure, but rather in a special assets archive that has its own rules.
|
||||
|
||||
This is somewhat more inefficient, but it should not be much of a bottleneck.
|
||||
================================================================ */
|
||||
#ifdef __ANDROID__
|
||||
ApkAssetCache::ApkAssetCache(const char *cache_dir) {
|
||||
assets = new HashTable<Asset*>(128);
|
||||
assets->setnull(NULL);
|
||||
fromDir(cache_dir);
|
||||
}
|
||||
int ApkAssetCache::fromFile(const char *cache_file) { return 0; }
|
||||
int ApkAssetCache::fromDir(const char *cache_dir) {
|
||||
directory.assign(cache_dir);
|
||||
return 0;
|
||||
}
|
||||
int ApkAssetCache::traverseDir_r(const char *dir) { return 0; }
|
||||
// NOTE: since we cannot traverse the apk assets AFAIK, we just try to add it to the cache on getAsset. This somewhat inefficient, but it will have to do.
|
||||
Asset* ApkAssetCache::getAsset(const char *filename) {
|
||||
Asset *asset = assets->get(filename);
|
||||
// if asset doesn't exist, let's check the apk
|
||||
if (asset == NULL) {
|
||||
std::string fullpath = directory;
|
||||
if (directory.size() > 0) fullpath.append("/");
|
||||
fullpath.append(filename);
|
||||
AAsset* aasset = AAssetManager_open(android_asset_manager, fullpath.c_str(), 0);
|
||||
if (aasset != NULL) {
|
||||
asset = new Asset();
|
||||
asset->filename.assign(filename);
|
||||
asset->data_length = AAsset_getLength(aasset);
|
||||
asset->flags &= ~Asset::IS_NULL;
|
||||
assets->set(filename, asset);
|
||||
}
|
||||
AAsset_close(aasset);
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
Asset* ApkAssetCache::loadAsset(const char *filename) {
|
||||
Asset *asset = getAsset(filename);
|
||||
if (asset == NULL) return NULL;
|
||||
if (!(asset->flags & Asset::IS_LOADED)) {
|
||||
std::string fullpath = directory;
|
||||
if (directory.size() > 0) fullpath.append("/");
|
||||
fullpath.append(filename);
|
||||
AAsset *aasset = AAssetManager_open(android_asset_manager, fullpath.c_str(), 0);
|
||||
const void *aasset_buffer = AAsset_getBuffer(aasset);
|
||||
if (aasset_buffer != NULL) {
|
||||
off_t data_size = AAsset_getLength(aasset) * sizeof(char);
|
||||
asset->data = (char*)malloc(data_size);
|
||||
memcpy((asset->data), aasset_buffer, data_size);
|
||||
asset->flags |= Asset::IS_LOADED;
|
||||
if (asset->data_checksum == 0) {
|
||||
asset->data_checksum = crc32(1337, asset->data, asset->data_length);
|
||||
}
|
||||
} else {
|
||||
LOG(LOG_WARNING) << FUNC_NAME << ": Could not open AAsset buffer!";
|
||||
}
|
||||
AAsset_close(aasset);
|
||||
}
|
||||
return asset;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -23,8 +23,8 @@ class AssetCache {
|
|||
int validateCache(); // checks if cache files are valid and exist
|
||||
int updateCache(); // scans directory for changes and updates the cache accordingly
|
||||
// get/add
|
||||
Asset *getAsset(const char *filename); // attempts to get the given asset via filename
|
||||
Asset *loadAsset(const char *filename); // attempts to get the given asset and load its contents into memory
|
||||
virtual Asset *getAsset(const char *filename); // attempts to get the given asset via filename
|
||||
virtual Asset *loadAsset(const char *filename); // attempts to get the given asset and load its contents into memory
|
||||
Asset *saveAsset(const char *filename); // saves the given asset to disk
|
||||
Asset *createAsset(const char *filename, const char *data, size_t data_len); // create a new Asset, populating it with given data
|
||||
protected:
|
||||
|
@ -35,7 +35,20 @@ class AssetCache {
|
|||
#ifdef __ANDROID__
|
||||
class ApkAssetCache : public AssetCache {
|
||||
public:
|
||||
ApkAssetCache(const char *cache_dir) : AssetCache(cache_dir) {};
|
||||
ApkAssetCache(const char *cache_dir);
|
||||
int fromFile(const char *cache_file); // load a cache file
|
||||
int fromDir(const char *dir); // create/load a cache from the given directory
|
||||
int traverseDir_r(const char *dir); // recursive function for adding Asset(s) from a given directory to the cache
|
||||
// save
|
||||
int toFile(const char *cache_file) {};
|
||||
// update
|
||||
int validateCache() {}; // checks if cache files are valid and exist
|
||||
int updateCache() {}; // scans directory for changes and updates the cache accordingly
|
||||
// get/add
|
||||
virtual Asset *getAsset(const char *filename); // attempts to get the given asset via filename
|
||||
virtual Asset *loadAsset(const char *filename); // attempts to get the given asset and load its contents into memory
|
||||
Asset *saveAsset(const char *filename) {}; // saves the given asset to disk
|
||||
Asset *createAsset(const char *filename, const char *data, size_t data_len) {}; // create a new Asset, populating it with given data
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -80,8 +80,11 @@ int Core::initSystem() {
|
|||
asset_manager = new AssetManager();
|
||||
// TODO: load APP cache as first cache (using ApkAssetCache in the case of Android)
|
||||
#ifdef __ANDROID__
|
||||
//asset_manager->addCache(new ApkAssetCache(""));
|
||||
// Load the built-in RO ApkAssetCache directory first
|
||||
asset_manager->addCache(new ApkAssetCache("data"));
|
||||
// Load in the application's RW location on the install location
|
||||
asset_manager->addCache(new AssetCache(android_app_dir.c_str()));
|
||||
// Load in the application's RW external location
|
||||
asset_manager->addCache(new AssetCache(android_ext_dir.c_str()));
|
||||
#else
|
||||
asset_manager->addCache(new AssetCache("data"));
|
||||
|
|
|
@ -30,7 +30,7 @@ std::ostringstream& Log::Get(LogLevel level) {
|
|||
}
|
||||
Log::~Log() {
|
||||
os << std::endl;
|
||||
char *title = "Undefined";
|
||||
char const *title = "Undefined";
|
||||
switch(l) {
|
||||
case LOG_INFO:
|
||||
title = "Info";
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include "Mesh.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "fio.hpp"
|
||||
#include <stdio.h> // fscanf
|
||||
#include <string.h> // strcmp
|
||||
#include <stdlib.h> // atof
|
||||
|
@ -40,7 +39,7 @@ int Mesh::loadObj(const char *buffer, size_t buffer_size) {
|
|||
}
|
||||
char word[128];
|
||||
char *cpos = (char*)buffer;
|
||||
size_t offset = 0;
|
||||
int offset = 0;
|
||||
size_t bpos = 0;
|
||||
#ifdef _WIN32
|
||||
while (sscanf_s(cpos, "%s %n", word, 128, &offset) == 1) {
|
||||
|
|
|
@ -6,7 +6,6 @@ loading, creating, and compiling OpenGL programs.
|
|||
================================================================ */
|
||||
#include "Program.hpp"
|
||||
#include "Log.hpp"
|
||||
#include "fio.hpp"
|
||||
#include <fstream>
|
||||
#include <sstream> // ostringstream
|
||||
#include <stdexcept> // oor
|
||||
|
|
13
src/fio.cpp
13
src/fio.cpp
|
@ -107,9 +107,9 @@ static int apk_close(void *asset) {
|
|||
AAsset_close((AAsset*)asset);
|
||||
return 0;
|
||||
}
|
||||
AAssetManager* asset_manager;
|
||||
AAssetManager* android_asset_manager;
|
||||
void apk_set_asset_manager(AAssetManager* manager) {
|
||||
asset_manager = manager;
|
||||
android_asset_manager = manager;
|
||||
}
|
||||
JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setAssetManager(JNIEnv* env, jobject obj, jobject assetManager) {
|
||||
AAssetManager *mgr = AAssetManager_fromJava(env, assetManager);
|
||||
|
@ -117,11 +117,15 @@ JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setAssetManager(JNIEnv* env,
|
|||
}
|
||||
FILE* apk_fopen(const char *filename, const char *mode) {
|
||||
if (mode[0] == 'w') return NULL;
|
||||
AAsset *asset = AAssetManager_open(asset_manager, filename, 0);
|
||||
AAsset *asset = AAssetManager_open(android_asset_manager, filename, 0);
|
||||
if (!asset) return NULL;
|
||||
return funopen(asset, apk_read, apk_write, apk_seek, apk_close);
|
||||
}
|
||||
|
||||
AAssetDir* apk_openDir(const char *dir) {
|
||||
return AAssetManager_openDir(android_asset_manager, dir);
|
||||
}
|
||||
|
||||
std::string android_app_dir;
|
||||
std::string android_ext_dir;
|
||||
JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setAppDirectory(JNIEnv* env, jobject obj, jstring app_dir) {
|
||||
|
@ -137,4 +141,7 @@ JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setExtDirectory(JNIEnv* env,
|
|||
android_ext_dir.assign(native_string);
|
||||
env->ReleaseStringUTFChars(ext_dir, native_string);
|
||||
}
|
||||
AAssetManager *getAAssetManager() {
|
||||
return android_asset_manager;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -20,12 +20,15 @@ FILE *asset_fopen(const char *filename, const char *mode);
|
|||
#include <android/asset_manager_jni.h>
|
||||
extern std::string android_app_dir;
|
||||
extern std::string android_ext_dir;
|
||||
extern "C" AAssetManager* android_asset_manager;
|
||||
extern "C" {
|
||||
void apk_set_asset_manager(AAssetManager* manager);
|
||||
FILE *apk_fopen(const char *filename, const char *mode);
|
||||
AAssetDir* apk_openDir(const char *dir);
|
||||
JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setAssetManager(JNIEnv* env, jobject obj, jobject assetManager);
|
||||
JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setAppDirectory(JNIEnv* env, jobject obj, jstring app_dir);
|
||||
JNIEXPORT void JNICALL Java_com_polymathic_RtB_RtB_setExtDirectory(JNIEnv* env, jobject obj, jstring ext_dir);
|
||||
AAssetManager *getAAssetManager();
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue