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 ? ">" : "<");
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
|