Logo

index : raylib-jai

---

  • summary
  • about
  • tree
  • log
  • branches
<< path: root/public/raylib-jai.git/html/Raylib/raylib/src/utils.c blob: 09158893a3d47ce23c566d19f4ab692e7944d152 [raw] [clear marker]

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