diff --git a/src/deh_soc.c b/src/deh_soc.c index 5960ac33693a8a307cb5e829d6e689c31d16d43a..36a0678b86e3374b5bf8ab4016ffc89cb560fc7e 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -3010,12 +3010,10 @@ void reademblemdata(MYFILE *f, INT32 num) emblemlocations[num-1].tag = (INT16)value; else if (fastcmp(word, "MAPNUM")) { - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); emblemlocations[num-1].level = (INT16)value; } @@ -3606,12 +3604,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); spstage_start = spmarathon_start = (INT16)value; } @@ -3621,12 +3617,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); spmarathon_start = (INT16)value; } @@ -3636,12 +3630,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); sstage_start = (INT16)value; sstage_end = (INT16)(sstage_start+7); // 7 special stages total plus one weirdo @@ -3652,12 +3644,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); smpstage_start = (INT16)value; smpstage_end = (INT16)(smpstage_start+6); // 7 special stages total @@ -3748,12 +3738,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); titlemap = (INT16)value; titlechanged = true; @@ -3922,15 +3910,12 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); bootmap = (INT16)value; - //titlechanged = true; } else if (fastcmp(word, "STARTCHAR")) { @@ -3943,12 +3928,10 @@ void readmaincfg(MYFILE *f) // i.e., Level AB, Level FZ, etc. // Convert to map number - if (!value) - { + if (G_IsValidMapName(word2)) value = G_GetMapNumber(word2); - if (!value) - value = get_number(word2); - } + if (!value) + value = get_number(word2); tutorialmap = (INT16)value; } diff --git a/src/dehacked.c b/src/dehacked.c index 142459fece3b3ccfaf78898df495a3dff42921b0..dcb5859317695f67d2fde7368d1c429142e8d1c0 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -364,14 +364,28 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile) } else if (fastcmp(word, "LEVEL")) { - if (!isdigit(word2[0])) + boolean is_valid_level = false; + + if (G_IsValidMapName(word2)) { INT16 mapnum = G_GetMapNumber(word2); if (mapnum != 0) + { i = mapnum; + is_valid_level = true; + } + } + else + { + is_valid_level = true; } - if (i > 0 && i <= numgamemaps) + if (!is_valid_level) + { + deh_warning("Unknown level %s", word2); + ignorelines(f); + } + else if (i > 0 && i <= numgamemaps) readlevelheader(f, i); else { diff --git a/src/doomstat.h b/src/doomstat.h index 3ad304452ca1e4df0705d21efa6e10ae8c162851..408e2a081af3169d6e67287e2f0125e68591921a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -288,6 +288,7 @@ typedef struct typedef struct { mapname_t name; + UINT32 lumpnum; char *thumbnail; char *thumbnail_wide; char *music; diff --git a/src/g_game.c b/src/g_game.c index d11cbedbaff09ebec4888434214aed0a15a044a0..f6d231d0a0894d8b4be8534504ba74d18cf1899c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -873,7 +873,7 @@ void G_InitMaps(void) for (UINT16 i = 0; i < NUMBASEMAPS; i++) { const char *name = G_BuildClassicMapName(i + 1); - G_AddMap(name); + G_AddMap(name, LUMPERROR); } G_MakeMapName(&nextmapnames[0], "SCENE_TITLE"); @@ -922,23 +922,22 @@ UINT16 G_GetNextMapNumber(const char *name) return MapIDForHashedString(name, name_length, name_hash); } -UINT16 G_AddMap(const char *name) +UINT16 G_AddMap(const char *name, UINT32 lumpnum) { + // Too many maps loaded if (numgamemaps == MAXMAPS) return 0; UINT16 mapnum = G_GetMapNumber(name); if (mapnum != 0) { - // That map already exists, silly. + // Update that map's lumpnum + gamemaps[mapnum - 1].lumpnum = lumpnum; return mapnum; } - size_t name_len = strlen(name); - if (name_len > MAX_MAP_NAME_SIZE) - return 0; - G_MakeMapName(&gamemaps[numgamemaps].name, name); + gamemaps[numgamemaps].lumpnum = lumpnum; numgamemaps++; @@ -949,14 +948,33 @@ UINT16 G_AddMap(const char *name) boolean G_MapFileExists(const char *name) { - return W_CheckNumForLongName(name) != LUMPERROR; + UINT16 mapnum = G_GetMapNumber(name); + if (mapnum == 0) + return false; + + return gamemaps[mapnum - 1].lumpnum != LUMPERROR; +} + +static boolean IsValidMapNameStartChar(const char chr) +{ + return isalpha(chr) || chr == '_' || chr == '$'; } boolean G_IsValidMapName(const char *name) { - if (name[0] == '\0' || !isalpha(name[0])) + // Can't be empty, and must begin with a letter, an underscore, or a dollar sign + if (name[0] == '\0' || !IsValidMapNameStartChar(name[0])) return false; + size_t length = strlen(name); + + // Middle and end of name must be a letter, a digit, an underscore, or a dollar sign + for (size_t i = 1; i < length; i++) + { + if (!(IsValidMapNameStartChar(name[i]) || isdigit(name[i]))) + return false; + } + return true; } diff --git a/src/g_game.h b/src/g_game.h index 930bc0b990d079668476f415263c27c98b5f12e9..22d84c016e4267728e1ec83c31bdf1f3c382f089 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -120,7 +120,7 @@ const char *G_BuildMapName(INT32 map); void G_InitMaps(void); UINT16 G_GetMapNumber(const char *name); UINT16 G_GetNextMapNumber(const char *name); -UINT16 G_AddMap(const char *name); +UINT16 G_AddMap(const char *name, UINT32 lumpnum); boolean G_MapFileExists(const char *name); boolean G_IsValidMapName(const char *name); diff --git a/src/p_setup.c b/src/p_setup.c index 0ab8974073c1338972915e031f3eecab13894c52..8a850fb6949f04889801827d5e57d7577e5d170c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -8119,60 +8119,90 @@ static lumpinfo_t* FindFolder(const char *folName, UINT16 *start, UINT16 *end, l return lumpinfo; } +static int P_AddMap(const char *name, UINT32 lumpnum) +{ + // Check filename length + size_t name_len = strlen(name); + if (name_len > MAX_MAP_NAME_SIZE) + { + CONS_Alert(CONS_WARNING, "Map name's length of %s exceeds maximum of %d -- skipping\n", sizeu1(name_len), MAX_MAP_NAME_SIZE); + return 0; + } + + if (!G_IsValidMapName(name)) + { + CONS_Alert(CONS_WARNING, "Map name %s is invalid -- skipping\n", name); + return 0; + } + + INT16 num = G_AddMap(name, lumpnum); + if (num == 0) + { + CONS_Alert(CONS_ERROR, "Too many maps loaded!\n"); + return -1; + } + + //If you replaced the map you're on, end the level when done. + if (gamestate == GS_LEVEL && num == gamemap) + replacedcurrentmap = true; + + return 1; +} + void P_LoadMapsFromFile(UINT16 wadnum, boolean added_ingame) { boolean mapsadded = false; - lumpinfo_t *lumpinfo = wadfiles[wadnum]->lumpinfo; + lumpinfo_t *lumpinfo = NULL; + UINT16 numlumps = 0; INT16 num; const char *name; if (W_FileHasFolders(wadfiles[wadnum])) { - UINT16 posStart = W_CheckNumForFolderStartPK3("Maps/", wadnum, 0); - if (posStart == INT16_MAX) - return; + UINT32 *list = NULL; + UINT16 capacity = 0; - UINT16 posEnd = W_CheckNumForFolderEndPK3("Maps/", wadnum, posStart); + W_GetFolderLumpsPwad("Maps/", wadnum, &list, &capacity, &numlumps); - lumpinfo += posStart; - - for (; posStart < posEnd; posStart++, lumpinfo++) + for (UINT16 i = 0; i < numlumps; i++) { + UINT32 lumpnum = list[i]; + + lumpinfo = wadfiles[wadnum]->lumpinfo + LUMPNUM(lumpnum); + name = M_GetFilenameFromPath(lumpinfo->fullname); // Full lump name, with its extension + // Extension must be .wad if (!M_CheckFilenameExtension(name, "wad")) - { - // Extension must be .wad continue; - } - - name = lumpinfo->longname; // Name without the extension - num = G_AddMap(name); + // Get the name without the extension + name = lumpinfo->longname; - if (num == 0) + int status = P_AddMap(name, lumpnum); + if (status == 1) { - CONS_Alert(CONS_ERROR, "Too many maps loaded!\n"); - break; + if (added_ingame) + CONS_Printf("%s\n", name); + mapsadded = true; } - //If you replaced the map you're on, end the level when done. - else if (gamestate == GS_LEVEL && num == gamemap) - replacedcurrentmap = true; - - if (added_ingame) - CONS_Printf("%s\n", name); - mapsadded = true; + else if (status < 0) + break; } + + Z_Free(list); } else { - UINT16 numlumps = wadfiles[wadnum]->numlumps; + lumpinfo = wadfiles[wadnum]->lumpinfo; + numlumps = wadfiles[wadnum]->numlumps; + for (size_t i = 0; i < numlumps; i++, lumpinfo++) { name = lumpinfo->name; - if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') // Ignore the headers + if (name[0] == 'M' && name[1] == 'A' && name[2] == 'P') { if (name[5]!='\0') continue; @@ -8187,6 +8217,41 @@ void P_LoadMapsFromFile(UINT16 wadnum, boolean added_ingame) mapsadded = true; } } + + // Now do markers + UINT16 start = W_CheckNumForMarkerStartPwad("LV_START", wadnum, 0); + UINT16 end = W_CheckNumForNamePwad("LV_END", wadnum, start); + + lumpinfo = wadfiles[wadnum]->lumpinfo + start; + + for (UINT16 l = start; l < end; l++, lumpinfo++) + { + name = lumpinfo->name; + + // Ignore any of these lump names + if (stricmp(name, "THINGS") == 0 + || stricmp(name, "LINEDEFS") == 0 + || stricmp(name, "SIDEDEFS") == 0 + || stricmp(name, "VERTEXES") == 0 + || stricmp(name, "SEGS") == 0 + || stricmp(name, "SSECTORS") == 0 + || stricmp(name, "NODES") == 0 + || stricmp(name, "SECTORS") == 0 + || stricmp(name, "REJECT") == 0 + || stricmp(name, "BLOCKMAP") == 0 + || stricmp(name, "BEHAVIOR") == 0) + continue; + + int status = P_AddMap(name, (wadnum << 16) + l); + if (status == 1) + { + if (added_ingame) + CONS_Printf("%s\n", name); + mapsadded = true; + } + else if (status < 0) + break; + } } if (!mapsadded && added_ingame) diff --git a/src/w_wad.c b/src/w_wad.c index 13749f630078f27382a456d52b522eda1798f892..e991531dc782834a662a97fa28284b884f4b2614 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -1158,6 +1158,7 @@ UINT16 W_InitFolder(const char *path, boolean mainfile, boolean startup) numwadfiles++; W_ReadFileShaders(wadfile); + P_LoadMapsFromFile(numwadfiles - 1, !startup); W_LoadDehackedLumpsPK3(numwadfiles - 1, mainfile); W_InvalidateLumpnumCache(); @@ -1338,6 +1339,42 @@ UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump) return i; } +void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps) +{ + size_t name_length = strlen(name); + lumpinfo_t *lump_p = wadfiles[wad]->lumpinfo; + + UINT16 capacity = *list_capacity; + UINT16 count = *numlumps; + + for (UINT16 i = 0; i < wadfiles[wad]->numlumps; i++, lump_p++) + { + if (strnicmp(name, lump_p->fullname, name_length) == 0) + { + if (strlen(lump_p->fullname) > name_length) + { + if (!capacity || count >= capacity) + { + capacity = capacity ? (capacity * 2) : 16; + *list = Z_Realloc(*list, capacity * sizeof(UINT32), PU_STATIC, NULL); + } + + (*list)[count] = (wad << 16) + i; + count++; + } + } + } + + (*list_capacity) = capacity; + (*numlumps) = count; +} + +void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps) +{ + for (UINT16 i = 0; i < numwadfiles; i++) + W_GetFolderLumpsPwad(name, i, list, list_capacity, numlumps); +} + // In a PK3 type of resource file, it looks for an entry with the specified full name. // Returns lump position in PK3's lumpinfo, or INT16_MAX if not found. UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump) diff --git a/src/w_wad.h b/src/w_wad.h index ffb9095ba21c9e1d79049adadaa893953b097260..4f59c40e05461405f3c60f86a551e25e3643747c 100644 --- a/src/w_wad.h +++ b/src/w_wad.h @@ -181,6 +181,9 @@ UINT16 W_CheckNumForFullNamePK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderStartPK3(const char *name, UINT16 wad, UINT16 startlump); UINT16 W_CheckNumForFolderEndPK3(const char *name, UINT16 wad, UINT16 startlump); +void W_GetFolderLumpsPwad(const char *name, UINT16 wad, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps); +void W_GetFolderLumps(const char *name, UINT32 **list, UINT16 *list_capacity, UINT16 *numlumps); + lumpnum_t W_CheckNumForMap(const char *name); lumpnum_t W_CheckNumForName(const char *name); lumpnum_t W_CheckNumForLongName(const char *name);