diff --git a/CMakeLists.txt b/CMakeLists.txt index df7c78d3..578f595b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -171,6 +171,14 @@ add_executable(CSE2 WIN32 "src/Backends/Controller.h" "src/Backends/Misc.h" "src/Backends/Rendering.h" + "src/Helpers/Asprintf.cpp" + "src/Helpers/Asprintf.h" + "src/Helpers/Vasprintf.cpp" + "src/Helpers/Vasprintf.h" + "src/Helpers/FopenFormatted.cpp" + "src/Helpers/FopenFormatted.h" + "src/Helpers/Strdup.cpp" + "src/Helpers/Strdup.h" ) set(RESOURCES diff --git a/src/ArmsItem.cpp b/src/ArmsItem.cpp index 9c39d1f9..dd25c6d1 100644 --- a/src/ArmsItem.cpp +++ b/src/ArmsItem.cpp @@ -1,5 +1,6 @@ #include "ArmsItem.h" +#include #include #include "WindowsWrapper.h" @@ -414,12 +415,13 @@ void PutCampObject(void) int CampLoop(void) { - char old_script_path[MAX_PATH]; - RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; + int ret = enum_ESCRETURN_continue; // Save the current script path (to restore it when we get out of the inventory) - GetTextScriptPath(old_script_path); + char *old_script_path = GetTextScriptPath(); + if (old_script_path == NULL) + return enum_ESCRETURN_exit; // Load the inventory script LoadTextScript2("ArmsItem.tsc"); @@ -450,10 +452,12 @@ int CampLoop(void) switch (Call_Escape()) { case enum_ESCRETURN_exit: - return enum_ESCRETURN_exit; // Quit game + free(old_script_path); + return enum_ESCRETURN_exit; case enum_ESCRETURN_restart: - return enum_ESCRETURN_restart; // Go to game intro + free(old_script_path); + return enum_ESCRETURN_restart; } } @@ -463,10 +467,12 @@ int CampLoop(void) switch (TextScriptProc()) { case enum_ESCRETURN_exit: - return enum_ESCRETURN_exit; // Quit game + free(old_script_path); + return enum_ESCRETURN_exit; case enum_ESCRETURN_restart: - return enum_ESCRETURN_restart; // Go to game intro + free(old_script_path); + return enum_ESCRETURN_restart; } // Get currently displayed image @@ -494,13 +500,17 @@ int CampLoop(void) } if (!Flip_SystemTask()) - return enum_ESCRETURN_exit; // Quit game + { + free(old_script_path); + return enum_ESCRETURN_exit; + } } // Resume original script LoadTextScript_Stage(old_script_path); gArmsEnergyX = 32; // Displays weapon rotation animation in case the weapon was changed - return enum_ESCRETURN_continue; // Go to game + free(old_script_path); + return enum_ESCRETURN_continue; } BOOL CheckItem(long a) diff --git a/src/Attributes.h b/src/Attributes.h index 35fcd26f..f62ca618 100644 --- a/src/Attributes.h +++ b/src/Attributes.h @@ -12,16 +12,22 @@ #ifdef __GNUC__ +#define ATTRIBUTE_FORMAT(archetype, formatArgumentIndex, firstToCheck) __attribute__((format(archetype, formatArgumentIndex, firstToCheck))) +#define ATTRIBUTE_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#define ATTRIBUTE_MALLOC __attribute__((malloc)) +#define ATTRIBUTE_NONNULL(...) __attribute__((nonnull(__VA_ARGS__))) #define ATTRIBUTE_HOT __attribute__((hot)) -#define ATTRIBUTE_OPTIMIZE(optString) __attribute__((optimize(optString))) #define LIKELY(condition) __builtin_expect((condition), 1) #define UNLIKELY(condition) __builtin_expect((condition), 0) #define PREFETCH(address, isWrite, locality) __builtin_prefetch((address), (isWrite), (locality)) #else +#define ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) +#define ATTRIBUTE_WARN_UNUSED_RESULT +#define ATTRIBUTE_MALLOC +#define ATTRIBUTE_NONNULL #define ATTRIBUTE_HOT -#define ATTRIBUTE_OPTIMIZE(optString) #define LIKELY(condition) condition #define UNLIKELY(condition) condition #define PREFETCH(address, isWrite, locality) diff --git a/src/Back.cpp b/src/Back.cpp index dab38a48..97f00350 100644 --- a/src/Back.cpp +++ b/src/Back.cpp @@ -13,6 +13,7 @@ #include "Main.h" #include "Map.h" #include "Stage.h" +#include "Helpers/FopenFormatted.h" BACK gBack; int gWaterY; @@ -25,10 +26,7 @@ BOOL InitBack(const char *fName, int type) color_black = GetCortBoxColor(RGB(0, 0, 0x10)); // Get width and height - char path[MAX_PATH]; - sprintf(path, "%s/%s.pbm", gDataPath, fName); - - FILE *fp = fopen(path, "rb"); + FILE *fp = fopenFormatted("rb", "%s/%s.pbm", gDataPath, fName); if (fp == NULL) return FALSE; diff --git a/src/Backends/Misc.h b/src/Backends/Misc.h index 103ff98c..25fbdf60 100644 --- a/src/Backends/Misc.h +++ b/src/Backends/Misc.h @@ -86,7 +86,7 @@ enum bool Backend_Init(void); void Backend_Deinit(void); void Backend_PostWindowCreation(void); -bool Backend_GetBasePath(char *string_buffer); +bool Backend_GetBasePath(char **string_buffer); void Backend_HideMouse(void); void Backend_SetWindowIcon(const unsigned char *rgb_pixels, unsigned int width, unsigned int height); void Backend_SetCursor(const unsigned char *rgb_pixels, unsigned int width, unsigned int height); diff --git a/src/Backends/Platform/GLFW3.cpp b/src/Backends/Platform/GLFW3.cpp index e36c3a4e..23ed0d17 100644 --- a/src/Backends/Platform/GLFW3.cpp +++ b/src/Backends/Platform/GLFW3.cpp @@ -181,7 +181,7 @@ void Backend_PostWindowCreation(void) glfwSetWindowSizeCallback(window, WindowSizeCallback); } -bool Backend_GetBasePath(char *string_buffer) +bool Backend_GetBasePath(char **string_buffer) { (void)string_buffer; diff --git a/src/Backends/Platform/Null.cpp b/src/Backends/Platform/Null.cpp index c4005d9b..bf4ab2f2 100644 --- a/src/Backends/Platform/Null.cpp +++ b/src/Backends/Platform/Null.cpp @@ -15,7 +15,7 @@ void Backend_PostWindowCreation(void) } -bool Backend_GetBasePath(char *string_buffer) +bool Backend_GetBasePath(char **string_buffer) { (void)string_buffer; diff --git a/src/Backends/Platform/SDL2.cpp b/src/Backends/Platform/SDL2.cpp index 1408b605..775f265c 100644 --- a/src/Backends/Platform/SDL2.cpp +++ b/src/Backends/Platform/SDL2.cpp @@ -13,6 +13,7 @@ #include "../../Organya.h" #include "../../Profile.h" #include "../../Resource.h" +#include "../../Helpers/Strdup.h" #define DO_KEY(SDL_KEY, BACKEND_KEY) \ case SDL_KEY: \ @@ -84,7 +85,7 @@ void Backend_PostWindowCreation(void) } -bool Backend_GetBasePath(char *string_buffer) +bool Backend_GetBasePath(char **string_buffer) { #ifdef _WIN32 // SDL_GetBasePath returns a UTF-8 string, but Windows' fopen uses (extended?) ASCII. @@ -100,7 +101,7 @@ bool Backend_GetBasePath(char *string_buffer) // Trim the trailing '/' size_t base_path_length = strlen(base_path); base_path[base_path_length - 1] = '\0'; - strcpy(string_buffer, base_path); + *string_buffer = strdup(base_path); SDL_free(base_path); return true; diff --git a/src/Backends/Platform/WiiU.cpp b/src/Backends/Platform/WiiU.cpp index 578e1df3..14e5f54d 100644 --- a/src/Backends/Platform/WiiU.cpp +++ b/src/Backends/Platform/WiiU.cpp @@ -12,6 +12,8 @@ #include #include +#include "../../Helpers/Asprintf.h" + static unsigned long ticks_per_second; bool Backend_Init(void) @@ -54,15 +56,13 @@ void Backend_PostWindowCreation(void) } -bool Backend_GetBasePath(char *string_buffer) +bool Backend_GetBasePath(char **string_buffer) { - strcpy(string_buffer, WHBGetSdCardMountPath()); #ifdef JAPANESE - strcat(string_buffer, "/CSE2-portable-jp"); + *string_buffer = asprintf("%s/CSE-portable-jp", WHBGetSdCardMountPath()); #else - strcat(string_buffer, "/CSE2-portable-en"); + *string_buffer = asprintf("%s/CSE-portable-en", WHBGetSdCardMountPath()); #endif - return true; } diff --git a/src/Config.cpp b/src/Config.cpp index e2afcb95..a0a5a585 100644 --- a/src/Config.cpp +++ b/src/Config.cpp @@ -7,6 +7,7 @@ #include "Config.h" #include "File.h" #include "Main.h" +#include "Helpers/FopenFormatted.h" const char* const gConfigName = "Config.dat"; const char* const gProof = "DOUKUTSU20041206"; @@ -16,12 +17,8 @@ BOOL LoadConfigData(CONFIG *conf) // Clear old configuration data memset(conf, 0, sizeof(CONFIG)); - // Get path - char path[MAX_PATH]; - sprintf(path, "%s/%s", gModulePath, gConfigName); - // Open file - FILE *fp = fopen(path, "rb"); + FILE *fp = fopenFormatted("rb", "%s/%s", gModulePath, gConfigName); if (fp == NULL) return FALSE; diff --git a/src/Draw.cpp b/src/Draw.cpp index 7673d59b..61804bc9 100644 --- a/src/Draw.cpp +++ b/src/Draw.cpp @@ -18,6 +18,7 @@ #include "MapName.h" #include "Resource.h" #include "TextScr.h" +#include "Helpers/Asprintf.h" typedef enum SurfaceType { @@ -250,12 +251,15 @@ BOOL MakeSurface_Resource(const char *name, SurfaceID surf_no) // TODO - Inaccurate stack frame BOOL MakeSurface_File(const char *name, SurfaceID surf_no) { - char path[MAX_PATH]; - sprintf(path, "%s/%s.pbm", gDataPath, name); + char *path; + + if (asprintf(&path, "%s/%s.pbm", gDataPath, name) < 0) + return FALSE; if (!IsEnableBitmap(path)) { ErrorLog(path, 0); + free(path); return FALSE; } @@ -266,12 +270,14 @@ BOOL MakeSurface_File(const char *name, SurfaceID surf_no) #endif { ErrorLog("surface no", surf_no); + free(path); return FALSE; } if (surf[surf_no] != NULL) { ErrorLog("existing", surf_no); + free(path); return FALSE; } @@ -281,8 +287,10 @@ BOOL MakeSurface_File(const char *name, SurfaceID surf_no) if (image_buffer == NULL) { ErrorLog(path, 1); + free(path); return FALSE; } + free(path); surf[surf_no] = RenderBackend_CreateSurface(width * mag, height * mag, false); @@ -341,12 +349,14 @@ BOOL ReloadBitmap_Resource(const char *name, SurfaceID surf_no) // TODO - Inaccurate stack frame BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) { - char path[MAX_PATH]; - sprintf(path, "%s/%s.pbm", gDataPath, name); + char *path; + if (asprintf(&path, "%s/%s.pbm", gDataPath, name) < 0) + return FALSE; if (!IsEnableBitmap(path)) { ErrorLog(path, 0); + free(path); return FALSE; } @@ -357,6 +367,7 @@ BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) #endif { ErrorLog("surface no", surf_no); + free(path); return FALSE; } @@ -366,8 +377,10 @@ BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) if (image_buffer == NULL) { ErrorLog(path, 1); + free(path); return FALSE; } + free(path); if (!ScaleAndUploadSurface(image_buffer, width, height, surf_no)) { @@ -378,7 +391,6 @@ BOOL ReloadBitmap_File(const char *name, SurfaceID surf_no) FreeBitmap(image_buffer); surface_metadata[surf_no].type = SURFACE_SOURCE_FILE; strcpy(surface_metadata[surf_no].name, name); - return TRUE; } @@ -647,8 +659,9 @@ void InitTextObject(const char *name) { (void)name; // Unused in this branch - char path[MAX_PATH]; - sprintf(path, "%s/Font/font", gDataPath); + char *path; + if (asprintf(&path, "%s/Font/font", gDataPath) < 0) + return; // Get font size unsigned int width, height; diff --git a/src/Ending.cpp b/src/Ending.cpp index 1a4532ff..73c75edd 100644 --- a/src/Ending.cpp +++ b/src/Ending.cpp @@ -16,6 +16,7 @@ #include "Organya.h" #include "Stage.h" #include "TextScr.h" +#include "Helpers/Asprintf.h" struct CREDIT { @@ -216,7 +217,6 @@ void ReleaseCreditScript(void) BOOL StartCreditScript(void) { FILE *fp; - char path[MAX_PATH]; // Clear previously existing credits data if (Credit.pData != NULL) @@ -226,18 +226,27 @@ BOOL StartCreditScript(void) } // Open file - sprintf(path, "%s/%s", gDataPath, credit_script); + char *path; + if (asprintf(&path, "%s/%s", gDataPath, credit_script) < 0) + return FALSE; Credit.size = GetFileSizeLong(path); if (Credit.size == -1) + { + free(path); return FALSE; + } // Allocate buffer data Credit.pData = (char*)malloc(Credit.size); if (Credit.pData == NULL) + { + free(path); return FALSE; + } fp = fopen(path, "rb"); + free(path); if (fp == NULL) { free(Credit.pData); diff --git a/src/Game.cpp b/src/Game.cpp index 3a0608aa..1a613ca4 100644 --- a/src/Game.cpp +++ b/src/Game.cpp @@ -44,6 +44,7 @@ #include "Star.h" #include "TextScr.h" #include "ValueView.h" +#include "Helpers/Asprintf.h" int g_GameFlags; int gCounter; @@ -701,10 +702,13 @@ BOOL Game(void) PlaySoundObject(7, -1); - char path[MAX_PATH]; - sprintf(path, "%s/npc.tbl", gDataPath); + char *path; + if (asprintf(&path, "%s/npc.tbl", gDataPath) < 0) + return FALSE; - if (!LoadNpcTable(path)) + BOOL load_npc_table_succeeded = LoadNpcTable(path); + free(path); + if (!load_npc_table_succeeded) { #ifdef JAPANESE Backend_ShowMessageBox("エラー", "NPCテーブルが読めない"); diff --git a/src/Generic.cpp b/src/Generic.cpp index 5ef2a272..753f7bfa 100644 --- a/src/Generic.cpp +++ b/src/Generic.cpp @@ -2,11 +2,14 @@ #include #include +#include #include #include "WindowsWrapper.h" #include "Main.h" +#include "Helpers/Asprintf.h" +#include "Helpers/FopenFormatted.h" void GetCompileDate(int *year, int *month, int *day) { @@ -49,19 +52,18 @@ BOOL GetCompileVersion(int *v1, int *v2, int *v3, int *v4) void DeleteLog(void) { - char path[MAX_PATH]; + char *path; + + if (asprintf(&path, "%s/debug.txt", gModulePath) < 0) + return; - sprintf(path, "%s/debug.txt", gModulePath); remove(path); + free(path); } BOOL WriteLog(const char *string, int value1, int value2, int value3) { - char path[MAX_PATH]; - FILE *fp; - - sprintf(path, "%s/debug.txt", gModulePath); - fp = fopen(path, "a+"); + FILE *fp = fopenFormatted("a+", "%s/debug.txt", gModulePath); if (fp == NULL) return FALSE; @@ -73,11 +75,7 @@ BOOL WriteLog(const char *string, int value1, int value2, int value3) BOOL IsKeyFile(const char *name) { - char path[MAX_PATH]; - - sprintf(path, "%s/%s", gModulePath, name); - - FILE *file = fopen(path, "rb"); + FILE *file = fopenFormatted("rb", "%s/%s", gModulePath, name); if (file == NULL) return FALSE; @@ -86,6 +84,7 @@ BOOL IsKeyFile(const char *name) return TRUE; } +// Some code uses this as CheckFileExists, checking if the return value is -1 long GetFileSizeLong(const char *path) { long len; @@ -105,15 +104,15 @@ long GetFileSizeLong(const char *path) BOOL ErrorLog(const char *string, int value) { - char path[MAX_PATH]; - FILE *fp; - - sprintf(path, "%s/%s", gModulePath, "error.log"); + char *path; + if (asprintf(&path, "%s/%s", gModulePath, "error.log") < 0) + return FALSE; if (GetFileSizeLong(path) > 0x19000) // Purge the error log if it gets too big, I guess remove(path); - fp = fopen(path, "a+"); + FILE *fp = fopen(path, "a+"); + free(path); if (fp == NULL) return FALSE; diff --git a/src/GenericLoad.cpp b/src/GenericLoad.cpp index 9f177091..29343894 100644 --- a/src/GenericLoad.cpp +++ b/src/GenericLoad.cpp @@ -293,8 +293,10 @@ BOOL LoadGenericData(void) pt_size += MakePixToneObject(&gPtpTable[137], 1, 6); pt_size += MakePixToneObject(&gPtpTable[138], 1, 7); - char str[0x40]; - sprintf(str, "PixTone = %d byte", pt_size); - // There must have been some kind of console print function here or something + /* + * char str[0x40]; + * sprintf(str, "PixTone = %d byte", pt_size); + * // There must have been some kind of console print function here or something + */ return TRUE; } diff --git a/src/Helpers/Asprintf.cpp b/src/Helpers/Asprintf.cpp new file mode 100644 index 00000000..6d8cfb54 --- /dev/null +++ b/src/Helpers/Asprintf.cpp @@ -0,0 +1,18 @@ +#ifndef _GNU_SOURCE + +#include "Asprintf.h" +#include "Vasprintf.h" +#include "../Attributes.h" +#include + +ATTRIBUTE_FORMAT(printf, 2, 3) ATTRIBUTE_WARN_UNUSED_RESULT int asprintf(char **result_string, const char *format_string, ...) +{ + // Handle variadic arguments and redirect to vasprintf + va_list arguments_local; + va_start(arguments_local, format_string); + int retVal = vasprintf(result_string, format_string, arguments_local); + va_end(arguments_local); // Destroy arguments_local + return retVal; +} + +#endif diff --git a/src/Helpers/Asprintf.h b/src/Helpers/Asprintf.h new file mode 100644 index 00000000..c1337abc --- /dev/null +++ b/src/Helpers/Asprintf.h @@ -0,0 +1,15 @@ +#pragma once + +// If defines asprintf for us, use its definition +#ifdef _GNU_SOURCE + +#include + +#else + +#include "../Attributes.h" +#define asprintf Portable_asprintf + +ATTRIBUTE_FORMAT(printf, 2, 3) ATTRIBUTE_WARN_UNUSED_RESULT int asprintf(char **resultString, const char *formatString, ...); + +#endif diff --git a/src/Helpers/FopenFormatted.cpp b/src/Helpers/FopenFormatted.cpp new file mode 100644 index 00000000..ded92eea --- /dev/null +++ b/src/Helpers/FopenFormatted.cpp @@ -0,0 +1,23 @@ +#include "FopenFormatted.h" +#include "../Attributes.h" +#include +#include +#include + +ATTRIBUTE_FORMAT(printf, 2, 3) ATTRIBUTE_WARN_UNUSED_RESULT FILE *fopenFormatted(const char *mode, const char *format_string, ...) +{ + // Handle variadic arguments and redirect to vasprintf + va_list arguments_local; + va_start(arguments_local, format_string); + char *path; + int vasprintf_retval = vasprintf(&path, format_string, arguments_local); + va_end(arguments_local); // Destroy arguments_local + + if (vasprintf_retval < 0) + return NULL; + + FILE *file = fopen(path, mode); + free(path); + + return file; +} diff --git a/src/Helpers/FopenFormatted.h b/src/Helpers/FopenFormatted.h new file mode 100644 index 00000000..e13c1726 --- /dev/null +++ b/src/Helpers/FopenFormatted.h @@ -0,0 +1,5 @@ +#pragma once +#include "../Attributes.h" +#include + +ATTRIBUTE_FORMAT(printf, 2, 3) ATTRIBUTE_WARN_UNUSED_RESULT FILE *fopenFormatted(const char *mode, const char *formatString, ...); diff --git a/src/Helpers/Strdup.cpp b/src/Helpers/Strdup.cpp new file mode 100644 index 00000000..84f9f478 --- /dev/null +++ b/src/Helpers/Strdup.cpp @@ -0,0 +1,20 @@ +#include +#if !(_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L) + +#include "Strdup.h" +#include "../Attributes.h" +#include +#include + +ATTRIBUTE_MALLOC ATTRIBUTE_NONNULL((1)) char *strdup(const char *duplicated_string) +{ + size_t duplicatedStringLength = strlen(duplicated_string) + sizeof(char); // Length of the whole string, plus the terminator + char *returnedString = (char *)malloc(duplicatedStringLength); // Memory for the new string is obtained with malloc. malloc also sets errno to ENOMEM on failure, which is exactly what we want for conformance + + if (returnedString) // If the result of malloc was NULL, allocation failed copying into it would be UB + memcpy(returnedString, duplicated_string, duplicatedStringLength); // Copy the entire duplicated string (including the null terminator) + + return returnedString; // Returns a pointer to the duplicated string on success, NULL if insufficient memory was available +} + +#endif diff --git a/src/Helpers/Strdup.h b/src/Helpers/Strdup.h new file mode 100644 index 00000000..08111b6a --- /dev/null +++ b/src/Helpers/Strdup.h @@ -0,0 +1,16 @@ +#pragma once +#include // Probably the smallest header that will include on systems with it + +// If defines strdup for us, use its definition +#if (_XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200809L) + +#include + +#else + +#include "../Attributes.h" +#define strdup Portable_strdup + +ATTRIBUTE_MALLOC ATTRIBUTE_NONNULL(1) char *strdup(const char *duplicatedString); + +#endif diff --git a/src/Helpers/Vasprintf.cpp b/src/Helpers/Vasprintf.cpp new file mode 100644 index 00000000..ba5babfd --- /dev/null +++ b/src/Helpers/Vasprintf.cpp @@ -0,0 +1,32 @@ +#ifndef _GNU_SOURCE + +#include "Vasprintf.h" +#include "../Attributes.h" +#include +#include +#include +#include + +ATTRIBUTE_FORMAT(printf, 2, 0) ATTRIBUTE_WARN_UNUSED_RESULT int vasprintf(char **result_string, const char *format_string, va_list arguments) +{ + const int error_return_value = -1; // According to the man page, this is returned on error + va_list arguments_local; + va_copy(arguments_local, arguments); // Copy the arguments so we can actually use them + + int size = vsnprintf(NULL, 0, format_string, arguments_local); // Get the amount of bytes we need for the output buffer + + va_end(arguments_local); // Destroy arguments_local + + if (size < 0) // If an output error is encountered, vsnprintf returns a negative value + return error_return_value; + + *result_string = (char *)malloc(size + 1); // Allocate enough space for the string (need + 1 for the null terminator) + + if (*result_string == NULL) // On error, malloc returns NULL + return error_return_value; + + // We know we have enough space, so we can use vsprintf safely + return vsprintf(*result_string, format_string, arguments); // vsprintf returns the amount of characters that got printed. This is what we're supposed to return +} + +#endif diff --git a/src/Helpers/Vasprintf.h b/src/Helpers/Vasprintf.h new file mode 100644 index 00000000..7af89984 --- /dev/null +++ b/src/Helpers/Vasprintf.h @@ -0,0 +1,16 @@ +#pragma once + +// If defines asprintf for us, use its definition +#ifdef _GNU_SOURCE + +#include + +#else + +#include "../Attributes.h" +#include +#define vasprintf Portable_vasprintf + +ATTRIBUTE_FORMAT(printf, 2, 0) ATTRIBUTE_WARN_UNUSED_RESULT int vasprintf(char **resultString, const char *formatString, va_list arguments); + +#endif diff --git a/src/Main.cpp b/src/Main.cpp index 7ecc3e91..61e861a1 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -24,9 +24,11 @@ #include "Resource.h" #include "Sound.h" #include "Triangle.h" +#include "Helpers/Asprintf.h" +#include "Helpers/Strdup.h" -char gModulePath[MAX_PATH]; -char gDataPath[MAX_PATH]; +char *gModulePath; +char *gDataPath; BOOL bFullscreen; BOOL gbUseJoystick = FALSE; @@ -82,6 +84,24 @@ void PutFramePerSecound(void) } } +static int main_out_backend_deinit(int return_value) +{ + Backend_Deinit(); + return return_value; +} + +static int main_out_free_module_path(int return_value) +{ + free(gModulePath); + return main_out_backend_deinit(return_value); +} + +static int main_out_free_data_path(int return_value) +{ + free(gDataPath); + return main_out_free_module_path(return_value); +} + // TODO - Inaccurate stack frame int main(int argc, char *argv[]) { @@ -93,10 +113,15 @@ int main(int argc, char *argv[]) return EXIT_FAILURE; // Get executable's path - if (!Backend_GetBasePath(gModulePath)) + if (!Backend_GetBasePath(&gModulePath)) { // Fall back on argv[0] if the backend cannot provide a path - strcpy(gModulePath, argv[0]); + gModulePath = strdup(argv[0]); + if (!gModulePath) + { + Backend_PrintError("Could not get executable path (not enough memory)"); + return main_out_backend_deinit(EXIT_FAILURE); + } for (size_t i = strlen(gModulePath);; --i) { @@ -109,8 +134,8 @@ int main(int argc, char *argv[]) } // Get path of the data folder - strcpy(gDataPath, gModulePath); - strcat(gDataPath, "/data"); + if (asprintf(&gDataPath, "%s/data", gModulePath) < 0) + return main_out_free_module_path(EXIT_FAILURE); CONFIG conf; if (!LoadConfigData(&conf)) @@ -223,18 +248,12 @@ int main(int argc, char *argv[]) if (conf.display_mode == 1) { if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 0)) - { - Backend_Deinit(); - return EXIT_FAILURE; - } + return main_out_free_data_path(EXIT_FAILURE); } else { if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 1)) - { - Backend_Deinit(); - return EXIT_FAILURE; - } + return main_out_free_data_path(EXIT_FAILURE); } #else // Doesn't handle StartDirectDraw failing @@ -255,10 +274,7 @@ int main(int argc, char *argv[]) #ifdef FIX_BUGS if (!StartDirectDraw(lpWindowName, windowWidth, windowHeight, 2)) - { - Backend_Deinit(); - return EXIT_FAILURE; - } + return main_out_free_data_path(EXIT_FAILURE); #else // Doesn't handle StartDirectDraw failing StartDirectDraw(lpWindowName, windowWidth, windowHeight, 2); @@ -326,10 +342,7 @@ int main(int argc, char *argv[]) // Draw to screen if (!Flip_SystemTask()) - { - Backend_Deinit(); - return EXIT_SUCCESS; - } + return main_out_free_data_path(EXIT_SUCCESS); // Initialize sound InitDirectSound(); @@ -353,9 +366,7 @@ int main(int argc, char *argv[]) EndDirectSound(); EndDirectDraw(); - Backend_Deinit(); - - return EXIT_SUCCESS; + return main_out_free_data_path(EXIT_SUCCESS); } void InactiveWindow(void) diff --git a/src/Main.h b/src/Main.h index 62d618bd..6c49da91 100644 --- a/src/Main.h +++ b/src/Main.h @@ -2,8 +2,8 @@ #include "WindowsWrapper.h" -extern char gModulePath[MAX_PATH]; -extern char gDataPath[MAX_PATH]; +extern char *gModulePath; +extern char *gDataPath; extern BOOL bFullscreen; extern BOOL gbUseJoystick; diff --git a/src/Map.cpp b/src/Map.cpp index 6cd6ac3e..05bf4357 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -12,6 +12,7 @@ #include "File.h" #include "Main.h" #include "NpChar.h" +#include "Helpers/FopenFormatted.h" #define PXM_BUFFER_SIZE 0x4B000 @@ -29,13 +30,9 @@ BOOL LoadMapData2(const char *path_map) { FILE *fp; char check[3]; - char path[MAX_PATH]; - - // Get path - sprintf(path, "%s/%s", gDataPath, path_map); // Open file - fp = fopen(path, "rb"); + fp = fopenFormatted("rb", "%s/%s", gDataPath, path_map); if (fp == NULL) return FALSE; @@ -69,12 +66,9 @@ BOOL LoadMapData2(const char *path_map) BOOL LoadAttributeData(const char *path_atrb) { FILE *fp; - char path[MAX_PATH]; // Open file - sprintf(path, "%s/%s", gDataPath, path_atrb); - - fp = fopen(path, "rb"); + fp = fopenFormatted("rb", "%s/%s", gDataPath, path_atrb); if (fp == NULL) return FALSE; diff --git a/src/MycParam.cpp b/src/MycParam.cpp index fe15772e..fd88f661 100644 --- a/src/MycParam.cpp +++ b/src/MycParam.cpp @@ -16,6 +16,8 @@ #include "Sound.h" #include "TextScr.h" #include "ValueView.h" +#include "Helpers/Asprintf.h" +#include "Helpers/FopenFormatted.h" ARMS_LEVEL gArmsLevelTable[14] = { @@ -436,14 +438,15 @@ BOOL SaveTimeCounter(void) unsigned char p[4]; REC rec; FILE *fp; - char path[MAX_PATH]; + char *path; // Quit if player doesn't have the Nikumaru Counter if (!(gMC.equip & EQUIP_NIKUMARU_COUNTER)) return TRUE; // Get last time - sprintf(path, "%s/290.rec", gModulePath); + if (asprintf(&path, "%s/290.rec", gModulePath) < 0) + return FALSE; fp = fopen(path, "rb"); if (fp != NULL) @@ -508,12 +511,9 @@ int LoadTimeCounter(void) unsigned char p[4]; REC rec; FILE *fp; - char path[MAX_PATH]; // Open file - sprintf(path, "%s/290.rec", gModulePath); - - fp = fopen(path, "rb"); + fp = fopenFormatted("rb", "%s/290.rec", gModulePath); if (fp == NULL) return 0; diff --git a/src/NpChar.cpp b/src/NpChar.cpp index d5d7b261..244006f5 100644 --- a/src/NpChar.cpp +++ b/src/NpChar.cpp @@ -17,6 +17,7 @@ #include "NpcTbl.h" #include "Sound.h" #include "ValueView.h" +#include "Helpers/FopenFormatted.h" NPCHAR gNPC[NPC_MAX]; int gCurlyShoot_wait; @@ -59,10 +60,7 @@ BOOL LoadEvent(const char *path_event) char code[4]; EVENT eve; - char path[MAX_PATH]; - sprintf(path, "%s/%s", gDataPath, path_event); - - fp = fopen(path, "rb"); + fp = fopenFormatted("rb", "%s/%s", gDataPath, path_event); if (fp == NULL) return FALSE; diff --git a/src/Profile.cpp b/src/Profile.cpp index 7d0c9cfa..b7fce47d 100644 --- a/src/Profile.cpp +++ b/src/Profile.cpp @@ -22,16 +22,14 @@ #include "Stage.h" #include "Star.h" #include "ValueView.h" +#include "Helpers/FopenFormatted.h" const char* const gDefaultName = "Profile.dat"; const char* const gProfileCode = "Do041220"; BOOL IsProfile(void) { - char path[MAX_PATH]; - sprintf(path, "%s/%s", gModulePath, gDefaultName); - - FILE *file = fopen(path, "rb"); + FILE *file = fopenFormatted("rb", "%s/%s", gModulePath, gDefaultName); if (file == NULL) return FALSE; @@ -41,24 +39,15 @@ BOOL IsProfile(void) BOOL SaveProfile(const char *name) { - FILE *fp; - PROFILE profile; const char *FLAG = "FLAG"; - char path[MAX_PATH]; - - // Get path - if (name != NULL) - sprintf(path, "%s/%s", gModulePath, name); - else - sprintf(path, "%s/%s", gModulePath, gDefaultName); - // Open file - fp = fopen(path, "wb"); + FILE *fp = fopenFormatted("wb", "%s/%s", gModulePath, ((name != NULL) ? name : gDefaultName)); if (fp == NULL) return FALSE; // Set up profile + PROFILE profile; memset(&profile, 0, sizeof(PROFILE)); memcpy(profile.code, gProfileCode, sizeof(profile.code)); memcpy(profile.FLAG, FLAG, sizeof(profile.FLAG)); @@ -124,16 +113,13 @@ BOOL LoadProfile(const char *name) { FILE *fp; PROFILE profile; - char path[MAX_PATH]; - - // Get path - if (name != NULL) - sprintf(path, "%s", name); - else - sprintf(path, "%s/%s", gModulePath, gDefaultName); // Open file - fp = fopen(path, "rb"); + if (name != NULL) + fp = fopenFormatted("rb", "%s", name); + else + fp = fopenFormatted("rb", "%s/%s", gModulePath, gDefaultName); + if (fp == NULL) return FALSE; diff --git a/src/SelStage.cpp b/src/SelStage.cpp index 1202ac01..377b84d0 100644 --- a/src/SelStage.cpp +++ b/src/SelStage.cpp @@ -1,5 +1,6 @@ #include "SelStage.h" +#include #include #include "WindowsWrapper.h" @@ -156,13 +157,13 @@ void PutStageSelectObject(void) int StageSelectLoop(int *p_event) { - char old_script_path[MAX_PATH]; - RECT rcView = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; gSelectedStage = 0; BackupSurface(SURFACE_ID_SCREEN_GRAB, &grcFull); - GetTextScriptPath(old_script_path); + char *old_script_path = GetTextScriptPath(); + if (!old_script_path) + return enum_ESCRETURN_exit; LoadTextScript2("StageSelect.tsc"); gStageSelectTitleY = (WINDOW_HEIGHT / 2) - 66; StartTextScript(gPermitStage[gSelectedStage].index + 1000); @@ -176,9 +177,11 @@ int StageSelectLoop(int *p_event) switch (Call_Escape()) { case enum_ESCRETURN_exit: + free(old_script_path); return enum_ESCRETURN_exit; case enum_ESCRETURN_restart: + free(old_script_path); return enum_ESCRETURN_restart; } } @@ -188,9 +191,11 @@ int StageSelectLoop(int *p_event) switch (TextScriptProc()) { case enum_ESCRETURN_exit: + free(old_script_path); return enum_ESCRETURN_exit; case enum_ESCRETURN_restart: + free(old_script_path); return enum_ESCRETURN_restart; } @@ -212,6 +217,7 @@ int StageSelectLoop(int *p_event) { StopTextScript(); LoadTextScript_Stage(old_script_path); + free(old_script_path); *p_event = 0; return enum_ESCRETURN_continue; } @@ -219,10 +225,14 @@ int StageSelectLoop(int *p_event) PutFramePerSecound(); if (!Flip_SystemTask()) + { + free(old_script_path); return enum_ESCRETURN_exit; + } } LoadTextScript_Stage(old_script_path); + free(old_script_path); *p_event = gPermitStage[gSelectedStage].event; return enum_ESCRETURN_continue; } diff --git a/src/Stage.cpp b/src/Stage.cpp index 21cafa53..15c094e9 100644 --- a/src/Stage.cpp +++ b/src/Stage.cpp @@ -131,8 +131,6 @@ const STAGE_TABLE gTMT[95] = { BOOL TransferStage(int no, int w, int x, int y) { - char path[MAX_PATH]; - char path_dir[20]; BOOL bError; // Move character @@ -141,7 +139,15 @@ BOOL TransferStage(int no, int w, int x, int y) bError = FALSE; // Get path - strcpy(path_dir, "Stage"); + char path_dir[sizeof("Stage")] = "Stage"; // Can only be either "Stage" or "Npc", and sizeof("Stage") > sizeof("Npc") + /* + * The size of path should be size of the format string (without the operands) + size of first operand + size of second operand - 2 (no null terminator needed for the first two operands, and sizeof will include the size for the null terminators here) + * The size of the format string is sizeof("/.pxa") because that's the biggest raw format (omitting the operands) used here + * Size of first operand is sizeof(path_dir) because that's always the first operand + * Size of second operand is sizeof(gTMT[no].parts) because all the operands used here (gTMT[no].parts, gTMT[no].map, gTMT[no].npc, gTMT[no].boss) are of the same size + * sprintf(path, "%s", gTMT[no].back) is irrelevant here because sizeof(gTMT[no].back) is the same as the size of all the operands discussed for the size of the second operand, so gTMT[no].back always fits into the size allocated for the second operand alone + */ + char path[sizeof("/.pxa") + sizeof(path_dir) + sizeof(gTMT[no].parts) - 2]; // Load tileset sprintf(path, "%s/Prt%s", path_dir, gTMT[no].parts); diff --git a/src/TextScr.cpp b/src/TextScr.cpp index 8c9bada9..660cea3c 100644 --- a/src/TextScr.cpp +++ b/src/TextScr.cpp @@ -33,6 +33,8 @@ #include "SelStage.h" #include "Sound.h" #include "Stage.h" +#include "Helpers/Asprintf.h" +#include "Helpers/Strdup.h" // This limits the size of a .tsc script to 0x5000 bytes (the game will crash above this) #define TSC_BUFFER_SIZE 0x5000 @@ -124,17 +126,22 @@ void EncryptionBinaryData2(unsigned char *pData, long size) BOOL LoadTextScript2(const char *name) { FILE *fp; - char path[MAX_PATH]; + char *path; // Get path - sprintf(path, "%s/%s", gDataPath, name); + if (asprintf(&path, "%s/%s", gDataPath, name) < 0) + return FALSE; gTS.size = GetFileSizeLong(path); if (gTS.size == -1) + { + free(path); return FALSE; + } // Open file fp = fopen(path, "rb"); + free(path); if (fp == NULL) return FALSE; @@ -144,7 +151,9 @@ BOOL LoadTextScript2(const char *name) fclose(fp); // Set path - strcpy(gTS.path, name); + if (gTS.path != NULL) + free(gTS.path); + gTS.path = strdup(name); // Decrypt data EncryptionBinaryData2((unsigned char*)gTS.data, gTS.size); @@ -156,18 +165,23 @@ BOOL LoadTextScript2(const char *name) BOOL LoadTextScript_Stage(const char *name) { FILE *fp; - char path[MAX_PATH]; long head_size; long body_size; // Open Head.tsc - sprintf(path, "%s/%s", gDataPath, "Head.tsc"); + char *path; + if (asprintf(&path, "%s/%s", gDataPath, "Head.tsc") < 0) + return FALSE; head_size = GetFileSizeLong(path); if (head_size == -1) + { + free(path); return FALSE; + } fp = fopen(path, "rb"); + free(path); if (fp == NULL) return FALSE; @@ -178,13 +192,18 @@ BOOL LoadTextScript_Stage(const char *name) fclose(fp); // Open stage's .tsc - sprintf(path, "%s/%s", gDataPath, name); + if (asprintf(&path, "%s/%s", gDataPath, name) < 0) + return FALSE; body_size = GetFileSizeLong(path); if (body_size == -1) + { + free(path); return FALSE; + } fp = fopen(path, "rb"); + free(path); if (fp == NULL) return FALSE; @@ -196,15 +215,17 @@ BOOL LoadTextScript_Stage(const char *name) // Set parameters gTS.size = head_size + body_size; - strcpy(gTS.path, name); + if (gTS.path != NULL) + free(gTS.path); + gTS.path = strdup(name); return TRUE; } // Get current path -void GetTextScriptPath(char *path) +char *GetTextScriptPath() { - strcpy(path, gTS.path); + return strdup(gTS.path); } // Get 4 digit number from TSC data @@ -1281,11 +1302,13 @@ int TextScriptProc(void) } else { - char str_0[0x40]; + // The size of str_0 is the size of the format string (includes null terminator so that's the space we'll be using for ours) + the 3 chars from the format string #ifdef JAPANESE + char str_0[sizeof("不明のコード:<") + (sizeof(char) * 3)]; sprintf(str_0, "不明のコード:<%c%c%c", gTS.data[gTS.p_read + 1], gTS.data[gTS.p_read + 2], gTS.data[gTS.p_read + 3]); Backend_ShowMessageBox("エラー", str_0); #else + char str_0[sizeof("Unknown code:<%c%c%c") + (sizeof(char) * 3)]; sprintf(str_0, "Unknown code:<%c%c%c", gTS.data[gTS.p_read + 1], gTS.data[gTS.p_read + 2], gTS.data[gTS.p_read + 3]); Backend_ShowMessageBox("Error", str_0); #endif diff --git a/src/TextScr.h b/src/TextScr.h index eb87f61f..c3ded179 100644 --- a/src/TextScr.h +++ b/src/TextScr.h @@ -5,7 +5,7 @@ typedef struct TEXT_SCRIPT { // Path (reload when exit teleporter menu/inventory) - char path[MAX_PATH]; + char *path; // Script buffer long size; @@ -62,7 +62,7 @@ void EndTextScript(void); void EncryptionBinaryData2(unsigned char *pData, long size); BOOL LoadTextScript2(const char *name); BOOL LoadTextScript_Stage(const char *name); -void GetTextScriptPath(char *path); +char *GetTextScriptPath(); BOOL StartTextScript(int no); void StopTextScript(void); void PutTextScript(void); diff --git a/src/WindowsWrapper.h b/src/WindowsWrapper.h index 58eda2c1..1db7be95 100644 --- a/src/WindowsWrapper.h +++ b/src/WindowsWrapper.h @@ -4,10 +4,9 @@ #define WIN32_LEAN_AND_MEAN #include #undef FindResource +#undef MAX_PATH // Explicitly undefine MAX_PATH to avoid accidental usage of it #else -#include - #define RGB(r,g,b) ((r) | ((g) << 8) | ((b) << 16)) typedef bool BOOL; @@ -23,6 +22,4 @@ struct RECT long bottom; }; -#define MAX_PATH FILENAME_MAX - #endif