mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-09-23 06:53:43 +00:00
Fix up Android asset directory scan
This commit is contained in:
@@ -1,14 +1,19 @@
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#include "GpFileSystem_Android.h"
|
||||
#include "GpIOStream.h"
|
||||
#include "HostDirectoryCursor.h"
|
||||
#include "VirtualDirectory.h"
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_rwops.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <jni.h>
|
||||
#include "UTF8.h"
|
||||
|
||||
|
||||
|
||||
@@ -242,37 +247,73 @@ void GpFileStream_Android_File::Flush()
|
||||
fflush(m_f);
|
||||
}
|
||||
|
||||
static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, std::string &resolution, bool &isAsset)
|
||||
static bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset)
|
||||
{
|
||||
isAsset = false;
|
||||
switch (virtualDirectory)
|
||||
{
|
||||
case PortabilityLayer::VirtualDirectories::kApplicationData:
|
||||
resolution = std::string("Packaged/") + path;
|
||||
resolution = std::string("Packaged") ;
|
||||
isAsset = true;
|
||||
return true;
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kGameData:
|
||||
resolution = std::string("Packaged/Houses/") + path;
|
||||
resolution = std::string("Packaged/Houses");
|
||||
isAsset = true;
|
||||
return true;
|
||||
break;
|
||||
case PortabilityLayer::VirtualDirectories::kFonts:
|
||||
resolution = std::string("Resources/") + path;
|
||||
resolution = std::string("Resources");
|
||||
isAsset = true;
|
||||
return true;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < numPaths; i++)
|
||||
{
|
||||
resolution += "/";
|
||||
resolution += paths[i];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
GpFileSystem_Android::GpFileSystem_Android()
|
||||
: m_activity(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
GpFileSystem_Android::~GpFileSystem_Android()
|
||||
{
|
||||
}
|
||||
|
||||
void GpFileSystem_Android::InitJNI()
|
||||
{
|
||||
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
|
||||
jobject activityLR = static_cast<jobject>(SDL_AndroidGetActivity());
|
||||
jclass activityClassLR = static_cast<jclass>(jni->GetObjectClass(activityLR));
|
||||
|
||||
m_scanAssetDirectoryMID = jni->GetMethodID(activityClassLR, "scanAssetDirectory", "(Ljava/lang/String;)[Ljava/lang/String;");
|
||||
|
||||
m_activity = jni->NewGlobalRef(activityLR);
|
||||
|
||||
jni->DeleteLocalRef(activityLR);
|
||||
jni->DeleteLocalRef(activityClassLR);
|
||||
}
|
||||
|
||||
void GpFileSystem_Android::ShutdownJNI()
|
||||
{
|
||||
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
|
||||
jni->DeleteGlobalRef(m_activity);
|
||||
m_activity = nullptr;
|
||||
}
|
||||
|
||||
bool GpFileSystem_Android::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
|
||||
{
|
||||
std::string resolvedPath;
|
||||
bool isAsset;
|
||||
if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset))
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
|
||||
return false;
|
||||
|
||||
if (isAsset)
|
||||
@@ -281,6 +322,7 @@ bool GpFileSystem_Android::FileExists(PortabilityLayer::VirtualDirectory_t virtu
|
||||
if (!rw)
|
||||
return false;
|
||||
SDL_RWclose(rw);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct stat s;
|
||||
@@ -291,21 +333,26 @@ bool GpFileSystem_Android::FileLocked(PortabilityLayer::VirtualDirectory_t virtu
|
||||
{
|
||||
std::string resolvedPath;
|
||||
bool isAsset;
|
||||
if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset))
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
|
||||
{
|
||||
*exists = false;
|
||||
if (exists)
|
||||
*exists = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isAsset)
|
||||
{
|
||||
if (exists)
|
||||
*exists = this->FileExists(virtualDirectory, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
int permissions = access(resolvedPath.c_str(), W_OK | F_OK);
|
||||
*exists = ((permissions & F_OK) != 0);
|
||||
return ((permissions & W_OK) != 0);
|
||||
}
|
||||
|
||||
GpIOStream *GpFileSystem_Android::OpenFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool writeAccess, GpFileCreationDisposition_t createDisposition)
|
||||
GpIOStream *GpFileSystem_Android::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition)
|
||||
{
|
||||
const char *mode = nullptr;
|
||||
bool canWrite = false;
|
||||
@@ -332,7 +379,7 @@ GpIOStream *GpFileSystem_Android::OpenFile(PortabilityLayer::VirtualDirectory_t
|
||||
|
||||
std::string resolvedPath;
|
||||
bool isAsset;
|
||||
if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset))
|
||||
if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, resolvedPath, isAsset))
|
||||
return nullptr;
|
||||
|
||||
if (isAsset)
|
||||
@@ -386,7 +433,7 @@ bool GpFileSystem_Android::DeleteFile(PortabilityLayer::VirtualDirectory_t virtu
|
||||
{
|
||||
std::string resolvedPath;
|
||||
bool isAsset;
|
||||
if (!ResolvePath(virtualDirectory, path, resolvedPath, isAsset))
|
||||
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
|
||||
{
|
||||
existed = false;
|
||||
return false;
|
||||
@@ -404,8 +451,11 @@ bool GpFileSystem_Android::DeleteFile(PortabilityLayer::VirtualDirectory_t virtu
|
||||
return true;
|
||||
}
|
||||
|
||||
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory)
|
||||
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths)
|
||||
{
|
||||
if (IsVirtualDirectoryLooseResources(virtualDirectory))
|
||||
return ScanAssetDirectory(virtualDirectory, paths, numPaths);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -455,9 +505,85 @@ bool GpFileSystem_Android::ValidateFilePathUnicodeChar(uint32_t c) const
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GpFileSystem_Android::IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const
|
||||
{
|
||||
return virtualDir == PortabilityLayer::VirtualDirectories::kApplicationData || virtualDir == PortabilityLayer::VirtualDirectories::kGameData;
|
||||
}
|
||||
|
||||
GpFileSystem_Android *GpFileSystem_Android::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
class GpDirectoryCursor_StringList final : public PortabilityLayer::HostDirectoryCursor
|
||||
{
|
||||
public:
|
||||
explicit GpDirectoryCursor_StringList(std::vector<std::string> &paths);
|
||||
~GpDirectoryCursor_StringList();
|
||||
|
||||
bool GetNext(const char *&outFileName) override;
|
||||
void Destroy() override;
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_paths;
|
||||
size_t m_index;
|
||||
};
|
||||
|
||||
GpDirectoryCursor_StringList::GpDirectoryCursor_StringList(std::vector<std::string> &paths)
|
||||
: m_index(0)
|
||||
{
|
||||
std::swap(paths, m_paths);
|
||||
}
|
||||
|
||||
GpDirectoryCursor_StringList::~GpDirectoryCursor_StringList()
|
||||
{
|
||||
}
|
||||
|
||||
bool GpDirectoryCursor_StringList::GetNext(const char *&outFileName)
|
||||
{
|
||||
if (m_index == m_paths.size())
|
||||
return false;
|
||||
outFileName = m_paths[m_index].c_str();
|
||||
m_index++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void GpDirectoryCursor_StringList::Destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths)
|
||||
{
|
||||
std::string resolvedPath;
|
||||
std::vector<std::string> subPaths;
|
||||
bool isAsset = true;
|
||||
if (!ResolvePath(virtualDirectory, paths, numPaths, resolvedPath, isAsset))
|
||||
return nullptr;
|
||||
|
||||
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
|
||||
|
||||
jstring directory = jni->NewStringUTF(resolvedPath.c_str());
|
||||
|
||||
jobjectArray resultArray = static_cast<jobjectArray>(jni->CallObjectMethod(m_activity, m_scanAssetDirectoryMID, directory));
|
||||
jni->DeleteLocalRef(directory);
|
||||
|
||||
size_t arrayLength = jni->GetArrayLength(resultArray);
|
||||
subPaths.reserve(arrayLength);
|
||||
for (size_t i = 0; i < arrayLength; i++)
|
||||
{
|
||||
jstring pathJStr = static_cast<jstring>(jni->GetObjectArrayElement(resultArray, i));
|
||||
const char *pathStrChars = jni->GetStringUTFChars(pathJStr, nullptr);
|
||||
|
||||
subPaths.push_back(std::string(pathStrChars, static_cast<size_t>(jni->GetStringUTFLength(pathJStr))));
|
||||
|
||||
jni->ReleaseStringUTFChars(pathJStr, pathStrChars);
|
||||
jni->DeleteLocalRef(pathJStr);
|
||||
}
|
||||
|
||||
jni->DeleteLocalRef(resultArray);
|
||||
|
||||
return new GpDirectoryCursor_StringList(subPaths);
|
||||
}
|
||||
|
||||
GpFileSystem_Android GpFileSystem_Android::ms_instance;
|
||||
|
@@ -4,22 +4,35 @@
|
||||
|
||||
#include "GpCoreDefs.h"
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
class GpFileSystem_Android final : public PortabilityLayer::HostFileSystem
|
||||
{
|
||||
public:
|
||||
GpFileSystem_Android();
|
||||
~GpFileSystem_Android();
|
||||
|
||||
void InitJNI();
|
||||
void ShutdownJNI();
|
||||
|
||||
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
|
||||
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) override;
|
||||
GpIOStream *OpenFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
|
||||
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
|
||||
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
|
||||
PortabilityLayer::HostDirectoryCursor *ScanDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory) override;
|
||||
PortabilityLayer::HostDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
|
||||
|
||||
bool ValidateFilePath(const char *path, size_t sz) const override;
|
||||
bool ValidateFilePath(const char *path, size_t pathLen) const override;
|
||||
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
|
||||
|
||||
bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override;
|
||||
|
||||
static GpFileSystem_Android *GetInstance();
|
||||
|
||||
private:
|
||||
PortabilityLayer::HostDirectoryCursor *ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
|
||||
|
||||
jobject m_activity;
|
||||
jmethodID m_scanAssetDirectoryMID;
|
||||
|
||||
static GpFileSystem_Android ms_instance;
|
||||
};
|
||||
|
@@ -33,7 +33,9 @@ int main(int argc, char* argv[])
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0)
|
||||
return -1;
|
||||
|
||||
SDL_GL_LoadLibrary("libGLESv2.so");
|
||||
//SDL_GL_LoadLibrary("libGLESv2.so");
|
||||
|
||||
GpFileSystem_Android::GetInstance()->InitJNI();
|
||||
|
||||
GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Android::GetInstance());
|
||||
GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Android::GetInstance());
|
||||
@@ -57,6 +59,8 @@ int main(int argc, char* argv[])
|
||||
|
||||
int returnCode = GpMain::Run();
|
||||
|
||||
GpFileSystem_Android::GetInstance()->ShutdownJNI();
|
||||
|
||||
SDL_Quit();
|
||||
|
||||
// This doesn't even actually exit, but it does stop this stupid brain-damaged OS from
|
||||
|
@@ -1,7 +1,30 @@
|
||||
package org.glideport.game;
|
||||
|
||||
import org.libsdl.app.SDLActivity;
|
||||
import android.content.res.AssetManager;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class GpActivity extends SDLActivity
|
||||
{
|
||||
private AssetManager assetManager;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
assetManager = getAssets();
|
||||
}
|
||||
|
||||
public String[] scanAssetDirectory(String directory)
|
||||
{
|
||||
try
|
||||
{
|
||||
return this.assetManager.list(directory);
|
||||
}
|
||||
catch (java.io.IOException ex)
|
||||
{
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user