+ return file;
+ }
+
+#if defined(PLATFORM_ANDROID)
+ file->asset_file = SDL_RWFromFile(filename, mode);
+
+ if (file->asset_file != NULL)
+ {
+ file->file_is_asset = TRUE;
+ file->filename = getStringCopy(filename);
+
+ return file;
+ }
+#endif
+
+ checked_free(file);
+
+ return NULL;
+}
+
+int closeFile(File *file)
+{
+ if (file == NULL)
+ return -1;
+
+ int result = 0;
+
+#if defined(PLATFORM_ANDROID)
+ if (file->asset_file)
+ result = SDL_RWclose(file->asset_file);
+#endif
+
+ if (file->file)
+ result = fclose(file->file);
+
+ checked_free(file->filename);
+ checked_free(file);
+
+ return result;
+}
+
+int checkEndOfFile(File *file)
+{
+#if defined(PLATFORM_ANDROID)
+ if (file->file_is_asset)
+ return file->end_of_file;
+#endif
+
+ return feof(file->file);
+}
+
+size_t readFile(File *file, void *buffer, size_t item_size, size_t num_items)
+{
+#if defined(PLATFORM_ANDROID)
+ if (file->file_is_asset)
+ {
+ if (file->end_of_file)
+ return 0;
+
+ size_t num_items_read =
+ SDL_RWread(file->asset_file, buffer, item_size, num_items);
+
+ if (num_items_read < num_items)
+ file->end_of_file = TRUE;
+
+ return num_items_read;
+ }
+#endif
+
+ return fread(buffer, item_size, num_items, file->file);
+}
+
+int seekFile(File *file, long offset, int whence)
+{
+#if defined(PLATFORM_ANDROID)
+ if (file->file_is_asset)
+ {
+ int sdl_whence = (whence == SEEK_SET ? RW_SEEK_SET :
+ whence == SEEK_CUR ? RW_SEEK_CUR :
+ whence == SEEK_END ? RW_SEEK_END : 0);
+
+ return (SDL_RWseek(file->asset_file, offset, sdl_whence) == -1 ? -1 : 0);
+ }
+#endif
+
+ return fseek(file->file, offset, whence);
+}
+
+int getByteFromFile(File *file)
+{
+#if defined(PLATFORM_ANDROID)
+ if (file->file_is_asset)
+ {
+ if (file->end_of_file)
+ return EOF;
+
+ byte c;
+ size_t num_bytes_read = SDL_RWread(file->asset_file, &c, 1, 1);
+
+ if (num_bytes_read < 1)
+ file->end_of_file = TRUE;
+
+ return (file->end_of_file ? EOF : (int)c);
+ }
+#endif
+
+ return fgetc(file->file);
+}
+
+char *getStringFromFile(File *file, char *line, int size)
+{
+#if defined(PLATFORM_ANDROID)
+ if (file->file_is_asset)
+ {
+ if (file->end_of_file)
+ return NULL;
+
+ char *line_ptr = line;
+ int num_bytes_read = 0;
+
+ while (num_bytes_read < size - 1 &&
+ SDL_RWread(file->asset_file, line_ptr, 1, 1) == 1 &&
+ *line_ptr++ != '\n')
+ num_bytes_read++;
+
+ *line_ptr = '\0';
+
+ if (strlen(line) == 0)
+ {
+ file->end_of_file = TRUE;
+
+ return NULL;
+ }
+
+ return line;
+ }
+#endif
+
+ return fgets(line, size, file->file);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for directory handling */
+/* ------------------------------------------------------------------------- */
+
+Directory *openDirectory(char *dir_name)
+{
+ Directory *dir = checked_calloc(sizeof(Directory));
+
+ dir->dir = opendir(dir_name);
+
+ if (dir->dir != NULL)
+ {
+ dir->filename = getStringCopy(dir_name);
+
+ return dir;
+ }
+
+#if defined(PLATFORM_ANDROID)
+ char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME);
+
+ dir->asset_toc_file = SDL_RWFromFile(asset_toc_filename, MODE_READ);
+
+ checked_free(asset_toc_filename);
+
+ if (dir->asset_toc_file != NULL)
+ {
+ dir->directory_is_asset = TRUE;
+ dir->filename = getStringCopy(dir_name);
+
+ return dir;
+ }
+#endif
+
+ checked_free(dir);
+
+ return NULL;
+}
+
+int closeDirectory(Directory *dir)
+{
+ if (dir == NULL)
+ return -1;
+
+ int result = 0;
+
+#if defined(PLATFORM_ANDROID)
+ if (dir->asset_toc_file)
+ result = SDL_RWclose(dir->asset_toc_file);
+#endif
+
+ if (dir->dir)
+ result = closedir(dir->dir);
+
+ if (dir->dir_entry)
+ freeDirectoryEntry(dir->dir_entry);
+
+ checked_free(dir->filename);
+ checked_free(dir);
+
+ return result;
+}
+
+DirectoryEntry *readDirectory(Directory *dir)
+{
+ if (dir->dir_entry)
+ freeDirectoryEntry(dir->dir_entry);
+
+ dir->dir_entry = NULL;
+
+#if defined(PLATFORM_ANDROID)
+ if (dir->directory_is_asset)
+ {
+ char line[MAX_LINE_LEN];
+ char *line_ptr = line;
+ int num_bytes_read = 0;
+
+ while (num_bytes_read < MAX_LINE_LEN - 1 &&
+ SDL_RWread(dir->asset_toc_file, line_ptr, 1, 1) == 1 &&
+ *line_ptr != '\n')
+ {
+ line_ptr++;
+ num_bytes_read++;
+ }
+
+ *line_ptr = '\0';
+
+ if (strlen(line) == 0)
+ return NULL;
+
+ dir->dir_entry = checked_calloc(sizeof(DirectoryEntry));
+
+ dir->dir_entry->is_directory = FALSE;
+ if (line[strlen(line) - 1] == '/')
+ {
+ dir->dir_entry->is_directory = TRUE;
+
+ line[strlen(line) - 1] = '\0';
+ }
+
+ dir->dir_entry->basename = getStringCopy(line);
+ dir->dir_entry->filename = getPath2(dir->filename, line);
+
+ return dir->dir_entry;
+ }
+#endif
+
+ struct dirent *dir_entry = readdir(dir->dir);
+
+ if (dir_entry == NULL)
+ return NULL;
+
+ dir->dir_entry = checked_calloc(sizeof(DirectoryEntry));
+
+ dir->dir_entry->basename = getStringCopy(dir_entry->d_name);
+ dir->dir_entry->filename = getPath2(dir->filename, dir_entry->d_name);
+
+ struct stat file_status;
+
+ dir->dir_entry->is_directory =
+ (stat(dir->dir_entry->filename, &file_status) == 0 &&
+ S_ISDIR(file_status.st_mode));
+
+ return dir->dir_entry;
+}
+
+void freeDirectoryEntry(DirectoryEntry *dir_entry)
+{
+ if (dir_entry == NULL)
+ return;
+
+ checked_free(dir_entry->basename);
+ checked_free(dir_entry->filename);
+ checked_free(dir_entry);
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for checking files and filenames */
+/* ------------------------------------------------------------------------- */
+
+boolean directoryExists(char *dir_name)
+{
+ if (dir_name == NULL)
+ return FALSE;
+
+ struct stat file_status;
+ boolean success = (stat(dir_name, &file_status) == 0 &&
+ S_ISDIR(file_status.st_mode));
+
+#if defined(PLATFORM_ANDROID)
+ if (!success)
+ {
+ // this might be an asset directory; check by trying to open toc file
+ char *asset_toc_filename = getPath2(dir_name, ASSET_TOC_BASENAME);
+ SDL_RWops *file = SDL_RWFromFile(asset_toc_filename, MODE_READ);
+
+ checked_free(asset_toc_filename);
+
+ success = (file != NULL);
+
+ if (success)
+ SDL_RWclose(file);
+ }
+#endif
+
+ return success;
+}
+
+boolean fileExists(char *filename)
+{
+ if (filename == NULL)
+ return FALSE;
+
+ boolean success = (access(filename, F_OK) == 0);
+
+#if defined(PLATFORM_ANDROID)
+ if (!success)
+ {
+ // this might be an asset file; check by trying to open it
+ SDL_RWops *file = SDL_RWFromFile(filename, MODE_READ);
+
+ success = (file != NULL);
+
+ if (success)
+ SDL_RWclose(file);
+ }
+#endif
+
+ return success;
+}
+
+boolean fileHasPrefix(char *basename, char *prefix)
+{
+ static char *basename_lower = NULL;
+ int basename_length, prefix_length;