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