X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;ds=sidebyside;f=src%2Ffiles.c;h=cb1199d340bb58212659431caadeb900800719ca;hb=05651fcbc154b1d8321d6e4e9374cfcdd274feda;hp=c14b9d994ec128b1c451f2bd87a96ec71792bcd8;hpb=c878cb2be6a0bffee850bf4f2dcb1939d5d2cd4f;p=rocksndiamonds.git diff --git a/src/files.c b/src/files.c index c14b9d99..cb1199d3 100644 --- a/src/files.c +++ b/src/files.c @@ -22,7 +22,17 @@ #include "tape.h" #include "joystick.h" -#define MAX_LINE_LEN 1000 +#define MAX_LINE_LEN 1000 /* file input line length */ +#define CHUNK_ID_LEN 4 /* IFF style chunk id length */ +#define LEVEL_HEADER_SIZE 80 /* size of level file header */ +#define LEVEL_HEADER_UNUSED 18 /* unused level header bytes */ +#define TAPE_HEADER_SIZE 20 /* size of tape file header */ +#define TAPE_HEADER_UNUSED 7 /* unused tape header bytes */ +#define FILE_VERSION_1_0 10 /* old 1.0 file version */ +#define FILE_VERSION_1_2 12 /* actual file version */ + +static void SaveUserLevelInfo(); /* for 'InitUserLevelDir()' */ +static char *getSetupLine(char *, int); /* for 'SaveUserLevelInfo()' */ static char *getGlobalDataDir() { @@ -50,6 +60,23 @@ static char *getSetupDir() return getUserDataDir(); } +static char *getUserLevelDir(char *level_subdir) +{ + static char *userlevel_dir = NULL; + char *data_dir = getUserDataDir(); + char *userlevel_subdir = LEVELS_DIRECTORY; + + if (userlevel_dir) + free(userlevel_dir); + + userlevel_dir = checked_malloc(strlen(data_dir) + strlen(userlevel_subdir) + + strlen(level_subdir) + 3); + sprintf(userlevel_dir, "%s/%s%s%s", data_dir, userlevel_subdir, + (strlen(level_subdir) > 0 ? "/" : ""), level_subdir); + + return userlevel_dir; +} + static char *getTapeDir(char *level_subdir) { static char *tape_dir = NULL; @@ -108,94 +135,154 @@ static void InitScoreDirectory(char *level_subdir) createDirectory(getScoreDir(level_subdir), "level score"); } +static void InitUserLevelDirectory(char *level_subdir) +{ + if (access(getUserLevelDir(level_subdir), F_OK) != 0) + { + createDirectory(getUserLevelDir(""), "main user level"); + createDirectory(getUserLevelDir(level_subdir), "user level"); + + SaveUserLevelInfo(); + } +} + +static void setLevelInfoToDefaults() +{ + int i, x, y; + + lev_fieldx = level.fieldx = STD_LEV_FIELDX; + lev_fieldy = level.fieldy = STD_LEV_FIELDY; + + for(x=0; x 0 && cookie[strlen(cookie) - 1] == '\n') + cookie[strlen(cookie) - 1] = '\0'; + + if (strcmp(cookie, LEVEL_COOKIE_10) == 0) /* old 1.0 level format */ + file_version = FILE_VERSION_1_0; + else if (strcmp(cookie, LEVEL_COOKIE) != 0) /* unknown level format */ { - fgets(cookie, LEVEL_COOKIE_LEN, file); - fgetc(file); + Error(ERR_WARN, "wrong file identifier of level file '%s'", filename); + fclose(file); + return; + } - if (strcmp(cookie,LEVEL_COOKIE)) + /* read chunk "HEAD" */ + if (file_version >= FILE_VERSION_1_2) + { + /* first check header chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + if (strcmp(chunk, "HEAD") || chunk_length != LEVEL_HEADER_SIZE) { - Error(ERR_WARN, "wrong format of level file '%s'", filename); + Error(ERR_WARN, "wrong 'HEAD' chunk of level file '%s'", filename); fclose(file); - file = NULL; + return; } } - if (file) - { - lev_fieldx = level.fieldx = fgetc(file); - lev_fieldy = level.fieldy = fgetc(file); - - level.time = (fgetc(file)<<8) | fgetc(file); - level.edelsteine = (fgetc(file)<<8) | fgetc(file); - for(i=0; i= FILE_VERSION_1_2) { - lev_fieldx = level.fieldx = STD_LEV_FIELDX; - lev_fieldy = level.fieldy = STD_LEV_FIELDY; - - level.time = 100; - level.edelsteine = 0; - strcpy(level.name, "Nameless Level"); - for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); fputc(level.fieldx, file); fputc(level.fieldy, file); @@ -236,9 +337,17 @@ void SaveLevel(int level_nr) fputc(level.dauer_ablenk, file); fputc(level.amoebe_inhalt, file); - for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); + for(y=0; y 0 && cookie[strlen(cookie) - 1] == '\n') + cookie[strlen(cookie) - 1] = '\0'; + + if (strcmp(cookie, TAPE_COOKIE_10) == 0) /* old 1.0 tape format */ + file_version = FILE_VERSION_1_0; + else if (strcmp(cookie, TAPE_COOKIE) != 0) /* unknown tape format */ { - fgets(cookie, LEVELREC_COOKIE_LEN, file); - fgetc(file); - if (!strcmp(cookie, LEVELREC_COOKIE_10)) /* old 1.0 tape format */ - levelrec_10 = TRUE; - else if (strcmp(cookie, LEVELREC_COOKIE)) /* unknown tape format */ + Error(ERR_WARN, "wrong file identifier of tape file '%s'", filename); + fclose(file); + return; + } + + /* read chunk "HEAD" */ + if (file_version >= FILE_VERSION_1_2) + { + /* first check header chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + + if (strcmp(chunk, "HEAD") || chunk_length != TAPE_HEADER_SIZE) { - Error(ERR_WARN, "wrong format of level recording file '%s'", filename); + Error(ERR_WARN, "wrong 'HEAD' chunk of tape file '%s'", filename); fclose(file); - file = NULL; + return; } } - if (!file) - return; - tape.random_seed = (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); tape.date = @@ -284,6 +413,28 @@ void LoadTape(int level_nr) tape.length = (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + /* read header fields that are new since version 1.2 */ + if (file_version >= FILE_VERSION_1_2) + { + byte store_participating_players = fgetc(file); + + for(i=0; i= FILE_VERSION_1_2) { - int j; + /* next check body chunk identifier and chunk length */ + fgets(chunk, CHUNK_ID_LEN + 1, file); + chunk_length = + (fgetc(file)<<24) | (fgetc(file)<<16) | (fgetc(file)<<8) | fgetc(file); + if (strcmp(chunk, "BODY") || + chunk_length != (num_participating_players + 1) * tape.length) + { + Error(ERR_WARN, "wrong 'BODY' chunk of tape file '%s'", filename); + fclose(file); + return; + } + } + for(i=0; i= MAX_TAPELEN) break; for(j=0; j 0) - { - tape.pos[i].action[j] = MV_NO_MOVING; + tape.pos[i].action[j] = MV_NO_MOVING; + + /* pre-1.2 tapes store data for only one player */ + if (file_version == FILE_VERSION_1_0 && j > 0) continue; - } - tape.pos[i].action[j] = fgetc(file); + + if (player_participates[j]) + tape.pos[i].action[j] = fgetc(file); } tape.pos[i].delay = fgetc(file); - if (levelrec_10) + if (file_version == FILE_VERSION_1_0) { /* eliminate possible diagonal moves in old tapes */ /* this is only for backward compatibility */ @@ -353,18 +520,22 @@ void LoadTape(int level_nr) void SaveTape(int level_nr) { - int i; + int i, j; char filename[MAX_FILENAME_LEN]; FILE *file; boolean new_tape = TRUE; + boolean player_participates[MAX_PLAYERS]; + byte store_participating_players; + int num_participating_players; + int chunk_length; + + InitTapeDirectory(leveldir[leveldir_nr].filename); sprintf(filename, "%s/%d.%s", getTapeDir(leveldir[leveldir_nr].filename), level_nr, TAPEFILE_EXTENSION); - InitTapeDirectory(leveldir[leveldir_nr].filename); - - /* Testen, ob bereits eine Aufnahme existiert */ + /* if a tape still exists, ask to overwrite it */ if ((file = fopen(filename, "r"))) { new_tape = FALSE; @@ -374,36 +545,80 @@ void SaveTape(int level_nr) return; } + for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); - fputc((tape.random_seed >> 24) & 0xff,file); - fputc((tape.random_seed >> 16) & 0xff,file); - fputc((tape.random_seed >> 8) & 0xff,file); - fputc((tape.random_seed >> 0) & 0xff,file); + fputc((tape.random_seed >> 24) & 0xff, file); + fputc((tape.random_seed >> 16) & 0xff, file); + fputc((tape.random_seed >> 8) & 0xff, file); + fputc((tape.random_seed >> 0) & 0xff, file); - fputc((tape.date >> 24) & 0xff,file); - fputc((tape.date >> 16) & 0xff,file); - fputc((tape.date >> 8) & 0xff,file); - fputc((tape.date >> 0) & 0xff,file); + fputc((tape.date >> 24) & 0xff, file); + fputc((tape.date >> 16) & 0xff, file); + fputc((tape.date >> 8) & 0xff, file); + fputc((tape.date >> 0) & 0xff, file); - fputc((tape.length >> 24) & 0xff,file); - fputc((tape.length >> 16) & 0xff,file); - fputc((tape.length >> 8) & 0xff,file); - fputc((tape.length >> 0) & 0xff,file); + fputc((tape.length >> 24) & 0xff, file); + fputc((tape.length >> 16) & 0xff, file); + fputc((tape.length >> 8) & 0xff, file); + fputc((tape.length >> 0) & 0xff, file); + + fputc(store_participating_players, file); + + for(i=0; i> 24) & 0xff, file); + fputc((chunk_length >> 16) & 0xff, file); + fputc((chunk_length >> 8) & 0xff, file); + fputc((chunk_length >> 0) & 0xff, file); for(i=0; isort_priority != entry2->sort_priority) + compare_result = entry1->sort_priority - entry2->sort_priority; + else + { + char *name1 = getStringToLower(entry1->name); + char *name2 = getStringToLower(entry2->name); + + compare_result = strcmp(name1, name2); + + free(name1); + free(name2); + } + + return compare_result; +} + +static int LoadLevelInfoFromLevelDir(char *level_directory, int start_entry) { DIR *dir; struct stat file_status; - char *level_directory = options.level_directory; char *directory = NULL; char *filename = NULL; struct SetupFileList *setup_file_list = NULL; struct dirent *dir_entry; - int i, num_entries = 0; + int i, current_entry = start_entry; if ((dir = opendir(level_directory)) == NULL) Error(ERR_EXIT, "cannot read level directory '%s'", level_directory); - while (num_entries < MAX_LEVDIR_ENTRIES) + while (current_entry < MAX_LEVDIR_ENTRIES) { if ((dir_entry = readdir(dir)) == NULL) /* last directory entry */ break; @@ -1066,17 +1303,19 @@ void LoadLevelInfo() if (setup_file_list) { checkSetupFileListIdentifier(setup_file_list, LEVELINFO_COOKIE); - setLevelDirInfoToDefaults(&leveldir[num_entries]); + setLevelDirInfoToDefaults(&leveldir[current_entry]); - ldi = leveldir[num_entries]; + ldi = leveldir[current_entry]; for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) setSetupInfo(i, getTokenValue(setup_file_list, token_info[i].text)); - leveldir[num_entries] = ldi; + leveldir[current_entry] = ldi; - leveldir[num_entries].filename = getStringCopy(dir_entry->d_name); + leveldir[current_entry].filename = getStringCopy(dir_entry->d_name); + leveldir[current_entry].user_defined = + (level_directory == options.level_directory ? FALSE : TRUE); freeSetupFileList(setup_file_list); - num_entries++; + current_entry++; } else Error(ERR_WARN, "ignoring level directory '%s'", directory); @@ -1085,18 +1324,64 @@ void LoadLevelInfo() free(filename); } - if (num_entries == MAX_LEVDIR_ENTRIES) + if (current_entry == MAX_LEVDIR_ENTRIES) Error(ERR_WARN, "using %d level directories -- ignoring the rest", - num_entries); + current_entry); closedir(dir); - num_leveldirs = num_entries; - leveldir_nr = 0; - - if (!num_leveldirs) + if (current_entry == start_entry && start_entry != -1) Error(ERR_EXIT, "cannot find any valid level series in directory '%s'", level_directory); + + return current_entry; +} + +void LoadLevelInfo() +{ + InitUserLevelDirectory(getLoginName()); + + num_leveldirs = 0; + leveldir_nr = 0; + + num_leveldirs = LoadLevelInfoFromLevelDir(options.level_directory, + num_leveldirs); + num_leveldirs = LoadLevelInfoFromLevelDir(getUserLevelDir(""), + num_leveldirs); + if (num_leveldirs > 1) + qsort(leveldir, num_leveldirs, sizeof(struct LevelDirInfo), + compareLevelDirInfoEntries); +} + +static void SaveUserLevelInfo() +{ + char filename[MAX_FILENAME_LEN]; + FILE *file; + int i; + + sprintf(filename, "%s/%s", + getUserLevelDir(getLoginName()), LEVELINFO_FILENAME); + + if (!(file = fopen(filename, "w"))) + { + Error(ERR_WARN, "cannot write level info file '%s'", filename); + return; + } + + ldi.name = getLoginName(); + ldi.levels = 100; + ldi.sort_priority = 300; + ldi.readonly = FALSE; + + fprintf(file, "%s\n\n", + getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, LEVELINFO_COOKIE)); + + for (i=FIRST_LEVELINFO_TOKEN; i<=LAST_LEVELINFO_TOKEN; i++) + fprintf(file, "%s\n", getSetupLine("", i)); + + fclose(file); + + chmod(filename, SETUP_PERMS); } void LoadSetup() @@ -1104,7 +1389,7 @@ void LoadSetup() char filename[MAX_FILENAME_LEN]; struct SetupFileList *setup_file_list = NULL; - /* always start with reliable default setup values */ + /* always start with reliable default values */ setSetupInfoToDefaults(&setup); sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME); @@ -1205,10 +1490,10 @@ void SaveSetup() char filename[MAX_FILENAME_LEN]; FILE *file; - sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME); - InitUserDataDirectory(); + sprintf(filename, "%s/%s", getSetupDir(), SETUP_FILENAME); + if (!(file = fopen(filename, "w"))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); @@ -1252,8 +1537,7 @@ void LoadLevelSetup() { char filename[MAX_FILENAME_LEN]; - /* always start with reliable default setup values */ - + /* always start with reliable default values */ leveldir_nr = 0; level_nr = 0; @@ -1288,6 +1572,8 @@ void SaveLevelSetup() struct SetupFileList *list_entry = level_setup_list; FILE *file; + InitUserDataDirectory(); + setTokenValue(level_setup_list, TOKEN_STR_LAST_LEVEL_SERIES, leveldir[leveldir_nr].filename); @@ -1296,17 +1582,14 @@ void SaveLevelSetup() sprintf(filename, "%s/%s", getSetupDir(), LEVELSETUP_FILENAME); - InitUserDataDirectory(); - if (!(file = fopen(filename, "w"))) { Error(ERR_WARN, "cannot write setup file '%s'", filename); return; } - fprintf(file, "%s: %s\n\n", - TOKEN_STR_FILE_IDENTIFIER, LEVELSETUP_COOKIE); - + fprintf(file, "%s\n\n", getFormattedSetupEntry(TOKEN_STR_FILE_IDENTIFIER, + LEVELSETUP_COOKIE)); while (list_entry) { if (strcmp(list_entry->token, TOKEN_STR_FILE_IDENTIFIER) != 0)