diff --git a/common/include/strutil.h b/common/include/strutil.h index 98be14d26..b35b04977 100644 --- a/common/include/strutil.h +++ b/common/include/strutil.h @@ -61,7 +61,8 @@ struct splitpath_t void removeext(const char *filename, std::array &out); //give a filename a new extension, doesn't work with paths with no extension already there -void change_filename_extension(std::span dest, const char *src, std::span ext); +[[nodiscard]] +bool change_filename_extension(std::span dest, const char *src, std::span ext); /* Given an MS-DOS path, return pointers to the start of the basename and the * start of the extension. diff --git a/common/misc/strutil.cpp b/common/misc/strutil.cpp index 4e787cef5..08b701f76 100644 --- a/common/misc/strutil.cpp +++ b/common/misc/strutil.cpp @@ -136,16 +136,17 @@ void removeext(const char *const filename, std::array &out) } //give a filename a new extension, won't append if strlen(dest) > 8 chars. -void change_filename_extension(const std::span dest, const char *const src, const std::span ext) +bool change_filename_extension(const std::span dest, const char *const src, const std::span ext) { const char *const p = strrchr(src, '.'); const std::size_t src_dist_to_last_dot = p ? std::distance(src, p) : strlen(src); if (src_dist_to_last_dot + 1 + ext.size() > dest.size()) { dest.front() = 0; - return; // a non-opened file is better than a bad memory access + return false; // a non-opened file is better than a bad memory access } std::snprintf(dest.data(), dest.size(), "%.*s.%s", static_cast(src_dist_to_last_dot), src, ext.data()); + return true; } splitpath_t d_splitpath(const char *name) diff --git a/d2x-rebirth/main/movie.cpp b/d2x-rebirth/main/movie.cpp index 020dc22ee..89e20196a 100644 --- a/d2x-rebirth/main/movie.cpp +++ b/d2x-rebirth/main/movie.cpp @@ -518,7 +518,11 @@ static int init_subtitles(d_loaded_subtitle_state &SubtitleState, const std::spa if (!ifile) { //no text version, try binary version std::array filename2; - change_filename_extension(filename2, filename.data(), "txb"); + if (!change_filename_extension(filename2, filename.data(), "txb")) + { + con_printf(CON_NORMAL, "Rebirth: skipping subtitles because cannot open \"%s\" (\"%s\")", filename.data(), PHYSFS_getErrorByCode(physfserr)); + return 0; + } auto &&[ifile2, physfserr2] = PHYSFSX_openReadBuffered(filename2.data()); if (!ifile2) { diff --git a/similar/main/bm.cpp b/similar/main/bm.cpp index ef29b69fd..9a4bff549 100644 --- a/similar/main/bm.cpp +++ b/similar/main/bm.cpp @@ -538,7 +538,11 @@ void load_robot_replacements(const d_fname &level_name) auto &Robot_joints = LevelSharedRobotJointState.Robot_joints; int t,j; std::array ifile_name; - change_filename_extension(ifile_name, level_name, "HXM"); + if (!change_filename_extension(ifile_name, level_name, "HXM")) + { + con_printf(CON_URGENT, "Failed to generate HXM name from level name \"%s\"", level_name.data()); + return; + } auto fp = PHYSFSX_openReadBuffered(ifile_name.data()).first; if (!fp) //no robot replacement file diff --git a/similar/main/gamesave.cpp b/similar/main/gamesave.cpp index 8d875ce10..916b9e76d 100644 --- a/similar/main/gamesave.cpp +++ b/similar/main/gamesave.cpp @@ -1845,12 +1845,18 @@ static int save_level_sub( } // else { + auto &level_file_extension = #if defined(DXX_BUILD_DESCENT_II) - if (Gamesave_current_version > 3) - change_filename_extension(temp_filename, filename, D2X_LEVEL_FILE_EXTENSION); - else + (Gamesave_current_version > 3) + ? D2X_LEVEL_FILE_EXTENSION + : #endif - change_filename_extension(temp_filename, filename, D1X_LEVEL_FILE_EXTENSION); + D1X_LEVEL_FILE_EXTENSION; + if (!change_filename_extension(temp_filename, filename, level_file_extension)) + { + con_printf(CON_URGENT, "Failed to generate filename for level data from \"%s\"", filename); + return 1; + } } auto &&[SaveFile, physfserr] = PHYSFSX_openWriteBuffered(temp_filename.data()); diff --git a/similar/main/menu.cpp b/similar/main/menu.cpp index 95d4ee4f3..b3cfa750e 100644 --- a/similar/main/menu.cpp +++ b/similar/main/menu.cpp @@ -876,7 +876,8 @@ static window_event_result demo_menu_keycommand( listbox *lb,const d_event &even // Get backup name const auto ic = items[citem]; - change_filename_extension(bakname, ic, DEMO_BACKUP_EXT); + if (!change_filename_extension(bakname, ic, DEMO_BACKUP_EXT)) + return window_event_result::handled; const auto x = nm_messagebox(menu_title{nullptr}, 2, TXT_YES, TXT_NO, "Are you sure you want to\n" "swap the endianness of\n" "%s? If the file is\n" diff --git a/similar/main/newdemo.cpp b/similar/main/newdemo.cpp index a37ede4a4..7dc1739bb 100644 --- a/similar/main/newdemo.cpp +++ b/similar/main/newdemo.cpp @@ -4360,11 +4360,9 @@ int newdemo_swap_endian(const char *filename) infile.reset(); outfile.reset(); - if (complete) + std::array bakpath; + if (complete && change_filename_extension(bakpath, inpath, DEMO_BACKUP_EXT)) { - std::array bakpath; - - change_filename_extension(bakpath, inpath, DEMO_BACKUP_EXT); PHYSFSX_rename(inpath, bakpath.data()); PHYSFSX_rename(DEMO_FILENAME, inpath); } diff --git a/similar/main/piggy.cpp b/similar/main/piggy.cpp index c24a2df85..7b499b279 100644 --- a/similar/main/piggy.cpp +++ b/similar/main/piggy.cpp @@ -1542,9 +1542,11 @@ static void piggy_write_pigfile(const std::span filena data_offset = bitmap_data_start; std::array tname; - change_filename_extension(tname, filename.data(), "lst"); + if (!change_filename_extension(tname, filename.data(), "lst")) + return; auto fp1 = PHYSFSX_openWriteBuffered(tname.data()).first; - change_filename_extension(tname, filename.data(), "all"); + if (!change_filename_extension(tname, filename.data(), "all")) + return; auto fp2 = PHYSFSX_openWriteBuffered(tname.data()).first; for (i=1; i < Num_bitmap_files; i++ ) { @@ -1785,7 +1787,8 @@ void load_bitmap_replacements(const std::span level_na free_bitmap_replacements(); std::array ifile_name; - change_filename_extension(ifile_name, level_name.data(), "POG"); + if (!change_filename_extension(ifile_name, level_name.data(), "POG")) + return; if (auto ifile = PHYSFSX_openReadBuffered(ifile_name.data()).first) { int id,version;