X-Git-Url: https://git.artsoft.org/?p=rocksndiamonds.git;a=blobdiff_plain;f=src%2Flibgame%2Fsetup.c;h=c64c95c8ee84c6d5fdb17d6b110eaded193a01a7;hp=626bb1f9e2d2475074a7e2042127dea37cdcbf9a;hb=7270af24b41bc33fbb89a97227a7696e343eacbb;hpb=12a8fd3a64d6bee5ca5f5b89e4a00b49d78bbd2c diff --git a/src/libgame/setup.c b/src/libgame/setup.c index 626bb1f9..c64c95c8 100644 --- a/src/libgame/setup.c +++ b/src/libgame/setup.c @@ -28,6 +28,7 @@ #include "text.h" #include "misc.h" #include "hash.h" +#include "zip/miniunz.h" #define ENABLE_UNUSED_CODE FALSE // for currently unused functions @@ -177,7 +178,7 @@ static char *getNetworkDir(void) return network_dir; } -static char *getLevelDirFromTreeInfo(TreeInfo *node) +char *getLevelDirFromTreeInfo(TreeInfo *node) { static char *level_dir = NULL; @@ -339,7 +340,7 @@ static char *getClassicArtworkDir(int type) getDefaultMusicDir(MUS_CLASSIC_SUBDIR) : ""); } -static char *getUserGraphicsDir(void) +char *getUserGraphicsDir(void) { static char *usergraphics_dir = NULL; @@ -349,7 +350,7 @@ static char *getUserGraphicsDir(void) return usergraphics_dir; } -static char *getUserSoundsDir(void) +char *getUserSoundsDir(void) { static char *usersounds_dir = NULL; @@ -359,7 +360,7 @@ static char *getUserSoundsDir(void) return usersounds_dir; } -static char *getUserMusicDir(void) +char *getUserMusicDir(void) { static char *usermusic_dir = NULL; @@ -2981,6 +2982,223 @@ static void setArtworkInfoCacheEntry(TreeInfo *artwork_info, // functions for loading level info and custom artwork info // ---------------------------------------------------------------------------- +int GetZipFileTreeType(char *zip_filename) +{ + static char *top_dir_path = NULL; + static char *top_dir_conf_filename[NUM_BASE_TREE_TYPES] = { NULL }; + static char *conf_basename[NUM_BASE_TREE_TYPES] = + { + GRAPHICSINFO_FILENAME, + SOUNDSINFO_FILENAME, + MUSICINFO_FILENAME, + LEVELINFO_FILENAME + }; + int j; + + checked_free(top_dir_path); + top_dir_path = NULL; + + for (j = 0; j < NUM_BASE_TREE_TYPES; j++) + { + checked_free(top_dir_conf_filename[j]); + top_dir_conf_filename[j] = NULL; + } + + char **zip_entries = zip_list(zip_filename); + + // check if zip file successfully opened + if (zip_entries == NULL || zip_entries[0] == NULL) + return TREE_TYPE_UNDEFINED; + + // first zip file entry is expected to be top level directory + char *top_dir = zip_entries[0]; + + // check if valid top level directory found in zip file + if (!strSuffix(top_dir, "/")) + return TREE_TYPE_UNDEFINED; + + // get filenames of valid configuration files in top level directory + for (j = 0; j < NUM_BASE_TREE_TYPES; j++) + top_dir_conf_filename[j] = getStringCat2(top_dir, conf_basename[j]); + + int tree_type = TREE_TYPE_UNDEFINED; + int e = 0; + + while (zip_entries[e] != NULL) + { + // check if every zip file entry is below top level directory + if (!strPrefix(zip_entries[e], top_dir)) + return TREE_TYPE_UNDEFINED; + + // check if this zip file entry is a valid configuration filename + for (j = 0; j < NUM_BASE_TREE_TYPES; j++) + { + if (strEqual(zip_entries[e], top_dir_conf_filename[j])) + { + // only exactly one valid configuration file allowed + if (tree_type != TREE_TYPE_UNDEFINED) + return TREE_TYPE_UNDEFINED; + + tree_type = j; + } + } + + e++; + } + + return tree_type; +} + +static boolean CheckZipFileForDirectory(char *zip_filename, char *directory, + int tree_type) +{ + static char *top_dir_path = NULL; + static char *top_dir_conf_filename = NULL; + + checked_free(top_dir_path); + checked_free(top_dir_conf_filename); + + top_dir_path = NULL; + top_dir_conf_filename = NULL; + + char *conf_basename = (tree_type == TREE_TYPE_LEVEL_DIR ? LEVELINFO_FILENAME : + ARTWORKINFO_FILENAME(tree_type)); + + // check if valid configuration filename determined + if (conf_basename == NULL || strEqual(conf_basename, "")) + return FALSE; + + char **zip_entries = zip_list(zip_filename); + + // check if zip file successfully opened + if (zip_entries == NULL || zip_entries[0] == NULL) + return FALSE; + + // first zip file entry is expected to be top level directory + char *top_dir = zip_entries[0]; + + // check if valid top level directory found in zip file + if (!strSuffix(top_dir, "/")) + return FALSE; + + // get path of extracted top level directory + top_dir_path = getPath2(directory, top_dir); + + // remove trailing directory separator from top level directory path + // (required to be able to check for file and directory in next step) + top_dir_path[strlen(top_dir_path) - 1] = '\0'; + + // check if zip file's top level directory already exists in target directory + if (fileExists(top_dir_path)) // (checks for file and directory) + return FALSE; + + // get filename of configuration file in top level directory + top_dir_conf_filename = getStringCat2(top_dir, conf_basename); + + boolean found_top_dir_conf_filename = FALSE; + int i = 0; + + while (zip_entries[i] != NULL) + { + // check if every zip file entry is below top level directory + if (!strPrefix(zip_entries[i], top_dir)) + return FALSE; + + // check if this zip file entry is the configuration filename + if (strEqual(zip_entries[i], top_dir_conf_filename)) + found_top_dir_conf_filename = TRUE; + + i++; + } + + // check if valid configuration filename was found in zip file + if (!found_top_dir_conf_filename) + return FALSE; + + return TRUE; +} + +char *ExtractZipFileIntoDirectory(char *zip_filename, char *directory, + int tree_type) +{ + boolean zip_file_valid = CheckZipFileForDirectory(zip_filename, directory, + tree_type); + + if (!zip_file_valid) + { + Error(ERR_WARN, "zip file '%s' rejected!", zip_filename); + + return NULL; + } + + char **zip_entries = zip_extract(zip_filename, directory); + + if (zip_entries == NULL) + { + Error(ERR_WARN, "zip file '%s' could not be extracted!", zip_filename); + + return NULL; + } + + Error(ERR_INFO, "zip file '%s' successfully extracted!", zip_filename); + + // first zip file entry contains top level directory + char *top_dir = zip_entries[0]; + + // remove trailing directory separator from top level directory + top_dir[strlen(top_dir) - 1] = '\0'; + + return top_dir; +} + +static void ProcessZipFilesInDirectory(char *directory, int tree_type) +{ + Directory *dir; + DirectoryEntry *dir_entry; + + if ((dir = openDirectory(directory)) == NULL) + { + // display error if directory is main "options.graphics_directory" etc. + if (tree_type == TREE_TYPE_LEVEL_DIR || + directory == OPTIONS_ARTWORK_DIRECTORY(tree_type)) + Error(ERR_WARN, "cannot read directory '%s'", directory); + + return; + } + + while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries + { + // skip non-zip files (and also directories with zip extension) + if (!strSuffixLower(dir_entry->basename, ".zip") || dir_entry->is_directory) + continue; + + char *zip_filename = getPath2(directory, dir_entry->basename); + char *zip_filename_extracted = getStringCat2(zip_filename, ".extracted"); + char *zip_filename_rejected = getStringCat2(zip_filename, ".rejected"); + + // check if zip file hasn't already been extracted or rejected + if (!fileExists(zip_filename_extracted) && + !fileExists(zip_filename_rejected)) + { + char *top_dir = ExtractZipFileIntoDirectory(zip_filename, directory, + tree_type); + char *marker_filename = (top_dir != NULL ? zip_filename_extracted : + zip_filename_rejected); + FILE *marker_file; + + // create empty file to mark zip file as extracted or rejected + if ((marker_file = fopen(marker_filename, MODE_WRITE))) + fclose(marker_file); + + free(zip_filename); + free(zip_filename_extracted); + free(zip_filename_rejected); + } + } + + closeDirectory(dir); +} + // forward declaration for recursive call by "LoadLevelInfoFromLevelDir()" static void LoadLevelInfoFromLevelDir(TreeInfo **, TreeInfo *, char *); @@ -3108,6 +3326,12 @@ static void LoadLevelInfoFromLevelDir(TreeInfo **node_first, TreeInfo *node_parent, char *level_directory) { + // ---------- 1st stage: process any level set zip files ---------- + + ProcessZipFilesInDirectory(level_directory, TREE_TYPE_LEVEL_DIR); + + // ---------- 2nd stage: check for level set directories ---------- + Directory *dir; DirectoryEntry *dir_entry; boolean valid_entry_found = FALSE; @@ -3351,6 +3575,12 @@ static void LoadArtworkInfoFromArtworkDir(TreeInfo **node_first, TreeInfo *node_parent, char *base_directory, int type) { + // ---------- 1st stage: process any artwork set zip files ---------- + + ProcessZipFilesInDirectory(base_directory, type); + + // ---------- 2nd stage: check for artwork set directories ---------- + Directory *dir; DirectoryEntry *dir_entry; boolean valid_entry_found = FALSE; @@ -3630,13 +3860,29 @@ void LoadLevelArtworkInfo(void) print_timestamp_done("LoadLevelArtworkInfo"); } -static boolean AddUserLevelSetToLevelInfoExt(char *level_subdir_new) +static boolean AddTreeSetToTreeInfoExt(TreeInfo *tree_node_old, char *tree_dir, + char *tree_subdir_new, int type) { - // get level info tree node of first (original) user level set - char *level_subdir_old = getLoginName(); - LevelDirTree *leveldir_old = getTreeInfoFromIdentifier(leveldir_first, - level_subdir_old); - if (leveldir_old == NULL) // should not happen + if (tree_node_old == NULL) + { + if (type == TREE_TYPE_LEVEL_DIR) + { + // get level info tree node of personal user level set + tree_node_old = getTreeInfoFromIdentifier(leveldir_first, getLoginName()); + } + else + { + // get artwork info tree node of first artwork set + tree_node_old = ARTWORK_FIRST_NODE(artwork, type); + } + } + + if (tree_dir == NULL) + tree_dir = TREE_USERDIR(type); + + if (tree_node_old == NULL || + tree_dir == NULL || + tree_subdir_new == NULL) // should not happen return FALSE; int draw_deactivation_mask = GetDrawDeactivationMask(); @@ -3644,33 +3890,54 @@ static boolean AddUserLevelSetToLevelInfoExt(char *level_subdir_new) // override draw deactivation mask (temporarily disable drawing) SetDrawDeactivationMask(REDRAW_ALL); - // load new level set config and add it next to first user level set - LoadLevelInfoFromLevelConf(&leveldir_old->next, NULL, - leveldir_old->basepath, level_subdir_new); + if (type == TREE_TYPE_LEVEL_DIR) + { + // load new level set config and add it next to first user level set + LoadLevelInfoFromLevelConf(&tree_node_old->next, + tree_node_old->node_parent, + tree_dir, tree_subdir_new); + } + else + { + // load new artwork set config and add it next to first artwork set + LoadArtworkInfoFromArtworkConf(&tree_node_old->next, + tree_node_old->node_parent, + tree_dir, tree_subdir_new, type); + } // set draw deactivation mask to previous value SetDrawDeactivationMask(draw_deactivation_mask); - // get level info tree node of newly added user level set - LevelDirTree *leveldir_new = getTreeInfoFromIdentifier(leveldir_first, - level_subdir_new); - if (leveldir_new == NULL) // should not happen + // get first node of level or artwork info tree + TreeInfo **tree_node_first = TREE_FIRST_NODE_PTR(type); + + // get tree info node of newly added level or artwork set + TreeInfo *tree_node_new = getTreeInfoFromIdentifier(*tree_node_first, + tree_subdir_new); + + if (tree_node_new == NULL) // should not happen return FALSE; // correct top link and parent node link of newly created tree node - leveldir_new->node_top = leveldir_old->node_top; - leveldir_new->node_parent = leveldir_old->node_parent; + tree_node_new->node_top = tree_node_old->node_top; + tree_node_new->node_parent = tree_node_old->node_parent; - // sort level info tree to adjust position of newly added level set - sortTreeInfo(&leveldir_first); + // sort tree info to adjust position of newly added tree set + sortTreeInfo(tree_node_first); return TRUE; } +void AddTreeSetToTreeInfo(TreeInfo *tree_node, char *tree_dir, + char *tree_subdir_new, int type) +{ + if (!AddTreeSetToTreeInfoExt(tree_node, tree_dir, tree_subdir_new, type)) + Error(ERR_EXIT, "internal tree info structure corrupted -- aborting"); +} + void AddUserLevelSetToLevelInfo(char *level_subdir_new) { - if (!AddUserLevelSetToLevelInfoExt(level_subdir_new)) - Error(ERR_EXIT, "internal level set structure corrupted -- aborting"); + AddTreeSetToTreeInfo(NULL, NULL, level_subdir_new, TREE_TYPE_LEVEL_DIR); } char *getArtworkIdentifierForUserLevelSet(int type) @@ -4069,6 +4336,11 @@ static void checkSeriesInfo(void) { static char *level_directory = NULL; Directory *dir; +#if 0 + DirectoryEntry *dir_entry; +#endif + + checked_free(level_directory); // check for more levels besides the 'levels' field of 'levelinfo.conf' @@ -4084,6 +4356,35 @@ static void checkSeriesInfo(void) return; } +#if 0 + while ((dir_entry = readDirectory(dir)) != NULL) // loop all entries + { + if (strlen(dir_entry->basename) > 4 && + dir_entry->basename[3] == '.' && + strEqual(&dir_entry->basename[4], LEVELFILE_EXTENSION)) + { + char levelnum_str[4]; + int levelnum_value; + + strncpy(levelnum_str, dir_entry->basename, 3); + levelnum_str[3] = '\0'; + + levelnum_value = atoi(levelnum_str); + + if (levelnum_value < leveldir_current->first_level) + { + Error(ERR_WARN, "additional level %d found", levelnum_value); + leveldir_current->first_level = levelnum_value; + } + else if (levelnum_value > leveldir_current->last_level) + { + Error(ERR_WARN, "additional level %d found", levelnum_value); + leveldir_current->last_level = levelnum_value; + } + } + } +#endif + closeDirectory(dir); }