CPUTFileSystem::CPUTandroidifstream::CPUTandroidifstream(const cString &fileName, std::ios_base::openmode mode) : iCPUTifstream(fileName, mode) { mpAsset = NULL; mpAssetDir = NULL; mbEOF = true; // Extract the file and dir int length = fileName.length(); int index = fileName.find_last_of("\\/"); cString file = fileName.substr(index + 1, (length - 1 - index)); cString dir = fileName.substr(0, index); // On Android, all files are in the APK and are compressed. // We do not have access to the standard file system, so // all files need streaming from memory through the android asset manager AAssetManager* assetManager = CPUTWindowAndroid::GetAppState()->activity->assetManager; mpAssetDir = AAssetManager_openDir(assetManager, dir.c_str()); if (!mpAssetDir) DEBUG_PRINT("Failed to load asset Dir"); const char* assetFileName = NULL; while ((assetFileName = AAssetDir_getNextFileName(mpAssetDir)) != NULL) { if (strcmp(file.c_str(), assetFileName) == 0) { // For some reason we need to pass in the fully pathed filename here, rather than the relative filename // that we have just been given. This feels like a bug in Android! mpAsset = AAssetManager_open(assetManager, fileName.c_str()/*assetFileName*/, AASSET_MODE_STREAMING); if (mpAsset) mbEOF = false; return; } } }
// Read the entire contents of a file and return a pointer/size to it //----------------------------------------------------------------------------- CPUTResult CPUTFileSystem::ReadFileContents(const cString &fileName, UINT *pSizeInBytes, void **ppData, bool bAddTerminator, bool bLoadAsBinary) { #ifdef CPUT_OS_ANDROID // Extract the file and dir int length = fileName.length(); int index = fileName.find_last_of("\\/"); cString file = fileName.substr(index + 1, (length - 1 - index)); cString dir = fileName.substr(0, index); DEBUG_PRINT("ReadFileContents(%s) : dir [%s], file [%s]", fileName.c_str(), dir.c_str(), file.c_str()); // On Android, all files are in the APK and are compressed. // We do not have access to the standard file system, so // all files need streaming from memory through the android asset manager AAssetManager* assetManager = CPUTWindowAndroid::GetAppState()->activity->assetManager; AAssetDir* assetDir = AAssetManager_openDir(assetManager, dir.c_str()); if (!assetDir) DEBUG_PRINT("Failed to load asset Dir"); const char* assetFileName = NULL; while ((assetFileName = AAssetDir_getNextFileName(assetDir)) != NULL) { if (strcmp(file.c_str(), assetFileName) == 0) { // For some reason we need to pass in the fully pathed filename here, rather than the relative filename // that we have just been given. This feels like a bug in Android! AAsset* asset = AAssetManager_open(assetManager, fileName.c_str()/*assetFileName*/, AASSET_MODE_STREAMING); if (!asset) { DEBUG_PRINT("Asset failed to load for file %s", fileName.c_str()); return CPUT_ERROR; } *pSizeInBytes = AAsset_getLength(asset); // allocate buffer if (bAddTerminator) *ppData = (void*) new char[*pSizeInBytes + 1]; else *ppData = (void*) new char[*pSizeInBytes]; if (!*ppData) { DEBUG_PRINT("Out of memory loading %s", fileName.c_str()); return CPUT_ERROR; } // read it all in int numBytesRead = AAsset_read(asset, *ppData, *pSizeInBytes); if (bAddTerminator) { ((char *)(*ppData))[numBytesRead++] = '\0'; *pSizeInBytes++; } ASSERT( numBytesRead == *pSizeInBytes, _L("File read byte count mismatch.") ); AAsset_close(asset); AAssetDir_close(assetDir); return CPUT_SUCCESS; } } AAssetDir_close(assetDir); #else FILE *pFile = NULL; if (bLoadAsBinary) { #if defined (UNICODE) || defined(_UNICODE) _wfopen_s(&pFile, fileName.c_str(), _L("r")); #else pFile = fopen(fileName.c_str(), "r"); #endif } else { #if defined (UNICODE) || defined(_UNICODE) _wfopen_s(&pFile, fileName.c_str(), _L("r")); #else pFile = fopen(fileName.c_str(), "r"); #endif } if(pFile) { // get file size fseek(pFile, 0, SEEK_END); *pSizeInBytes = ftell(pFile); fseek (pFile, 0, SEEK_SET); // allocate buffer *ppData = (void*) new char[*pSizeInBytes]; ASSERT( *ppData, _L("Out of memory") ); // read it all in UINT numBytesRead = (UINT) fread(*ppData, sizeof(char), *pSizeInBytes, pFile); if (bAddTerminator) { ((char *)(*ppData))[numBytesRead++] = '\0'; *pSizeInBytes++; } ASSERT( numBytesRead == *pSizeInBytes, _L("File read byte count mismatch.") ); // close and return fclose(pFile); return CPUT_SUCCESS; } #endif // some kind of file error, translate the error code and return it return CPUT_ERROR; // return TranslateFileError(err); }