LCOV - code coverage report
Current view: top level - utils - os_config_init.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 628 804 78.1 %
Date: 2021-04-29 23:48:07 Functions: 33 33 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2000-2021
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / common tools sub-project
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : #ifndef GPAC_DISABLE_CORE_TOOLS
      27             : 
      28             : #include <gpac/config_file.h>
      29             : 
      30             : 
      31             : #if defined(WIN32) || defined(_WIN32_WCE)
      32             : #include <windows.h> /*for GetModuleFileName*/
      33             : 
      34             : #ifndef _WIN32_WCE
      35             : #include <direct.h>  /*for _mkdir*/
      36             : #include <gpac/utf.h>
      37             : #include <shlobj.h>  /*for getting user-dir*/
      38             : 
      39             : #ifndef SHGFP_TYPE_CURRENT
      40             : #define SHGFP_TYPE_CURRENT 0 /*needed for MinGW*/
      41             : #endif
      42             : 
      43             : #endif
      44             : 
      45             : #define CFG_FILE_NAME   "GPAC.cfg"
      46             : #define TEST_MODULE             "gm_"
      47             : 
      48             : #elif (defined(__DARWIN__) || defined(__APPLE__) )
      49             : #include <mach-o/dyld.h> /*for _NSGetExecutablePath */
      50             : 
      51             : #ifdef GPAC_CONFIG_IOS
      52             : #define TEST_MODULE     "osmo4ios"
      53             : #else
      54             : #define TEST_MODULE             "gm_"
      55             : #endif
      56             : #define CFG_FILE_NAME   "GPAC.cfg"
      57             : 
      58             : #else
      59             : #ifdef GPAC_CONFIG_LINUX
      60             : #include <unistd.h>
      61             : #endif
      62             : #ifdef GPAC_CONFIG_ANDROID
      63             : #define DEFAULT_ANDROID_PATH_APP        "/data/data/com.gpac.Osmo4"
      64             : #define DEFAULT_ANDROID_PATH_CFG        "/sdcard/osmo"
      65             : #endif
      66             : #define CFG_FILE_NAME   "GPAC.cfg"
      67             : 
      68             : #if defined(GPAC_CONFIG_WIN32)
      69             : #define TEST_MODULE             "gm_"
      70             : #else
      71             : #define TEST_MODULE             "gm_"
      72             : #endif
      73             : 
      74             : #endif
      75             : 
      76             : #if !defined(GPAC_STATIC_MODULES) && !defined(GPAC_MP4BOX_MINI)
      77             : 
      78       12452 : static Bool mod_enum(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info)
      79             : {
      80       12452 :         if (!strncmp(item_name, "gm_", 3) || !strncmp(item_name, "gf_", 3)) {
      81       12452 :                 *(Bool*)cbck = GF_TRUE;
      82       12452 :                 return GF_TRUE;
      83             :         }
      84             :         return GF_FALSE;
      85             : }
      86             : #endif
      87             : 
      88       87262 : static Bool check_file_exists(char *name, char *path, char *outPath)
      89             : {
      90             :         char szPath[GF_MAX_PATH];
      91             :         FILE *f;
      92             :         int concatres;
      93             : 
      94       87262 :         if (! gf_dir_exists(path)) return 0;
      95             : 
      96       43631 :         if (!strcmp(name, TEST_MODULE)) {
      97       12452 :                 Bool res = GF_FALSE;
      98             : #if defined(GPAC_STATIC_MODULES) || defined(GPAC_MP4BOX_MINI)
      99             :                 res = GF_TRUE;
     100             : #else
     101       12452 :                 gf_enum_directory(path, GF_FALSE, mod_enum, &res, NULL);
     102             : #endif
     103       12452 :                 if (!res) return GF_FALSE;
     104       12452 :                 if (outPath != path) strcpy(outPath, path);
     105             :                 return 1;
     106             :         }
     107             : 
     108             :         concatres = snprintf(szPath, GF_MAX_PATH, "%s%c%s", path, GF_PATH_SEPARATOR, name);
     109       31179 :         if (concatres<0) {
     110           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Path too long (limit %d) when trying to concatenate %s and %s\n", GF_MAX_PATH, path, name));
     111             :         }
     112             : 
     113             :         //do not use gf_fopen here, we don't want to throw en error if failure
     114       31179 :         f = fopen(szPath, "rb");
     115       31179 :         if (!f) return GF_FALSE;
     116       18727 :         fclose(f);
     117       18727 :         if (outPath != path) strcpy(outPath, path);
     118             :         return GF_TRUE;
     119             : }
     120             : 
     121             : enum
     122             : {
     123             :         GF_PATH_APP,
     124             :         GF_PATH_CFG,
     125             :         //were we store gui/%, shaders/*, scripts/*
     126             :         GF_PATH_SHARE,
     127             :         GF_PATH_MODULES,
     128             :         GF_PATH_LIB
     129             : };
     130             : 
     131             : #if defined(WIN32) || defined(_WIN32_WCE)
     132             : static Bool get_default_install_path(char *file_path, u32 path_type)
     133             : {
     134             :         FILE *f;
     135             :         char szPath[GF_MAX_PATH];
     136             : 
     137             : #ifdef _WIN32_WCE
     138             :         TCHAR w_szPath[GF_MAX_PATH];
     139             :         GetModuleFileName(NULL, w_szPath, GF_MAX_PATH);
     140             :         CE_WideToChar((u16 *) w_szPath, file_path);
     141             : #else
     142             :         wchar_t wtmp_file_path[GF_MAX_PATH];
     143             :         char* tmp_file_path;
     144             : 
     145             :         GetModuleFileNameA(NULL, file_path, GF_MAX_PATH);
     146             : #endif
     147             : 
     148             :         /*remove exe name*/
     149             :         if (strstr(file_path, ".exe")) {
     150             :                 char *sep = strrchr(file_path, '\\');
     151             :                 if (sep) sep[0] = 0;
     152             :         }
     153             : 
     154             :         strcpy(szPath, file_path);
     155             :         strlwr(szPath);
     156             : 
     157             :         /*if this is run from a browser, we do not get our app path - fortunately on Windows, we always use 'GPAC' in the
     158             :         installation path*/
     159             :         if (!strstr(file_path, "gpac") && !strstr(file_path, "GPAC") ) {
     160             :                 HKEY hKey = NULL;
     161             :                 DWORD dwSize = GF_MAX_PATH;
     162             :                 file_path[0] = 0;
     163             : 
     164             :                 /*locate the key in current user, then in local machine*/
     165             : #ifdef _WIN32_WCE
     166             :                 DWORD dwType = REG_SZ;
     167             :                 u16 w_path[1024];
     168             :                 RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\GPAC"), 0, KEY_READ, &hKey);
     169             : #ifdef _DEBUG
     170             :                 if (RegQueryValueEx(hKey, TEXT("DebugDir"), 0, &dwType, (LPBYTE) w_path, &dwSize) != ERROR_SUCCESS)
     171             : #endif
     172             :                         RegQueryValueEx(hKey, TEXT("InstallDir"), 0, &dwType, (LPBYTE) w_path, &dwSize);
     173             :                 CE_WideToChar(w_path, (char *)file_path);
     174             :                 RegCloseKey(hKey);
     175             : #else
     176             :                 if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\GPAC", 0, KEY_READ, &hKey) != ERROR_SUCCESS)
     177             :                         RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\GPAC", 0, KEY_READ, &hKey);
     178             : 
     179             :                 dwSize = GF_MAX_PATH;
     180             : 
     181             : #ifdef _DEBUG
     182             :                 if (RegQueryValueEx(hKey, "DebugDir", NULL, NULL,(unsigned char*) file_path, &dwSize) != ERROR_SUCCESS)
     183             : #endif
     184             :                         RegQueryValueEx(hKey, "InstallDir", NULL, NULL,(unsigned char*) file_path, &dwSize);
     185             : 
     186             :                 RegCloseKey(hKey);
     187             : #endif
     188             :         }
     189             :         //empty path, try DLL
     190             :         if (!file_path[0] && (path_type != GF_PATH_LIB)) {
     191             :                 get_default_install_path(file_path, GF_PATH_LIB);
     192             :         }
     193             : 
     194             :         if (path_type==GF_PATH_APP) return GF_TRUE;
     195             : 
     196             :         if (path_type==GF_PATH_SHARE) {
     197             :                 char *sep;
     198             :                 strcat(file_path, "\\share");
     199             :                 if (check_file_exists("gui\\gui.bt", file_path, file_path)) return GF_TRUE;
     200             :                 sep = strstr(file_path, "\\bin\\");
     201             :                 if (sep) {
     202             :                         sep[0] = 0;
     203             :                         strcat(file_path, "\\share");
     204             :                         if (check_file_exists("gui\\gui.bt", file_path, file_path)) return GF_TRUE;
     205             :                 }
     206             :                 return GF_FALSE;
     207             :         }
     208             :         /*modules are stored in the GPAC directory (should be changed to GPAC/modules)*/
     209             :         if (path_type==GF_PATH_MODULES) return GF_TRUE;
     210             : 
     211             :         if (path_type == GF_PATH_LIB) {
     212             :                 HMODULE hm=NULL;
     213             :                 if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
     214             :                         (LPCSTR)&get_default_install_path, &hm) == 0) {
     215             :                         return 0;
     216             :                 }
     217             :                 if (GetModuleFileName(hm, file_path, GF_MAX_PATH) == 0) {
     218             :                         return 0;
     219             :                 }
     220             :                 char *sep = strrchr(file_path, '\\');
     221             :                 if (!sep) sep = strrchr(file_path, '/');
     222             :                 if (sep) sep[0] = 0;
     223             :                 return 1;
     224             :         }
     225             : 
     226             :         /*we are looking for the config file path - make sure it is writable*/
     227             :         assert(path_type == GF_PATH_CFG);
     228             : 
     229             :         strcpy(szPath, file_path);
     230             :         strcat(szPath, "\\gpaccfgtest.txt");
     231             :         //do not use gf_fopen here, we don't want to through any error if failure
     232             :         f = fopen(szPath, "wb");
     233             :         if (f != NULL) {
     234             :                 fclose(f);
     235             :                 gf_file_delete(szPath);
     236             :                 return GF_TRUE;
     237             :         }
     238             : #ifdef _WIN32_WCE
     239             :         return 0;
     240             : #else
     241             :         /*no write access, get user home directory*/
     242             :         SHGetSpecialFolderPathW(NULL, wtmp_file_path, CSIDL_APPDATA, 1);
     243             :         tmp_file_path = gf_wcs_to_utf8(wtmp_file_path);
     244             :         strncpy(file_path, tmp_file_path, GF_MAX_PATH);
     245             :         file_path[GF_MAX_PATH-1] = 0;
     246             :         gf_free(tmp_file_path);
     247             : 
     248             :         if (file_path[strlen(file_path)-1] != '\\') strcat(file_path, "\\");
     249             :         strcat(file_path, "GPAC");
     250             :         /*create GPAC dir*/
     251             :         gf_mkdir(file_path);
     252             :         strcpy(szPath, file_path);
     253             :         strcat(szPath, "\\gpaccfgtest.txt");
     254             :         f = gf_fopen(szPath, "wb");
     255             :         /*COMPLETE FAILURE*/
     256             :         if (!f) return GF_FALSE;
     257             : 
     258             :         gf_fclose(f);
     259             :         gf_file_delete(szPath);
     260             :         return GF_TRUE;
     261             : #endif
     262             : }
     263             : 
     264             : /*FIXME - the paths defined here MUST be coherent with the paths defined in applications/osmo4_android/src/com/gpac/Osmo4/GpacConfig.java'*/
     265             : #elif defined(GPAC_CONFIG_ANDROID)
     266             : 
     267             : static Bool get_default_install_path(char *file_path, u32 path_type)
     268             : {
     269             :         if (!file_path) return 0;
     270             : 
     271             :         if (path_type==GF_PATH_APP) {
     272             :                 strcpy(file_path, DEFAULT_ANDROID_PATH_APP);
     273             :                 return 1;
     274             :         } else if (path_type==GF_PATH_CFG) {
     275             :                 strcpy(file_path, DEFAULT_ANDROID_PATH_CFG);
     276             :                 return 1;
     277             :         } else if (path_type==GF_PATH_SHARE) {
     278             :                 if (!get_default_install_path(file_path, GF_PATH_APP))
     279             :                         return 0;
     280             :                 strcat(file_path, "/share");
     281             :                 return 1;
     282             :         } else if (path_type==GF_PATH_MODULES) {
     283             :                 if (!get_default_install_path(file_path, GF_PATH_APP))
     284             :                         return 0;
     285             :                 strcat(file_path, "/lib");
     286             :                 return 1;
     287             :         }
     288             :         return 0;
     289             : }
     290             : 
     291             : 
     292             : #elif defined(__SYMBIAN__)
     293             : 
     294             : #if defined(__SERIES60_3X__)
     295             : #define SYMBIAN_GPAC_CFG_DIR    "\\private\\F01F9075"
     296             : #define SYMBIAN_GPAC_GUI_DIR    "\\private\\F01F9075\\gui"
     297             : #define SYMBIAN_GPAC_MODULES_DIR        "\\sys\\bin"
     298             : #else
     299             : #define SYMBIAN_GPAC_CFG_DIR    "\\system\\apps\\Osmo4"
     300             : #define SYMBIAN_GPAC_GUI_DIR    "\\system\\apps\\Osmo4\\gui"
     301             : #define SYMBIAN_GPAC_MODULES_DIR        GPAC_CFG_DIR
     302             : #endif
     303             : 
     304             : static Bool get_default_install_path(char *file_path, u32 path_type)
     305             : {
     306             :         if (path_type==GF_PATH_APP) strcpy(file_path, SYMBIAN_GPAC_MODULES_DIR);
     307             :         else if (path_type==GF_PATH_CFG) strcpy(file_path, SYMBIAN_GPAC_CFG_DIR);
     308             :         else if (path_type==GF_PATH_GUI) strcpy(file_path, SYMBIAN_GPAC_GUI_DIR);
     309             :         else if (path_type==GF_PATH_MODULES) strcpy(file_path, SYMBIAN_GPAC_MODULES_DIR);
     310             :         return 1;
     311             : }
     312             : 
     313             : /*Linux, OSX, iOS*/
     314             : #else
     315             : 
     316             : //dlinfo
     317             : #if defined(__DARWIN__) || defined(__APPLE__)
     318             : #include <dlfcn.h>
     319             : 
     320             : typedef Dl_info _Dl_info;
     321             : #elif defined(GPAC_CONFIG_LINUX)
     322             : 
     323             : 
     324             : typedef struct
     325             : {
     326             :         const char *dli_fname;
     327             :         void *dli_fbase;
     328             :         const char *dli_sname;
     329             :         void *dli_saddr;
     330             : } _Dl_info;
     331             : int dladdr(void *, _Dl_info *);
     332             : 
     333             : #endif
     334             : 
     335       74810 : static Bool get_default_install_path(char *file_path, u32 path_type)
     336             : {
     337             :         char app_path[GF_MAX_PATH];
     338             :         char *sep;
     339             : #if (defined(__DARWIN__) || defined(__APPLE__) || defined(GPAC_CONFIG_LINUX))
     340             :         u32 size;
     341             : #endif
     342             : 
     343             :         /*on OSX, Linux & co, user home is where we store the cfg file*/
     344       74810 :         if (path_type==GF_PATH_CFG) {
     345       12452 :                 char *user_home = getenv("HOME");
     346             : #ifdef GPAC_CONFIG_IOS
     347             :                 char buf[PATH_MAX];
     348             :                 char *res;
     349             : #endif
     350             : 
     351       12452 :                 if (!user_home) {
     352           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Couldn't find HOME directory\n"));
     353             :                         return 0;
     354             :                 }
     355             : #ifdef GPAC_CONFIG_IOS
     356             :                 res = realpath(user_home, buf);
     357             :                 if (res) {
     358             :                         strcpy(file_path, buf);
     359             :                         strcat(file_path, "/Documents");
     360             :                 } else
     361             : #endif
     362             :                         strcpy(file_path, user_home);
     363             : 
     364       12452 :                 if (file_path[strlen(file_path)-1] == '/') file_path[strlen(file_path)-1] = 0;
     365             : 
     366             :                 //cleanup of old install in .gpacrc
     367       12452 :                 if (check_file_exists(".gpacrc", file_path, file_path)) {
     368             :                         strcpy(app_path, file_path);
     369             :                         strcat(app_path, "/.gpacrc");
     370           0 :                         gf_file_delete(app_path);
     371             :                 }
     372             : 
     373             :                 strcat(file_path, "/.gpac");
     374       12452 :                 if (!gf_dir_exists(file_path)) {
     375           1 :                         gf_mkdir(file_path);
     376             :                 }
     377             :                 return 1;
     378             :         }
     379             : 
     380       62358 :         if (path_type==GF_PATH_APP) {
     381             : #if (defined(__DARWIN__) || defined(__APPLE__) )
     382             :                 size = GF_MAX_PATH-1;
     383             :                 if (_NSGetExecutablePath(app_path, &size) ==0) {
     384             :                         realpath(app_path, file_path);
     385             :                         sep = strrchr(file_path, '/');
     386             :                         if (sep) sep[0] = 0;
     387             :                         return 1;
     388             :                 }
     389             : 
     390             : #elif defined(GPAC_CONFIG_LINUX)
     391       31179 :                 size = readlink("/proc/self/exe", file_path, GF_MAX_PATH-1);
     392       31179 :                 if (size>0) {
     393       31179 :                         file_path[size] = 0;
     394       31179 :                         sep = strrchr(file_path, '/');
     395       31179 :                         if (sep) sep[0] = 0;
     396             :                         return 1;
     397             :                 }
     398             : 
     399             : #elif defined(GPAC_CONFIG_WIN32)
     400             :                 GetModuleFileNameA(NULL, file_path, GF_MAX_PATH);
     401             :                 if (strstr(file_path, ".exe")) {
     402             :                         sep = strrchr(file_path, '\\');
     403             :                         if (sep) sep[0] = 0;
     404             :                         if ((file_path[1]==':') && (file_path[2]=='\\')) {
     405             :                                 strcpy(file_path, &file_path[2]);
     406             :                         }
     407             :                         sep = file_path;
     408             :                         while ( sep[0] ) {
     409             :                                 if (sep[0]=='\\') sep[0]='/';
     410             :                                 sep++;
     411             :                         }
     412             :                         //get rid of /mingw32 or /mingw64
     413             :                         sep = strstr(file_path, "/usr/");
     414             :                         if (sep) {
     415             :                                 strcpy(file_path, sep);
     416             :                         }
     417             :                         return 1;
     418             :                 }
     419             : #endif
     420           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unknown arch, cannot find executable path\n"));
     421             :                 return 0;
     422             :         }
     423             : 
     424       31179 :         if (path_type==GF_PATH_LIB) {
     425             : #if defined(__DARWIN__) || defined(__APPLE__) || defined(GPAC_CONFIG_LINUX)
     426             :                 _Dl_info dl_info;
     427           0 :                 dladdr((void *)get_default_install_path, &dl_info);
     428           0 :                 if (dl_info.dli_fname) {
     429             :                         strcpy(file_path, dl_info.dli_fname);
     430           0 :                         sep = strrchr(file_path, '/');
     431           0 :                         if (sep) sep[0] = 0;
     432             :                         return 1;
     433             :                 }
     434             :                 return 0;
     435             : #endif
     436             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unknown arch, cannot find library path\n"));
     437             :                 return 0;
     438             :         }
     439             : 
     440             :         /*locate the app*/
     441       31179 :         if (!get_default_install_path(app_path, GF_PATH_APP)) {
     442           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Couldn't find GPAC binaries install directory\n"));
     443             :                 return 0;
     444             :         }
     445             :         /*installed or symlink on system, user user home directory*/
     446       31179 :         if (!strnicmp(app_path, "/usr/", 5) || !strnicmp(app_path, "/opt/", 5)) {
     447       31179 :                 if (path_type==GF_PATH_SHARE) {
     448             :                         /*look in possible install dirs ...*/
     449       18727 :                         if (check_file_exists("gui/gui.bt", "/usr/share/gpac", file_path)) return 1;
     450       18727 :                         if (check_file_exists("gui/gui.bt", "/usr/local/share/gpac", file_path)) return 1;
     451           0 :                         if (check_file_exists("gui/gui.bt", "/opt/share/gpac", file_path)) return 1;
     452           0 :                         if (check_file_exists("gui/gui.bt", "/opt/local/share/gpac", file_path)) return 1;
     453       12452 :                 } else if (path_type==GF_PATH_MODULES) {
     454             :                         /*look in possible install dirs ...*/
     455       12452 :                         if (check_file_exists(TEST_MODULE, "/usr/lib64/gpac", file_path)) return 1;
     456       12452 :                         if (check_file_exists(TEST_MODULE, "/usr/lib/gpac", file_path)) return 1;
     457       12452 :                         if (check_file_exists(TEST_MODULE, "/usr/local/lib/gpac", file_path)) return 1;
     458           0 :                         if (check_file_exists(TEST_MODULE, "/opt/lib/gpac", file_path)) return 1;
     459           0 :                         if (check_file_exists(TEST_MODULE, "/opt/local/lib/gpac", file_path)) return 1;
     460           0 :                         if (check_file_exists(TEST_MODULE, "/usr/lib/x86_64-linux-gnu/gpac", file_path)) return 1;
     461           0 :                         if (check_file_exists(TEST_MODULE, "/usr/lib/i386-linux-gnu/gpac", file_path)) return 1;
     462             :                 }
     463             :         }
     464             : 
     465           0 :         if (path_type==GF_PATH_SHARE) {
     466             :                 Bool try_lib=GF_TRUE;
     467           0 :                 if (get_default_install_path(app_path, GF_PATH_CFG)) {
     468           0 :                         sep = strstr(app_path, ".gpac/");
     469           0 :                         if (sep) sep[5]=0;
     470             :                         /*GUI not found, look in ~/.gpac/share/gui/ */
     471             :                         strcat(app_path, "/share");
     472           0 :                         if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     473             :                 }
     474             : 
     475             :                 /*GUI not found, look in gpac distribution if any */
     476           0 :                 if (get_default_install_path(app_path, GF_PATH_APP)) {
     477           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] trying to locate share from application dir %s\n", app_path));
     478             :                         strcat(app_path, "/");
     479           0 : retry_lib:
     480           0 :                         sep = strstr(app_path, "/bin/");
     481           0 :                         if (sep) {
     482           0 :                                 sep[0] = 0;
     483             :                                 strcat(app_path, "/share");
     484           0 :                                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     485             :                                 strcat(app_path, "/gpac");
     486           0 :                                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     487             :                         }
     488           0 :                         sep = strstr(app_path, "/build/");
     489           0 :                         if (sep) {
     490           0 :                                 sep[0] = 0;
     491             :                                 strcat(app_path, "/share");
     492           0 :                                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     493             :                         }
     494             :                 }
     495           0 :                 if (get_default_install_path(app_path, GF_PATH_LIB)) {
     496           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] trying to locate share from dynamic libgpac dir %s\n", app_path));
     497           0 :                         sep = strstr(app_path, "/lib");
     498           0 :                         if (sep) {
     499           0 :                                 sep[0] = 0;
     500             :                                 strcat(app_path, "/share");
     501           0 :                                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     502             :                         }
     503           0 :                         if (try_lib) {
     504             :                                 try_lib = GF_FALSE;
     505             :                                 goto retry_lib;
     506             :                         }
     507             :                 }
     508             :                 /*GUI not found, look in .app for OSX case*/
     509             :         }
     510             : 
     511           0 :         if (path_type==GF_PATH_MODULES) {
     512             :                 /*look in gpac compilation tree (modules are output in the same folder as apps) and in distrib tree */
     513           0 :                 if (get_default_install_path(app_path, GF_PATH_APP)) {
     514           0 :                         if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     515             : 
     516             :                         /*on OSX check modules subdirectory */
     517             :                         strcat(app_path, "/modules");
     518           0 :                         if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     519             : 
     520           0 :                         get_default_install_path(app_path, GF_PATH_APP);
     521             :                         strcat(app_path, "/");
     522           0 :                         sep = strstr(app_path, "/bin/");
     523           0 :                         if (sep) {
     524           0 :                                 sep[0] = 0;
     525             :                                 strcat(app_path, "/lib/gpac");
     526           0 :                                 if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     527             :                         }
     528             : 
     529             :                         /*modules not found*/
     530           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("Couldn't find any modules in standard path (app path %s)\n", app_path));
     531             :                 }
     532             : 
     533             :                 /*look in lib install */
     534           0 :                 if (get_default_install_path(app_path, GF_PATH_LIB)) {
     535           0 :                         if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     536             :                         strcat(app_path, "/gpac");
     537           0 :                         if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     538           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Couldn't find any modules in lib path %s\n", app_path));
     539             :                 }
     540             : 
     541             : 
     542             :                 /*modules not found, look in ~/.gpac/modules/ */
     543           0 :                 if (get_default_install_path(app_path, GF_PATH_CFG)) {
     544             :                         strcat(app_path, "/modules");
     545           0 :                         if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     546             :                 }
     547             :                 /*modules not found, failure*/
     548           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Couldn't find any modules in HOME path (app path %s)\n", app_path));
     549             :                 return 0;
     550             :         }
     551             : 
     552             :         /*OSX way vs iPhone*/
     553           0 :         sep = strstr(app_path, ".app/");
     554           0 :         if (sep) sep[4] = 0;
     555             : 
     556             :         /*we are looking for .app install path, or GUI */
     557           0 :         if (path_type==GF_PATH_SHARE) {
     558             : #ifndef GPAC_CONFIG_IOS
     559             :                 strcat(app_path, "/Contents/MacOS/share");
     560           0 :                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     561             : #else /*iOS: for now, everything is set flat within the package*/
     562             :                 /*iOS app is distributed with embedded GUI*/
     563             :                 get_default_install_path(app_path, GF_PATH_APP);
     564             :                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     565             :                 strcat(app_path, "/share");
     566             :                 if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1;
     567             : #endif
     568             :         }
     569             :         else { // (path_type==GF_PATH_MODULES)
     570             :                 strcat(app_path, "/Contents/MacOS/modules");
     571           0 :                 if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1;
     572             :         }
     573             :         /*not found ...*/
     574             :         return 0;
     575             : }
     576             : 
     577             : #endif
     578             : 
     579             : //get real path where the .gpac dir has been created, and use this as the default path
     580             : //for cache (tmp/ dir of ios app) and last working fir
     581             : #ifdef GPAC_CONFIG_IOS
     582             : static void gf_ios_refresh_cache_directory( GF_Config *cfg, const char *file_path)
     583             : {
     584             :         char *cache_dir, *old_cache_dir;
     585             :         char buf[GF_MAX_PATH], *res, *sep;
     586             :         res = realpath(file_path, buf);
     587             :         if (!res) return;
     588             : 
     589             :         sep = strstr(res, ".gpac");
     590             :         assert(sep);
     591             :         sep[0] = 0;
     592             :         gf_cfg_set_key(cfg, "General", "LastWorkingDir", res);
     593             :         gf_cfg_set_key(cfg, "General", "iOSDocumentsDir", res);
     594             : 
     595             :         strcat(res, "cache/");
     596             :         cache_dir = res;
     597             :         old_cache_dir = (char*) gf_opts_get_key("core", "cache");
     598             : 
     599             :         if (!gf_dir_exists(cache_dir)) {
     600             :                 if (old_cache_dir && strcmp(old_cache_dir, cache_dir)) {
     601             :                         GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Cache dir changed: old %d -> new %s\n\n", old_cache_dir, cache_dir ));
     602             :                 }
     603             :                 gf_mkdir(cache_dir);
     604             :         }
     605             :         gf_cfg_set_key(cfg, "core", "cache", cache_dir);
     606             : }
     607             : 
     608             : #endif
     609             : 
     610             : const char * gf_get_default_cache_directory_ex(Bool do_create);
     611             : 
     612             : GF_EXPORT
     613        6211 : void gf_get_default_font_dir(char szPath[GF_MAX_PATH])
     614             : {
     615             : #if defined(_WIN32_WCE)
     616             :         strcpy(szPath, "\\Windows");
     617             : 
     618             : #elif defined(WIN32)
     619             :         GetWindowsDirectory((char*)szPath, MAX_PATH);
     620             :         if (szPath[strlen((char*)szPath)-1] != '\\') strcat((char*)szPath, "\\");
     621             :         strcat((char *)szPath, "Fonts");
     622             : 
     623             : #elif defined(__APPLE__) && defined(GPAC_CONFIG_IOS)
     624             :         strcpy(szPath, "/System/Library/Fonts/Cache,/System/Library/Fonts/AppFonts,/System/Library/Fonts/Core,/System/Library/Fonts/Extra");
     625             : #elif defined(__APPLE__)
     626             :         strcpy(szPath, "/System/Library/Fonts,/Library/Fonts");
     627             : 
     628             : #elif defined(GPAC_CONFIG_ANDROID)
     629             :         strcpy(szPath, "/system/fonts/");
     630             : #else
     631             :         //scan all /usr/share/fonts, not just /usr/share/fonts/truetype/ which does not exist in some distrros
     632             :         strcpy(szPath, "/usr/share/fonts/");
     633             : #endif
     634        6211 : }
     635             : 
     636             : 
     637        6211 : static GF_Config *create_default_config(char *file_path, const char *profile)
     638             : {
     639             :         Bool moddir_found;
     640             :         GF_Config *cfg;
     641             :         char szPath[GF_MAX_PATH];
     642             : 
     643        6211 :         if (! get_default_install_path(file_path, GF_PATH_CFG)) {
     644             :                 profile = "0";
     645             :         }
     646             :         /*Create temp config file*/
     647        6211 :         if (profile && !strcmp(profile, "0")) {
     648        6209 :                 cfg = gf_cfg_new(NULL, NULL);
     649             :         } else {
     650             :                 FILE *f;
     651             : 
     652             :                 /*create config file from disk*/
     653           2 :                 if (profile) {
     654             :                         sprintf(szPath, "%s%cprofiles%c%s%c%s", file_path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, profile, GF_PATH_SEPARATOR, CFG_FILE_NAME);
     655             :                 } else {
     656             :                         sprintf(szPath, "%s%c%s", file_path, GF_PATH_SEPARATOR, CFG_FILE_NAME);
     657             :                 }
     658           2 :                 GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Trying to create config file: %s\n", szPath ));
     659             : 
     660           2 :                 f = gf_fopen(szPath, "wt");
     661           2 :                 if (!f) return NULL;
     662           2 :                 gf_fclose(f);
     663             : 
     664           2 :                 cfg = gf_cfg_new(NULL, szPath);
     665             :         }
     666             : 
     667        6211 :         if (!cfg) return NULL;
     668             : 
     669             : 
     670             : #ifndef GPAC_CONFIG_IOS
     671        6211 :         moddir_found = get_default_install_path(szPath, GF_PATH_MODULES);
     672             : #else
     673             :         moddir_found = get_default_install_path(szPath, GF_PATH_APP);
     674             : #endif
     675             : 
     676             : #if defined(GPAC_CONFIG_IOS)
     677             :         gf_cfg_set_key(cfg, "core", "devclass", "ios");
     678             : #elif defined(GPAC_CONFIG_ANDROID)
     679             :         gf_cfg_set_key(cfg, "core", "devclass", "android");
     680             : #else
     681        6211 :         gf_cfg_set_key(cfg, "core", "devclass", "desktop");
     682             : #endif
     683             : 
     684             : 
     685        6211 :         if (!moddir_found) {
     686           0 :                 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Core] default modules directory not found\n"));
     687             :         } else {
     688        6211 :                 gf_cfg_set_key(cfg, "core", "module-dir", szPath);
     689             :         }
     690             : 
     691             : #if defined(GPAC_CONFIG_IOS)
     692             :         gf_ios_refresh_cache_directory(cfg, file_path);
     693             : #elif defined(GPAC_CONFIG_ANDROID)
     694             :         if (get_default_install_path(szPath, GF_PATH_APP)) {
     695             :                 strcat(szPath, "/cache");
     696             :                 gf_cfg_set_key(cfg, "core", "cache", szPath);
     697             :         }
     698             : #else
     699             :         /*get default temporary directoy */
     700        6211 :         gf_cfg_set_key(cfg, "core", "cache", gf_get_default_cache_directory_ex(GF_FALSE));
     701             : #endif
     702             : 
     703        6211 :         gf_cfg_set_key(cfg, "core", "ds-disable-notif", "no");
     704             : 
     705             :         /*Setup font engine to FreeType by default, and locate TrueType font directory on the system*/
     706        6211 :         gf_cfg_set_key(cfg, "core", "font-reader", "FreeType Font Reader");
     707        6211 :         gf_cfg_set_key(cfg, "core", "rescan-fonts", "yes");
     708             : 
     709             : 
     710        6211 :         gf_get_default_font_dir(szPath);
     711        6211 :         gf_cfg_set_key(cfg, "core", "font-dirs", szPath);
     712             : 
     713        6211 :         gf_cfg_set_key(cfg, "core", "cache-size", "100M");
     714             : 
     715             : #if defined(_WIN32_WCE)
     716             :         gf_cfg_set_key(cfg, "core", "video-output", "GAPI Video Output");
     717             : #elif defined(WIN32)
     718             :         gf_cfg_set_key(cfg, "core", "video-output", "DirectX Video Output");
     719             : #elif defined(__DARWIN__) || defined(__APPLE__)
     720             :         gf_cfg_set_key(cfg, "core", "video-output", "SDL Video Output");
     721             : #elif defined(GPAC_CONFIG_ANDROID)
     722             :         gf_cfg_set_key(cfg, "core", "video-output", "Android Video Output");
     723             :         gf_cfg_set_key(cfg, "core", "audio-output", "Android Audio Output");
     724             : #else
     725        6211 :         gf_cfg_set_key(cfg, "core", "video-output", "X11 Video Output");
     726        6211 :         gf_cfg_set_key(cfg, "core", "audio-output", "SDL Audio Output");
     727             : #endif
     728             : 
     729        6211 :         gf_cfg_set_key(cfg, "core", "switch-vres", "no");
     730        6211 :         gf_cfg_set_key(cfg, "core", "hwvmem", "auto");
     731             : 
     732             : 
     733             :         /*locate GUI*/
     734        6211 :         if ( get_default_install_path(szPath, GF_PATH_SHARE) ) {
     735             :                 char gui_path[GF_MAX_PATH+100];
     736             :                 sprintf(gui_path, "%s%cgui%cgui.bt", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
     737        6211 :                 if (gf_file_exists(gui_path)) {
     738        6211 :                         gf_cfg_set_key(cfg, "General", "StartupFile", gui_path);
     739             :                 }
     740             : 
     741             :                 /*shaders are at the same location*/
     742             :                 sprintf(gui_path, "%s%cshaders%cvertex.glsl", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
     743        6211 :                 gf_cfg_set_key(cfg, "filter@compositor", "vertshader", gui_path);
     744             :                 sprintf(gui_path, "%s%cshaders%cfragment.glsl", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
     745        6211 :                 gf_cfg_set_key(cfg, "filter@compositor", "fragshader", gui_path);
     746             : 
     747             :                 //aliases and other defaults
     748             :                 sprintf(gui_path, "%s%cdefault.cfg", szPath, GF_PATH_SEPARATOR);
     749        6211 :                 if (gf_file_exists(gui_path)) {
     750        6211 :                         GF_Config *aliases = gf_cfg_new(NULL, gui_path);
     751        6211 :                         if (aliases) {
     752        6211 :                                 u32 i, count = gf_cfg_get_section_count(aliases);
     753       18633 :                                 for (i=0; i<count; i++) {
     754             :                                         u32 j, count2;
     755       12422 :                                         const char *sec_name = gf_cfg_get_section_name(aliases, i);
     756       12422 :                                         if (!sec_name) continue;
     757       12422 :                                         count2 = gf_cfg_get_key_count(aliases, sec_name);
     758       99376 :                                         for (j=0; j<count2; j++) {
     759       86954 :                                                 const char *name = gf_cfg_get_key_name(aliases, sec_name, j);
     760       86954 :                                                 const char *val = gf_cfg_get_key(aliases, sec_name, name);
     761       86954 :                                                 gf_cfg_set_key(cfg, sec_name, name, val);
     762             :                                         }
     763             :                                 }
     764             :                         }
     765        6211 :                         gf_cfg_del(aliases);
     766             :                 }
     767             :         }
     768             : 
     769        6211 :         if (profile && !strcmp(profile, "0")) {
     770             :                 GF_Err gf_cfg_set_filename(GF_Config *iniFile, const char * fileName);
     771             : //              sprintf(szPath, "%s%c%s", gf_get_default_cache_directory(), GF_PATH_SEPARATOR, CFG_FILE_NAME);
     772        6209 :                 gf_cfg_set_filename(cfg, CFG_FILE_NAME);
     773        6209 :                 gf_cfg_discard_changes(cfg);
     774        6209 :                 return cfg;
     775             :         }
     776             :         /*store and reload*/
     777           2 :         strcpy(szPath, gf_cfg_get_filename(cfg));
     778           2 :         gf_cfg_del(cfg);
     779           2 :         return gf_cfg_new(NULL, szPath);
     780             : }
     781             : 
     782             : /*check if modules directory has changed in the config file
     783             : */
     784        6241 : static void check_modules_dir(GF_Config *cfg)
     785             : {
     786             :         char path[GF_MAX_PATH];
     787             : 
     788             : #ifdef GPAC_CONFIG_IOS
     789             :         const char *cfg_path;
     790             :         if ( get_default_install_path(path, GF_PATH_SHARE) ) {
     791             :                 char *sep;
     792             :                 char shader_path[GF_MAX_PATH];
     793             :                 strcat(path, "/gui/gui.bt");
     794             :                 gf_cfg_set_key(cfg, "General", "StartupFile", path);
     795             :                 //get rid of "/gui/gui.bt"
     796             :                 sep = strrchr(path, '/');
     797             :                 sep[0] = 0;
     798             :                 sep = strrchr(path, '/');
     799             :                 sep[0] = 0;
     800             : 
     801             :                 sprintf(shader_path, "%s%cshaders%cvertex.glsl", path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
     802             :                 gf_cfg_set_key(cfg, "filter@compositor", "vertshader", shader_path);
     803             :                 sprintf(shader_path, "%s%cshaders%cfragment.glsl", path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR);
     804             :                 gf_cfg_set_key(cfg, "filter@compositor", "fragshader", shader_path);
     805             :         }
     806             :         cfg_path = gf_cfg_get_filename(cfg);
     807             :         gf_ios_refresh_cache_directory(cfg, cfg_path);
     808             : 
     809             : #else
     810             :         const char *opt;
     811             : 
     812        6241 :         if ( get_default_install_path(path, GF_PATH_MODULES) ) {
     813        6241 :                 opt = gf_cfg_get_key(cfg, "core", "module-dir");
     814             :                 //for OSX, we can have an install in /usr/... and an install in /Applications/Osmo4.app - always change
     815             : #if defined(__DARWIN__) || defined(__APPLE__)
     816             :                 if (!opt || strcmp(opt, path))
     817             :                         gf_cfg_set_key(cfg, "core", "module-dir", path);
     818             : #else
     819             : 
     820             :                 //otherwise only check we didn't switch between a 64 bit version and a 32 bit version
     821        6241 :                 if (!opt) {
     822           0 :                         gf_cfg_set_key(cfg, "core", "module-dir", path);
     823             :                 } else  {
     824             :                         Bool erase_modules_dir = GF_FALSE;
     825        6241 :                         const char *opt64 = gf_cfg_get_key(cfg, "core", "64bits");
     826        6241 :                         if (!opt64) {
     827             :                                 //first run or old versions, erase
     828             :                                 erase_modules_dir = GF_TRUE;
     829          30 :                         } else if (!strcmp(opt64, "yes") ) {
     830             : #ifndef GPAC_64_BITS
     831             :                                 erase_modules_dir = GF_TRUE;
     832             : #endif
     833             :                         } else {
     834             : #ifdef GPAC_64_BITS
     835             :                                 erase_modules_dir = GF_TRUE;
     836             : #endif
     837             :                         }
     838             : 
     839             : #ifdef GPAC_64_BITS
     840             :                         opt64 = "yes";
     841             : #else
     842             :                         opt64 = "no";
     843             : #endif
     844        6241 :                         gf_cfg_set_key(cfg, "core", "64bits", opt64);
     845             : 
     846        6241 :                         if (erase_modules_dir) {
     847        6211 :                                 gf_cfg_set_key(cfg, "core", "module-dir", path);
     848             :                         }
     849             :                 }
     850             : #endif
     851             :         }
     852             : 
     853             :         /*if startup file was disabled, do not attempt to correct it*/
     854        6241 :         if (gf_cfg_get_key(cfg, "General", "StartupFile")==NULL) return;
     855             : 
     856        6241 :         if ( get_default_install_path(path, GF_PATH_SHARE) ) {
     857        6241 :                 opt = gf_cfg_get_key(cfg, "General", "StartupFile");
     858             :                 if (strstr(opt, "gui.bt") && strcmp(opt, path) && strstr(path, ".app") ) {
     859             : #if defined(__DARWIN__) || defined(__APPLE__)
     860             :                         strcat(path, "/gui/gui.bt");
     861             :                         gf_cfg_set_key(cfg, "General", "StartupFile", path);
     862             : #endif
     863             :                 }
     864             :         }
     865             : 
     866             : #endif
     867             : }
     868             : 
     869             : 
     870             : /*!
     871             : \brief configuration file initialization
     872             :  *
     873             :  * Constructs a configuration file from fileName. If fileName is NULL, the default GPAC configuration file is loaded with the
     874             :  * proper module directory, font directory and other default options. If fileName is non-NULL no configuration file is found,
     875             :  * a "light" default configuration file is created.
     876             : \param profile name or path to existing config file
     877             : \return the configuration file object, NULL if the file could not be created
     878             :  */
     879             :  #include <gpac/network.h>
     880             : 
     881        6241 : static GF_Config *gf_cfg_init(const char *profile)
     882             : {
     883             :         GF_Config *cfg=NULL;
     884             :         u32 prof_len=0;
     885             :         Bool force_new_cfg=GF_FALSE;
     886             :         char szPath[GF_MAX_PATH];
     887             :         char *prof_opt = NULL;
     888             : 
     889        6241 :         if (profile) {
     890        6210 :                 prof_len = (u32) strlen(profile);
     891        6210 :                 prof_opt = gf_url_colon_suffix(profile);
     892        6210 :                 if (prof_opt) {
     893           0 :                         prof_len -= (u32) strlen(prof_opt);
     894           0 :                         if (strstr(prof_opt, "reload")) force_new_cfg = GF_TRUE;
     895             : 
     896           0 :                         prof_opt[0] = 0;
     897             :                 }
     898             :         }
     899        6241 :         if (profile && !prof_len)
     900             :                 profile = NULL;
     901             : 
     902        6241 :         if (profile && (strchr(profile, '/') || strchr(profile, '\\')) ) {
     903           0 :                 if (!gf_file_exists(profile)) {
     904           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Config file %s does not exist\n", profile));
     905             :                         goto exit;
     906             :                 }
     907           0 :                 cfg = gf_cfg_new(NULL, profile);
     908           0 :                 if (!cfg) {
     909           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Failed to load existing config file %s\n", profile));
     910             :                         goto exit;
     911             :                 }
     912           0 :                 if (force_new_cfg) {
     913           0 :                         gf_cfg_del(cfg);
     914           0 :                         cfg = create_default_config(NULL, profile);
     915             :                 }
     916           0 :                 check_modules_dir(cfg);
     917           0 :                 goto exit;
     918             :         }
     919             : 
     920        6241 :         if (!get_default_install_path(szPath, GF_PATH_CFG)) {
     921           0 :                 if (!profile || strcmp(profile, "0")) {
     922           0 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] Cannot locate global config path in application or user home directory, using temporary config file\n"));
     923             :                 }
     924             :                 profile="0";
     925           0 :                 cfg = create_default_config(szPath, profile);
     926           0 :                 goto skip_cfg;
     927             :         }
     928             : 
     929        6241 :         if (profile) {
     930             :                 strcat(szPath, "/profiles/");
     931             :                 strcat(szPath, profile);
     932             :         }
     933             : 
     934        6241 :         cfg = gf_cfg_new(szPath, CFG_FILE_NAME);
     935             :         //config file not compatible with old arch, check it:
     936        6241 :         if (cfg) {
     937          30 :                 u32 nb_old_sec = gf_cfg_get_key_count(cfg, "Compositor");
     938          30 :                 nb_old_sec += gf_cfg_get_key_count(cfg, "MimeTypes");
     939          30 :                 nb_old_sec += gf_cfg_get_key_count(cfg, "Video");
     940          30 :                 nb_old_sec += gf_cfg_get_key_count(cfg, "Audio");
     941          30 :                 nb_old_sec += gf_cfg_get_key_count(cfg, "Systems");
     942          30 :                 if (! gf_cfg_get_key_count(cfg, "core"))
     943           0 :                         nb_old_sec += 1;
     944             : 
     945          30 :                 if (nb_old_sec || force_new_cfg) {
     946           0 :                         if (nb_old_sec && (!profile || strcmp(profile, "0"))) {
     947           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[core] Incompatible (0.8.0 or older) config file %s found in %s - creating new file\n", CFG_FILE_NAME, szPath ));
     948             :                         }
     949           0 :                         gf_cfg_del(cfg);
     950           0 :                         cfg = create_default_config(szPath, profile);
     951             :                 }
     952             :         }
     953             :         //no config file found
     954             :         else {
     955        6211 :                 if (!profile || strcmp(profile, "0")) {
     956           2 :                         GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] Config file %s not found in %s - creating new file\n", CFG_FILE_NAME, szPath ));
     957             :                 }
     958        6211 :                 cfg = create_default_config(szPath, profile);
     959             :         }
     960             : 
     961        6241 : skip_cfg:
     962        6241 :         if (!cfg) {
     963           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Cannot create config file %s in %s directory\n", CFG_FILE_NAME, szPath));
     964             :                 goto exit;
     965             :         }
     966             : 
     967             : #ifndef GPAC_CONFIG_IOS
     968        6241 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] Using global config file in %s directory\n", szPath));
     969             : #endif
     970             : 
     971        6241 :         check_modules_dir(cfg);
     972             : 
     973        6241 :         if (!gf_cfg_get_key(cfg, "core", "store-dir")) {
     974        6211 :                 if (profile && !strcmp(profile, "0")) {
     975        6209 :                         strcpy(szPath, gf_get_default_cache_directory_ex(GF_FALSE) );
     976             :                         strcat(szPath, "/Storage");
     977             :                 } else {
     978             :                         char *sep;
     979           2 :                         strcpy(szPath, gf_cfg_get_filename(cfg));
     980           2 :                         sep = strrchr(szPath, '/');
     981           2 :                         if (!sep) sep = strrchr(szPath, '\\');
     982           2 :                         if (sep) sep[0] = 0;
     983             :                         strcat(szPath, "/Storage");
     984           2 :                         if (!gf_dir_exists(szPath)) gf_mkdir(szPath);
     985             :                 }
     986        6211 :                 gf_cfg_set_key(cfg, "core", "store-dir", szPath);
     987             :         }
     988             : 
     989        6271 : exit:
     990        6241 :         if (prof_opt) prof_opt[0] = ':';
     991        6241 :         return cfg;
     992             : }
     993             : 
     994             : 
     995             : GF_EXPORT
     996          56 : Bool gf_opts_default_shared_directory(char *path_buffer)
     997             : {
     998          56 :         return get_default_install_path(path_buffer, GF_PATH_SHARE);
     999             : }
    1000             : 
    1001             : void gf_modules_new(GF_Config *config);
    1002             : void gf_modules_del();
    1003             : 
    1004             : GF_Config *gpac_global_config = NULL;
    1005             : 
    1006        6241 : void gf_init_global_config(const char *profile)
    1007             : {
    1008        6241 :         if (!gpac_global_config) {
    1009        6241 :                 gpac_global_config = gf_cfg_init(profile);
    1010        6241 :                 if (!gpac_global_config) {
    1011           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Fatal error: failed to initialize GPAC global configuration\n"));
    1012           0 :                         exit(1);
    1013             :                 }
    1014             : 
    1015        6241 :                 gf_modules_new(gpac_global_config);
    1016             :         }
    1017        6241 : }
    1018             : 
    1019        6240 : void gf_uninit_global_config(Bool discard_config)
    1020             : {
    1021        6240 :         if (gpac_global_config) {
    1022        6240 :                 if (discard_config) gf_cfg_discard_changes(gpac_global_config);
    1023        6240 :                 gf_cfg_del(gpac_global_config);
    1024        6240 :                 gpac_global_config = NULL;
    1025        6240 :                 gf_modules_del();
    1026             :         }
    1027        6240 : }
    1028             : 
    1029             : GF_Err gf_cfg_set_key_internal(GF_Config *iniFile, const char *secName, const char *keyName, const char *keyValue, Bool is_restrict);
    1030             : 
    1031        6219 : void gf_cfg_load_restrict()
    1032             : {
    1033             :         char szPath[GF_MAX_PATH];
    1034        6219 :         if (get_default_install_path(szPath, GF_PATH_SHARE)) {
    1035             :                 strcat(szPath, "/");
    1036             :                 strcat(szPath, "restrict.cfg");
    1037        6219 :                 if (gf_file_exists(szPath)) {
    1038           0 :                         GF_Config *rcfg = gf_cfg_new(NULL, szPath);
    1039           0 :                         if (rcfg) {
    1040           0 :                                 u32 i, count = gf_cfg_get_section_count(rcfg);
    1041           0 :                                 for (i=0; i<count; i++) {
    1042             :                                         u32 j, kcount;
    1043           0 :                                         const char *sname = gf_cfg_get_section_name(rcfg, i);
    1044           0 :                                         if (!sname) break;
    1045           0 :                                         kcount = gf_cfg_get_key_count(rcfg, sname);
    1046           0 :                                         for (j=0; j<kcount; j++) {
    1047           0 :                                                 const char *kname = gf_cfg_get_key_name(rcfg, sname, j);
    1048           0 :                                                 const char *kval = gf_cfg_get_key(rcfg, sname, kname);
    1049           0 :                                                 gf_cfg_set_key_internal(gpac_global_config, sname, kname, kval, GF_TRUE);
    1050             :                                         }
    1051             :                                 }
    1052           0 :                                 gf_cfg_del(rcfg);
    1053             :                         }
    1054             :                 }
    1055             :         }
    1056        6219 : }
    1057             : 
    1058             : GF_EXPORT
    1059      454539 : const char *gf_opts_get_key(const char *secName, const char *keyName)
    1060             : {
    1061      454539 :         if (!gpac_global_config) return NULL;
    1062             : 
    1063      442119 :         if (!strcmp(secName, "core")) {
    1064      110028 :                 const char *opt = gf_cfg_get_key(gpac_global_config, "temp", keyName);
    1065      110028 :                 if (opt) return opt;
    1066             :         }
    1067      439148 :         return gf_cfg_get_key(gpac_global_config, secName, keyName);
    1068             : }
    1069             : GF_EXPORT
    1070       26707 : GF_Err gf_opts_set_key(const char *secName, const char *keyName, const char *keyValue)
    1071             : {
    1072       26707 :         if (!gpac_global_config) return GF_BAD_PARAM;
    1073       26707 :         return gf_cfg_set_key(gpac_global_config, secName, keyName, keyValue);
    1074             : }
    1075             : GF_EXPORT
    1076        1290 : void gf_opts_del_section(const char *secName)
    1077             : {
    1078        1290 :         if (!gpac_global_config) return;
    1079        1290 :         gf_cfg_del_section(gpac_global_config, secName);
    1080             : }
    1081             : GF_EXPORT
    1082         269 : u32 gf_opts_get_section_count()
    1083             : {
    1084         269 :         if (!gpac_global_config) return 0;
    1085         269 :         return gf_cfg_get_section_count(gpac_global_config);
    1086             : }
    1087             : GF_EXPORT
    1088        2274 : const char *gf_opts_get_section_name(u32 secIndex)
    1089             : {
    1090        2274 :         if (!gpac_global_config) return NULL;
    1091        2274 :         return gf_cfg_get_section_name(gpac_global_config, secIndex);
    1092             : }
    1093             : GF_EXPORT
    1094        5094 : u32 gf_opts_get_key_count(const char *secName)
    1095             : {
    1096        5094 :         if (!gpac_global_config) return 0;
    1097        5094 :         return gf_cfg_get_key_count(gpac_global_config, secName);
    1098             : }
    1099             : GF_EXPORT
    1100       12723 : const char *gf_opts_get_key_name(const char *secName, u32 keyIndex)
    1101             : {
    1102       12723 :         if (!gpac_global_config) return NULL;
    1103       12723 :         return gf_cfg_get_key_name(gpac_global_config, secName, keyIndex);
    1104             : }
    1105             : 
    1106             : GF_EXPORT
    1107       18060 : const char *gf_opts_get_key_restricted(const char *secName, const char *keyName)
    1108             : {
    1109             :         const char *res = NULL;
    1110             :         const char *gf_cfg_get_key_internal(GF_Config *iniFile, const char *secName, const char *keyName, Bool restricted_only);
    1111       18060 :         if (gpac_global_config)
    1112       18060 :                 res = gf_cfg_get_key_internal(gpac_global_config, secName, keyName, GF_TRUE);
    1113       18060 :         return res;
    1114             : }
    1115             : 
    1116             : GF_EXPORT
    1117          38 : const char *gf_opts_get_filename()
    1118             : {
    1119          38 :         return gf_cfg_get_filename(gpac_global_config);
    1120             : }
    1121             : GF_EXPORT
    1122           2 : GF_Err gf_opts_discard_changes()
    1123             : {
    1124           2 :         return gf_cfg_discard_changes(gpac_global_config);
    1125             : }
    1126             : 
    1127             : #include <gpac/main.h>
    1128             : 
    1129             : GF_GPACArg GPAC_Args[] = {
    1130             :  GF_DEF_ARG("tmp", NULL, "specify directory for temporary file creation instead of OS-default temportary file management", NULL, NULL, GF_ARG_STRING, 0),
    1131             :  GF_DEF_ARG("noprog", NULL, "disable progress messages", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_LOG),
    1132             :  GF_DEF_ARG("quiet", NULL, "disable all messages, including errors", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_LOG),
    1133             :  GF_DEF_ARG("log-file", "lf", "set output log file", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_LOG),
    1134             :  GF_DEF_ARG("log-clock", "lc", "log time in micro sec since start time of GPAC before each log line", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_LOG),
    1135             :  GF_DEF_ARG("log-utc", "lu", "log UTC time in ms before each log line", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_LOG),
    1136             :  GF_DEF_ARG("logs", NULL, "set log tools and levels.  \n"\
    1137             :                         "  \n"\
    1138             :                         "You can independently log different tools involved in a session.  \n"\
    1139             :                         "log_args is formatted as a colon (':') separated list of `toolX[:toolZ]@levelX`  \n"\
    1140             :                 "`levelX` can be one of:\n"\
    1141             :                 "- quiet: skip logs\n"\
    1142             :                 "- error: logs only error messages\n"\
    1143             :                 "- warning: logs error+warning messages\n"\
    1144             :                 "- info: logs error+warning+info messages\n"\
    1145             :                 "- debug: logs all messages\n"\
    1146             :                 "\n`toolX` can be one of:\n"\
    1147             :                 "- core: libgpac core\n"\
    1148             :                 "- coding: bitstream formats (audio, video, scene)\n"\
    1149             :                 "- container: container formats (ISO File, MPEG-2 TS, AVI, ...)\n"\
    1150             :                 "- network: network data except RTP traffic\n"\
    1151             :                 "- http: HTTP traffic\n"\
    1152             :                 "- rtp: RTP traffic\n"\
    1153             :                 "- author: authoring tools (hint, import, export)\n"\
    1154             :                 "- sync: terminal sync layer\n"\
    1155             :                 "- codec: terminal codec messages\n"\
    1156             :                 "- parser: scene parsers (svg, xmt, bt) and other\n"\
    1157             :                 "- media: terminal media object management\n"\
    1158             :                 "- scene: scene graph and scene manager\n"\
    1159             :                 "- script: scripting engine messages\n"\
    1160             :                 "- interact: interaction engine (events, scripts, etc)\n"\
    1161             :                 "- smil: SMIL timing engine\n"\
    1162             :                 "- compose: composition engine (2D, 3D, etc)\n"\
    1163             :                 "- mmio: Audio/Video HW I/O management\n"\
    1164             :                 "- rti: various run-time stats\n"\
    1165             :                 "- cache: HTTP cache subsystem\n"\
    1166             :                 "- audio: Audio renderer and mixers\n"\
    1167             :                 "- mem: GPAC memory tracker\n"\
    1168             :                 "- dash: HTTP streaming logs\n"\
    1169             :                 "- module: GPAC modules (av out, font engine, 2D rasterizer)\n"\
    1170             :                 "- filter: filters debugging\n"\
    1171             :                 "- sched: filter session scheduler debugging\n"\
    1172             :                 "- mutex: log all mutex calls\n"\
    1173             :                 "- route: ROUTE (ATSC3) debugging\n"\
    1174             :                 "- all: all tools logged - other tools can be specified afterwards.  \n"\
    1175             :                 "The special keyword `ncl` can be set to disable color logs.  \n"\
    1176             :                 "The special keyword `strict` can be set to exit at first error.  \n"\
    1177             :                 "\nEX -logs=all@info:dash@debug:ncl\n"\
    1178             :                         "This moves all log to info level, dash to debug level and disable color logs"\
    1179             :                         , NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_LOG),
    1180             :  GF_DEF_ARG("proglf", NULL, "use new line at each progress messages", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_LOG),
    1181             : 
    1182             :  GF_DEF_ARG("strict-error", "se", "exit after the first error is reported", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_CORE),
    1183             :  GF_DEF_ARG("store-dir", NULL, "set storage directory", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_CORE),
    1184             :  GF_DEF_ARG("mod-dirs", NULL, "set additional module directories as a semi-colon `;` separated list", NULL, NULL, GF_ARG_STRINGS, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1185             :  GF_DEF_ARG("js-dirs", NULL, "set javascript directories", NULL, NULL, GF_ARG_STRINGS, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1186             :  GF_DEF_ARG("no-js-mods", NULL, "disable javascript module loading", NULL, NULL, GF_ARG_STRINGS, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1187             :  GF_DEF_ARG("ifce", NULL, "set default multicast interface through interface IP address (default is 127.0.0.1)", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_CORE),
    1188             :  GF_DEF_ARG("lang", NULL, "set preferred language", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_CORE),
    1189             :  GF_DEF_ARG("cfg", "opt", "get or set configuration file value. The string parameter can be formatted as:\n"\
    1190             :                 "- `section:key=val`: set the key to a new value\n"\
    1191             :                 "- `section:key=null`, `section:key`: remove the key\n"\
    1192             :                 "- `section=null`: remove the section\n"\
    1193             :                 "- no argument: print the entire configuration file\n"\
    1194             :                 "- `section`: print the given section\n"\
    1195             :                 "- `section:key`: print the given `key` in `section` (section can be set to `*`)"\
    1196             :                 "- `*:key`: print the given `key` in all sections"\
    1197             :                         , NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_CORE),
    1198             :  GF_DEF_ARG("no-save", NULL, "discard any changes made to the config file upon exit", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1199             :  GF_DEF_ARG("version", NULL, "set to GPAC version, used to check config file refresh", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_HIDE|GF_ARG_SUBSYS_CORE),
    1200             :  GF_DEF_ARG("mod-reload", NULL, "unload / reload module shared libs when no longer used", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1201             :  GF_DEF_ARG("for-test", NULL, "disable all creation/modification dates and GPAC versions in files", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1202             :  GF_DEF_ARG("old-arch", NULL, "enable compatibility with pre-filters versions of GPAC", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1203             :  GF_DEF_ARG("ntp-shift", NULL, "shift NTP clock by given amount in seconds", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1204             :  GF_DEF_ARG("devclass", NULL, "set device class\n"
    1205             :  "- ios: iOS-based mobile device\n"
    1206             :  "- android: Android-based mobile device\n"
    1207             :  "- desktop: desktop device", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_HIDE|GF_ARG_SUBSYS_CORE),
    1208             : 
    1209             :  GF_DEF_ARG("bs-cache-size", NULL, "cache size for bitstream read and write from file (0 disable cache, slower IOs)", "512", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1210             :  GF_DEF_ARG("no-check", NULL, "disable compliancy tests for inputs (ISOBMFF for now). This will likely result in random crashes", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE),
    1211             :  GF_DEF_ARG("cache", NULL, "cache directory location", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1212             :  GF_DEF_ARG("proxy-on", NULL, "enable HTTP proxy", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1213             :  GF_DEF_ARG("proxy-name", NULL, "set HTTP proxy address", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1214             :  GF_DEF_ARG("proxy-port", NULL, "set HTTP proxy port", "80", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1215             :  GF_DEF_ARG("maxrate", NULL, "set max HTTP download rate in bits per sec. 0 means unlimited", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1216             :  GF_DEF_ARG("no-cache", NULL, "disable HTTP caching", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1217             :  GF_DEF_ARG("offline-cache", NULL, "enable offline HTTP caching (no revalidation of existing resource in cache)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1218             :  GF_DEF_ARG("clean-cache", NULL, "indicate if HTTP cache should be clean upon launch/exit", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_HTTP),
    1219             :  GF_DEF_ARG("cache-size", NULL, "specify cache size in bytes", "100M", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1220             :  GF_DEF_ARG("head-timeout", NULL, "set HTTP head request timeout in milliseconds", "5000", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1221             :  GF_DEF_ARG("req-timeout", NULL, "set HTTP/RTSP request timeout in milliseconds", "20000", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1222             :  GF_DEF_ARG("broken-cert", NULL, "enable accepting broken SSL certificates", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1223             :  GF_DEF_ARG("user-agent", "ua", "set user agent name for HTTP/RTSP", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP),
    1224             :  GF_DEF_ARG("user-profileid", NULL, "set user profile ID (through **X-UserProfileID** entity header) in HTTP requests", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1225             :  GF_DEF_ARG("user-profile", NULL, "set user profile filename. Content of file is appended as body to HTTP HEAD/GET requests, associated Mime is **text/xml**", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1226             :  GF_DEF_ARG("query-string", NULL, "insert query string (without `?`) to URL on requests", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1227             :  GF_DEF_ARG("dm-threads", NULL, "force using threads for async download requests rather than session scheduler", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1228             :  GF_DEF_ARG("cte-rate-wnd", NULL, "set window analysis length in milliseconds for chunk-transfer encoding rate estimation", "20", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1229             : 
    1230             : #ifdef GPAC_HAS_HTTP2
    1231             :  GF_DEF_ARG("no-h2", NULL, "disable HTTP2", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1232             :  GF_DEF_ARG("no-h2c", NULL, "disable HTTP2 upgrade (i.e. over non-TLS)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1233             :  GF_DEF_ARG("h2-copy", NULL, "enable intermediate copy of data in nghttp2 (default is disabled but may report as broken frames in wireshark)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP),
    1234             : #endif
    1235             : 
    1236             :  GF_DEF_ARG("dbg-edges", NULL, "log edges status in filter graph before dijkstra resolution (for debug). Edges are logged as edge_source(status, weight, src_cap_idx, dst_cap_idx)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1237             : GF_DEF_ARG("full-link", NULL, "throw error if any pid in the filter graph cannot be linked", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1238             : 
    1239             :  GF_DEF_ARG("no-block", NULL, "disable blocking mode of filters\n"
    1240             :                         "- no: enable blocking mode\n"
    1241             :                         "- fanout: disable blocking on fanout, unblocking the PID as soon as one of its destinations requires a packet\n"
    1242             :                         "- all: disable blocking", "no", "no|fanout|all", GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS),
    1243             :  GF_DEF_ARG("no-reg", NULL, "disable regulation (no sleep) in session", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1244             :  GF_DEF_ARG("no-reassign", NULL, "disable source filter reassignment in pid graph resolution", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1245             :  GF_DEF_ARG("sched", NULL, "set scheduler mode\n"\
    1246             :                 "- free: lock-free queues except for task list (default)\n"\
    1247             :                 "- lock: mutexes for queues when several threads\n"\
    1248             :                 "- freex: lock-free queues including for task lists (experimental)\n"\
    1249             :                 "- flock: mutexes for queues even when no thread (debug mode)\n"\
    1250             :                 "- direct: no threads and direct dispatch of tasks whenever possible (debug mode)", "free", "free|lock|flock|freex|direct", GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1251             :  GF_DEF_ARG("max-chain", NULL, "set maximum chain length when resolving filter links. Default value covers for __[ in -> ] demux -> reframe -> decode -> encode -> reframe -> mux [ -> out]__. Filter chains loaded for adaptation (eg pixel format change) are loaded after the link resolution. Setting the value to 0 disables dynamic link resolution. You will have to specify the entire chain manually", "6", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1252             :  GF_DEF_ARG("max-sleep", NULL, "set maximum sleep time slot in milliseconds when regulation is enabled", "50", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1253             : 
    1254             :  GF_DEF_ARG("threads", NULL, "set N extra thread for the session. -1 means use all available cores", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS),
    1255             :  GF_DEF_ARG("no-probe", NULL, "disable data probing on sources and relies on extension (faster load but more error-prone)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS),
    1256             :  GF_DEF_ARG("no-argchk", NULL, "disable tracking of argument usage (all arguments will be considered as used)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS),
    1257             :  GF_DEF_ARG("blacklist", NULL, "blacklist the filters listed in the given string (comma-separated list)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS),
    1258             :  GF_DEF_ARG("no-graph-cache", NULL, "disable internal caching of filter graph connections. If disabled, the graph will be recomputed at each link resolution (lower memory usage but slower)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1259             :  GF_DEF_ARG("no-reservoir", NULL, "disable memory recycling for packets and properties. This uses much less memory but stresses the system memory allocator much more", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS),
    1260             : 
    1261             :  GF_DEF_ARG("switch-vres", NULL, "select smallest video resolution larger than scene size, otherwise use current video resolution", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1262             :  GF_DEF_ARG("hwvmem", NULL, "specify (2D rendering only) memory type of main video backbuffer. Depending on the scene type, this may drastically change the playback speed\n"
    1263             :  "- always: always on hardware\n"
    1264             :  "- never: always on system memory\n"
    1265             :  "- auto: selected by GPAC based on content type (graphics or video)", "auto", "auto|always|never", GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1266             :  GF_DEF_ARG("pref-yuv4cc", NULL, "set preferred YUV 4CC for overlays (used by DirectX only)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1267             :  GF_DEF_ARG("yuv-overlay", NULL, "indicate YUV overlay is possible on the video card. Always overridden by video output module", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_HIDE|GF_ARG_SUBSYS_VIDEO),
    1268             :  GF_DEF_ARG("offscreen-yuv", NULL, "indicate if offscreen yuv->rgb is enabled. can be set to false to force disabling", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1269             :  GF_DEF_ARG("overlay-color-key", NULL, "color to use for overlay keying, hex format", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1270             :  GF_DEF_ARG("gl-bits-comp", NULL, "number of bits per color component in openGL", "8", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_VIDEO),
    1271             :  GF_DEF_ARG("gl-bits-depth", NULL, "number of bits for depth buffer in openGL", "16", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_VIDEO),
    1272             :  GF_DEF_ARG("gl-doublebuf", NULL, "enable openGL double buffering", "yes", NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_VIDEO),
    1273             :  GF_DEF_ARG("sdl-defer", NULL, "use defer rendering for SDL", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1274             :  GF_DEF_ARG("no-colorkey", NULL, "disable color keying at the video output level", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_VIDEO),
    1275             :  GF_DEF_ARG("glfbo-txid", NULL, "set output texture ID when using `glfbo` output. The OpenGL context shall be initialized and gf_term_process shall be called with the OpenGL context active", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1276             :  GF_DEF_ARG("video-output", NULL, "indicate the name of the video output module to use (see `gpac -h modules`)."
    1277             :         " The reserved name `glfbo` is used in player mode to draw in the openGL texture identified by [-glfbo-txid](). "
    1278             :         " In this mode, the application is responsible for sending event to the terminal"
    1279             :  , NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1280             :  GF_DEF_ARG("audio-output", NULL, "indicate the name of the audio output module to use", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO),
    1281             :  GF_DEF_ARG("alsa-devname", NULL, "set ALSA dev name", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_AUDIO),
    1282             :  GF_DEF_ARG("force-alsarate", NULL, "force ALSA and OSS output sample rate", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_AUDIO),
    1283             :  GF_DEF_ARG("ds-disable-notif", NULL, "disable DirectSound audio buffer notifications when supported", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_AUDIO),
    1284             :  GF_DEF_ARG("font-reader", NULL, "indicate name of font reader module", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_TEXT),
    1285             :  GF_DEF_ARG("font-dirs", NULL, "indicate comma-separated list of directories to scan for fonts", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_TEXT),
    1286             :  GF_DEF_ARG("rescan-fonts", NULL, "indicate the font directory must be rescanned", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_TEXT),
    1287             :  GF_DEF_ARG("wait-fonts", NULL, "wait for SVG fonts to be loaded before displaying frames", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_TEXT),
    1288             :  GF_DEF_ARG("webvtt-hours", NULL, "force writing hour when serializing WebVTT", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_TEXT),
    1289             :  GF_DEF_ARG("rmt", NULL, "enable profiling through [Remotery](https://github.com/Celtoys/Remotery). A copy of Remotery visualizer is in gpac/share/vis, usually installed in __/usr/share/gpac/vis__ or __Program Files/GPAC/vis__", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1290             :  GF_DEF_ARG("rmt-port", NULL, "set remotery port", "17815", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1291             :  GF_DEF_ARG("rmt-reuse", NULL, "allow remotery to reuse port", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1292             :  GF_DEF_ARG("rmt-localhost", NULL, "make remotery only accepts localhost connection", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1293             :  GF_DEF_ARG("rmt-sleep", NULL, "set remotery sleep (ms) between server updates", "10", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1294             :  GF_DEF_ARG("rmt-nmsg", NULL, "set remotery number of messages per update", "10", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1295             :  GF_DEF_ARG("rmt-qsize", NULL, "set remotery message queue size in bytes", "131072", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1296             :  GF_DEF_ARG("rmt-log", NULL, "redirect logs to remotery (experimental, usually not well handled by browser)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1297             :  GF_DEF_ARG("rmt-ogl", NULL, "make remotery sample opengl calls", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT),
    1298             : 
    1299             :  GF_DEF_ARG("m2ts-vvc-old", NULL, "hack for old TS streams using 0x32 for VVC instead of 0x33", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HACKS),
    1300             :  GF_DEF_ARG("piff-force-subsamples", NULL, "hack for PIFF PSEC files generated by 0.9.0 and 1.0 MP4Box with wrong subsample_count inserted for audio", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HACKS),
    1301             : 
    1302             :  {0}
    1303             : };
    1304             : 
    1305             : 
    1306             : const GF_Config *gf_sys_get_lang_file();
    1307             : 
    1308             : GF_EXPORT
    1309          16 : const GF_GPACArg *gf_sys_get_options()
    1310             : {
    1311          16 :         return GPAC_Args;
    1312             : }
    1313             : 
    1314       60151 : static const char *gpac_opt_default(const char *argname)
    1315             : {
    1316             :         const GF_GPACArg *arg = NULL;
    1317             :         u32 i=0;
    1318     2711441 :         while (GPAC_Args[i].name) {
    1319     2651096 :                 arg = &GPAC_Args[i];
    1320     2651096 :                 i++;
    1321     2651096 :                 if (!strcmp(arg->name, argname)) break;
    1322             :                 arg = NULL;
    1323             :         }
    1324       60151 :         if (!arg) return NULL;
    1325       59957 :         return arg->val;
    1326             : }
    1327             : 
    1328             : GF_EXPORT
    1329       54966 : Bool gf_opts_get_bool(const char *secName, const char *keyName)
    1330             : {
    1331       54966 :         const char *opt = gf_opts_get_key(secName, keyName);
    1332             : 
    1333       54966 :         if (!opt && !strcmp(secName, "core")) {
    1334       41076 :                 opt = gpac_opt_default(keyName);
    1335             :         }
    1336             : 
    1337       54966 :         if (!opt) return GF_FALSE;
    1338        1816 :         if (!strcmp(opt, "yes")) return GF_TRUE;
    1339          13 :         if (!strcmp(opt, "true")) return GF_TRUE;
    1340          12 :         if (!strcmp(opt, "1")) return GF_TRUE;
    1341          12 :         return GF_FALSE;
    1342             : }
    1343             : GF_EXPORT
    1344       19339 : u32 gf_opts_get_int(const char *secName, const char *keyName)
    1345             : {
    1346             :         u32 times=1, val;
    1347       19339 :         char *opt = (char *) gf_opts_get_key(secName, keyName);
    1348             : 
    1349       19339 :         if (!opt && !strcmp(secName, "core")) {
    1350       19075 :                 opt = (char *) gpac_opt_default(keyName);
    1351             :         }
    1352       19339 :         if (!opt) return 0;
    1353       16415 :         char *sep = strchr(opt, 'k');
    1354       16415 :         if (sep) times=1000;
    1355             :         else {
    1356       16415 :                 sep = strchr(opt, 'K');
    1357       16415 :                 if (sep) times=1000;
    1358             :                 else {
    1359       16415 :                         sep = strchr(opt, 'm');
    1360       16415 :                         if (sep) times=1000000;
    1361             :                         else {
    1362       16415 :                                 sep = strchr(opt, 'M');
    1363       16415 :                                 if (sep) times=1000000;
    1364             :                         }
    1365             :                 }
    1366             :         }
    1367       16415 :         sscanf(opt, "%d", &val);
    1368       16415 :         val = atoi(opt);
    1369       16415 :         return val*times;
    1370             : }
    1371             : 
    1372             : GF_EXPORT
    1373         235 : Bool gf_sys_set_cfg_option(const char *opt_string)
    1374             : {
    1375             :         size_t sepIdx;
    1376             :         char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024];
    1377         235 :         sep = strchr(opt_string, ':');
    1378         235 :         if (!sep) {
    1379           0 :                 sep = strchr(opt_string, '=');
    1380           0 :                 if (sep && !stricmp(sep, "=null")) {
    1381           0 :                         sepIdx = sep - opt_string;
    1382           0 :                         if (sepIdx>=1024) sepIdx = 1023;
    1383             :                         strncpy(szSec, opt_string, sepIdx);
    1384           0 :                         szSec[sepIdx] = 0;
    1385           0 :                         gf_opts_del_section(szSec);
    1386           0 :                         return  GF_TRUE;
    1387             :                 }
    1388             : 
    1389           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CoreArgs] Badly formatted option %s - expected Section:Name=Value\n", opt_string ) );
    1390             :                 return GF_FALSE;
    1391             :         }
    1392             : 
    1393         235 :         sepIdx = sep - opt_string;
    1394         235 :         if (sepIdx>=1024)
    1395             :                 sepIdx = 1023;
    1396             :         strncpy(szSec, opt_string, sepIdx);
    1397         235 :         szSec[sepIdx] = 0;
    1398             : 
    1399         235 :         sep ++;
    1400         235 :         sep2 = strchr(sep, '=');
    1401         235 :         if (!sep2) {
    1402           0 :                 gf_opts_set_key(szSec, sep, NULL);
    1403           0 :                 return  GF_TRUE;
    1404             :         }
    1405             : 
    1406         235 :         sepIdx = sep2 - sep;
    1407         235 :         if (sepIdx>=1024)
    1408             :                 sepIdx = 1023;
    1409             :         strncpy(szKey, sep, sepIdx);
    1410         235 :         szKey[sepIdx] = 0;
    1411             : 
    1412         235 :         sepIdx = strlen(sep2+1);
    1413         235 :         if (sepIdx>=1024)
    1414             :                 sepIdx = 1023;
    1415             :         memcpy(szVal, sep2+1, sepIdx);
    1416         235 :         szVal[sepIdx] = 0;
    1417             : 
    1418         235 :         if (!stricmp(szKey, "*")) {
    1419           0 :                 if (stricmp(szVal, "null")) {
    1420           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CoreArgs] Badly formatted option %s - expected Section:*=null\n", opt_string));
    1421             :                         return GF_FALSE;
    1422             :                 }
    1423           0 :                 gf_opts_del_section(szSec);
    1424           0 :                 return GF_TRUE;
    1425             :         }
    1426             : 
    1427         235 :         if (!stricmp(szVal, "null")) {
    1428           0 :                 szVal[0]=0;
    1429             :         }
    1430         235 :         gf_opts_set_key(szSec, szKey, szVal[0] ? szVal : NULL);
    1431             : 
    1432         235 :         if (!strcmp(szSec, "core")) {
    1433           3 :                 if (!strcmp(szKey, "noprog") && (!strcmp(szVal, "yes")||!strcmp(szVal, "true")||!strcmp(szVal, "1")) ) {
    1434             :                         void gpac_disable_progress();
    1435             : 
    1436           3 :                         gpac_disable_progress();
    1437             :                 }
    1438             :         }
    1439             :         return GF_TRUE;
    1440             : }
    1441             : 
    1442             : void gf_module_reload_dirs();
    1443             : 
    1444       28088 : Bool gf_opts_load_option(const char *arg_name, const char *val, Bool *consumed_next, GF_Err *e)
    1445             : {
    1446             :         const GF_GPACArg *arg = NULL;
    1447             :         u32 i=0;
    1448       28088 :         *e = GF_OK;
    1449       28088 :         *consumed_next = GF_FALSE;
    1450       28088 :         arg_name = arg_name+1;
    1451     2463186 :         while (GPAC_Args[i].name) {
    1452     2409810 :                 arg = &GPAC_Args[i];
    1453     2409810 :                 i++;
    1454     2409810 :                 if (!strcmp(arg->name, arg_name)) break;
    1455     2407010 :                 if (arg->altname && !strcmp(arg->altname, arg_name)) break;
    1456             : 
    1457             :                 arg = NULL;
    1458             :         }
    1459       28088 :         if (!arg) return GF_FALSE;
    1460             : 
    1461        2800 :         if (!strcmp(arg->name, "cfg")) {
    1462         232 :                 *consumed_next = GF_TRUE;
    1463         232 :                 if (val && strchr(val, '=')) {
    1464         232 :                         if (! gf_sys_set_cfg_option(val)) *e = GF_BAD_PARAM;
    1465             :                 } else {
    1466             :                         u32 sec_len = 0;
    1467           0 :                         char *sep = val ? strchr(val, ':') : NULL;
    1468           0 :                         u32 sec_count = gf_opts_get_section_count();
    1469           0 :                         if (sep) {
    1470           0 :                                 sec_len = (u32) (sep - val - 1);
    1471           0 :                                 sep++;
    1472           0 :                         } else if (val) {
    1473           0 :                                 sec_len = (u32) strlen(val);
    1474             :                         }
    1475           0 :                         for (i=0; i<sec_count; i++) {
    1476             :                                 u32 k, key_count;
    1477             :                                 Bool sec_hdr_done = GF_FALSE;
    1478           0 :                                 const char *sname = gf_opts_get_section_name(i);
    1479           0 :                                 key_count = sname ? gf_opts_get_key_count(sname) : 0;
    1480           0 :                                 if (!key_count) continue;
    1481             : 
    1482           0 :                                 if (sec_len) {
    1483           0 :                                         if (!strncmp(val, "*", sec_len) || !strncmp(val, "@", sec_len)) {
    1484           0 :                                         } else if (strncmp(val, sname, sec_len) || (sec_len != (u32) strlen(sname) ) ) {
    1485           0 :                                                 continue;
    1486             :                                         }
    1487             :                                 }
    1488           0 :                                 for (k=0; k<key_count; k++) {
    1489           0 :                                         const char *kname = gf_opts_get_key_name(sname, k);
    1490           0 :                                         const char *kval = kname ? gf_opts_get_key(sname, kname) : NULL;
    1491           0 :                                         if (!kval) continue;
    1492           0 :                                         if (sep && strcmp(sep, kname)) continue;
    1493             : 
    1494           0 :                                         if (!sec_hdr_done) {
    1495             :                                                 sec_hdr_done = GF_TRUE;
    1496           0 :                                                 fprintf(stdout, "[%s]\n", sname);
    1497             :                                         }
    1498           0 :                                         fprintf(stdout, "%s=%s\n", kname, kval);
    1499             :                                 }
    1500           0 :                                 if (sec_hdr_done)
    1501           0 :                                         fprintf(stdout, "\n");
    1502             :                         }
    1503           0 :                         exit(0);
    1504             :                 }
    1505             :                 return GF_TRUE;
    1506             :         }
    1507        2568 :         if (!strcmp(arg->name, "strict-error")) {
    1508          15 :                 gf_log_set_strict_error(1);
    1509          15 :                 return GF_TRUE;
    1510             :         }
    1511             : 
    1512        2553 :         if (arg->type==GF_ARG_BOOL) {
    1513        1801 :                 if (!val) gf_opts_set_key("temp", arg->name, "yes");
    1514             :                 else {
    1515        1799 :                         if (!strcmp(val, "yes") || !strcmp(val, "true") || !strcmp(val, "1")) {
    1516           0 :                                 *consumed_next = GF_TRUE;
    1517           0 :                                 gf_opts_set_key("temp", arg->name, "yes");
    1518             :                         } else {
    1519        1799 :                                 if (!strcmp(val, "no") || !strcmp(val, "false") || !strcmp(val, "0")) {
    1520          11 :                                         *consumed_next = GF_TRUE;
    1521          11 :                                         gf_opts_set_key("temp", arg->name, "no");
    1522             :                                 } else {
    1523        1788 :                                         gf_opts_set_key("temp", arg->name, "yes");
    1524             :                                 }
    1525             :                         }
    1526             :                 }
    1527             :         } else {
    1528         752 :                 *consumed_next = GF_TRUE;
    1529         752 :                 if (!val && (arg->type==GF_ARG_BOOL))
    1530           0 :                         gf_opts_set_key("temp", arg->name, "true");
    1531             :                 else {
    1532         752 :                         gf_opts_set_key("temp", arg->name, val);
    1533         752 :                         if (!strcmp(arg->name, "mod-dirs")) {
    1534           0 :                                 gf_module_reload_dirs();
    1535             :                         }
    1536             :                 }
    1537             :         }
    1538             :         return GF_TRUE;
    1539             : }
    1540             : 
    1541             : GF_EXPORT
    1542       21468 : u32 gf_sys_is_gpac_arg(const char *arg_name)
    1543             : {
    1544             :         char *argsep;
    1545             :         u32 arglen;
    1546             :         const GF_GPACArg *arg = NULL;
    1547             :         u32 i=0;
    1548       21468 :         arg_name = arg_name+1;
    1549       21468 :         if (arg_name[0]=='-')
    1550             :                 return 1;
    1551       21371 :         if (arg_name[0]=='+')
    1552             :                 return 1;
    1553             : 
    1554       21371 :         argsep = strchr(arg_name, '=');
    1555       21371 :         if (argsep) arglen = (u32) (argsep - arg_name);
    1556       21366 :         else arglen = (u32) strlen(arg_name);
    1557             : 
    1558      398792 :         while (GPAC_Args[i].name) {
    1559      398786 :                 arg = &GPAC_Args[i];
    1560      398786 :                 i++;
    1561      398786 :                 if ((strlen(arg->name) == arglen) && !strncmp(arg->name, arg_name, arglen)) break;
    1562      377429 :                 if (arg->altname) {
    1563       77967 :                         char *alt = strstr(arg->altname, arg_name);
    1564       77967 :                         if (alt) {
    1565           8 :                                 char c = alt[strlen(arg_name)];
    1566           8 :                                 if (!c || (c==' ')) break;
    1567             :                         }
    1568             :                 }
    1569             :                 arg = NULL;
    1570             :         }
    1571       21371 :         if (!arg) return 0;
    1572       21365 :         if (arg->type==GF_ARG_BOOL) return 1;
    1573         921 :         if (argsep) return 1;
    1574         917 :         return 2;
    1575             : }
    1576             : 
    1577             : 
    1578             : GF_EXPORT
    1579        3928 : void gf_sys_print_arg(FILE *helpout, u32 flags, const GF_GPACArg *arg, const char *arg_subsystem)
    1580             : {
    1581             :         u32 gen_doc = 0;
    1582        3928 :         if (flags & GF_PRINTARG_MD)
    1583             :                 gen_doc = 1;
    1584        3928 :         if (!helpout) helpout = stderr;
    1585             : 
    1586             : //#ifdef GPAC_ENABLE_COVERAGE
    1587             : #if 1
    1588        3928 :         if ((arg->name[0]>='A') && (arg->name[0]<='Z')) {
    1589           2 :                 if ((arg->name[1]<'A') || (arg->name[1]>'Z')) {
    1590           0 :                         fprintf(stderr, "\nWARNING: arg %s bad name format, should use lowercase\n", arg->name);
    1591           0 :                         exit(1);
    1592             :                 }
    1593             :         }
    1594        3928 :         if (arg->description) {
    1595             :                 char *sep;
    1596             : 
    1597        3891 :                 if ((arg->description[0]>='A') && (arg->description[0]<='Z')) {
    1598          36 :                         if ((arg->description[1]<'A') || (arg->description[1]>'Z')) {
    1599           0 :                                 fprintf(stderr, "\nWARNING: arg %s bad name format \"%s\", should use lowercase\n", arg->name, arg->description);
    1600           0 :                                 exit(1);
    1601             :                         }
    1602             :                 }
    1603        3891 :                 if (strchr(arg->description, '\t')) {
    1604           0 :                         fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not use tab\n", arg->name, arg->description);
    1605           0 :                         exit(1);
    1606             :                 }
    1607             : 
    1608        3891 :                 u8 achar = arg->description[strlen(arg->description)-1];
    1609        3891 :                 if (achar == '.') {
    1610           0 :                         fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not end with .\n", arg->name, arg->description);
    1611           0 :                         exit(1);
    1612             :                 }
    1613        3891 :                 sep = strstr(arg->description, ".\n");
    1614        3891 :                 if (sep) {
    1615           0 :                         fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not contain .\\n \n", arg->name, arg->description);
    1616           0 :                         exit(1);
    1617             :                 }
    1618        3891 :                 sep = strstr(arg->description, "- ");
    1619        3891 :                 if (sep && (sep[-1]!='\n') && !strcmp(sep, "- see")) {
    1620           0 :                         fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should have \\n before first bullet\n", arg->name, arg->description);
    1621           0 :                         exit(1);
    1622             :                 }
    1623             : 
    1624        3891 :                 sep = strchr(arg->description, ' ');
    1625        3891 :                 if (sep) {
    1626             :                         sep--;
    1627        3891 :                         if ((sep[0] == 's') && (sep[-1] != 's')) {
    1628           0 :                                 fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should use infintive\n", arg->name, arg->description);
    1629           0 :                                 exit(1);
    1630             :                         }
    1631             :                 }
    1632             :         }
    1633             : #endif
    1634             : 
    1635        3928 :         if (arg->flags & GF_ARG_HINT_HIDE)
    1636             :                 return;
    1637             : 
    1638        2194 :         const char *syntax=strchr(arg->name, ' ');
    1639             :         char *arg_name=NULL;
    1640        2194 :         if (syntax) {
    1641           0 :                 arg_name = gf_strdup(arg->name);
    1642           0 :                 char *sep = strchr(arg_name, ' ');
    1643           0 :                 sep[0]=0;
    1644             :         }
    1645             : 
    1646        2194 :         if (flags & GF_PRINTARG_MAN) {
    1647         537 :                 fprintf(helpout, ".TP\n.B %s%s", (flags&GF_PRINTARG_NO_DASH) ? "" : "\\-", arg_name ? arg_name : arg->name);
    1648             :         }
    1649        1657 :         else if (gen_doc==1) {
    1650         553 :                 if (flags&GF_PRINTARG_NO_DASH) {
    1651          99 :                         gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s", arg_name ? arg_name : arg->name);
    1652             :                 } else {
    1653         454 :                         gf_sys_format_help(helpout, flags, "<a id=\"%s\">", arg_name ? arg_name : arg->name);
    1654         454 :                         gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "-%s", arg_name ? arg_name : arg->name);
    1655         454 :                         gf_sys_format_help(helpout, flags, "</a>");
    1656             :                 }
    1657             :         } else {
    1658        3312 :                 gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s%s%s",
    1659        1104 :                         (flags&GF_PRINTARG_ADD_DASH) ? "-" : "",
    1660        2010 :                         (flags&GF_PRINTARG_NO_DASH) ? "" : ((flags&GF_PRINTARG_COLON) ? ":" : "-"),
    1661             :                         arg_name ? arg_name : arg->name
    1662             :                 );
    1663             :         }
    1664        2194 :         if (arg->altname) {
    1665          77 :                 gf_sys_format_help(helpout, flags, ",");
    1666          77 :                 gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s-%s", (flags&GF_PRINTARG_ADD_DASH) ? "-" : "", arg->altname);
    1667             :         }
    1668        2194 :         if (syntax) {
    1669           0 :                 gf_sys_format_help(helpout, flags, " %s", syntax);
    1670           0 :                 gf_free(arg_name);
    1671             :         }
    1672             : 
    1673        2194 :         if (arg->type==GF_ARG_CUSTOM) {
    1674         112 :                 if (arg->val)
    1675         112 :                         gf_sys_format_help(helpout, flags, " `%s`", arg->val);
    1676        2082 :         } else if (arg->type==GF_ARG_INT && arg->values && strchr(arg->values, '|')) {
    1677          18 :                 gf_sys_format_help(helpout, flags, " (Enum");
    1678          18 :                 if (arg->val)
    1679          18 :                         gf_sys_format_help(helpout, flags, ", default: **%s**", arg->val);
    1680          18 :                 gf_sys_format_help(helpout, flags, ")");
    1681        2064 :         } else if (arg->type != GF_ARG_BOOL) {
    1682        1000 :                 gf_sys_format_help(helpout, flags, " (");
    1683        1000 :                 switch (arg->type) {
    1684           0 :                 case GF_ARG_BOOL: gf_sys_format_help(helpout, flags, "boolean"); break;
    1685         394 :                 case GF_ARG_INT: gf_sys_format_help(helpout, flags, "int"); break;
    1686          60 :                 case GF_ARG_DOUBLE: gf_sys_format_help(helpout, flags, "number"); break;
    1687         534 :                 case GF_ARG_STRING: gf_sys_format_help(helpout, flags, "string"); break;
    1688          12 :                 case GF_ARG_STRINGS: gf_sys_format_help(helpout, flags, "string list"); break;
    1689           0 :                 case GF_ARG_4CC: gf_sys_format_help(helpout, flags, "4CC"); break;
    1690           0 :                 case GF_ARG_4CCS: gf_sys_format_help(helpout, flags, "4CC list"); break;
    1691             :                 default: break;
    1692             :                 }
    1693        1000 :                 if (arg->val)
    1694         109 :                         gf_sys_format_help(helpout, flags, ", default: **%s**", arg->val);
    1695        1000 :                 if (arg->values)
    1696           4 :                         gf_sys_format_help(helpout, flags, ", values: __%s__", arg->values);
    1697        1000 :                 gf_sys_format_help(helpout, flags, ")");
    1698             :         }
    1699             : 
    1700        2194 :         if (flags & GF_PRINTARG_MAN) {
    1701         537 :                 gf_sys_format_help(helpout, flags, "\n%s\n", gf_sys_localized(arg_subsystem, arg->name, arg->description) );
    1702             :         } else {
    1703        1657 :                 if (arg->description) {
    1704        1620 :                         gf_sys_format_help(helpout, flags | GF_PRINTARG_OPT_DESC, ": %s", gf_sys_localized(arg_subsystem, arg->name, arg->description) );
    1705             :                 }
    1706        1657 :                 gf_sys_format_help(helpout, flags, "\n");
    1707             :         }
    1708             : 
    1709        2194 :         if ((gen_doc==1) && arg->description && strstr(arg->description, "- "))
    1710          43 :                 gf_sys_format_help(helpout, flags, "\n");
    1711             : }
    1712             : 
    1713             : 
    1714             : GF_EXPORT
    1715          10 : void gf_sys_print_core_help(FILE *helpout, u32 flags, GF_SysArgMode mode, u32 subsystem_flags)
    1716             : {
    1717             :         u32 i=0;
    1718          10 :         const GF_GPACArg *args = gf_sys_get_options();
    1719             : 
    1720         920 :         while (args[i].name) {
    1721             :                 const GF_GPACArg *arg = &args[i];
    1722         900 :                 i++;
    1723         900 :                 if (arg->flags & GF_ARG_HINT_HIDE) continue;
    1724             : 
    1725         870 :                 if (subsystem_flags && !(arg->flags & subsystem_flags)) {
    1726         474 :                         continue;
    1727             :                 }
    1728         396 :                 if (mode != GF_ARGMODE_ALL) {
    1729           0 :                         if ((mode==GF_ARGMODE_EXPERT) && !(arg->flags & GF_ARG_HINT_EXPERT)) continue;
    1730           0 :                         else if ((mode==GF_ARGMODE_ADVANCED) && !(arg->flags & GF_ARG_HINT_ADVANCED)) continue;
    1731           0 :                         else if ((mode==GF_ARGMODE_BASE) && (arg->flags & (GF_ARG_HINT_ADVANCED|GF_ARG_HINT_EXPERT) )) continue;
    1732             :                 }
    1733         396 :                 gf_sys_print_arg(helpout, flags, arg, "core");
    1734             :         }
    1735          10 : }
    1736             : 
    1737             : 
    1738             : #define LINE_OFFSET_DESCR 30
    1739             : 
    1740             : static char *help_buf = NULL;
    1741             : static u32 help_buf_size=0;
    1742             : 
    1743        6240 : void gf_sys_cleanup_help()
    1744             : {
    1745        6240 :         if (help_buf) gf_free(help_buf);
    1746        6240 : }
    1747             : 
    1748             : 
    1749             : enum
    1750             : {
    1751             :         TOK_CODE,
    1752             :         TOK_BOLD,
    1753             :         TOK_ITALIC,
    1754             :         TOK_STRIKE,
    1755             :         TOK_OPTLINK,
    1756             :         TOK_LINKSTART,
    1757             : };
    1758             : struct _token {
    1759             :         char *tok;
    1760             :         GF_ConsoleCodes cmd_type;
    1761             : } Tokens[] =
    1762             : {
    1763             :  {"`", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC},
    1764             :  {"**", GF_CONSOLE_BOLD},
    1765             :  {"__", GF_CONSOLE_ITALIC},
    1766             :  {"~~", GF_CONSOLE_STRIKE},
    1767             :  {"[-", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC},
    1768             :  {"[", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC},
    1769             : };
    1770             : static u32 nb_tokens = sizeof(Tokens) / sizeof(struct _token);
    1771             : 
    1772             : static u32 line_pos = 0;
    1773             : 
    1774             : //#define CHECK_BALANCED_SEPS
    1775             : 
    1776             : #ifdef CHECK_BALANCED_SEPS
    1777             : static void check_char_balanced(char *buf, char c)
    1778             : {
    1779             :         char *txt = buf;
    1780             :         while (txt) {
    1781             :                 char *bquote_next;
    1782             :                 char *bquote = strchr(txt, c);
    1783             :                 if (!bquote) break;
    1784             :                 if (c=='\'') {
    1785             :                         if ((bquote[1]=='s') && (bquote[2]==' ')) {
    1786             :                                 txt = bquote + 1;
    1787             :                                 continue;
    1788             :                         }
    1789             :                 }
    1790             :                 bquote_next = strchr(bquote+1, c);
    1791             :                 if (!bquote_next) {
    1792             :                         fprintf(stderr, "Missing closing %c after %s\n", c, bquote);
    1793             :                         exit(1);
    1794             :                 }
    1795             :                 switch (bquote_next[1] ) {
    1796             :                 case 0:
    1797             :                 case '\n':
    1798             :                 case ' ':
    1799             :                 case ',':
    1800             :                 case '.':
    1801             :                 case ')':
    1802             :                 case ']':
    1803             :                 case ':':
    1804             :                         break;
    1805             :                 default:
    1806             :                         if (c=='\'') {
    1807             :                                 if ((bquote_next[1]>='A') && (bquote_next[1]<='Z'))
    1808             :                                         break;
    1809             :                         }
    1810             :                         fprintf(stderr, "Missing space after closing %c %s\n", c, bquote_next);
    1811             :                         exit(1);
    1812             :                 }
    1813             :                 txt = bquote_next + 1;
    1814             :         }
    1815             : }
    1816             : #endif
    1817             : 
    1818             : GF_EXPORT
    1819       82592 : void gf_sys_format_help(FILE *helpout, u32 flags, const char *fmt, ...)
    1820             : {
    1821             :         char *line;
    1822             :         u32 len;
    1823             :         va_list vlist;
    1824             :         Bool escape_xml = GF_FALSE;
    1825             :         Bool escape_pipe = GF_FALSE;
    1826             :         Bool prev_was_example = GF_FALSE;
    1827             :         u32 gen_doc = 0;
    1828             :         u32 is_app_opts = 0;
    1829       82592 :         if (flags & GF_PRINTARG_MD) {
    1830             :                 gen_doc = 1;
    1831        9299 :                 if (flags & GF_PRINTARG_ESCAPE_XML)
    1832             :                         escape_xml = GF_TRUE;
    1833        9299 :                 if (flags & GF_PRINTARG_ESCAPE_PIPE)
    1834             :                         escape_pipe = GF_TRUE;
    1835             :         }
    1836       82592 :         if (flags & GF_PRINTARG_MAN)
    1837             :                 gen_doc = 2;
    1838       82592 :         if (flags & GF_PRINTARG_IS_APP)
    1839             :                 is_app_opts = 1;
    1840       82592 :         if (!helpout) helpout = stderr;
    1841             : 
    1842       82592 :         va_start(vlist, fmt);
    1843       82592 :         len=vsnprintf(NULL, 0, fmt, vlist);
    1844       82592 :         va_end(vlist);
    1845       82592 :         if (help_buf_size < len+2) {
    1846         218 :                 help_buf_size = len+2;
    1847         218 :                 help_buf = gf_realloc(help_buf, help_buf_size);
    1848             :         }
    1849       82592 :         va_start(vlist, fmt);
    1850       82592 :         vsprintf(help_buf, fmt, vlist);
    1851       82592 :         va_end(vlist);
    1852             : 
    1853             : #ifdef CHECK_BALANCED_SEPS
    1854             :         if (gen_doc) {
    1855             :                 check_char_balanced(help_buf, '`');
    1856             :                 check_char_balanced(help_buf, '\'');
    1857             :         }
    1858             : #endif
    1859             : 
    1860       82592 :         line = help_buf;
    1861      216402 :         while (line[0]) {
    1862             :                 u32 att_len = 0;
    1863             :                 char *tok_sep = NULL;
    1864             :                 GF_ConsoleCodes console_code = GF_CONSOLE_RESET;
    1865             :                 Bool line_before = GF_FALSE;
    1866             :                 Bool line_after = GF_FALSE;
    1867             :                 const char *footer_string = NULL;
    1868             :                 const char *header_string = NULL;
    1869       96680 :                 char *next_line = strchr(line, '\n');
    1870             :                 Bool has_token=GF_FALSE;
    1871             : 
    1872       96680 :                 if (next_line) next_line[0]=0;
    1873             : 
    1874             : 
    1875       96680 :                 if ((line[0]=='#') && (line[1]==' ')) {
    1876        4447 :                         if (!gen_doc)
    1877        3853 :                                 line+=2;
    1878         594 :                         else if (gen_doc==2) {
    1879             :                                 header_string = ".SH ";
    1880             :                                 footer_string = "\n.LP";
    1881         296 :                                 line+=2;
    1882             :                         }
    1883             : 
    1884             :                         console_code = GF_CONSOLE_GREEN;
    1885             :                         line_after = line_before = GF_TRUE;
    1886       92233 :                 } else if ((line[0]=='#') && (line[1]=='#') && (line[2]==' ')) {
    1887          78 :                         if (!gen_doc)
    1888          28 :                                 line+=3;
    1889          50 :                         else if (gen_doc==2) {
    1890          24 :                                 line+=3;
    1891             :                                 header_string = ".P\n.B\n";
    1892             :                         }
    1893             : 
    1894             :                         console_code = GF_CONSOLE_MAGENTA;
    1895             :                         line_before = GF_TRUE;
    1896       92155 :                 } else if ((line[0]=='E') && (line[1]=='X') && (line[2]==' ')) {
    1897         530 :                         line+=3;
    1898             :                         console_code = GF_CONSOLE_YELLOW;
    1899             : 
    1900         530 :                         if (gen_doc==1) {
    1901             :                                 header_string = "Example\n```\n";
    1902             :                                 footer_string = "\n```";
    1903         356 :                         } else if (gen_doc==2) {
    1904             :                                 header_string = "Example\n.br\n";
    1905             :                                 footer_string = "\n.br\n";
    1906             :                         } else {
    1907             :                                 header_string = "Example:\n";
    1908             :                         }
    1909             : 
    1910         530 :                         if (prev_was_example) {
    1911             :                                 header_string = NULL;
    1912             :                         }
    1913             : 
    1914         530 :                         if (next_line && (next_line[1]=='E') && (next_line[2]=='X') && (next_line[3]==' ')) {
    1915             :                                 prev_was_example = GF_TRUE;
    1916             :                                 footer_string = NULL;
    1917             :                         } else {
    1918             :                                 prev_was_example = GF_FALSE;
    1919             :                         }
    1920       91625 :                 } else if (!strncmp(line, "Note: ", 6)) {
    1921             :                         console_code = GF_CONSOLE_CYAN | GF_CONSOLE_ITALIC;
    1922       91499 :                 } else if (!strncmp(line, "Warning: ", 9)) {
    1923             :                         line_after = line_before = GF_TRUE;
    1924             :                         console_code = GF_CONSOLE_RED | GF_CONSOLE_BOLD;
    1925       91408 :                 } else if ( (
    1926        4833 :                          ((line[0]=='-') && (line[1]==' '))
    1927       88038 :                          || ((line[0]==' ') && (line[1]=='-') && (line[2]==' '))
    1928       84183 :                          || ((line[0]==' ') && (line[1]==' ') && (line[2]=='-') && (line[3]==' '))
    1929             :                         )
    1930             : 
    1931             :                         //look for ": "
    1932        7481 :                         && ((tok_sep=strstr(line, ": ")) != NULL )
    1933             :                 ) {
    1934        5994 :                         if (!gen_doc)
    1935             :                                 fprintf(helpout, "\t");
    1936        9305 :                         while (line[0] != '-') {
    1937             :                                 fprintf(helpout, " ");
    1938        3311 :                                 line++;
    1939        3311 :                                 line_pos++;
    1940             : 
    1941             :                         }
    1942             :                         fprintf(helpout, "* ");
    1943        5994 :                         line_pos+=2;
    1944        5994 :                         if (!gen_doc)
    1945        4309 :                                 gf_sys_set_console_code(helpout, GF_CONSOLE_YELLOW);
    1946        5994 :                         tok_sep[0] = 0;
    1947        5994 :                         fprintf(helpout, "%s", line+2);
    1948        5994 :                         line_pos += (u32) strlen(line+2);
    1949        5994 :                         tok_sep[0] = ':';
    1950             :                         line = tok_sep;
    1951        5994 :                         if (!gen_doc)
    1952        4309 :                                 gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    1953       85414 :                 } else if (flags & (GF_PRINTARG_HIGHLIGHT_FIRST | GF_PRINTARG_OPT_DESC)) {
    1954       19809 :                         char *sep = strchr(line, ' ');
    1955             : 
    1956       19809 :                         if (sep) sep[0] = 0;
    1957             : 
    1958       19809 :                         if (!gen_doc && !(flags & GF_PRINTARG_OPT_DESC) )
    1959        8662 :                                 gf_sys_set_console_code(helpout, GF_CONSOLE_GREEN);
    1960             : 
    1961       19809 :                         if ((gen_doc==1) && !(flags & GF_PRINTARG_OPT_DESC) ) {
    1962             :                                 fprintf(helpout, "__%s__", line);
    1963        1532 :                                 line_pos += 4+ (u32) strlen(line);
    1964             :                         } else {
    1965             :                                 fprintf(helpout, "%s", line);
    1966       18277 :                                 line_pos += (u32) strlen(line);
    1967             :                         }
    1968             : 
    1969       19809 :                         if (!gen_doc && !(flags & GF_PRINTARG_OPT_DESC) )
    1970        8662 :                                 gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    1971             : 
    1972       19809 :                         if (flags & GF_PRINTARG_OPT_DESC) {
    1973             :                                 flags = 0;
    1974        8636 :                                 att_len = line_pos;
    1975             :                         }
    1976             : 
    1977             : 
    1978       19809 :                         if (sep) {
    1979       16792 :                                 sep[0] = ' ';
    1980             :                                 line = sep;
    1981             :                         } else {
    1982             :                                 line = NULL;
    1983             :                         }
    1984             :                 }
    1985       96680 :                 if (!line) break;
    1986       93663 :                 if (gen_doc==2) {
    1987             :                         line_before = line_after = GF_FALSE;
    1988             :                 }
    1989       84313 :                 if (line_before) {
    1990             :                         fprintf(helpout, "\n");
    1991        4268 :                         line_pos=0;
    1992             :                 }
    1993             : 
    1994       93663 :                 if (console_code != GF_CONSOLE_RESET) {
    1995        5272 :                         if (gen_doc==1) {
    1996         564 :                                 if (console_code & GF_CONSOLE_BOLD) {
    1997             :                                         fprintf(helpout, "__");
    1998          28 :                                         line_pos+=2;
    1999             :                                 }
    2000         536 :                                 else if (console_code & GF_CONSOLE_ITALIC) {
    2001             :                                         fprintf(helpout, "_");
    2002          38 :                                         line_pos++;
    2003             :                                 }
    2004        4708 :                         } else if (!gen_doc) {
    2005        4148 :                                 gf_sys_set_console_code(helpout, console_code);
    2006             :                         }
    2007             :                 }
    2008             : 
    2009       93663 :                 if (att_len) {
    2010       42724 :                         while (att_len < LINE_OFFSET_DESCR) {
    2011             :                                 fprintf(helpout, " ");
    2012       34088 :                                 att_len++;
    2013       34088 :                                 line_pos++;
    2014             :                         }
    2015             :                 }
    2016             : 
    2017             : 
    2018       93663 :                 if (header_string) {
    2019             :                         fprintf(helpout, "%s", header_string);
    2020         808 :                         line_pos += (u32) strlen(header_string);
    2021             :                 }
    2022             : 
    2023      115367 :                 while (line) {
    2024             :                         char *skip_url = NULL;
    2025             :                         char *link_start = NULL;
    2026             :                         u32 tid=0, i;
    2027             :                         char *next_token = NULL;
    2028      692202 :                         for (i=0; i<nb_tokens; i++) {
    2029      692202 :                                 char *tok = strstr(line, Tokens[i].tok);
    2030      692202 :                                 if (!tok) continue;
    2031       24196 :                                 if (next_token && ((next_token-line) < (tok-line)) ) continue;
    2032             :                                 //check we have an end of token, otherwise consider this regular text
    2033       23258 :                                 if ((i == TOK_LINKSTART) || (i == TOK_OPTLINK)) {
    2034        2243 :                                         char *end_tok = strstr(tok, "](");
    2035        2243 :                                         if (!end_tok) continue;
    2036             :                                 }
    2037             : 
    2038       22889 :                                 if (i == TOK_LINKSTART) {
    2039         995 :                                         if (tid == TOK_OPTLINK) continue;
    2040         116 :                                         if (gen_doc!=1) {
    2041             :                                                 char *link_end;
    2042          81 :                                                 skip_url = strstr(tok, "](");
    2043             :                                                 link_end = skip_url;
    2044          81 :                                                 if (skip_url) skip_url = strstr(skip_url, ")");
    2045          81 :                                                 if (skip_url) skip_url ++;
    2046             : 
    2047          81 :                                                 if (!skip_url) continue;
    2048          81 :                                                 link_start = tok+1;
    2049          81 :                                                 link_end[0] = 0;
    2050             :                                         } else {
    2051          35 :                                                 continue;
    2052             :                                         }
    2053             :                                 }
    2054             :                                 next_token=tok;
    2055             :                                 tid=i;
    2056             :                         }
    2057      115367 :                         if (next_token) {
    2058       21704 :                                 next_token[0]=0;
    2059             :                         }
    2060      115367 :                         if ((gen_doc==1) && has_token) {
    2061        2024 :                                 if (tid==TOK_CODE) {
    2062             :                                         fprintf(helpout, "`%s`", line);
    2063        1104 :                                         line_pos+=2;
    2064         920 :                                 } else if (tid==TOK_ITALIC) {
    2065             :                                         fprintf(helpout, "_%s_", line);
    2066         767 :                                         line_pos+=2;
    2067         153 :                                 } else if (tid==TOK_BOLD) {
    2068             :                                         fprintf(helpout, "__%s__", line);
    2069         153 :                                         line_pos+=4;
    2070             :                                 } else {
    2071             :                                         fprintf(helpout, "%s", line);
    2072             :                                 }
    2073      113343 :                         } else if (escape_xml) {
    2074             :                                 char *xml_line = line;
    2075        2125 :                                 while (xml_line) {
    2076        2125 :                                         char *xml_start = strchr(xml_line, '<');
    2077        2125 :                                         char *xml_end = strchr(xml_line, '>');
    2078             : 
    2079        2125 :                                         if (xml_end && (xml_start > xml_end)) xml_start = xml_end;
    2080        2120 :                                         else if (!xml_start && xml_end) xml_start = xml_end;
    2081        2114 :                                         else if (xml_start && xml_end) xml_end = NULL;
    2082             : 
    2083        2125 :                                         if (xml_start) {
    2084          21 :                                                 u8 c = xml_start[0];
    2085          21 :                                                 xml_start[0] = 0;
    2086             :                                                 fprintf(helpout, "%s", xml_line);
    2087          21 :                                                 fprintf(helpout, xml_end ? "&gt;" : "&lt;");
    2088          21 :                                                 xml_start[0] = c;
    2089          21 :                                                 xml_line = xml_start+1;
    2090             :                                         } else {
    2091             :                                                 fprintf(helpout, "%s", xml_line);
    2092             :                                                 break;
    2093             :                                         }
    2094             :                                 }
    2095      111239 :                         } else if (escape_pipe) {
    2096             :                                 char *src_line = line;
    2097         150 :                                 while (src_line) {
    2098         150 :                                         char *pipe_start = strchr(src_line, '|');
    2099         150 :                                         if (pipe_start && (pipe_start[1]==' '))
    2100             :                                                 pipe_start = NULL;
    2101             : 
    2102          44 :                                         if (pipe_start) {
    2103          44 :                                                 pipe_start[0] = 0;
    2104             :                                                 fprintf(helpout, "%s,", src_line);
    2105          44 :                                                 pipe_start[0] = '|';
    2106          44 :                                                 src_line = pipe_start+1;
    2107             :                                         } else {
    2108             :                                                 fprintf(helpout, "%s", src_line);
    2109             :                                                 break;
    2110             :                                         }
    2111             :                                 }
    2112             :                         } else {
    2113             :                                 fprintf(helpout, "%s", line);
    2114             :                         }
    2115      115367 :                         line_pos+=(u32) strlen(line);
    2116             : 
    2117      115367 :                         if (!next_token) break;
    2118       21704 :                         has_token = !has_token;
    2119             : 
    2120       21704 :                         if (!gen_doc) {
    2121       13272 :                                 if (has_token) {
    2122             :                                         u32 cmd;
    2123        6835 :                                         if (Tokens[tid].cmd_type & 0xFFFF) {
    2124             :                                                 cmd = Tokens[tid].cmd_type;
    2125             :                                         } else {
    2126        4834 :                                                 cmd = Tokens[tid].cmd_type | console_code;
    2127             :                                         }
    2128             : 
    2129        6835 :                                         if (console_code&GF_CONSOLE_ITALIC) {
    2130          50 :                                                 if (Tokens[tid].cmd_type & GF_CONSOLE_ITALIC) {
    2131          49 :                                                         cmd &= ~GF_CONSOLE_ITALIC;
    2132          49 :                                                         cmd |= GF_CONSOLE_BOLD;
    2133             :                                                 }
    2134             :                                         }
    2135        6785 :                                         else if (console_code&GF_CONSOLE_BOLD) {
    2136           8 :                                                 if (Tokens[tid].cmd_type & GF_CONSOLE_BOLD) {
    2137           0 :                                                         cmd &= ~GF_CONSOLE_BOLD;
    2138           0 :                                                         cmd |= GF_CONSOLE_ITALIC;
    2139             :                                                 }
    2140             :                                         }
    2141        6835 :                                         gf_sys_set_console_code(helpout, cmd);
    2142             :                                 } else {
    2143        6437 :                                         gf_sys_set_console_code(helpout, console_code);
    2144             :                                 }
    2145             :                         }
    2146       21704 :                         line = next_token + (u32) strlen(Tokens[tid].tok);
    2147             : 
    2148       21704 :                         if (skip_url) {
    2149          81 :                                 if (link_start)
    2150             :                                         fprintf(helpout, "%s", link_start);
    2151          81 :                                 if (!gen_doc)
    2152          52 :                                         gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    2153             :                                 has_token = GF_FALSE;
    2154             :                                 line = skip_url;
    2155             : 
    2156             :                         }
    2157             : 
    2158       21704 :                         if (has_token && tid==TOK_OPTLINK) {
    2159         879 :                                 char *link = strchr(line, '(');
    2160             :                                 assert(link);
    2161         879 :                                 link++;
    2162         879 :                                 char *end_link = strchr(line, ')');
    2163         879 :                                 if (end_link) end_link[0] = 0;
    2164         879 :                                 char *end_tok = strchr(line, ']');
    2165         879 :                                 if (end_tok) end_tok[0] = 0;
    2166             : 
    2167         879 :                                 if (gen_doc==1) {
    2168         269 :                                         if (!strncmp(link, "GPAC", 4)) {
    2169             :                                                 fprintf(helpout, "[-%s](gpac_general/#%s)", line, line);
    2170           7 :                                                 line_pos+=7 + 2*(u32)strlen(line) + (u32)strlen("gpac_general");
    2171         262 :                                         } else if (!strncmp(link, "LOG", 3)) {
    2172             :                                                 fprintf(helpout, "[-%s](core_logs/#%s)", line, line);
    2173           0 :                                                 line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("core_logs");
    2174         262 :                                         } else if (!strncmp(link, "CORE", 3)) {
    2175             :                                                 fprintf(helpout, "[-%s](core_options/#%s)", line, line);
    2176           9 :                                                 line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("core_options");
    2177           9 :                                                 line_pos+=7 + 2*(u32)strlen(line) + (u32)strlen("core_options");
    2178         253 :                                         } else if (!strncmp(link, "CFG", 3)) {
    2179             :                                                 fprintf(helpout, "[-%s](core_config/#%s)", line, line);
    2180           0 :                                                 line_pos+=7 + 2*(u32)strlen(line) + (u32)strlen("core_config");
    2181         253 :                                         } else if (!strncmp(link, "MP4B_GEN", 3)) {
    2182             :                                                 fprintf(helpout, "[-%s](mp4box-gen-opts/#%s)", line, line);
    2183           6 :                                                 line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("mp4box-gen-opts");
    2184         247 :                                         } else if (strlen(link)) {
    2185             :                                                 fprintf(helpout, "[-%s](%s/#%s)", line, link, line);
    2186           3 :                                                 line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen(link);
    2187         244 :                                         } else if (is_app_opts || !strcmp(line, "i") || !strcmp(line, "o") || !strcmp(line, "h")) {
    2188             :                                                 fprintf(helpout, "[-%s](#%s)", line, line);
    2189          58 :                                                 line_pos+=5 + 2* (u32)strlen(line) + (u32)strlen(link);
    2190             :                                         } else {
    2191             :                                                 //this is a filter opt, don't print '-'
    2192             :                                                 fprintf(helpout, "[%s](#%s)", line, line);
    2193         186 :                                                 line_pos+=4 + 2* (u32)strlen(line) + (u32)strlen(link);
    2194             :                                         }
    2195             :                                 } else {
    2196         610 :                                         if (gen_doc==2)
    2197             :                                                 fprintf(helpout, ".I ");
    2198             : 
    2199         610 :                                         if (!strncmp(link, "GPAC", 4)
    2200         598 :                                                 || !strncmp(link, "LOG", 3)
    2201         598 :                                                 || !strncmp(link, "CORE", 3)
    2202         580 :                                                 || strlen(link)
    2203         551 :                                                 || !strcmp(line, "i") || !strcmp(line, "o") || !strcmp(line, "h")
    2204             :                                         ) {
    2205             :                                                 fprintf(helpout, "-%s", line);
    2206          74 :                                                 line_pos+=1+ (u32)strlen(line);
    2207             :                                         } else {
    2208             :                                                 fprintf(helpout, "%s", line);
    2209         536 :                                                 line_pos+= (u32)strlen(line);
    2210             :                                         }
    2211         610 :                                         if (!gen_doc)
    2212         342 :                                                 gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    2213             :                                 }
    2214         879 :                                 if (!end_link) break;
    2215         879 :                                 line = end_link+1;
    2216             :                                 has_token = GF_FALSE;
    2217             :                         }
    2218             :                 }
    2219             : 
    2220       93663 :                 if (has_token && !gen_doc)
    2221           4 :                         gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    2222             : 
    2223       93663 :                 if (footer_string) {
    2224             :                         fprintf(helpout, "%s", footer_string);
    2225         616 :                         line_pos += (u32) strlen(footer_string);
    2226             :                 }
    2227       93663 :                 if (console_code != GF_CONSOLE_RESET) {
    2228        5272 :                         if (gen_doc==1) {
    2229         564 :                                 if (console_code & GF_CONSOLE_BOLD) {
    2230             :                                         fprintf(helpout, "__");
    2231          28 :                                         line_pos+=2;
    2232         536 :                                 } else if (console_code & GF_CONSOLE_ITALIC) {
    2233             :                                         fprintf(helpout, "_");
    2234          38 :                                         line_pos++;
    2235             :                                 }
    2236        4708 :                         } else if (!gen_doc) {
    2237        4148 :                                 gf_sys_set_console_code(helpout, GF_CONSOLE_RESET);
    2238             :                         }
    2239             :                 }
    2240             : 
    2241       93663 :                 if (line_after) {
    2242        4214 :                         if (gen_doc==1) fprintf(helpout, "  ");
    2243        4214 :                         fprintf(helpout, (flags & GF_PRINTARG_NL_TO_BR) ? "<br/>" : "\n");
    2244        4214 :                         line_pos=0;
    2245             :                 }
    2246             : 
    2247       93663 :                 if (!next_line) break;
    2248       51218 :                 next_line[0]=0;
    2249       51218 :                 if (gen_doc==1) fprintf(helpout, "  ");
    2250       51218 :                 line = next_line+1;
    2251       51218 :                 if (gen_doc==2) {
    2252        6638 :                         if (line[0] != '.')
    2253             :                                 fprintf(helpout, "\n.br\n");
    2254             :                         else
    2255             :                                 fprintf(helpout, "\n");
    2256             :                 } else
    2257       44580 :                         fprintf(helpout, (line[0] && (flags & GF_PRINTARG_NL_TO_BR)) ? "<br/>" : "\n");
    2258       51218 :                 line_pos=0;
    2259             :         }
    2260       82592 : }
    2261             : 
    2262             : 
    2263             : GF_EXPORT
    2264       20744 : Bool gf_sys_word_match(const char *orig, const char *dst)
    2265             : {
    2266             :         s32 dist = 0;
    2267             :         u32 match = 0;
    2268             :         u32 i;
    2269       20744 :         u32 olen = (u32) strlen(orig);
    2270       20744 :         u32 dlen = (u32) strlen(dst);
    2271             :         u32 *run;
    2272             : 
    2273       20744 :         if ((olen>=3) && (olen<dlen) && !strncmp(orig, dst, olen))
    2274             :                 return GF_TRUE;
    2275       20743 :         if ((dlen>=3) && (dlen<olen) && !strncmp(orig, dst, dlen))
    2276             :                 return GF_TRUE;
    2277             : 
    2278       20742 :         if (olen*2 < dlen) {
    2279        4389 :                 char *s1 = strchr(orig, ':');
    2280        4389 :                 char *s2 = strchr(dst, ':');
    2281        4389 :                 if (s1 && !s2) return GF_FALSE;
    2282        4389 :                 if (!s1 && s2) return GF_FALSE;
    2283             : 
    2284        1625 :                 if (strstr(dst, orig))
    2285             :                         return GF_TRUE;
    2286        1624 :                 return GF_FALSE;
    2287             :         }
    2288       16353 :         run = gf_malloc(sizeof(u32) * olen);
    2289             :         memset(run, 0, sizeof(u32) * olen);
    2290             : 
    2291      148913 :         for (i=0; i<dlen; i++) {
    2292             :                 u32 dist_char;
    2293             :                 u32 offset=0;
    2294             :                 char *pos;
    2295             : 
    2296      154576 : retry_char:
    2297      154576 :                 pos = strchr(orig+offset, dst[i]);
    2298      154576 :                 if (!pos) continue;
    2299       52310 :                 dist_char = (u32) (pos - orig);
    2300       52310 :                 if (!run[dist_char]) {
    2301       30294 :                         run[dist_char] = i+1;
    2302       30294 :                         match++;
    2303       22016 :                 } else if (run[dist_char] > i) {
    2304           0 :                         run[dist_char] = i+1;
    2305           0 :                         match++;
    2306             :                 } else {
    2307             :                         //this can be a repeated character
    2308       22016 :                         offset++;
    2309       22016 :                         goto retry_char;
    2310             : 
    2311             :                 }
    2312             :         }
    2313       16353 :         if (match*2<olen) {
    2314       12956 :                 gf_free(run);
    2315       12956 :                 return GF_FALSE;
    2316             :         }
    2317             :         //if 4/5 of characters are matched, suggest it
    2318        3397 :         if (match * 5 >= 4 * dlen ) {
    2319          33 :                 gf_free(run);
    2320          33 :                 return GF_TRUE;
    2321             :         }
    2322             : /*      if ((olen<=4) && (match>=3) && (dlen*2<olen*3) ) {
    2323             :                 gf_free(run);
    2324             :                 return GF_TRUE;
    2325             :         }
    2326             : */
    2327       21852 :         for (i=0; i<olen; i++) {
    2328       21852 :                 if (!i) {
    2329        3364 :                         if (run[0]==1)
    2330         321 :                                 dist++;
    2331       18488 :                 } else if (run[i-1] + 1 == run[i]) {
    2332        2585 :                         dist++;
    2333             :                 }
    2334             :         }
    2335        3364 :         gf_free(run);
    2336             :         //if half the characters are in order, consider a match
    2337             :         //if arg is small only check dst
    2338        3364 :         if ((olen<=4) && (dist >= 2))
    2339             :                 return GF_TRUE;
    2340        3340 :         if ((dist*2 >= (s32) olen) && (dist*2 >= (s32) dlen))
    2341             :                 return GF_TRUE;
    2342        3336 :         return GF_FALSE;
    2343             : }
    2344             : 
    2345             : #endif

Generated by: LCOV version 1.13