+void dumpList(ListNode *node_first)
+{
+ ListNode *node = node_first;
+
+ while (node)
+ {
+ printf("['%s' (%d)]\n", node->key,
+ ((struct ListNodeInfo *)node->content)->num_references);
+ node = node->next;
+ }
+
+ printf("[%d nodes]\n", getNumNodes(node_first));
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* functions for reading directories */
+/* ------------------------------------------------------------------------- */
+
+struct Directory *openDirectory(char *dir_name)
+{
+ struct Directory *dir = checked_calloc(sizeof(struct 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(struct Directory *dir)
+{
+ if (dir == NULL)
+ return -1;
+
+ int result;
+
+#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;
+}
+
+struct DirectoryEntry *readDirectory(struct 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;
+ char *last_line_ptr = line_ptr;
+ int num_bytes_read = 0;
+
+ while (num_bytes_read < MAX_LINE_LEN &&
+ SDL_RWread(dir->asset_toc_file, line_ptr, 1, 1) == 1 &&
+ *line_ptr != '\n')
+ {
+ last_line_ptr = line_ptr;
+ line_ptr++;
+ num_bytes_read++;
+ }
+
+ *line_ptr = '\0';
+
+ if (strlen(line) == 0)
+ return NULL;
+
+ dir->dir_entry = checked_calloc(sizeof(struct 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(struct 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 &&
+ (file_status.st_mode & S_IFMT) != S_IFDIR);
+
+ return dir->dir_entry;
+}
+
+void freeDirectoryEntry(struct DirectoryEntry *dir_entry)