mirror of
https://github.com/gnustep/libs-base.git
synced 2025-05-10 08:10:49 +00:00
Added support for asset loading on Android.
Requires passing the activity's AssetManager object from Java to GNUstep by calling +[NSBundle setJavaAssetManager:withJNIEnv:], which then enables the following features: - NSBundle main bundle resource paths support for Android assets, e.g. for pathForResource:ofType:, URLForResource:ofType: and related methods. - NSBundle main bundle info dictionary support if Info.plist exists in Android assets. - -initWithContentsOfFile: and related methods support for reading Android assets from main bundle in various classes (e.g. NSData, NSDictionary, NSArray, etc.). - NSFileManager fileExistsAtPath:(isDirectory:) and isReadableFileAtPath: return YES for main bundle asset / asset directory paths. - NSFileHandle support for reading Android assets from main bundle. - NSDirectoryEnumerator support for enumerating Android assets from main bundle. Note that recursion into subdirectories is currently not supported by the native Android asset manager API (see https://issuetracker.google.com/issues/37002833). Also adds support for automatic NSProcessInfo initialization on Android with a fake executable path "/data/data/<app identifier>/exe" (as Android apps don't have a real executable path), and tweaks main bundle initialization to allow that path. Main bundle resource paths are prefixed by "/data/data/<app identifier>/Resources".
This commit is contained in:
parent
ecbecbeabd
commit
3b60b1a8be
10 changed files with 440 additions and 46 deletions
29
ChangeLog
29
ChangeLog
|
@ -1,3 +1,32 @@
|
|||
2019-05-23 Frederik Seiffert <frederik@algoriddim.com>
|
||||
|
||||
* configure:
|
||||
* configure.ac:
|
||||
Link against libandroid on Android.
|
||||
* Headers/Foundation/NSBundle.h:
|
||||
* Source/NSBundle.m:
|
||||
Added methods for passing Android asset manager from Java to GNUstep
|
||||
and for getting AAsset/AAssetDir for given path in main bundle. Skip
|
||||
app bundle suffix check on Android. Extended bundle resource paths
|
||||
backbone to check for known paths directly on Android as we can't
|
||||
enumerate directories. Extracted path cache cleaning into separate
|
||||
method.
|
||||
* Source/GSFileHandle.h:
|
||||
* Source/GSFileHandle.m:
|
||||
Added file handle support for reading Android assets from main bundle.
|
||||
* Source/NSData.m:
|
||||
Added support for reading Android assets from main bundle in
|
||||
readContentsOfFile(). This is also used by all other
|
||||
-initWithContentsOfFile: and related methods from other classes.
|
||||
* Source/NSFileManager.m:
|
||||
Added support for Android assets from main bundle in
|
||||
fileExistsAtPath:isDirectory:, isReadableFileAtPath:, and
|
||||
NSDirectoryEnumerator.
|
||||
* Source/NSProcessInfo.m:
|
||||
Added +initialize method to auto-initialize NSProcessInfo on Android
|
||||
using fake executable path "/data/data/<app identifier>/exe" (Android
|
||||
apps don't have a real executable path).
|
||||
|
||||
2019-05-20 Frederik Seiffert <frederik@algoriddim.com>
|
||||
|
||||
* Source/NSLog.m: Have all logs go to syslog on android.
|
||||
|
|
|
@ -36,6 +36,10 @@ extern "C" {
|
|||
#import <Foundation/NSObject.h>
|
||||
#import <Foundation/NSString.h>
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/asset_manager_jni.h>
|
||||
#endif
|
||||
|
||||
@class NSString;
|
||||
@class NSArray;
|
||||
@class NSDictionary;
|
||||
|
@ -540,6 +544,38 @@ GS_EXPORT NSString* const NSLoadedClasses;
|
|||
ofType: (NSString*)extension
|
||||
inDirectory: (NSString*)bundlePath;
|
||||
|
||||
/** Cleans up the path cache for the bundle. */
|
||||
- (void) cleanPathCache;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
/**
|
||||
* Sets the Java Android asset manager.
|
||||
* The developer can call this method to enable asset loading via NSBundle.
|
||||
*/
|
||||
+ (void) setJavaAssetManager:(jobject)jassetManager withJNIEnv:(JNIEnv *)env;
|
||||
|
||||
/**
|
||||
* Returns the native Android asset manager.
|
||||
*/
|
||||
+ (AAssetManager *) assetManager;
|
||||
|
||||
/**
|
||||
* Returns the Android asset for the given path if path is in main bundle
|
||||
* resources and asset exists.
|
||||
* The returned object must be released using AAsset_close().
|
||||
*/
|
||||
+ (AAsset *)assetForPath:(NSString *)path;
|
||||
|
||||
/**
|
||||
* Returns the Android asset dir for the given path if path is in main bundle
|
||||
* resources and the asset directory exists.
|
||||
* The returned object must be released using AAssetDir_close().
|
||||
*/
|
||||
+ (AAssetDir *)assetDirForPath:(NSString *)path;
|
||||
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
@end
|
||||
|
||||
#endif /* GNUSTEP */
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
#include <zlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/asset_manager_jni.h>
|
||||
#endif
|
||||
|
||||
struct sockaddr_in;
|
||||
|
||||
/**
|
||||
|
@ -69,6 +73,9 @@ struct sockaddr_in;
|
|||
#if defined(_WIN32)
|
||||
WSAEVENT event;
|
||||
#endif
|
||||
#ifdef __ANDROID__
|
||||
AAsset *asset;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -285,6 +285,13 @@ static GSTcpTune *tune = nil;
|
|||
|
||||
do
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
result = AAsset_read(asset, buf, len);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if USE_ZLIB
|
||||
if (gzDescriptor != 0)
|
||||
{
|
||||
|
@ -379,6 +386,14 @@ static GSTcpTune *tune = nil;
|
|||
[self ignoreReadDescriptor];
|
||||
[self ignoreWriteDescriptor];
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
AAsset_close(asset);
|
||||
asset = NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (closeOnDealloc == YES && descriptor != -1)
|
||||
{
|
||||
[self closeFile];
|
||||
|
@ -1075,6 +1090,14 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
|
||||
if (d < 0)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
asset = [NSBundle assetForPath:path];
|
||||
if (asset) {
|
||||
readOK = YES;
|
||||
return self;
|
||||
}
|
||||
#endif
|
||||
|
||||
DESTROY(self);
|
||||
return nil;
|
||||
}
|
||||
|
@ -1645,6 +1668,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
result = AAsset_seek(asset, 0, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
{
|
||||
#if USE_ZLIB
|
||||
|
@ -1669,6 +1699,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
result = AAsset_seek(asset, 0, SEEK_END);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
{
|
||||
#if USE_ZLIB
|
||||
|
@ -1693,6 +1730,13 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
{
|
||||
off_t result = -1;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
result = AAsset_seek(asset, (off_t)pos, SEEK_SET);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (isStandardFile && descriptor >= 0)
|
||||
{
|
||||
#if USE_ZLIB
|
||||
|
@ -1726,6 +1770,15 @@ NSString * const GSSOCKSRecvAddr = @"GSSOCKSRecvAddr";
|
|||
[self ignoreWriteDescriptor];
|
||||
|
||||
[self setNonBlocking: NO];
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (asset)
|
||||
{
|
||||
AAsset_close(asset);
|
||||
asset = NULL;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#if USE_ZLIB
|
||||
if (gzDescriptor != 0)
|
||||
{
|
||||
|
|
|
@ -241,6 +241,11 @@ static NSString *library_combo =
|
|||
nil;
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
static jobject _jassetManager = NULL;
|
||||
static AAssetManager *_assetManager = NULL;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Try to find the absolute path of an executable.
|
||||
|
@ -1382,6 +1387,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
|
|||
isNonInstalledTool = YES;
|
||||
}
|
||||
|
||||
#ifndef __ANDROID__ /* don't check suffix on Android's fake executable path */
|
||||
if (isApplication == YES)
|
||||
{
|
||||
s = [path lastPathComponent];
|
||||
|
@ -1422,6 +1428,7 @@ _bundle_load_callback(Class theClass, struct objc_category *theCategory)
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif /* !__ANDROID__ */
|
||||
|
||||
if (isApplication == NO)
|
||||
{
|
||||
|
@ -1805,9 +1812,6 @@ IF_NO_GC(
|
|||
{
|
||||
NSString *identifier = [self bundleIdentifier];
|
||||
NSUInteger count;
|
||||
NSUInteger plen = [_path length];
|
||||
NSEnumerator *enumerator;
|
||||
NSString *path;
|
||||
|
||||
[load_lock lock];
|
||||
if (_bundles != nil)
|
||||
|
@ -1835,38 +1839,7 @@ IF_NO_GC(
|
|||
|
||||
/* Clean up path cache for this bundle.
|
||||
*/
|
||||
[pathCacheLock lock];
|
||||
enumerator = [pathCache keyEnumerator];
|
||||
while (nil != (path = [enumerator nextObject]))
|
||||
{
|
||||
if (YES == [path hasPrefix: _path])
|
||||
{
|
||||
if ([path length] == plen)
|
||||
{
|
||||
/* Remove the bundle directory path from the cache.
|
||||
*/
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
else
|
||||
{
|
||||
unichar c = [path characterAtIndex: plen];
|
||||
|
||||
/* if the directory is inside the bundle, remove from cache.
|
||||
*/
|
||||
if ('/' == c)
|
||||
{
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
else if ('\\' == c)
|
||||
{
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
[pathCacheLock unlock];
|
||||
[self cleanPathCache];
|
||||
RELEASE(_path);
|
||||
}
|
||||
TEST_RELEASE(_frameworkVersion);
|
||||
|
@ -2144,6 +2117,48 @@ IF_NO_GC(
|
|||
addBundlePath(array, contents, primary, subPath, language);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Android: check subdir and localization directly, as AAssetDir and thereby
|
||||
// NSDirectoryEnumerator doesn't list directories
|
||||
NSString *originalPrimary = primary;
|
||||
if (subPath) {
|
||||
primary = [originalPrimary stringByAppendingPathComponent: subPath];
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, nil, nil);
|
||||
|
||||
if (localization) {
|
||||
primary = [primary stringByAppendingPathComponent:
|
||||
[localization stringByAppendingPathExtension:@"lproj"]];
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, nil, nil);
|
||||
} else {
|
||||
NSString *subPathPrimary = primary;
|
||||
enumerate = [languages objectEnumerator];
|
||||
while ((language = [enumerate nextObject])) {
|
||||
primary = [subPathPrimary stringByAppendingPathComponent:
|
||||
[localization stringByAppendingPathExtension:@"lproj"]];
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, nil, nil);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localization) {
|
||||
primary = [originalPrimary stringByAppendingPathComponent:
|
||||
[localization stringByAppendingPathExtension:@"lproj"]];
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, nil, nil);
|
||||
} else {
|
||||
enumerate = [languages objectEnumerator];
|
||||
while ((language = [enumerate nextObject])) {
|
||||
primary = [originalPrimary stringByAppendingPathComponent:
|
||||
[localization stringByAppendingPathExtension:@"lproj"]];
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, nil, nil);
|
||||
}
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
primary = rootPath;
|
||||
contents = bundle_directory_readable(primary);
|
||||
addBundlePath(array, contents, primary, subPath, nil);
|
||||
|
@ -2525,6 +2540,10 @@ IF_NO_GC(
|
|||
locale = [[locale lastPathComponent] stringByDeletingPathExtension];
|
||||
[array addObject: locale];
|
||||
}
|
||||
#ifdef __ANDROID__
|
||||
// TODO: check known languages for existance directly, as AAssetDir and thereby
|
||||
// NSDirectoryEnumerator doesn't list directories
|
||||
#endif
|
||||
return GS_IMMUTABLE(array);
|
||||
}
|
||||
|
||||
|
@ -3202,5 +3221,126 @@ IF_NO_GC(
|
|||
return path;
|
||||
}
|
||||
|
||||
- (void)cleanPathCache
|
||||
{
|
||||
NSUInteger plen = [_path length];
|
||||
NSEnumerator *enumerator;
|
||||
NSString *path;
|
||||
|
||||
[pathCacheLock lock];
|
||||
enumerator = [pathCache keyEnumerator];
|
||||
while (nil != (path = [enumerator nextObject]))
|
||||
{
|
||||
if (YES == [path hasPrefix: _path])
|
||||
{
|
||||
if ([path length] == plen)
|
||||
{
|
||||
/* Remove the bundle directory path from the cache.
|
||||
*/
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
else
|
||||
{
|
||||
unichar c = [path characterAtIndex: plen];
|
||||
|
||||
/* if the directory is inside the bundle, remove from cache.
|
||||
*/
|
||||
if ('/' == c)
|
||||
{
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
#if defined(_WIN32)
|
||||
else if ('\\' == c)
|
||||
{
|
||||
[pathCache removeObjectForKey: path];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
[pathCacheLock unlock];
|
||||
|
||||
/* also destroy cached variables depending on bundle paths */
|
||||
DESTROY(_infoDict);
|
||||
DESTROY(_localizations);
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
+ (AAssetManager *)assetManager
|
||||
{
|
||||
return _assetManager;
|
||||
}
|
||||
|
||||
+ (void)setJavaAssetManager:(jobject)jassetManager withJNIEnv:(JNIEnv *)env
|
||||
{
|
||||
// create global reference to Java asset manager to prevent garbage
|
||||
// collection
|
||||
_jassetManager = (*env)->NewGlobalRef(env, jassetManager);
|
||||
|
||||
// get native asset manager (may be shared across multiple threads)
|
||||
_assetManager = AAssetManager_fromJava(env, _jassetManager);
|
||||
|
||||
// clean main bundle path cache in case it was accessed before
|
||||
[_mainBundle cleanPathCache];
|
||||
}
|
||||
|
||||
+ (AAsset *)assetForPath:(NSString *)path
|
||||
{
|
||||
AAsset *asset = NULL;
|
||||
|
||||
if (_assetManager && _mainBundle)
|
||||
{
|
||||
NSString *resourcePath = [_mainBundle resourcePath];
|
||||
|
||||
if ([path hasPrefix:resourcePath] && [path length] > [resourcePath length])
|
||||
{
|
||||
NSString *assetPath = [path substringFromIndex:[resourcePath length]+1];
|
||||
|
||||
asset = AAssetManager_open(_assetManager,
|
||||
[assetPath fileSystemRepresentation], AASSET_MODE_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
+ (AAssetDir *)assetDirForPath:(NSString *)path
|
||||
{
|
||||
AAssetDir *assetDir = NULL;
|
||||
|
||||
if (_assetManager && _mainBundle)
|
||||
{
|
||||
NSString *resourcePath = [_mainBundle resourcePath];
|
||||
|
||||
if ([path hasPrefix:resourcePath])
|
||||
{
|
||||
NSString *assetPath = @"";
|
||||
if ([path length] > [resourcePath length]) {
|
||||
assetPath = [path substringFromIndex:[resourcePath length] + 1];
|
||||
}
|
||||
|
||||
assetDir = AAssetManager_openDir(_assetManager,
|
||||
[assetPath fileSystemRepresentation]);
|
||||
|
||||
if (assetDir) {
|
||||
// AAssetManager_openDir() always returns an object, so we check if
|
||||
// the directory exists by ensuring it contains a file
|
||||
BOOL exists = AAssetDir_getNextFileName(assetDir) != NULL;
|
||||
if (exists) {
|
||||
AAssetDir_rewind(assetDir);
|
||||
} else {
|
||||
AAssetDir_close(assetDir);
|
||||
assetDir = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return assetDir;
|
||||
}
|
||||
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
@end
|
||||
|
||||
|
|
|
@ -254,6 +254,35 @@ readContentsOfFile(NSString *path, void **buf, off_t *len, NSZone *zone)
|
|||
return NO;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Android: try using asset manager if path is in main bundle resources
|
||||
AAsset *asset = [NSBundle assetForPath:path];
|
||||
if (asset) {
|
||||
fileLength = AAsset_getLength(asset);
|
||||
|
||||
tmp = NSZoneMalloc(zone, fileLength);
|
||||
if (tmp == 0) {
|
||||
NSLog(@"Malloc failed for file (%@) of length %jd - %@", path,
|
||||
(intmax_t)fileLength, [NSError _last]);
|
||||
AAsset_close(asset);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
int result = AAsset_read(asset, tmp, fileLength);
|
||||
AAsset_close(asset);
|
||||
|
||||
if (result < 0) {
|
||||
NSWarnFLog(@"read of file (%@) contents failed - %@", path,
|
||||
[NSError errorWithDomain:NSPOSIXErrorDomain code:result userInfo:nil]);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
*buf = tmp;
|
||||
*len = fileLength;
|
||||
return YES;
|
||||
}
|
||||
#endif /* __ANDROID__ */
|
||||
|
||||
att = [mgr fileAttributesAtPath: path traverseLink: YES];
|
||||
if (nil == att)
|
||||
{
|
||||
|
|
|
@ -1652,6 +1652,24 @@ static NSStringEncoding defaultEncoding;
|
|||
|
||||
if (_STAT(lpath, &statbuf) != 0)
|
||||
{
|
||||
#ifdef __ANDROID__
|
||||
// Android: try using asset manager if path is in main bundle resources
|
||||
AAsset *asset = [NSBundle assetForPath:path];
|
||||
if (asset) {
|
||||
AAsset_close(asset);
|
||||
return YES;
|
||||
}
|
||||
|
||||
AAssetDir *assetDir = [NSBundle assetDirForPath:path];
|
||||
if (assetDir) {
|
||||
AAssetDir_close(assetDir);
|
||||
if (isDirectory) {
|
||||
*isDirectory = YES;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
@ -1700,6 +1718,16 @@ static NSStringEncoding defaultEncoding;
|
|||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
#ifdef __ANDROID__
|
||||
// Android: try using asset manager if path is in main bundle resources
|
||||
AAsset *asset = [NSBundle assetForPath:path];
|
||||
if (asset) {
|
||||
AAsset_close(asset);
|
||||
return YES;
|
||||
}
|
||||
#endif
|
||||
|
||||
return NO;
|
||||
}
|
||||
#endif
|
||||
|
@ -2379,6 +2407,9 @@ static NSStringEncoding defaultEncoding;
|
|||
typedef struct _GSEnumeratedDirectory {
|
||||
NSString *path;
|
||||
_DIR *pointer;
|
||||
#ifdef __ANDROID__
|
||||
AAssetDir *assetDir;
|
||||
#endif
|
||||
} GSEnumeratedDirectory;
|
||||
|
||||
|
||||
|
@ -2386,6 +2417,11 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
|
|||
{
|
||||
DESTROY(X.path);
|
||||
_CLOSEDIR(X.pointer);
|
||||
#ifdef __ANDROID__
|
||||
if (X.assetDir) {
|
||||
AAssetDir_close(X.assetDir);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#define GSI_ARRAY_TYPES 0
|
||||
|
@ -2443,12 +2479,26 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
|
|||
|
||||
localPath = [_mgr fileSystemRepresentationWithPath: path];
|
||||
dir_pointer = _OPENDIR(localPath);
|
||||
|
||||
#ifdef __ANDROID__
|
||||
AAssetDir *assetDir = NULL;
|
||||
if (!dir_pointer) {
|
||||
// Android: try using asset manager if path is in main bundle resources
|
||||
assetDir = [NSBundle assetDirForPath:path];
|
||||
}
|
||||
|
||||
if (dir_pointer || assetDir)
|
||||
#else
|
||||
if (dir_pointer)
|
||||
#endif
|
||||
{
|
||||
GSIArrayItem item;
|
||||
|
||||
item.ext.path = @"";
|
||||
item.ext.pointer = dir_pointer;
|
||||
#ifdef __ANDROID__
|
||||
item.ext.assetDir = assetDir;
|
||||
#endif
|
||||
|
||||
GSIArrayAddItem(_stack, item);
|
||||
}
|
||||
|
@ -2535,35 +2585,54 @@ static inline void gsedRelease(GSEnumeratedDirectory X)
|
|||
while (GSIArrayCount(_stack) > 0)
|
||||
{
|
||||
GSEnumeratedDirectory dir = GSIArrayLastItem(_stack).ext;
|
||||
struct _DIRENT *dirbuf;
|
||||
struct _STATB statbuf;
|
||||
#if defined(_WIN32)
|
||||
const wchar_t *dirname = NULL;
|
||||
#else
|
||||
const char *dirname = NULL;
|
||||
#endif
|
||||
|
||||
dirbuf = _READDIR(dir.pointer);
|
||||
#ifdef __ANDROID__
|
||||
if (dir.assetDir)
|
||||
{
|
||||
// This will only return files and not directories, which means that
|
||||
// recursion is not supported.
|
||||
// See https://issuetracker.google.com/issues/37002833
|
||||
dirname = AAssetDir_getNextFileName(dir.assetDir);
|
||||
}
|
||||
else if (dir.pointer)
|
||||
#endif
|
||||
{
|
||||
struct _DIRENT *dirbuf = _READDIR(dir.pointer);
|
||||
if (dirbuf) {
|
||||
dirname = dirbuf->d_name;
|
||||
}
|
||||
}
|
||||
|
||||
if (dirbuf)
|
||||
if (dirname)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
/* Skip "." and ".." directory entries */
|
||||
if (wcscmp(dirbuf->d_name, L".") == 0
|
||||
|| wcscmp(dirbuf->d_name, L"..") == 0)
|
||||
if (wcscmp(dirname, L".") == 0
|
||||
|| wcscmp(dirname, L"..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Name of file to return */
|
||||
returnFileName = [_mgr
|
||||
stringWithFileSystemRepresentation: dirbuf->d_name
|
||||
length: wcslen(dirbuf->d_name)];
|
||||
stringWithFileSystemRepresentation: dirname
|
||||
length: wcslen(dirname)];
|
||||
#else
|
||||
/* Skip "." and ".." directory entries */
|
||||
if (strcmp(dirbuf->d_name, ".") == 0
|
||||
|| strcmp(dirbuf->d_name, "..") == 0)
|
||||
if (strcmp(dirname, ".") == 0
|
||||
|| strcmp(dirname, "..") == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
/* Name of file to return */
|
||||
returnFileName = [_mgr
|
||||
stringWithFileSystemRepresentation: dirbuf->d_name
|
||||
length: strlen(dirbuf->d_name)];
|
||||
stringWithFileSystemRepresentation: dirname
|
||||
length: strlen(dirname)];
|
||||
#endif
|
||||
/* if we have a null FileName something went wrong (charset?) and we skip it */
|
||||
if (returnFileName == nil)
|
||||
|
|
|
@ -943,6 +943,31 @@ extern char **__libc_argv;
|
|||
}
|
||||
}
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
|
||||
+ (void) initialize
|
||||
{
|
||||
if (nil == procLock) procLock = [NSRecursiveLock new];
|
||||
if (self == [NSProcessInfo class]
|
||||
&& !_gnu_processName && !_gnu_arguments && !_gnu_environment)
|
||||
{
|
||||
FILE *f = fopen("/proc/self/cmdline", "r");
|
||||
if (f) {
|
||||
char identifier[BUFSIZ];
|
||||
fgets(identifier, sizeof(identifier), f);
|
||||
fclose(f);
|
||||
|
||||
// construct fake executable path
|
||||
char *arg0;
|
||||
asprintf(&arg0, "/data/data/%s/exe", identifier);
|
||||
|
||||
char *argv[] = { arg0 };
|
||||
_gnu_process_args(sizeof(argv)/sizeof(char *), argv, NULL);
|
||||
} else {
|
||||
fprintf(stderr, "Failed to read cmdline\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
+ (void) initialize
|
||||
|
|
3
configure
vendored
3
configure
vendored
|
@ -5996,6 +5996,9 @@ case "$target_os" in
|
|||
LDFLAGS="$LDFLAGS -L/usr/local/lib";;
|
||||
netbsd*) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
|
||||
LDFLAGS="$LDFLAGS -Wl,-R/usr/pkg/lib -L/usr/pkg/lib";;
|
||||
linux-android* )
|
||||
# link against libandroid for native application APIs
|
||||
LIBS="$LIBS -landroid";;
|
||||
esac
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
|
|
@ -1246,6 +1246,9 @@ case "$target_os" in
|
|||
LDFLAGS="$LDFLAGS -L/usr/local/lib";;
|
||||
netbsd*) CPPFLAGS="$CPPFLAGS -I/usr/pkg/include"
|
||||
LDFLAGS="$LDFLAGS -Wl,-R/usr/pkg/lib -L/usr/pkg/lib";;
|
||||
linux-android* )
|
||||
# link against libandroid for native application APIs
|
||||
LIBS="$LIBS -landroid";;
|
||||
esac
|
||||
|
||||
#--------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue