Android File System

Post your questions, suggestions and experiences regarding game design, integration of external libraries here. For irrEdit, irrXML and irrKlang, see the
ambiera forums
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Android File System

Post by LunaRebirth »

I've created a game that runs all *.lua files in a directory.

I'm porting this game to Android, and it should read all file names in a directory and run all *.lua files.
Unfortunately I'm having a ton of problems reading all files in a directory on Android.
If I load a texture like so

Code: Select all

IGUIImage* startIMG = Game::guienv->addImage(rect<s32>(0,0,640,480),0,0);
startIMG->setImage(Game::driver->getTexture("media/blank.png"));
There are no issues loading the file on both, Android or Windows.

However if I use the file system and do

Code: Select all

bool check = device->getFileSystem()->existFile("media/blank.png");
check returns true on Windows, and false on Android.

I've also searched around on how to read all files with POSIX or on UNIX systems. Nothing seems to work.

I'm unsure why this problem is occurring, so I figured maybe it's my file permissions? In the Android Manifest I'm using permissions for
READ_EXTERNAL_STORAGE and READ_INTERNAL_STORAGE
Any suggestions?
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

When I try

Code: Select all

char c[255];
sprintf(c, "%s",(char*)Game::fs->getWorkingDirectory().c_str());
Game::logger->log(c);
on Android I get "" as the working directory.
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Android File System

Post by CuteAlien »

You have to manually add the directory to the archive first. Check the android example - it has code for that (the part with "addDirectoryToFileList").
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

Ah okay that worked for existFile.

Here's what I'm doing to find all files in a directory:

Code: Select all

std::vector<std::string> allDirs(char* folder_name) {
    std::vector<std::string> allFiles;
    char c[255];
    
    sprintf(c, "Looking for files...");
    Game::logger->log(c);
 
    //Game::fs is an IFileSystem
    if(!Game::fs->changeWorkingDirectoryTo(folder_name))
        return allFiles;
 
    sprintf(c, "Creating file list...");
    Game::logger->log(c);
    io::IFileList* filelist = Game::fs->createFileList();
    if(filelist == NULL)
        return allFiles;
    
    sprintf(c, "Getting count...");
    Game::logger->log(c);
    if(filelist->getFileCount() == 0) {
        return allFiles;
    } else {
        sprintf(c, "Adding files...");
        Game::logger->log(c);
        for(int i = 2; i < filelist->getFileCount(); i++) {
            std::string fullFile = filelist->getFileName(i).c_str();
            allFiles.push_back((char*)((std::string)folder_name+fullFile).c_str());
            sprintf(c, "File::%s!",(char*)allFiles[i-2].c_str());
            Game::logger->log(c);
        }
    }
    Game::fs->changeWorkingDirectoryTo("../");
    filelist->drop();
 
    return allFiles;
}
The code works and successfully outputs all found files on Windows.
But it fails on Android, last outputting "Looking for files..." (line 5 in code above).
I read that changeWorkingDirectoryTo could return a fail, and still change the directory, in a different forum post. So I tested without the if statement on line 5, and I got to output "Creating file list..." before the function returned.

I believe it isn't finding the folder for changeWorkingDirectoryTo, but I'm unsure why?
Calling "allDirs("Weapons/")" where the Weapons folder exists in Android assets.
allDirs("/sdcard/Weapons/"); doesn't work either
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

Cool, I found all the files:

Code: Select all

char c[255];
    sprintf(c, "Getting archive count...");
    Game::logger->log(c);
    for ( u32 i=0; i < Game::fs->getFileArchiveCount(); ++i )
    {
        IFileArchive* archive = Game::fs->getFileArchive(i);
        if ( archive->getType() == EFAT_ANDROID_ASSET )
        {
            bool inFolder = false;
            for ( u32 y=0; y < archive->getFileList()->getFileCount(); ++y )
            {
                if (inFolder) {
                    std::string fullName = (std::string)folder_name + (std::string)archive->getFileList()->getFileName(y).c_str();
                    allFiles.push_back(fullName);
                    sprintf(c, "File Found::%s", (char*)fullName.c_str());
                    Game::logger->log(c);
                }
 
                if (archive->getFileList()->isDirectory(y)) {
                    std::string newName = folder_name;
                        newName = newName.substr(0,newName.length()-1);
                    if (archive->getFileList()->getFileName(y).c_str() == newName) {
                        inFolder = true;
                    } else {
                        inFolder = false;
                    }
                }
            }
        }
    }
 
    return allFiles;
Now I'm trying to run these files with Lua using luaL_dofile, but of course because the file is in the assets, it won't run.

