#include #include #include #include "mpq-fs.h" #define MAX_FNAME 2048 typedef struct directory_list_t { struct directory_list_t * child; char * name; struct mpq_archive_t * mpq_a; int entry; struct directory_list_t * next; } directory_list; static directory_list root_dir = { NULL, "", NULL, -1, NULL }; static directory_list * root = &root_dir; static char * strtoupper(char * _str) { char * str = _str; while (*str) { *str = toupper(*str); str++; } return _str; } /* * The 'new' keyword is abusive: the function returns an existing entry if it matches, allowing overrites. */ static directory_list * new_directory_list(directory_list * parent, struct mpq_archive_t * mpq_a, const char * name) { directory_list * r; for (r = parent->child; r; r = r->next) { if (!strcasecmp(r->name, name)) break; } if (!r) { r = (directory_list *) malloc(sizeof(directory_list)); r->child = NULL; r->next = parent->child; parent->child = r; r->name = strtoupper(strdup(name)); } r->mpq_a = mpq_a; r->entry = -1; return r; } /* * Recursively adds a new entry into our directory structure. */ static directory_list * add_file_r(directory_list * parent, struct mpq_archive_t * mpq_a, char * fname, int entry) { char * bs; directory_list * r; int tail = 0; bs = strchr(fname, '\\'); if (bs) { *bs = 0; } else { tail = 1; } if (!(r = new_directory_list(parent, mpq_a, fname))) return NULL; if (tail) { r->entry = entry; return r; } return add_file_r(r, mpq_a, bs + 1, entry); } static directory_list * add_file(struct mpq_archive_t * mpq_a, char * fname) { int entry; if ((entry = mpqlib_find_hash_entry_by_name(mpq_a, fname, 0, 0)) < 0) return NULL; return add_file_r(root, mpq_a, fname, entry); } /* * Adds an opened archive file into the system, and try to automagically import the list file. */ void mpqlib_fs_add_archive(struct mpq_archive_t * mpq_a) { struct mpq_file_t * listfile; char * buffer; int s; if (!(listfile = mpqlib_open_filename(mpq_a, "(listfile)"))) return; s = mpqlib_seek(listfile, 0, MPQLIB_SEEK_END); mpqlib_seek(listfile, 0, MPQLIB_SEEK_SET); if (!(buffer = (char *) malloc(s + 1))) { mpqlib_close(listfile); return; } buffer[s] = 0; mpqlib_read(listfile, buffer, s); mpqlib_fs_attach_listfile(mpq_a, buffer); free(buffer); mpqlib_close(listfile); } /* * Generalistic function to add an archive to the directory structure using a custom listfile. */ void mpqlib_fs_attach_listfile(struct mpq_archive_t * mpq_a, const char * listfile) { char fname[MAX_FNAME]; const char * p; char * fnp; for (p = listfile, fnp = fname; *p; p++) { switch (*p) { /* Each entry in the listfile may be separated by CR, LF, and/or ';'. */ case '\r': case '\n': case ';': *fnp = 0; if (fnp != fname) add_file(mpq_a, fname); fnp = fname; break; default: *(fnp++) = *p; break; } } } /* * Recursively find a file. */ static directory_list * find_file_r(directory_list * parent, char * fname) { char * bs; directory_list * r; int tail = 0; bs = strchr(fname, '\\'); if (bs) { *bs = 0; } else { tail = 1; } for (r = parent->child; r; r = r->next) { if (!strcmp(fname, r->name)) { if (tail) { return r; } else { return find_file_r(r, bs + 1); } } } return NULL; } static directory_list * find_file(char * fname) { return find_file_r(root, fname); } struct mpq_file_t * mpqlib_fs_open(const char * _fname) { char * fname = strtoupper(strdup(_fname)); directory_list * entry; entry = find_file(fname); free(fname); if (entry) { return mpqlib_open_file(entry->mpq_a, entry->entry); } return NULL; }