github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/utils.c (about) 1 /********************************************************************************************** 2 * 3 * raylib.utils - Some common utility functions 4 * 5 * CONFIGURATION: 6 * 7 * #define SUPPORT_TRACELOG 8 * Show TraceLog() output messages 9 * NOTE: By default LOG_DEBUG traces not shown 10 * 11 * 12 * LICENSE: zlib/libpng 13 * 14 * Copyright (c) 2014-2022 Ramon Santamaria (@raysan5) 15 * 16 * This software is provided "as-is", without any express or implied warranty. In no event 17 * will the authors be held liable for any damages arising from the use of this software. 18 * 19 * Permission is granted to anyone to use this software for any purpose, including commercial 20 * applications, and to alter it and redistribute it freely, subject to the following restrictions: 21 * 22 * 1. The origin of this software must not be misrepresented; you must not claim that you 23 * wrote the original software. If you use this software in a product, an acknowledgment 24 * in the product documentation would be appreciated but is not required. 25 * 26 * 2. Altered source versions must be plainly marked as such, and must not be misrepresented 27 * as being the original software. 28 * 29 * 3. This notice may not be removed or altered from any source distribution. 30 * 31 **********************************************************************************************/ 32 33 #include "raylib.h" // WARNING: Required for: LogType enum 34 35 // Check if config flags have been externally provided on compilation line 36 #if !defined(EXTERNAL_CONFIG_FLAGS) 37 #include "config.h" // Defines module configuration flags 38 #endif 39 40 #include "utils.h" 41 42 #if defined(PLATFORM_ANDROID) 43 #include <errno.h> // Required for: Android error types 44 #include <android/log.h> // Required for: Android log system: __android_log_vprint() 45 #include <android/asset_manager.h> // Required for: Android assets manager: AAsset, AAssetManager_open(), ... 46 #endif 47 48 #include <stdlib.h> // Required for: exit() 49 #include <stdio.h> // Required for: FILE, fopen(), fseek(), ftell(), fread(), fwrite(), fprintf(), vprintf(), fclose() 50 #include <stdarg.h> // Required for: va_list, va_start(), va_end() 51 #include <string.h> // Required for: strcpy(), strcat() 52 53 //---------------------------------------------------------------------------------- 54 // Defines and Macros 55 //---------------------------------------------------------------------------------- 56 #ifndef MAX_TRACELOG_MSG_LENGTH 57 #define MAX_TRACELOG_MSG_LENGTH 128 // Max length of one trace-log message 58 #endif 59 60 //---------------------------------------------------------------------------------- 61 // Global Variables Definition 62 //---------------------------------------------------------------------------------- 63 static int logTypeLevel = LOG_INFO; // Minimum log type level 64 65 static TraceLogCallback traceLog = NULL; // TraceLog callback function pointer 66 static LoadFileDataCallback loadFileData = NULL; // LoadFileData callback funtion pointer 67 static SaveFileDataCallback saveFileData = NULL; // SaveFileText callback funtion pointer 68 static LoadFileTextCallback loadFileText = NULL; // LoadFileText callback funtion pointer 69 static SaveFileTextCallback saveFileText = NULL; // SaveFileText callback funtion pointer 70 71 //---------------------------------------------------------------------------------- 72 // Functions to set internal callbacks 73 //---------------------------------------------------------------------------------- 74 void SetTraceLogCallback(TraceLogCallback callback) { traceLog = callback; } // Set custom trace log 75 void SetLoadFileDataCallback(LoadFileDataCallback callback) { loadFileData = callback; } // Set custom file data loader 76 void SetSaveFileDataCallback(SaveFileDataCallback callback) { saveFileData = callback; } // Set custom file data saver 77 void SetLoadFileTextCallback(LoadFileTextCallback callback) { loadFileText = callback; } // Set custom file text loader 78 void SetSaveFileTextCallback(SaveFileTextCallback callback) { saveFileText = callback; } // Set custom file text saver 79 80 81 #if defined(PLATFORM_ANDROID) 82 static AAssetManager *assetManager = NULL; // Android assets manager pointer 83 static const char *internalDataPath = NULL; // Android internal data path 84 #endif 85 86 //---------------------------------------------------------------------------------- 87 // Module specific Functions Declaration 88 //---------------------------------------------------------------------------------- 89 #if defined(PLATFORM_ANDROID) 90 FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), 91 fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)); 92 93 static int android_read(void *cookie, char *buf, int size); 94 static int android_write(void *cookie, const char *buf, int size); 95 static fpos_t android_seek(void *cookie, fpos_t offset, int whence); 96 static int android_close(void *cookie); 97 #endif 98 99 //---------------------------------------------------------------------------------- 100 // Module Functions Definition - Utilities 101 //---------------------------------------------------------------------------------- 102 103 // Set the current threshold (minimum) log level 104 void SetTraceLogLevel(int logType) { logTypeLevel = logType; } 105 106 // Show trace log messages (LOG_INFO, LOG_WARNING, LOG_ERROR, LOG_DEBUG) 107 void TraceLog(int logType, const char *text, ...) 108 { 109 #if defined(SUPPORT_TRACELOG) 110 // Message has level below current threshold, don't emit 111 if (logType < logTypeLevel) return; 112 113 va_list args; 114 va_start(args, text); 115 116 if (traceLog) 117 { 118 traceLog(logType, text, args); 119 va_end(args); 120 return; 121 } 122 123 #if defined(PLATFORM_ANDROID) 124 switch (logType) 125 { 126 case LOG_TRACE: __android_log_vprint(ANDROID_LOG_VERBOSE, "raylib", text, args); break; 127 case LOG_DEBUG: __android_log_vprint(ANDROID_LOG_DEBUG, "raylib", text, args); break; 128 case LOG_INFO: __android_log_vprint(ANDROID_LOG_INFO, "raylib", text, args); break; 129 case LOG_WARNING: __android_log_vprint(ANDROID_LOG_WARN, "raylib", text, args); break; 130 case LOG_ERROR: __android_log_vprint(ANDROID_LOG_ERROR, "raylib", text, args); break; 131 case LOG_FATAL: __android_log_vprint(ANDROID_LOG_FATAL, "raylib", text, args); break; 132 default: break; 133 } 134 #else 135 char buffer[MAX_TRACELOG_MSG_LENGTH] = { 0 }; 136 137 switch (logType) 138 { 139 case LOG_TRACE: strcpy(buffer, "TRACE: "); break; 140 case LOG_DEBUG: strcpy(buffer, "DEBUG: "); break; 141 case LOG_INFO: strcpy(buffer, "INFO: "); break; 142 case LOG_WARNING: strcpy(buffer, "WARNING: "); break; 143 case LOG_ERROR: strcpy(buffer, "ERROR: "); break; 144 case LOG_FATAL: strcpy(buffer, "FATAL: "); break; 145 default: break; 146 } 147 148 strcat(buffer, text); 149 strcat(buffer, "\n"); 150 vprintf(buffer, args); 151 fflush(stdout); 152 #endif 153 154 va_end(args); 155 156 if (logType == LOG_FATAL) exit(EXIT_FAILURE); // If fatal logging, exit program 157 158 #endif // SUPPORT_TRACELOG 159 } 160 161 // Internal memory allocator 162 // NOTE: Initializes to zero by default 163 void *MemAlloc(unsigned int size) 164 { 165 void *ptr = RL_CALLOC(size, 1); 166 return ptr; 167 } 168 169 // Internal memory reallocator 170 void *MemRealloc(void *ptr, unsigned int size) 171 { 172 void *ret = RL_REALLOC(ptr, size); 173 return ret; 174 } 175 176 // Internal memory free 177 void MemFree(void *ptr) 178 { 179 RL_FREE(ptr); 180 } 181 182 // Load data from file into a buffer 183 unsigned char *LoadFileData(const char *fileName, unsigned int *bytesRead) 184 { 185 unsigned char *data = NULL; 186 *bytesRead = 0; 187 188 if (fileName != NULL) 189 { 190 if (loadFileData) 191 { 192 data = loadFileData(fileName, bytesRead); 193 return data; 194 } 195 #if defined(SUPPORT_STANDARD_FILEIO) 196 FILE *file = fopen(fileName, "rb"); 197 198 if (file != NULL) 199 { 200 // WARNING: On binary streams SEEK_END could not be found, 201 // using fseek() and ftell() could not work in some (rare) cases 202 fseek(file, 0, SEEK_END); 203 int size = ftell(file); 204 fseek(file, 0, SEEK_SET); 205 206 if (size > 0) 207 { 208 data = (unsigned char *)RL_MALLOC(size*sizeof(unsigned char)); 209 210 // NOTE: fread() returns number of read elements instead of bytes, so we read [1 byte, size elements] 211 unsigned int count = (unsigned int)fread(data, sizeof(unsigned char), size, file); 212 *bytesRead = count; 213 214 if (count != size) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially loaded", fileName); 215 else TRACELOG(LOG_INFO, "FILEIO: [%s] File loaded successfully", fileName); 216 } 217 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read file", fileName); 218 219 fclose(file); 220 } 221 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); 222 #else 223 TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); 224 #endif 225 } 226 else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); 227 228 return data; 229 } 230 231 // Unload file data allocated by LoadFileData() 232 void UnloadFileData(unsigned char *data) 233 { 234 RL_FREE(data); 235 } 236 237 // Save data to file from buffer 238 bool SaveFileData(const char *fileName, void *data, unsigned int bytesToWrite) 239 { 240 bool success = false; 241 242 if (fileName != NULL) 243 { 244 if (saveFileData) 245 { 246 return saveFileData(fileName, data, bytesToWrite); 247 } 248 #if defined(SUPPORT_STANDARD_FILEIO) 249 FILE *file = fopen(fileName, "wb"); 250 251 if (file != NULL) 252 { 253 unsigned int count = (unsigned int)fwrite(data, sizeof(unsigned char), bytesToWrite, file); 254 255 if (count == 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write file", fileName); 256 else if (count != bytesToWrite) TRACELOG(LOG_WARNING, "FILEIO: [%s] File partially written", fileName); 257 else TRACELOG(LOG_INFO, "FILEIO: [%s] File saved successfully", fileName); 258 259 int result = fclose(file); 260 if (result == 0) success = true; 261 } 262 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open file", fileName); 263 #else 264 TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); 265 #endif 266 } 267 else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); 268 269 return success; 270 } 271 272 // Export data to code (.h), returns true on success 273 bool ExportDataAsCode(const unsigned char *data, unsigned int size, const char *fileName) 274 { 275 bool success = false; 276 277 #ifndef TEXT_BYTES_PER_LINE 278 #define TEXT_BYTES_PER_LINE 20 279 #endif 280 281 // NOTE: Text data buffer size is estimated considering raw data size in bytes 282 // and requiring 6 char bytes for every byte: "0x00, " 283 char *txtData = (char *)RL_CALLOC(size*6 + 2000, sizeof(char)); 284 285 int byteCount = 0; 286 byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n"); 287 byteCount += sprintf(txtData + byteCount, "// //\n"); 288 byteCount += sprintf(txtData + byteCount, "// DataAsCode exporter v1.0 - Raw data exported as an array of bytes //\n"); 289 byteCount += sprintf(txtData + byteCount, "// //\n"); 290 byteCount += sprintf(txtData + byteCount, "// more info and bugs-report: github.com/raysan5/raylib //\n"); 291 byteCount += sprintf(txtData + byteCount, "// feedback and support: ray[at]raylib.com //\n"); 292 byteCount += sprintf(txtData + byteCount, "// //\n"); 293 byteCount += sprintf(txtData + byteCount, "// Copyright (c) 2022 Ramon Santamaria (@raysan5) //\n"); 294 byteCount += sprintf(txtData + byteCount, "// //\n"); 295 byteCount += sprintf(txtData + byteCount, "////////////////////////////////////////////////////////////////////////////////////////\n\n"); 296 297 // Get file name from path and convert variable name to uppercase 298 char varFileName[256] = { 0 }; 299 strcpy(varFileName, GetFileNameWithoutExt(fileName)); 300 for (int i = 0; varFileName[i] != '\0'; i++) if ((varFileName[i] >= 'a') && (varFileName[i] <= 'z')) { varFileName[i] = varFileName[i] - 32; } 301 302 byteCount += sprintf(txtData + byteCount, "static unsigned char %s_DATA[%i] = { ", varFileName, size); 303 for (unsigned int i = 0; i < size - 1; i++) byteCount += sprintf(txtData + byteCount, ((i%TEXT_BYTES_PER_LINE == 0)? "0x%x,\n" : "0x%x, "), data[i]); 304 byteCount += sprintf(txtData + byteCount, "0x%x };\n", data[size - 1]); 305 306 // NOTE: Text data size exported is determined by '\0' (NULL) character 307 success = SaveFileText(fileName, txtData); 308 309 RL_FREE(txtData); 310 311 if (success != 0) TRACELOG(LOG_INFO, "FILEIO: [%s] Data as code exported successfully", fileName); 312 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to export data as code", fileName); 313 314 return success; 315 } 316 317 // Load text data from file, returns a '\0' terminated string 318 // NOTE: text chars array should be freed manually 319 char *LoadFileText(const char *fileName) 320 { 321 char *text = NULL; 322 323 if (fileName != NULL) 324 { 325 if (loadFileText) 326 { 327 text = loadFileText(fileName); 328 return text; 329 } 330 #if defined(SUPPORT_STANDARD_FILEIO) 331 FILE *file = fopen(fileName, "rt"); 332 333 if (file != NULL) 334 { 335 // WARNING: When reading a file as 'text' file, 336 // text mode causes carriage return-linefeed translation... 337 // ...but using fseek() should return correct byte-offset 338 fseek(file, 0, SEEK_END); 339 unsigned int size = (unsigned int)ftell(file); 340 fseek(file, 0, SEEK_SET); 341 342 if (size > 0) 343 { 344 text = (char *)RL_MALLOC((size + 1)*sizeof(char)); 345 unsigned int count = (unsigned int)fread(text, sizeof(char), size, file); 346 347 // WARNING: \r\n is converted to \n on reading, so, 348 // read bytes count gets reduced by the number of lines 349 if (count < size) text = RL_REALLOC(text, count + 1); 350 351 // Zero-terminate the string 352 text[count] = '\0'; 353 354 TRACELOG(LOG_INFO, "FILEIO: [%s] Text file loaded successfully", fileName); 355 } 356 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to read text file", fileName); 357 358 fclose(file); 359 } 360 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); 361 #else 362 TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); 363 #endif 364 } 365 else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); 366 367 return text; 368 } 369 370 // Unload file text data allocated by LoadFileText() 371 void UnloadFileText(char *text) 372 { 373 RL_FREE(text); 374 } 375 376 // Save text data to file (write), string must be '\0' terminated 377 bool SaveFileText(const char *fileName, char *text) 378 { 379 bool success = false; 380 381 if (fileName != NULL) 382 { 383 if (saveFileText) 384 { 385 return saveFileText(fileName, text); 386 } 387 #if defined(SUPPORT_STANDARD_FILEIO) 388 FILE *file = fopen(fileName, "wt"); 389 390 if (file != NULL) 391 { 392 int count = fprintf(file, "%s", text); 393 394 if (count < 0) TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to write text file", fileName); 395 else TRACELOG(LOG_INFO, "FILEIO: [%s] Text file saved successfully", fileName); 396 397 int result = fclose(file); 398 if (result == 0) success = true; 399 } 400 else TRACELOG(LOG_WARNING, "FILEIO: [%s] Failed to open text file", fileName); 401 #else 402 TRACELOG(LOG_WARNING, "FILEIO: Standard file io not supported, use custom file callback"); 403 #endif 404 } 405 else TRACELOG(LOG_WARNING, "FILEIO: File name provided is not valid"); 406 407 return success; 408 } 409 410 #if defined(PLATFORM_ANDROID) 411 // Initialize asset manager from android app 412 void InitAssetManager(AAssetManager *manager, const char *dataPath) 413 { 414 assetManager = manager; 415 internalDataPath = dataPath; 416 } 417 418 // Replacement for fopen() 419 // Ref: https://developer.android.com/ndk/reference/group/asset 420 FILE *android_fopen(const char *fileName, const char *mode) 421 { 422 if (mode[0] == 'w') 423 { 424 // fopen() is mapped to android_fopen() that only grants read access to 425 // assets directory through AAssetManager but we want to also be able to 426 // write data when required using the standard stdio FILE access functions 427 // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only 428 #undef fopen 429 return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode); 430 #define fopen(name, mode) android_fopen(name, mode) 431 } 432 else 433 { 434 // NOTE: AAsset provides access to read-only asset 435 AAsset *asset = AAssetManager_open(assetManager, fileName, AASSET_MODE_UNKNOWN); 436 437 if (asset != NULL) 438 { 439 // Get pointer to file in the assets 440 return funopen(asset, android_read, android_write, android_seek, android_close); 441 } 442 else 443 { 444 #undef fopen 445 // Just do a regular open if file is not found in the assets 446 return fopen(TextFormat("%s/%s", internalDataPath, fileName), mode); 447 #define fopen(name, mode) android_fopen(name, mode) 448 } 449 } 450 } 451 #endif // PLATFORM_ANDROID 452 453 //---------------------------------------------------------------------------------- 454 // Module specific Functions Definition 455 //---------------------------------------------------------------------------------- 456 #if defined(PLATFORM_ANDROID) 457 static int android_read(void *cookie, char *buf, int size) 458 { 459 return AAsset_read((AAsset *)cookie, buf, size); 460 } 461 462 static int android_write(void *cookie, const char *buf, int size) 463 { 464 TRACELOG(LOG_WARNING, "ANDROID: Failed to provide write access to APK"); 465 466 return EACCES; 467 } 468 469 static fpos_t android_seek(void *cookie, fpos_t offset, int whence) 470 { 471 return AAsset_seek((AAsset *)cookie, offset, whence); 472 } 473 474 static int android_close(void *cookie) 475 { 476 AAsset_close((AAsset *)cookie); 477 return 0; 478 } 479 #endif // PLATFORM_ANDROID