Whats the best way to run the Lua file?
I was thinking about maybe if I could take the file out of the assets folder and move it to the /sdcard location and doing luaL_dofile from there, but I don't see any way to access the file directly from Irrlicht. Possible better ideas or anything that might help?
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

Solved
CuteAlien
Admin
Posts: 9734
Joined: Mon Mar 06, 2006 2:25 pm
Location: Tübingen, Germany
Contact:

Re: Android File System

Post by CuteAlien »

LunaRebirth wrote:Solved
Nice. I wasn't sure what's going on myself. My suspicion was that it's somehow caused by the mix of real filesystem and archive filesystem somehow, but would have needed some time to debug.

If you can share the solution it might also help others in future :-)
IRC: #irrlicht on irc.libera.chat
Code snippet repository: https://github.com/mzeilfelder/irr-playground-micha
Free racer made with Irrlicht: http://www.irrgheist.com/hcraftsource.htm
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

CuteAlien wrote:If you can share the solution it might also help others in future :-)
Yeah,
I used the code mentioned above to find all the files, then I saved them as an IReadFile and read their contents line-by-line, storing the full file contents in a string and then doing luaL_dostring() directly from the file in the assets folder
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

I decided to post another question I had here rather than in a new post.

So I've made it so the server sends file contents to the client, in which the client receives to a file.
The server also sends whether it is only part of a file, or a while file (meaning the client saves the file, and, if it's another part of the file, it appends more data to the file rather than overwriting it)
I've got it working on Windows with

Code: Select all

IWriteFile* file = Game::fs->createAndWriteFile((char*)fileName.c_str(), overwrite);
if (file > 0) {
    file->write(cont, len);
    file->drop();
}
Doesn't seem to create a new file on Android, and I'd like it to.

So THE QUESTION:
How do I write files on Android?
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

I'm using this code I found from http://stackoverflow.com/questions/1129 ... -code-only

Code: Select all

    #ifdef _IRR_ANDROID_PLATFORM_
    ANativeActivity* nativeActivity = Game::state->activity;
    const char* internalPath = nativeActivity->internalDataPath;
    std::string dataPath(internalPath);
    // internalDataPath points directly to the files/ directory
    std::string configFile = dataPath + "/" + fileName;
 
    // sometimes if this is the first time we run the app
    // then we need to create the internal storage "files" directory
    struct stat sb;
    int32_t res = stat(dataPath.c_str(), &sb);
    if (0 == res && sb.st_mode & S_IFDIR)
    {
        Game::log("'files/' dir already in app's internal data storage.");
    }
    else if (ENOENT == errno)
    {
        res = mkdir(dataPath.c_str(), 0770);
    }
 
    if (0 == res)
    {
        // test to see if the config file is already present
        res = stat(configFile.c_str(), &sb);
        if (0 == res && sb.st_mode & S_IFREG)
        {
            Game::log("Application config file already present");
        }
        else
        {
            Game::log("Application config file does not exist. Creating it ...");
            // read our application config file from the assets inside the apk
            // save the config file contents in the application's internal storage
            Game::log("Reading config file using the asset manager.\n");
 
            AAssetManager* assetManager = nativeActivity->assetManager;
            AAsset* configFileAsset = AAssetManager_open(assetManager, (char*)fileName.c_str(), AASSET_MODE_BUFFER);
            const void* configData = AAsset_getBuffer(configFileAsset);
            const off_t configLen = AAsset_getLength(configFileAsset);
            FILE* appConfigFile = std::fopen(configFile.c_str(), "w+");
            if (NULL == appConfigFile)
            {
                Game::log("Could not create app configuration file.\n");
            }
            else
            {
                Game::log("App config file created successfully. Writing config data ...\n");
                res = std::fwrite(configData, sizeof(char), configLen, appConfigFile);
                if (configLen != res)
                {
                    Game::log("Error generating app configuration file.\n");
                }
            }
            std::fclose(appConfigFile);
            AAsset_close(configFileAsset);
        }
    }
    #endif // _IRR_ANDROID_PLATFORM_
but Irrlicht is crashing with output

Code: Select all

08-23 22:54:44.589  1710  1732 I Irrlicht: 'files/' dir already in app's internal data storage.
08-23 22:54:44.589  1710  1732 I Irrlicht: Application config file does not exist. Creating it ...
08-23 22:54:44.589  1710  1732 I Irrlicht: Reading config file using the asset manager.
08-23 22:54:44.589  1710  1732 I Irrlicht:
08-23 22:54:44.699   509   509 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
08-23 22:54:44.700   509   509 F DEBUG   : Build fingerprint: 'motorola/kinzie_verizon/kinzie:6.0/MCK24.78-13.16/16:user/release-keys'
08-23 22:54:44.700   509   509 F DEBUG   : Revision: 'p301'
08-23 22:54:44.701   509   509 F DEBUG   : ABI: 'arm'
08-23 22:54:44.701   509   509 F DEBUG   : pid: 1710, tid: 1732, name: Thread-21751  >>> com.app3D <<<
08-23 22:54:44.701   509   509 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
08-23 22:54:44.717   509   509 F DEBUG   :     r0 00000000  r1 00000000  r2 00000000  r3 00000002
08-23 22:54:44.717   509   509 F DEBUG   :     r4 ef749334  r5 ef749270  r6 00000000  r7 f543dd00
08-23 22:54:44.717   509   509 F DEBUG   :     r8 f766ab84  r9 f543ddf0  sl ef64b000  fp f400549d
08-23 22:54:44.717   509   509 F DEBUG   :     ip f409aaf4  sp ef749250  lr f3eac097  pc e9093dc6  cpsr 40070030
08-23 22:54:44.722   509   509 F DEBUG   :
08-23 22:54:44.722   509   509 F DEBUG   : backtrace:
08-23 22:54:44.722   509   509 F DEBUG   :     #00 pc 00008dc6  /system/lib/libandroid.so (AAsset_close+31)
08-23 22:54:44.722   509   509 F DEBUG   :     #01 pc 0013e093  /data/app/com.app3D-1/lib/arm/libapp3D.so (_Z11receiveFilev+826)
08-23 22:54:44.722   509   509 F DEBUG   :     #02 pc 0013e92f  /data/app/com.app3D-1/lib/arm/libapp3D.so (_ZN6Server10ConnectionEv+446)
08-23 22:54:44.722   509   509 F DEBUG   :     #03 pc 0013368b  /data/app/com.app3D-1/lib/arm/libapp3D.so (main+118)
08-23 22:54:44.722   509   509 F DEBUG   :     #04 pc 00135c7f  /data/app/com.app3D-1/lib/arm/libapp3D.so (android_main+798)
08-23 22:54:44.722   509   509 F DEBUG   :     #05 pc 00297513  /data/app/com.app3D-1/lib/arm/libapp3D.so
08-23 22:54:44.722   509   509 F DEBUG   :     #06 pc 0003fc6b  /system/lib/libc.so (_ZL15__pthread_startPv+30)
08-23 22:54:44.722   509   509 F DEBUG   :     #07 pc 0001a095  /system/lib/libc.so (__start_thread+6)
08-23 22:54:44.972   509   509 F DEBUG   :
08-23 22:54:44.972   509   509 F DEBUG   : Tombstone written to: /data/tombstones/tombstone_06
08-23 22:54:44.972   509   509 E DEBUG   : AM write failed: Broken pipe
I've played around with some pieces of the code and can't determine how to fix the problem

Crash @ >> const void* configData = AAsset_getBuffer(configFileAsset);
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Android File System

Post by mongoose7 »

You didn't check the return from

AAsset* configFileAsset = AAssetManager_open(assetManager, (char*)fileName.c_str(), AASSET_MODE_BUFFER);
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

mongoose7 wrote:You didn't check the return from

AAsset* configFileAsset = AAssetManager_open(assetManager, (char*)fileName.c_str(), AASSET_MODE_BUFFER);
Good point. Any ideas to why that line might be failing?
mongoose7
Posts: 1227
Joined: Wed Apr 06, 2011 12:13 pm

Re: Android File System

Post by mongoose7 »

Print out fileName.c_str().
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

So if I create the file and build it into the APK, obviously it finds it, but if I want to write (save) a new .txt file on Android, it can't.
I've put the internal and external read/write rights in the manifest, and the correct permissions are visible on App Info on my phone.
It won't create a new file?
I've searched all over the internet for this and there is little to no information
LunaRebirth
Posts: 386
Joined: Sun May 11, 2014 12:13 am

Re: Android File System

Post by LunaRebirth »

Fails if the file doesn't already exist (can't create file):
Printed out --

Code: Select all

08-24 21:54:30.131 14168 14205 I Irrlicht: dataPath: /data/user/0/com.myapp/files
08-24 21:54:30.131 14168 14205 I Irrlicht: configFile: /data/user/0/com.myapp/files/myfile.txt
08-24 21:54:30.131 14168 14205 I Irrlicht: 'files/' dir already in app's internal data storage.
08-24 21:54:30.131 14168 14205 I Irrlicht: Application config file does not exist. Creating it ...
08-24 21:54:30.131 14168 14205 I Irrlicht: Reading config file using the asset manager.
08-24 21:54:30.131 14168 14205 I Irrlicht: configFileAsset failed.
Post Reply