From 74c486201d699139280b359df79e8fd32ef6910f Mon Sep 17 00:00:00 2001 From: Ray Date: Wed, 4 Mar 2020 00:21:46 +0100 Subject: [PATCH] ADDED: LoadFileText() and SaveFileText() Improved file access checks --- src/raylib.h | 6 ++- src/rlgl.h | 105 +++++++++++++++++++++-------------------- src/utils.c | 130 ++++++++++++++++++++++++++++++++++++++++----------- 3 files changed, 158 insertions(+), 83 deletions(-) diff --git a/src/raylib.h b/src/raylib.h index 48728fc17..0c15849ef 100644 --- a/src/raylib.h +++ b/src/raylib.h @@ -156,6 +156,7 @@ #define FormatText TextFormat #define SubText TextSubtext #define ShowWindow UnhideWindow +#define LoadText LoadFileText //---------------------------------------------------------------------------------- // Structures Definition @@ -951,6 +952,8 @@ RLAPI int GetRandomValue(int min, int max); // Returns a r // Files management functions RLAPI unsigned char *LoadFileData(const char *fileName, int *bytesRead); // Load file data as byte array (read) RLAPI void SaveFileData(const char *fileName, void *data, int bytesToWrite); // Save data to file from byte array (write) +RLAPI char *LoadFileText(const char *fileName); // Load text data from file (read), returns a '\0' terminated string +RLAPI void SaveFileText(const char *fileName, char *text); // Save text data to file (write), string must be '\0' terminated RLAPI bool FileExists(const char *fileName); // Check if file exists RLAPI bool IsFileExtension(const char *fileName, const char *ext);// Check file extension RLAPI bool DirectoryExists(const char *dirPath); // Check if a directory path exists @@ -1322,9 +1325,8 @@ RLAPI RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight); //------------------------------------------------------------------------------------ // Shader loading/unloading functions -RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetShaderDefault(void); // Get default shader diff --git a/src/rlgl.h b/src/rlgl.h index 536f8103e..c90905dc5 100644 --- a/src/rlgl.h +++ b/src/rlgl.h @@ -546,9 +546,8 @@ RLAPI void rlUnloadMesh(Mesh mesh); // Unl // NOTE: This functions are useless when using OpenGL 1.1 //------------------------------------------------------------------------------------ // Shader loading/unloading functions -RLAPI char *LoadText(const char *fileName); // Load chars array from text file RLAPI Shader LoadShader(const char *vsFileName, const char *fsFileName); // Load shader from files and bind default locations -RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations +RLAPI Shader LoadShaderCode(const char *vsCode, const char *fsCode); // Load shader from code strings and bind default locations RLAPI void UnloadShader(Shader shader); // Unload shader from GPU memory (VRAM) RLAPI Shader GetShaderDefault(void); // Get default shader @@ -588,6 +587,7 @@ RLAPI void ToggleVrMode(void); // Enable/Disable VR exp RLAPI void BeginVrDrawing(void); // Begin VR simulator stereo rendering RLAPI void EndVrDrawing(void); // End VR simulator stereo rendering +RLAPI char *LoadFileText(const char *fileName); // Load chars array from text file RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data size in bytes (image or texture) #endif @@ -605,22 +605,20 @@ RLAPI int GetPixelDataSize(int width, int height, int format);// Get pixel data #if defined(RLGL_IMPLEMENTATION) -#if !defined(RLGL_STANDALONE) +#if defined(RLGL_STANDALONE) + #include // Required for: fopen(), fseek(), fread(), fclose() [LoadFileText] +#else // Check if config flags have been externally provided on compilation line #if !defined(EXTERNAL_CONFIG_FLAGS) #include "config.h" // Defines module configuration flags #endif + #include "raymath.h" // Required for: Vector3 and Matrix functions #endif #include // Required for: malloc(), free() -#include // Required for: fopen(), fseek(), fread(), fclose() [LoadText] #include // Required for: strcmp(), strlen() [Used in rlglInit(), on extensions loading] #include // Required for: atan2f(), fabs() -#if !defined(RLGL_STANDALONE) - #include "raymath.h" // Required for: Vector3 and Matrix functions -#endif - #if defined(GRAPHICS_API_OPENGL_11) #if defined(__APPLE__) #include // OpenGL 1.1 library for OSX @@ -2984,49 +2982,6 @@ Shader GetShaderDefault(void) #endif } -// Load text data from file -// NOTE: text chars array should be freed manually -char *LoadText(const char *fileName) -{ - char *text = NULL; - - if (fileName != NULL) - { - FILE *textFile = fopen(fileName, "rt"); - - if (textFile != NULL) - { - // WARNING: When reading a file as 'text' file, - // text mode causes carriage return-linefeed translation... - // ...but using fseek() should return correct byte-offset - fseek(textFile, 0, SEEK_END); - int size = ftell(textFile); - fseek(textFile, 0, SEEK_SET); - - if (size > 0) - { - text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); - int count = fread(text, sizeof(char), size, textFile); - - // WARNING: \r\n is converted to \n on reading, so, - // read bytes count gets reduced by the number of lines - if (count < size) - { - text = RL_REALLOC(text, count + 1); - } - - // zero-terminate the string - text[count] = '\0'; - } - - fclose(textFile); - } - else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); - } - - return text; -} - // Load shader from files and bind default locations // NOTE: If shader string is NULL, using default vertex/fragment shaders Shader LoadShader(const char *vsFileName, const char *fsFileName) @@ -3038,8 +2993,8 @@ Shader LoadShader(const char *vsFileName, const char *fsFileName) char *vShaderStr = NULL; char *fShaderStr = NULL; - if (vsFileName != NULL) vShaderStr = LoadText(vsFileName); - if (fsFileName != NULL) fShaderStr = LoadText(fsFileName); + if (vsFileName != NULL) vShaderStr = LoadFileText(vsFileName); + if (fsFileName != NULL) fShaderStr = LoadFileText(fsFileName); shader = LoadShaderCode(vShaderStr, fShaderStr); @@ -4643,6 +4598,50 @@ static Color *GenNextMipmap(Color *srcData, int srcWidth, int srcHeight) #endif #if defined(RLGL_STANDALONE) +// Load text data from file, returns a '\0' terminated string +// NOTE: text chars array should be freed manually +char *LoadFileText(const char *fileName) +{ + char *text = NULL; + + if (fileName != NULL) + { + FILE *textFile = fopen(fileName, "rt"); + + if (textFile != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(textFile, 0, SEEK_END); + int size = ftell(textFile); + fseek(textFile, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); + int count = fread(text, sizeof(char), size, textFile); + + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < size) text = RL_REALLOC(text, count + 1); + + // Zero-terminate the string + text[count] = '\0'; + + TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName); + + fclose(textFile); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); + + return text; +} + // Get pixel data size in bytes (image or texture) // NOTE: Size depends on pixel format int GetPixelDataSize(int width, int height, int format) diff --git a/src/utils.c b/src/utils.c index 9aaf548b4..34369744f 100644 --- a/src/utils.c +++ b/src/utils.c @@ -169,32 +169,36 @@ unsigned char *LoadFileData(const char *fileName, int *bytesRead) unsigned char *data = NULL; *bytesRead = 0; - FILE *file = fopen(fileName, "rb"); - - if (file != NULL) + if (fileName != NULL) { - // WARNING: On binary streams SEEK_END could not be found, - // using fseek() and ftell() could not work in some (rare) cases - fseek(file, 0, SEEK_END); - int size = ftell(file); - fseek(file, 0, SEEK_SET); + FILE *file = fopen(fileName, "rb"); - if (size > 0) + if (file != NULL) { - data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size); - - // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] - int count = fread(data, sizeof(unsigned char), size, file); - *bytesRead = count; - - if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName); - else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName); + // WARNING: On binary streams SEEK_END could not be found, + // using fseek() and ftell() could not work in some (rare) cases + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, 0, SEEK_SET); + + if (size > 0) + { + data = (unsigned char *)RL_MALLOC(sizeof(unsigned char)*size); + + // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] + int count = fread(data, sizeof(unsigned char), size, file); + *bytesRead = count; + + if (count != size) TRACELOG(LOG_WARNING, "[%s] File partially loaded", fileName); + else TRACELOG(LOG_INFO, "[%s] File loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName); + + fclose(file); } - else TRACELOG(LOG_WARNING, "[%s] File could not be read", fileName); - - fclose(file); + else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); } - else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); + else TRACELOG(LOG_WARNING, "File name provided is not valid"); return data; } @@ -202,18 +206,88 @@ unsigned char *LoadFileData(const char *fileName, int *bytesRead) // Save data to file from buffer void SaveFileData(const char *fileName, void *data, int bytesToWrite) { - FILE *file = fopen(fileName, "wb"); + if (fileName != NULL) + { + FILE *file = fopen(fileName, "wb"); + + if (file != NULL) + { + int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file); + + if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName); + else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName); + else TRACELOG(LOG_INFO, "[%s] File successfully saved", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); +} + +// Load text data from file, returns a '\0' terminated string +// NOTE: text chars array should be freed manually +char *LoadFileText(const char *fileName) +{ + char *text = NULL; - if (file != NULL) + if (fileName != NULL) { - int count = fwrite(data, sizeof(unsigned char), bytesToWrite, file); + FILE *textFile = fopen(fileName, "rt"); - if (count == 0) TRACELOG(LOG_WARNING, "[%s] File could not be written", fileName); - else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "[%s] File partially written", fileName); + if (textFile != NULL) + { + // WARNING: When reading a file as 'text' file, + // text mode causes carriage return-linefeed translation... + // ...but using fseek() should return correct byte-offset + fseek(textFile, 0, SEEK_END); + int size = ftell(textFile); + fseek(textFile, 0, SEEK_SET); + + if (size > 0) + { + text = (char *)RL_MALLOC(sizeof(char)*(size + 1)); + int count = fread(text, sizeof(char), size, textFile); + + // WARNING: \r\n is converted to \n on reading, so, + // read bytes count gets reduced by the number of lines + if (count < size) text = RL_REALLOC(text, count + 1); + + // Zero-terminate the string + text[count] = '\0'; + + TRACELOG(LOG_INFO, "[%s] Text file loaded successfully", fileName); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be read", fileName); + + fclose(textFile); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); + } + else TRACELOG(LOG_WARNING, "File name provided is not valid"); - fclose(file); + return text; +} + +// Save text data to file (write), string must be '\0' terminated +void SaveFileText(const char *fileName, char *text) +{ + if (fileName != NULL) + { + FILE *file = fopen(fileName, "wt"); + + if (file != NULL) + { + int count = fprintf(file, "%s", text); + + if (count == 0) TRACELOG(LOG_WARNING, "[%s] Text file could not be written", fileName); + else TRACELOG(LOG_INFO, "[%s] Text file successfully saved", fileName); + + fclose(file); + } + else TRACELOG(LOG_WARNING, "[%s] Text file could not be opened", fileName); } - else TRACELOG(LOG_WARNING, "[%s] File could not be opened", fileName); + else TRACELOG(LOG_WARNING, "File name provided is not valid"); } #if defined(PLATFORM_ANDROID)