X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Flibgame%2Fmisc.c;h=b3edef75f1bbf367d8a8d244ad6ef3b67a3ac8c8;hb=4311b2aed4570447d0e082334e8b8a6b7da6e9f9;hp=1e481dc3f37041b2d08dfa1112e59af6b1180e94;hpb=f2c89dee62e731d161c6e2b3e6a0471a4609fb87;p=rocksndiamonds.git diff --git a/src/libgame/misc.c b/src/libgame/misc.c index 1e481dc3..b3edef75 100644 --- a/src/libgame/misc.c +++ b/src/libgame/misc.c @@ -473,7 +473,8 @@ void GetOptions(char *argv[]) " -l, --level directory alternative level directory\n" " -s, --serveronly only start network server\n" " -n, --network network multiplayer game\n" - " -v, --verbose verbose mode\n", + " -v, --verbose verbose mode\n" + " --debug display debugging information\n", program.command_basename); exit(0); } @@ -700,28 +701,46 @@ void putFile32BitInteger(FILE *file, int value, int byte_order) } } -boolean getFileChunk(FILE *file, char *chunk_buffer, int *chunk_length, +boolean getFileChunk(FILE *file, char *chunk_name, int *chunk_size, int byte_order) { - const int chunk_identifier_length = 4; + const int chunk_name_length = 4; - /* read chunk identifier */ - fgets(chunk_buffer, chunk_identifier_length + 1, file); + /* read chunk name */ + fgets(chunk_name, chunk_name_length + 1, file); - /* read chunk length */ - *chunk_length = getFile32BitInteger(file, byte_order); + if (chunk_size != NULL) + { + /* read chunk size */ + *chunk_size = getFile32BitInteger(file, byte_order); + } return (feof(file) || ferror(file) ? FALSE : TRUE); } -void putFileChunk(FILE *file, char *chunk_name, int chunk_length, +void putFileChunk(FILE *file, char *chunk_name, int chunk_size, int byte_order) { - /* write chunk identifier */ + /* write chunk name */ fputs(chunk_name, file); - /* write chunk length */ - putFile32BitInteger(file, chunk_length, byte_order); + if (chunk_size >= 0) + { + /* write chunk size */ + putFile32BitInteger(file, chunk_size, byte_order); + } +} + +void ReadUnusedBytesFromFile(FILE *file, unsigned long bytes) +{ + while (bytes--) + fgetc(file); +} + +void WriteUnusedBytesToFile(FILE *file, unsigned long bytes) +{ + while (bytes--) + fputc(0, file); } #define TRANSLATE_KEYSYM_TO_KEYNAME 0 @@ -1268,10 +1287,41 @@ inline void swap_number_pairs(int *x1, int *y1, int *x2, int *y2) /* some stuff from "files.c" */ /* ========================================================================= */ +#if defined(PLATFORM_WIN32) +#ifndef S_IRGRP +#define S_IRGRP S_IRUSR +#endif +#ifndef S_IROTH +#define S_IROTH S_IRUSR +#endif +#ifndef S_IWGRP +#define S_IWGRP S_IWUSR +#endif +#ifndef S_IWOTH +#define S_IWOTH S_IWUSR +#endif +#ifndef S_IXGRP +#define S_IXGRP S_IXUSR +#endif +#ifndef S_IXOTH +#define S_IXOTH S_IXUSR +#endif +#endif /* PLATFORM_WIN32 */ + +/* file permissions for newly written files */ #define MODE_R_ALL (S_IRUSR | S_IRGRP | S_IROTH) #define MODE_W_ALL (S_IWUSR | S_IWGRP | S_IWOTH) #define MODE_X_ALL (S_IXUSR | S_IXGRP | S_IXOTH) -#define USERDATA_DIR_MODE (MODE_R_ALL | MODE_X_ALL | S_IWUSR) + +#define MODE_W_PRIVATE (S_IWUSR) +#define MODE_W_PUBLIC (S_IWUSR | S_IWGRP) +#define MODE_W_PUBLIC_DIR (S_IWUSR | S_IWGRP | S_ISGID) + +#define DIR_PERMS_PRIVATE (MODE_R_ALL | MODE_X_ALL | MODE_W_PRIVATE) +#define DIR_PERMS_PUBLIC (MODE_R_ALL | MODE_X_ALL | MODE_W_PUBLIC_DIR) + +#define FILE_PERMS_PRIVATE (MODE_R_ALL | MODE_W_PRIVATE) +#define FILE_PERMS_PUBLIC (MODE_R_ALL | MODE_W_PUBLIC) char *getUserDataDir(void) { @@ -1288,20 +1338,350 @@ char *getUserDataDir(void) return userdata_dir; } -void createDirectory(char *dir, char *text) +char *getSetupDir() { + return getUserDataDir(); +} + +void createDirectory(char *dir, char *text, int permission_class) +{ +#if defined(PLATFORM_UNIX) + /* leave "other" permissions in umask untouched, but ensure group parts + of USERDATA_DIR_MODE are not masked */ + mode_t dir_mode = (permission_class == PERMS_PRIVATE ? + DIR_PERMS_PRIVATE : DIR_PERMS_PUBLIC); + mode_t normal_umask = umask(0); + mode_t group_umask = ~(dir_mode & S_IRWXG); + umask(normal_umask & group_umask); +#endif + if (access(dir, F_OK) != 0) #if defined(PLATFORM_WIN32) if (mkdir(dir) != 0) #else - if (mkdir(dir, USERDATA_DIR_MODE) != 0) + if (mkdir(dir, dir_mode) != 0) #endif Error(ERR_WARN, "cannot create %s directory '%s'", text, dir); + +#if defined(PLATFORM_UNIX) + umask(normal_umask); /* reset normal umask */ +#endif } void InitUserDataDirectory() { - createDirectory(getUserDataDir(), "user data"); + createDirectory(getUserDataDir(), "user data", PERMS_PRIVATE); +} + +void SetFilePermissions(char *filename, int permission_class) +{ + chmod(filename, (permission_class == PERMS_PRIVATE ? + FILE_PERMS_PRIVATE : FILE_PERMS_PUBLIC)); +} + +int getFileVersionFromCookieString(const char *cookie) +{ + const char *ptr_cookie1, *ptr_cookie2; + const char *pattern1 = "_FILE_VERSION_"; + const char *pattern2 = "?.?"; + const int len_cookie = strlen(cookie); + const int len_pattern1 = strlen(pattern1); + const int len_pattern2 = strlen(pattern2); + const int len_pattern = len_pattern1 + len_pattern2; + int version_major, version_minor; + + if (len_cookie <= len_pattern) + return -1; + + ptr_cookie1 = &cookie[len_cookie - len_pattern]; + ptr_cookie2 = &cookie[len_cookie - len_pattern2]; + + if (strncmp(ptr_cookie1, pattern1, len_pattern1) != 0) + return -1; + + if (ptr_cookie2[0] < '0' || ptr_cookie2[0] > '9' || + ptr_cookie2[1] != '.' || + ptr_cookie2[2] < '0' || ptr_cookie2[2] > '9') + return -1; + + version_major = ptr_cookie2[0] - '0'; + version_minor = ptr_cookie2[2] - '0'; + + return VERSION_IDENT(version_major, version_minor, 0); +} + +boolean checkCookieString(const char *cookie, const char *template) +{ + const char *pattern = "_FILE_VERSION_?.?"; + const int len_cookie = strlen(cookie); + const int len_template = strlen(template); + const int len_pattern = strlen(pattern); + + if (len_cookie != len_template) + return FALSE; + + if (strncmp(cookie, template, len_cookie - len_pattern) != 0) + return FALSE; + + return TRUE; +} + +/* ------------------------------------------------------------------------- */ +/* setup file stuff */ +/* ------------------------------------------------------------------------- */ + +static char *string_tolower(char *s) +{ + static char s_lower[100]; + int i; + + if (strlen(s) >= 100) + return s; + + strcpy(s_lower, s); + + for (i=0; itoken) + free(setup_file_list->token); + if (setup_file_list->value) + free(setup_file_list->value); + if (setup_file_list->next) + freeSetupFileList(setup_file_list->next); + free(setup_file_list); +} + +static struct SetupFileList *newSetupFileList(char *token, char *value) +{ + struct SetupFileList *new = checked_malloc(sizeof(struct SetupFileList)); + + new->token = checked_malloc(strlen(token) + 1); + strcpy(new->token, token); + + new->value = checked_malloc(strlen(value) + 1); + strcpy(new->value, value); + + new->next = NULL; + + return new; +} + +char *getTokenValue(struct SetupFileList *setup_file_list, char *token) +{ + if (!setup_file_list) + return NULL; + + if (strcmp(setup_file_list->token, token) == 0) + return setup_file_list->value; + else + return getTokenValue(setup_file_list->next, token); +} + +static void setTokenValue(struct SetupFileList *setup_file_list, + char *token, char *value) +{ + if (!setup_file_list) + return; + + if (strcmp(setup_file_list->token, token) == 0) + { + free(setup_file_list->value); + setup_file_list->value = checked_malloc(strlen(value) + 1); + strcpy(setup_file_list->value, value); + } + else if (setup_file_list->next == NULL) + setup_file_list->next = newSetupFileList(token, value); + else + setTokenValue(setup_file_list->next, token, value); +} + +#ifdef DEBUG +static void printSetupFileList(struct SetupFileList *setup_file_list) +{ + if (!setup_file_list) + return; + + printf("token: '%s'\n", setup_file_list->token); + printf("value: '%s'\n", setup_file_list->value); + + printSetupFileList(setup_file_list->next); +} +#endif + +struct SetupFileList *loadSetupFileList(char *filename) +{ + int line_len; + char line[MAX_LINE_LEN]; + char *token, *value, *line_ptr; + struct SetupFileList *setup_file_list = newSetupFileList("", ""); + struct SetupFileList *first_valid_list_entry; + + FILE *file; + + if (!(file = fopen(filename, MODE_READ))) + { + Error(ERR_WARN, "cannot open configuration file '%s'", filename); + return NULL; + } + + while(!feof(file)) + { + /* read next line of input file */ + if (!fgets(line, MAX_LINE_LEN, file)) + break; + + /* cut trailing comment or whitespace from input line */ + for (line_ptr = line; *line_ptr; line_ptr++) + { + if (*line_ptr == '#' || *line_ptr == '\n' || *line_ptr == '\r') + { + *line_ptr = '\0'; + break; + } + } + + /* cut trailing whitespaces from input line */ + for (line_ptr = &line[strlen(line)]; line_ptr > line; line_ptr--) + if ((*line_ptr == ' ' || *line_ptr == '\t') && line_ptr[1] == '\0') + *line_ptr = '\0'; + + /* ignore empty lines */ + if (*line == '\0') + continue; + + line_len = strlen(line); + + /* cut leading whitespaces from token */ + for (token = line; *token; token++) + if (*token != ' ' && *token != '\t') + break; + + /* find end of token */ + for (line_ptr = token; *line_ptr; line_ptr++) + { + if (*line_ptr == ' ' || *line_ptr == '\t' || *line_ptr == ':') + { + *line_ptr = '\0'; + break; + } + } + + if (line_ptr < line + line_len) + value = line_ptr + 1; + else + value = "\0"; + + /* cut leading whitespaces from value */ + for (; *value; value++) + if (*value != ' ' && *value != '\t') + break; + + if (*token && *value) + setTokenValue(setup_file_list, token, value); + } + + fclose(file); + + first_valid_list_entry = setup_file_list->next; + + /* free empty list header */ + setup_file_list->next = NULL; + freeSetupFileList(setup_file_list); + + if (first_valid_list_entry == NULL) + Error(ERR_WARN, "configuration file '%s' is empty", filename); + + return first_valid_list_entry; +} + +void checkSetupFileListIdentifier(struct SetupFileList *setup_file_list, + char *identifier) +{ + if (!setup_file_list) + return; + + if (strcmp(setup_file_list->token, TOKEN_STR_FILE_IDENTIFIER) == 0) + { + if (strcmp(setup_file_list->value, identifier) != 0) + { + Error(ERR_WARN, "configuration file has wrong version"); + return; + } + else + return; + } + + if (setup_file_list->next) + checkSetupFileListIdentifier(setup_file_list->next, identifier); + else + { + Error(ERR_WARN, "configuration file has no version information"); + return; + } }