/src/gpac/src/utils/os_config_init.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * GPAC - Multimedia Framework C SDK |
3 | | * |
4 | | * Authors: Jean Le Feuvre |
5 | | * Copyright (c) Telecom ParisTech 2000-2023 |
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 | | #include <gpac/config_file.h> |
27 | | |
28 | | |
29 | | #if defined(WIN32) || defined(_WIN32_WCE) |
30 | | #include <windows.h> /*for GetModuleFileName*/ |
31 | | |
32 | | #ifndef _WIN32_WCE |
33 | | #include <direct.h> /*for _mkdir*/ |
34 | | #include <gpac/utf.h> |
35 | | #include <shlobj.h> /*for getting user-dir*/ |
36 | | |
37 | | #ifndef SHGFP_TYPE_CURRENT |
38 | | #define SHGFP_TYPE_CURRENT 0 /*needed for MinGW*/ |
39 | | #endif |
40 | | |
41 | | #endif |
42 | | |
43 | | #define CFG_FILE_NAME "GPAC.cfg" |
44 | | #define TEST_MODULE "gm_" |
45 | | |
46 | | #elif (defined(__DARWIN__) || defined(__APPLE__) ) |
47 | | #include <mach-o/dyld.h> /*for _NSGetExecutablePath */ |
48 | | |
49 | | #ifdef GPAC_CONFIG_IOS |
50 | | #define TEST_MODULE "gpac4ios" |
51 | | #else |
52 | | #define TEST_MODULE "gm_" |
53 | | #endif |
54 | | #define CFG_FILE_NAME "GPAC.cfg" |
55 | | |
56 | | #else |
57 | | #ifdef GPAC_CONFIG_LINUX |
58 | | #include <unistd.h> |
59 | | #endif |
60 | | |
61 | 0 | #define CFG_FILE_NAME "GPAC.cfg" |
62 | | |
63 | | #if defined(GPAC_CONFIG_WIN32) |
64 | | #define TEST_MODULE "gm_" |
65 | | #else |
66 | 0 | #define TEST_MODULE "gm_" |
67 | | #endif |
68 | | |
69 | | #endif |
70 | | |
71 | | #if !defined(GPAC_STATIC_MODULES) && !defined(GPAC_MP4BOX_MINI) |
72 | | |
73 | | static Bool mod_enum(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) |
74 | | { |
75 | | if (!strncmp(item_name, "gm_", 3) || !strncmp(item_name, "gf_", 3)) { |
76 | | *(Bool*)cbck = GF_TRUE; |
77 | | return GF_TRUE; |
78 | | } |
79 | | return GF_FALSE; |
80 | | } |
81 | | #endif |
82 | | |
83 | | static Bool check_file_exists(char *name, char *path, char *outPath) |
84 | 0 | { |
85 | 0 | char szPath[GF_MAX_PATH]; |
86 | 0 | FILE *f; |
87 | 0 | int concatres; |
88 | |
|
89 | 0 | if (! gf_dir_exists(path)) return 0; |
90 | | |
91 | 0 | if (!strcmp(name, TEST_MODULE)) { |
92 | 0 | Bool res = GF_FALSE; |
93 | 0 | #if defined(GPAC_STATIC_MODULES) || defined(GPAC_MP4BOX_MINI) |
94 | 0 | res = GF_TRUE; |
95 | | #else |
96 | | gf_enum_directory(path, GF_FALSE, mod_enum, &res, NULL); |
97 | | #endif |
98 | 0 | if (!res) return GF_FALSE; |
99 | 0 | if (outPath != path) strcpy(outPath, path); |
100 | 0 | return 1; |
101 | 0 | } |
102 | | |
103 | 0 | concatres = snprintf(szPath, GF_MAX_PATH, "%s%c%s", path, GF_PATH_SEPARATOR, name); |
104 | 0 | if (concatres<0) { |
105 | 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)); |
106 | 0 | } |
107 | | |
108 | | //do not use gf_fopen here, we don't want to throw en error if failure |
109 | 0 | f = fopen(szPath, "rb"); |
110 | 0 | if (!f) return GF_FALSE; |
111 | 0 | fclose(f); |
112 | 0 | if (outPath != path) strcpy(outPath, path); |
113 | 0 | return GF_TRUE; |
114 | 0 | } |
115 | | |
116 | | enum |
117 | | { |
118 | | GF_PATH_APP, |
119 | | GF_PATH_CFG, |
120 | | //were we store gui/%, shaders/*, scripts/* |
121 | | GF_PATH_SHARE, |
122 | | GF_PATH_MODULES, |
123 | | GF_PATH_LIB |
124 | | }; |
125 | | |
126 | | #if defined(WIN32) || defined(_WIN32_WCE) |
127 | | static Bool get_default_install_path(char *file_path, u32 path_type) |
128 | | { |
129 | | FILE *f; |
130 | | char szPath[GF_MAX_PATH]; |
131 | | |
132 | | #ifdef _WIN32_WCE |
133 | | TCHAR w_szPath[GF_MAX_PATH]; |
134 | | GetModuleFileName(NULL, w_szPath, GF_MAX_PATH); |
135 | | CE_WideToChar((u16 *) w_szPath, file_path); |
136 | | #else |
137 | | wchar_t wtmp_file_path[GF_MAX_PATH]; |
138 | | char* tmp_file_path; |
139 | | |
140 | | GetModuleFileNameA(NULL, file_path, GF_MAX_PATH); |
141 | | #endif |
142 | | |
143 | | /*remove exe name*/ |
144 | | if (strstr(file_path, ".exe")) { |
145 | | char *sep = strrchr(file_path, '\\'); |
146 | | if (sep) sep[0] = 0; |
147 | | } |
148 | | |
149 | | strcpy(szPath, file_path); |
150 | | strlwr(szPath); |
151 | | |
152 | | /*if this is run from a browser, we do not get our app path - fortunately on Windows, we always use 'GPAC' in the |
153 | | installation path*/ |
154 | | if (!strstr(file_path, "gpac") && !strstr(file_path, "GPAC") ) { |
155 | | HKEY hKey = NULL; |
156 | | DWORD dwSize = GF_MAX_PATH; |
157 | | file_path[0] = 0; |
158 | | |
159 | | /*locate the key in current user, then in local machine*/ |
160 | | #ifdef _WIN32_WCE |
161 | | DWORD dwType = REG_SZ; |
162 | | u16 w_path[1024]; |
163 | | RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Software\\GPAC"), 0, KEY_READ, &hKey); |
164 | | #ifdef _DEBUG |
165 | | if (RegQueryValueEx(hKey, TEXT("DebugDir"), 0, &dwType, (LPBYTE) w_path, &dwSize) != ERROR_SUCCESS) |
166 | | #endif |
167 | | RegQueryValueEx(hKey, TEXT("InstallDir"), 0, &dwType, (LPBYTE) w_path, &dwSize); |
168 | | CE_WideToChar(w_path, (char *)file_path); |
169 | | RegCloseKey(hKey); |
170 | | #else |
171 | | if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\GPAC", 0, KEY_READ, &hKey) != ERROR_SUCCESS) |
172 | | RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\GPAC", 0, KEY_READ, &hKey); |
173 | | |
174 | | dwSize = GF_MAX_PATH; |
175 | | |
176 | | #ifdef _DEBUG |
177 | | if (RegQueryValueEx(hKey, "DebugDir", NULL, NULL,(unsigned char*) file_path, &dwSize) != ERROR_SUCCESS) |
178 | | #endif |
179 | | RegQueryValueEx(hKey, "InstallDir", NULL, NULL,(unsigned char*) file_path, &dwSize); |
180 | | |
181 | | RegCloseKey(hKey); |
182 | | #endif |
183 | | } |
184 | | //empty path, try DLL |
185 | | if (!file_path[0] && (path_type != GF_PATH_LIB)) { |
186 | | get_default_install_path(file_path, GF_PATH_LIB); |
187 | | } |
188 | | |
189 | | if (path_type==GF_PATH_APP) return GF_TRUE; |
190 | | |
191 | | if (path_type==GF_PATH_SHARE) { |
192 | | char *sep; |
193 | | strcat(file_path, "\\share"); |
194 | | if (check_file_exists("gui\\gui.bt", file_path, file_path)) return GF_TRUE; |
195 | | sep = strstr(file_path, "\\bin\\"); |
196 | | if (sep) { |
197 | | sep[0] = 0; |
198 | | strcat(file_path, "\\share"); |
199 | | if (check_file_exists("gui\\gui.bt", file_path, file_path)) return GF_TRUE; |
200 | | } |
201 | | return GF_FALSE; |
202 | | } |
203 | | /*modules are stored in the GPAC directory (should be changed to GPAC/modules)*/ |
204 | | if (path_type==GF_PATH_MODULES) return GF_TRUE; |
205 | | |
206 | | if (path_type == GF_PATH_LIB) { |
207 | | HMODULE hm=NULL; |
208 | | if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, |
209 | | (LPCSTR)&get_default_install_path, &hm) == 0) { |
210 | | return 0; |
211 | | } |
212 | | if (GetModuleFileName(hm, file_path, GF_MAX_PATH) == 0) { |
213 | | return 0; |
214 | | } |
215 | | char *sep = strrchr(file_path, '\\'); |
216 | | if (!sep) sep = strrchr(file_path, '/'); |
217 | | if (sep) sep[0] = 0; |
218 | | return 1; |
219 | | } |
220 | | |
221 | | /*we are looking for the config file path - make sure it is writable*/ |
222 | | assert(path_type == GF_PATH_CFG); |
223 | | |
224 | | strcpy(szPath, file_path); |
225 | | strcat(szPath, "\\gpaccfgtest.txt"); |
226 | | //do not use gf_fopen here, we don't want to through any error if failure |
227 | | f = fopen(szPath, "wb"); |
228 | | if (f != NULL) { |
229 | | fclose(f); |
230 | | gf_file_delete(szPath); |
231 | | return GF_TRUE; |
232 | | } |
233 | | #ifdef _WIN32_WCE |
234 | | return 0; |
235 | | #else |
236 | | /*no write access, get user home directory*/ |
237 | | SHGetSpecialFolderPathW(NULL, wtmp_file_path, CSIDL_APPDATA, 1); |
238 | | tmp_file_path = gf_wcs_to_utf8(wtmp_file_path); |
239 | | strncpy(file_path, tmp_file_path, GF_MAX_PATH); |
240 | | file_path[GF_MAX_PATH-1] = 0; |
241 | | gf_free(tmp_file_path); |
242 | | |
243 | | if (file_path[strlen(file_path)-1] != '\\') strcat(file_path, "\\"); |
244 | | strcat(file_path, "GPAC"); |
245 | | /*create GPAC dir*/ |
246 | | gf_mkdir(file_path); |
247 | | strcpy(szPath, file_path); |
248 | | strcat(szPath, "\\gpaccfgtest.txt"); |
249 | | f = gf_fopen(szPath, "wb"); |
250 | | /*COMPLETE FAILURE*/ |
251 | | if (!f) return GF_FALSE; |
252 | | |
253 | | gf_fclose(f); |
254 | | gf_file_delete(szPath); |
255 | | return GF_TRUE; |
256 | | #endif |
257 | | } |
258 | | |
259 | | #elif defined(GPAC_CONFIG_ANDROID) |
260 | | static char android_app_data[512]; |
261 | | static char android_external_storage[512]; |
262 | | |
263 | | /* |
264 | | Called by GPAC JNI wrappers. If not set, default to app_data=/data/data/io.gpac.gpac and ext_storage=/sdcard |
265 | | */ |
266 | | GF_EXPORT |
267 | | void gf_sys_set_android_paths(const char *app_data, const char *ext_storage) |
268 | | { |
269 | | if (app_data && (strlen(app_data)<512)) { |
270 | | strcpy(android_app_data, app_data); |
271 | | } |
272 | | if (ext_storage && (strlen(ext_storage)<512)) { |
273 | | strcpy(android_external_storage, ext_storage); |
274 | | } |
275 | | } |
276 | | |
277 | | |
278 | | static Bool get_default_install_path(char *file_path, u32 path_type) |
279 | | { |
280 | | if (!file_path) return 0; |
281 | | |
282 | | if (path_type==GF_PATH_APP) { |
283 | | strcpy(file_path, android_app_data[0] ? android_app_data : "/data/data/io.gpac.gpac"); |
284 | | return 1; |
285 | | } else if (path_type==GF_PATH_CFG) { |
286 | | const char *res = android_external_storage[0] ? android_external_storage : getenv("EXTERNAL_STORAGE"); |
287 | | if (!res) res = "/sdcard"; |
288 | | strcpy(file_path, res); |
289 | | strcat(file_path, "/GPAC"); |
290 | | //GPAC folder exists in external storage, use profile from this location |
291 | | if (gf_dir_exists(file_path)) { |
292 | | return 1; |
293 | | } |
294 | | //otherwise use profile in app data store |
295 | | strcpy(file_path, android_app_data[0] ? android_app_data : "/data/data/io.gpac.gpac"); |
296 | | strcat(file_path, "/GPAC"); |
297 | | return 1; |
298 | | } else if (path_type==GF_PATH_SHARE) { |
299 | | if (!get_default_install_path(file_path, GF_PATH_APP)) |
300 | | return 0; |
301 | | strcat(file_path, "/share"); |
302 | | return 1; |
303 | | } else if (path_type==GF_PATH_MODULES) { |
304 | | if (!get_default_install_path(file_path, GF_PATH_APP)) |
305 | | return 0; |
306 | | strcat(file_path, "/lib"); |
307 | | return 1; |
308 | | } |
309 | | return 0; |
310 | | } |
311 | | |
312 | | |
313 | | #elif defined(__SYMBIAN__) |
314 | | |
315 | | #if defined(__SERIES60_3X__) |
316 | | #define SYMBIAN_GPAC_CFG_DIR "\\private\\F01F9075" |
317 | | #define SYMBIAN_GPAC_GUI_DIR "\\private\\F01F9075\\gui" |
318 | | #define SYMBIAN_GPAC_MODULES_DIR "\\sys\\bin" |
319 | | #else |
320 | | #define SYMBIAN_GPAC_CFG_DIR "\\system\\apps\\GPAC" |
321 | | #define SYMBIAN_GPAC_GUI_DIR "\\system\\apps\\GPAC\\gui" |
322 | | #define SYMBIAN_GPAC_MODULES_DIR GPAC_CFG_DIR |
323 | | #endif |
324 | | |
325 | | static Bool get_default_install_path(char *file_path, u32 path_type) |
326 | | { |
327 | | if (path_type==GF_PATH_APP) strcpy(file_path, SYMBIAN_GPAC_MODULES_DIR); |
328 | | else if (path_type==GF_PATH_CFG) strcpy(file_path, SYMBIAN_GPAC_CFG_DIR); |
329 | | else if (path_type==GF_PATH_GUI) strcpy(file_path, SYMBIAN_GPAC_GUI_DIR); |
330 | | else if (path_type==GF_PATH_MODULES) strcpy(file_path, SYMBIAN_GPAC_MODULES_DIR); |
331 | | return 1; |
332 | | } |
333 | | |
334 | | /*Linux, OSX, iOS*/ |
335 | | #else |
336 | | |
337 | | //dlinfo |
338 | | #if defined(__DARWIN__) || defined(__APPLE__) |
339 | | #include <dlfcn.h> |
340 | | |
341 | | typedef Dl_info _Dl_info; |
342 | | #elif defined(GPAC_CONFIG_LINUX) |
343 | | |
344 | | |
345 | | typedef struct |
346 | | { |
347 | | const char *dli_fname; |
348 | | void *dli_fbase; |
349 | | const char *dli_sname; |
350 | | void *dli_saddr; |
351 | | } _Dl_info; |
352 | | int dladdr(void *, _Dl_info *); |
353 | | |
354 | | #endif |
355 | | |
356 | | static Bool get_default_install_path(char *file_path, u32 path_type) |
357 | 0 | { |
358 | 0 | char app_path[GF_MAX_PATH]; |
359 | 0 | char *sep; |
360 | 0 | #if (defined(__DARWIN__) || defined(__APPLE__) || defined(GPAC_CONFIG_LINUX)) |
361 | 0 | u32 size; |
362 | 0 | #endif |
363 | | |
364 | | /*on OSX, Linux & co, user home is where we store the cfg file*/ |
365 | 0 | if (path_type==GF_PATH_CFG) { |
366 | |
|
367 | | #ifdef GPAC_CONFIG_EMSCRIPTEN |
368 | | if (gf_dir_exists("/idbfs")) { |
369 | | if (!gf_dir_exists("/idbfs/.gpac")) { |
370 | | gf_mkdir("/idbfs/.gpac"); |
371 | | } |
372 | | strcpy(file_path, "/idbfs/.gpac"); |
373 | | return 1; |
374 | | } |
375 | | #endif |
376 | |
|
377 | 0 | char *user_home = getenv("HOME"); |
378 | | #ifdef GPAC_CONFIG_IOS |
379 | | char buf[PATH_MAX]; |
380 | | char *res; |
381 | | #endif |
382 | |
|
383 | 0 | if (!user_home) { |
384 | 0 | GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Couldn't find HOME directory\n")); |
385 | 0 | return 0; |
386 | 0 | } |
387 | | #ifdef GPAC_CONFIG_IOS |
388 | | res = realpath(user_home, buf); |
389 | | if (res) { |
390 | | strcpy(file_path, buf); |
391 | | strcat(file_path, "/Documents"); |
392 | | } else |
393 | | #endif |
394 | 0 | strcpy(file_path, user_home); |
395 | |
|
396 | 0 | if (file_path[strlen(file_path)-1] == '/') file_path[strlen(file_path)-1] = 0; |
397 | | |
398 | | //cleanup of old install in .gpacrc |
399 | 0 | if (check_file_exists(".gpacrc", file_path, file_path)) { |
400 | 0 | strcpy(app_path, file_path); |
401 | 0 | strcat(app_path, "/.gpacrc"); |
402 | 0 | gf_file_delete(app_path); |
403 | 0 | } |
404 | |
|
405 | 0 | strcat(file_path, "/.gpac"); |
406 | 0 | if (!gf_dir_exists(file_path)) { |
407 | 0 | gf_mkdir(file_path); |
408 | 0 | } |
409 | 0 | return 1; |
410 | 0 | } |
411 | | |
412 | 0 | if (path_type==GF_PATH_APP) { |
413 | | #if (defined(__DARWIN__) || defined(__APPLE__) ) |
414 | | size = GF_MAX_PATH-1; |
415 | | if (_NSGetExecutablePath(app_path, &size) ==0) { |
416 | | realpath(app_path, file_path); |
417 | | sep = strrchr(file_path, '/'); |
418 | | if (sep) sep[0] = 0; |
419 | | return 1; |
420 | | } |
421 | | |
422 | | #elif defined(GPAC_CONFIG_LINUX) |
423 | 0 | size = readlink("/proc/self/exe", file_path, GF_MAX_PATH-1); |
424 | 0 | if (size>0) { |
425 | 0 | file_path[size] = 0; |
426 | 0 | sep = strrchr(file_path, '/'); |
427 | 0 | if (sep) sep[0] = 0; |
428 | 0 | return 1; |
429 | 0 | } |
430 | | |
431 | | #elif defined(GPAC_CONFIG_WIN32) |
432 | | GetModuleFileNameA(NULL, file_path, GF_MAX_PATH); |
433 | | if (strstr(file_path, ".exe")) { |
434 | | sep = strrchr(file_path, '\\'); |
435 | | if (sep) sep[0] = 0; |
436 | | if ((file_path[1]==':') && (file_path[2]=='\\')) { |
437 | | strcpy(file_path, &file_path[2]); |
438 | | } |
439 | | sep = file_path; |
440 | | while ( sep[0] ) { |
441 | | if (sep[0]=='\\') sep[0]='/'; |
442 | | sep++; |
443 | | } |
444 | | //get rid of /mingw32 or /mingw64 |
445 | | sep = strstr(file_path, "/usr/"); |
446 | | if (sep) { |
447 | | strcpy(file_path, sep); |
448 | | } |
449 | | return 1; |
450 | | } |
451 | | #elif defined(GPAC_CONFIG_EMSCRIPTEN) |
452 | | return 0; |
453 | | #endif |
454 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Unknown arch, cannot find executable path\n")); |
455 | 0 | return 0; |
456 | 0 | } |
457 | | |
458 | 0 | if (path_type==GF_PATH_LIB) { |
459 | 0 | #if defined(__DARWIN__) || defined(__APPLE__) || defined(GPAC_CONFIG_LINUX) |
460 | 0 | _Dl_info dl_info; |
461 | 0 | dl_info.dli_fname = NULL; |
462 | 0 | if (dladdr((void *)get_default_install_path, &dl_info) |
463 | 0 | && dl_info.dli_fname |
464 | 0 | ) { |
465 | 0 | strcpy(file_path, dl_info.dli_fname); |
466 | 0 | sep = strrchr(file_path, '/'); |
467 | 0 | if (sep) sep[0] = 0; |
468 | 0 | return 1; |
469 | 0 | } |
470 | 0 | return 0; |
471 | 0 | #endif |
472 | | |
473 | | //for emscripten we use a static load for now |
474 | 0 | #if !defined(GPAC_CONFIG_EMSCRIPTEN) |
475 | 0 | GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("Unknown arch, cannot find library path\n")); |
476 | 0 | #endif |
477 | 0 | return 0; |
478 | 0 | } |
479 | | |
480 | | #if defined(GPAC_CONFIG_EMSCRIPTEN) |
481 | | strcpy(app_path, "/usr/"); |
482 | | #else |
483 | | /*locate the app*/ |
484 | 0 | if (!get_default_install_path(app_path, GF_PATH_APP)) { |
485 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Couldn't find GPAC binaries install directory\n")); |
486 | 0 | return 0; |
487 | 0 | } |
488 | 0 | #endif |
489 | | |
490 | | /*installed or symlink on system, user user home directory*/ |
491 | 0 | if (!strnicmp(app_path, "/usr/", 5) || !strnicmp(app_path, "/opt/", 5)) { |
492 | 0 | if (path_type==GF_PATH_SHARE) { |
493 | | /*look in possible install dirs ...*/ |
494 | 0 | if (check_file_exists("gui/gui.bt", "/usr/share/gpac", file_path)) return 1; |
495 | 0 | if (check_file_exists("gui/gui.bt", "/usr/local/share/gpac", file_path)) return 1; |
496 | 0 | if (check_file_exists("gui/gui.bt", "/opt/share/gpac", file_path)) return 1; |
497 | 0 | if (check_file_exists("gui/gui.bt", "/opt/local/share/gpac", file_path)) return 1; |
498 | 0 | } else if (path_type==GF_PATH_MODULES) { |
499 | | /*look in possible install dirs ...*/ |
500 | 0 | if (check_file_exists(TEST_MODULE, "/usr/lib64/gpac", file_path)) return 1; |
501 | 0 | if (check_file_exists(TEST_MODULE, "/usr/lib/gpac", file_path)) return 1; |
502 | 0 | if (check_file_exists(TEST_MODULE, "/usr/local/lib/gpac", file_path)) return 1; |
503 | 0 | if (check_file_exists(TEST_MODULE, "/opt/lib/gpac", file_path)) return 1; |
504 | 0 | if (check_file_exists(TEST_MODULE, "/opt/local/lib/gpac", file_path)) return 1; |
505 | 0 | if (check_file_exists(TEST_MODULE, "/usr/lib/x86_64-linux-gnu/gpac", file_path)) return 1; |
506 | 0 | if (check_file_exists(TEST_MODULE, "/usr/lib/i386-linux-gnu/gpac", file_path)) return 1; |
507 | 0 | } |
508 | 0 | } |
509 | | |
510 | 0 | if (path_type==GF_PATH_SHARE) { |
511 | 0 | Bool try_lib=GF_TRUE; |
512 | 0 | if (get_default_install_path(app_path, GF_PATH_CFG)) { |
513 | 0 | sep = strstr(app_path, ".gpac/"); |
514 | 0 | if (sep) sep[5]=0; |
515 | | /*GUI not found, look in ~/.gpac/share/gui/ */ |
516 | 0 | strcat(app_path, "/share"); |
517 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
518 | 0 | } |
519 | | |
520 | | /*GUI not found, look in gpac distribution if any */ |
521 | 0 | if (get_default_install_path(app_path, GF_PATH_APP)) { |
522 | 0 | GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] trying to locate share from application dir %s\n", app_path)); |
523 | 0 | strcat(app_path, "/"); |
524 | 0 | retry_lib: |
525 | 0 | sep = strstr(app_path, "/bin/"); |
526 | 0 | if (sep) { |
527 | 0 | sep[0] = 0; |
528 | 0 | strcat(app_path, "/share"); |
529 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
530 | 0 | strcat(app_path, "/gpac"); |
531 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
532 | 0 | } |
533 | 0 | sep = strstr(app_path, "/build/"); |
534 | 0 | if (sep) { |
535 | 0 | sep[0] = 0; |
536 | 0 | strcat(app_path, "/share"); |
537 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
538 | 0 | } |
539 | 0 | } |
540 | 0 | if (get_default_install_path(app_path, GF_PATH_LIB)) { |
541 | 0 | GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] trying to locate share from dynamic libgpac dir %s\n", app_path)); |
542 | 0 | sep = strstr(app_path, "/lib"); |
543 | 0 | if (sep) { |
544 | 0 | sep[0] = 0; |
545 | 0 | strcat(app_path, "/share"); |
546 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
547 | 0 | } |
548 | 0 | if (try_lib) { |
549 | 0 | try_lib = GF_FALSE; |
550 | 0 | goto retry_lib; |
551 | 0 | } |
552 | 0 | } |
553 | | /*GUI not found, look in .app for OSX case*/ |
554 | 0 | } |
555 | | |
556 | 0 | if (path_type==GF_PATH_MODULES) { |
557 | | /*look in gpac compilation tree (modules are output in the same folder as apps) and in distrib tree */ |
558 | 0 | if (get_default_install_path(app_path, GF_PATH_APP)) { |
559 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
560 | | |
561 | | /*on OSX check modules subdirectory */ |
562 | 0 | strcat(app_path, "/modules"); |
563 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
564 | | |
565 | 0 | get_default_install_path(app_path, GF_PATH_APP); |
566 | 0 | strcat(app_path, "/"); |
567 | 0 | sep = strstr(app_path, "/bin/"); |
568 | 0 | if (sep) { |
569 | 0 | sep[0] = 0; |
570 | 0 | strcat(app_path, "/lib/gpac"); |
571 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
572 | 0 | } |
573 | | |
574 | | /*modules not found*/ |
575 | 0 | GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("Couldn't find any modules in standard path (app path %s)\n", app_path)); |
576 | 0 | } |
577 | | |
578 | | /*look in lib install */ |
579 | 0 | if (get_default_install_path(app_path, GF_PATH_LIB)) { |
580 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
581 | 0 | strcat(app_path, "/gpac"); |
582 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
583 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Couldn't find any modules in lib path %s\n", app_path)); |
584 | 0 | } |
585 | | |
586 | | |
587 | | /*modules not found, look in ~/.gpac/modules/ */ |
588 | 0 | if (get_default_install_path(app_path, GF_PATH_CFG)) { |
589 | 0 | strcat(app_path, "/modules"); |
590 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
591 | 0 | } |
592 | | /*modules not found, failure*/ |
593 | | #ifndef GPAC_STATIC_MODULES |
594 | | GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Couldn't find any modules in HOME path (app path %s)\n", app_path)); |
595 | | #endif |
596 | 0 | return 0; |
597 | 0 | } |
598 | | |
599 | | /*OSX way vs iPhone*/ |
600 | 0 | sep = strstr(app_path, ".app/"); |
601 | 0 | if (sep) sep[4] = 0; |
602 | | |
603 | | /*we are looking for .app install path, or GUI */ |
604 | 0 | if (path_type==GF_PATH_SHARE) { |
605 | 0 | #ifndef GPAC_CONFIG_IOS |
606 | 0 | strcat(app_path, "/Contents/MacOS/share"); |
607 | 0 | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
608 | | #else /*iOS: for now, everything is set flat within the package*/ |
609 | | /*iOS app is distributed with embedded GUI*/ |
610 | | get_default_install_path(app_path, GF_PATH_APP); |
611 | | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
612 | | strcat(app_path, "/share"); |
613 | | if (check_file_exists("gui/gui.bt", app_path, file_path)) return 1; |
614 | | #endif |
615 | 0 | } |
616 | 0 | else { // (path_type==GF_PATH_MODULES) |
617 | 0 | strcat(app_path, "/Contents/MacOS/modules"); |
618 | 0 | if (check_file_exists(TEST_MODULE, app_path, file_path)) return 1; |
619 | 0 | } |
620 | | /*not found ...*/ |
621 | 0 | return 0; |
622 | 0 | } |
623 | | |
624 | | #endif |
625 | | |
626 | | //get real path where the .gpac dir has been created, and use this as the default path |
627 | | //for cache (tmp/ dir of ios app) and last working fir |
628 | | #ifdef GPAC_CONFIG_IOS |
629 | | static void gf_ios_refresh_cache_directory( GF_Config *cfg, const char *file_path) |
630 | | { |
631 | | char *cache_dir, *old_cache_dir; |
632 | | char buf[GF_MAX_PATH], *res, *sep; |
633 | | res = realpath(file_path, buf); |
634 | | if (!res) return; |
635 | | |
636 | | sep = strstr(res, ".gpac"); |
637 | | assert(sep); |
638 | | sep[0] = 0; |
639 | | gf_cfg_set_key(cfg, "core", "docs-dir", res); |
640 | | if (!gf_cfg_get_key(cfg, "core", "last-dir")) |
641 | | gf_cfg_set_key(cfg, "core", "last-dir", res); |
642 | | |
643 | | strcat(res, "cache/"); |
644 | | cache_dir = res; |
645 | | old_cache_dir = (char*) gf_opts_get_key("core", "cache"); |
646 | | |
647 | | if (!gf_dir_exists(cache_dir)) { |
648 | | if (old_cache_dir && strcmp(old_cache_dir, cache_dir)) { |
649 | | GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("Cache dir changed: old %d -> new %s\n\n", old_cache_dir, cache_dir )); |
650 | | } |
651 | | gf_mkdir(cache_dir); |
652 | | } |
653 | | gf_cfg_set_key(cfg, "core", "cache", cache_dir); |
654 | | } |
655 | | |
656 | | #endif |
657 | | |
658 | | const char * gf_get_default_cache_directory_ex(Bool do_create); |
659 | | |
660 | | GF_EXPORT |
661 | | void gf_get_default_font_dir(char szPath[GF_MAX_PATH]) |
662 | 0 | { |
663 | | #if defined(_WIN32_WCE) |
664 | | strcpy(szPath, "\\Windows"); |
665 | | |
666 | | #elif defined(WIN32) |
667 | | GetWindowsDirectory((char*)szPath, MAX_PATH); |
668 | | if (szPath[strlen((char*)szPath)-1] != '\\') strcat((char*)szPath, "\\"); |
669 | | strcat((char *)szPath, "Fonts"); |
670 | | |
671 | | #elif defined(__APPLE__) && defined(GPAC_CONFIG_IOS) |
672 | | strcpy(szPath, "/System/Library/Fonts/Cache,/System/Library/Fonts/AppFonts,/System/Library/Fonts/Core,/System/Library/Fonts/Extra"); |
673 | | #elif defined(__APPLE__) |
674 | | strcpy(szPath, "/System/Library/Fonts,/Library/Fonts"); |
675 | | |
676 | | #elif defined(GPAC_CONFIG_ANDROID) |
677 | | strcpy(szPath, "/system/fonts/"); |
678 | | #else |
679 | | //scan all /usr/share/fonts, not just /usr/share/fonts/truetype/ which does not exist in some distrros |
680 | 0 | strcpy(szPath, "/usr/share/fonts/"); |
681 | 0 | #endif |
682 | 0 | } |
683 | | |
684 | | |
685 | | static GF_Config *create_default_config(char *file_path, const char *profile) |
686 | 0 | { |
687 | 0 | Bool moddir_found; |
688 | 0 | GF_Config *cfg; |
689 | 0 | char szPath[GF_MAX_PATH]; |
690 | |
|
691 | 0 | if (file_path && ! get_default_install_path(file_path, GF_PATH_CFG)) { |
692 | 0 | profile = "0"; |
693 | 0 | } |
694 | | /*Create temp config file*/ |
695 | 0 | if (profile && (!strcmp(profile, "0") || !stricmp(profile, "n"))) { |
696 | 0 | cfg = gf_cfg_new(NULL, NULL); |
697 | 0 | if (!stricmp(profile, "n")) { |
698 | 0 | gf_cfg_discard_changes(cfg); |
699 | 0 | return cfg; |
700 | 0 | } |
701 | 0 | } else { |
702 | 0 | FILE *f; |
703 | | |
704 | | /*create config file from disk*/ |
705 | 0 | if (profile) { |
706 | 0 | sprintf(szPath, "%s%cprofiles%c%s%c%s", file_path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR, profile, GF_PATH_SEPARATOR, CFG_FILE_NAME); |
707 | 0 | } else { |
708 | 0 | sprintf(szPath, "%s%c%s", file_path, GF_PATH_SEPARATOR, CFG_FILE_NAME); |
709 | 0 | } |
710 | 0 | GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("Trying to create config file: %s\n", szPath )); |
711 | |
|
712 | 0 | f = gf_fopen(szPath, "wt"); |
713 | 0 | if (!f) return NULL; |
714 | 0 | gf_fclose(f); |
715 | |
|
716 | 0 | cfg = gf_cfg_new(NULL, szPath); |
717 | 0 | } |
718 | | |
719 | 0 | if (!cfg) return NULL; |
720 | | |
721 | | |
722 | 0 | #ifndef GPAC_CONFIG_IOS |
723 | 0 | moddir_found = get_default_install_path(szPath, GF_PATH_MODULES); |
724 | | #else |
725 | | moddir_found = get_default_install_path(szPath, GF_PATH_APP); |
726 | | #endif |
727 | |
|
728 | | #if defined(GPAC_CONFIG_IOS) |
729 | | gf_cfg_set_key(cfg, "core", "devclass", "ios"); |
730 | | #elif defined(GPAC_CONFIG_ANDROID) |
731 | | gf_cfg_set_key(cfg, "core", "devclass", "android"); |
732 | | #elif defined(GPAC_CONFIG_EMSCRIPTEN) |
733 | | gf_cfg_set_key(cfg, "core", "devclass", "wasm"); |
734 | | #else |
735 | 0 | gf_cfg_set_key(cfg, "core", "devclass", "desktop"); |
736 | 0 | #endif |
737 | | |
738 | |
|
739 | 0 | if (!moddir_found) { |
740 | 0 | #if !defined(GPAC_CONFIG_EMSCRIPTEN) |
741 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Core] default modules directory not found\n")); |
742 | 0 | #endif |
743 | 0 | } else { |
744 | 0 | gf_cfg_set_key(cfg, "core", "module-dir", szPath); |
745 | 0 | } |
746 | | |
747 | |
|
748 | | #if defined(GPAC_CONFIG_IOS) |
749 | | gf_ios_refresh_cache_directory(cfg, file_path); |
750 | | #elif defined(GPAC_CONFIG_ANDROID) |
751 | | if (get_default_install_path(szPath, GF_PATH_APP)) { |
752 | | strcat(szPath, "/cache"); |
753 | | gf_cfg_set_key(cfg, "core", "cache", szPath); |
754 | | strcat(szPath, "/.nomedia"); |
755 | | //create .nomedia in cache and in app dir |
756 | | if (!gf_file_exists(szPath)) { |
757 | | FILE *f = gf_fopen(szPath, "w"); |
758 | | if (f) gf_fclose(f); |
759 | | } |
760 | | get_default_install_path(szPath, GF_PATH_APP); |
761 | | strcat(szPath, "/.nomedia"); |
762 | | if (!gf_file_exists(szPath)) { |
763 | | FILE *f = gf_fopen(szPath, "w"); |
764 | | if (f) gf_fclose(f); |
765 | | } |
766 | | //add a tmp as well, tmpfile() does not work on android |
767 | | get_default_install_path(szPath, GF_PATH_APP); |
768 | | strcat(szPath, "/gpac_tmp"); |
769 | | gf_cfg_set_key(cfg, "core", "tmp", szPath); |
770 | | strcat(szPath, "/.nomedia"); |
771 | | if (!gf_file_exists(szPath)) { |
772 | | FILE *f = gf_fopen(szPath, "w"); |
773 | | if (f) gf_fclose(f); |
774 | | } |
775 | | } |
776 | | #else |
777 | | /*get default temporary directoy */ |
778 | 0 | gf_cfg_set_key(cfg, "core", "cache", gf_get_default_cache_directory_ex(GF_FALSE)); |
779 | 0 | #endif |
780 | | |
781 | | /*Setup font engine to FreeType by default, and locate TrueType font directory on the system*/ |
782 | 0 | gf_cfg_set_key(cfg, "core", "font-reader", "freetype"); |
783 | 0 | gf_cfg_set_key(cfg, "core", "rescan-fonts", "yes"); |
784 | | |
785 | |
|
786 | 0 | gf_get_default_font_dir(szPath); |
787 | 0 | gf_cfg_set_key(cfg, "core", "font-dirs", szPath); |
788 | |
|
789 | 0 | gf_cfg_set_key(cfg, "core", "cache-size", "100M"); |
790 | |
|
791 | | #if defined(_WIN32_WCE) |
792 | | gf_cfg_set_key(cfg, "core", "video-output", "gapi"); |
793 | | #elif defined(WIN32) |
794 | | gf_cfg_set_key(cfg, "core", "video-output", "directx"); |
795 | | #elif defined(__DARWIN__) || defined(__APPLE__) |
796 | | gf_cfg_set_key(cfg, "core", "video-output", "sdl"); |
797 | | #elif defined(GPAC_CONFIG_ANDROID) |
798 | | gf_cfg_set_key(cfg, "core", "video-output", "android"); |
799 | | gf_cfg_set_key(cfg, "core", "audio-output", "android"); |
800 | | #else |
801 | | //use SDL by default, will fallback to X11 if not found (our X11 wrapper is old and does not have all features of the SDL one) |
802 | 0 | gf_cfg_set_key(cfg, "core", "video-output", "sdl"); |
803 | 0 | gf_cfg_set_key(cfg, "core", "audio-output", "sdla"); |
804 | 0 | #endif |
805 | | |
806 | |
|
807 | 0 | #if !defined(GPAC_CONFIG_IOS) && !defined(GPAC_CONFIG_ANDROID) |
808 | 0 | gf_cfg_set_key(cfg, "core", "switch-vres", "no"); |
809 | 0 | gf_cfg_set_key(cfg, "core", "hwvmem", "auto"); |
810 | 0 | #endif |
811 | |
|
812 | | #ifdef GPAC_CONFIG_ANDROID |
813 | | const char *opt = android_external_storage[0] ? android_external_storage : getenv("EXTERNAL_STORAGE"); |
814 | | if (!opt) opt = "/sdcard"; |
815 | | gf_cfg_set_key(cfg, "core", "docs-dir", opt); |
816 | | gf_cfg_set_key(cfg, "core", "last-dir", opt); |
817 | | #endif |
818 | | |
819 | | /*locate GUI*/ |
820 | 0 | if ( get_default_install_path(szPath, GF_PATH_SHARE) ) { |
821 | 0 | char gui_path[GF_MAX_PATH+100]; |
822 | 0 | sprintf(gui_path, "%s%cgui%cgui.bt", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); |
823 | 0 | if (gf_file_exists(gui_path)) { |
824 | 0 | gf_cfg_set_key(cfg, "core", "startup-file", gui_path); |
825 | 0 | } |
826 | | |
827 | | /*shaders are at the same location*/ |
828 | 0 | sprintf(gui_path, "%s%cshaders%cvertex.glsl", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); |
829 | 0 | gf_cfg_set_key(cfg, "filter@compositor", "vertshader", gui_path); |
830 | 0 | sprintf(gui_path, "%s%cshaders%cfragment.glsl", szPath, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); |
831 | 0 | gf_cfg_set_key(cfg, "filter@compositor", "fragshader", gui_path); |
832 | | |
833 | | //aliases and other defaults |
834 | 0 | sprintf(gui_path, "%s%cdefault.cfg", szPath, GF_PATH_SEPARATOR); |
835 | 0 | if (gf_file_exists(gui_path)) { |
836 | 0 | GF_Config *aliases = gf_cfg_new(NULL, gui_path); |
837 | 0 | if (aliases) { |
838 | 0 | u32 i, count = gf_cfg_get_section_count(aliases); |
839 | 0 | for (i=0; i<count; i++) { |
840 | 0 | u32 j, count2; |
841 | 0 | const char *sec_name = gf_cfg_get_section_name(aliases, i); |
842 | 0 | if (!sec_name) continue; |
843 | 0 | count2 = gf_cfg_get_key_count(aliases, sec_name); |
844 | 0 | for (j=0; j<count2; j++) { |
845 | 0 | const char *name = gf_cfg_get_key_name(aliases, sec_name, j); |
846 | 0 | const char *val = gf_cfg_get_key(aliases, sec_name, name); |
847 | 0 | gf_cfg_set_key(cfg, sec_name, name, val); |
848 | 0 | } |
849 | 0 | } |
850 | 0 | } |
851 | 0 | gf_cfg_del(aliases); |
852 | 0 | } |
853 | 0 | } |
854 | |
|
855 | 0 | if (profile && !strcmp(profile, "0")) { |
856 | 0 | GF_Err gf_cfg_set_filename(GF_Config *iniFile, const char * fileName); |
857 | | // sprintf(szPath, "%s%c%s", gf_get_default_cache_directory(), GF_PATH_SEPARATOR, CFG_FILE_NAME); |
858 | 0 | gf_cfg_set_filename(cfg, CFG_FILE_NAME); |
859 | 0 | gf_cfg_discard_changes(cfg); |
860 | 0 | return cfg; |
861 | 0 | } |
862 | | /*store and reload*/ |
863 | 0 | strcpy(szPath, gf_cfg_get_filename(cfg)); |
864 | 0 | gf_cfg_del(cfg); |
865 | 0 | return gf_cfg_new(NULL, szPath); |
866 | 0 | } |
867 | | |
868 | | /*check if modules directory has changed in the config file |
869 | | */ |
870 | | static void check_modules_dir(GF_Config *cfg) |
871 | 0 | { |
872 | 0 | char path[GF_MAX_PATH]; |
873 | |
|
874 | | #ifdef GPAC_CONFIG_IOS |
875 | | const char *cfg_path; |
876 | | if ( get_default_install_path(path, GF_PATH_SHARE) ) { |
877 | | char *sep; |
878 | | char shader_path[GF_MAX_PATH]; |
879 | | strcat(path, "/gui/gui.bt"); |
880 | | gf_cfg_set_key(cfg, "core", "startup-file", path); |
881 | | //get rid of "/gui/gui.bt" |
882 | | sep = strrchr(path, '/'); |
883 | | sep[0] = 0; |
884 | | sep = strrchr(path, '/'); |
885 | | sep[0] = 0; |
886 | | |
887 | | sprintf(shader_path, "%s%cshaders%cvertex.glsl", path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); |
888 | | gf_cfg_set_key(cfg, "filter@compositor", "vertshader", shader_path); |
889 | | sprintf(shader_path, "%s%cshaders%cfragment.glsl", path, GF_PATH_SEPARATOR, GF_PATH_SEPARATOR); |
890 | | gf_cfg_set_key(cfg, "filter@compositor", "fragshader", shader_path); |
891 | | } |
892 | | cfg_path = gf_cfg_get_filename(cfg); |
893 | | gf_ios_refresh_cache_directory(cfg, cfg_path); |
894 | | |
895 | | #else |
896 | 0 | const char *opt; |
897 | |
|
898 | 0 | if ( get_default_install_path(path, GF_PATH_MODULES) ) { |
899 | 0 | opt = gf_cfg_get_key(cfg, "core", "module-dir"); |
900 | | //for OSX, we can have an install in /usr/... and an install in /Applications/GPAC.app - always change |
901 | | #if defined(__DARWIN__) || defined(__APPLE__) |
902 | | if (!opt || strcmp(opt, path)) |
903 | | gf_cfg_set_key(cfg, "core", "module-dir", path); |
904 | | #else |
905 | | |
906 | | //otherwise only check we didn't switch between a 64 bit version and a 32 bit version |
907 | 0 | if (!opt) { |
908 | 0 | gf_cfg_set_key(cfg, "core", "module-dir", path); |
909 | 0 | } else { |
910 | 0 | Bool erase_modules_dir = GF_FALSE; |
911 | 0 | const char *opt64 = gf_cfg_get_key(cfg, "core", "64bits"); |
912 | 0 | if (!opt64) { |
913 | | //first run or old versions, erase |
914 | 0 | erase_modules_dir = GF_TRUE; |
915 | 0 | } else if (!strcmp(opt64, "yes") ) { |
916 | | #ifndef GPAC_64_BITS |
917 | | erase_modules_dir = GF_TRUE; |
918 | | #endif |
919 | 0 | } else { |
920 | 0 | #ifdef GPAC_64_BITS |
921 | 0 | erase_modules_dir = GF_TRUE; |
922 | 0 | #endif |
923 | 0 | } |
924 | |
|
925 | 0 | #ifdef GPAC_64_BITS |
926 | 0 | opt64 = "yes"; |
927 | | #else |
928 | | opt64 = "no"; |
929 | | #endif |
930 | 0 | gf_cfg_set_key(cfg, "core", "64bits", opt64); |
931 | |
|
932 | 0 | if (erase_modules_dir) { |
933 | 0 | gf_cfg_set_key(cfg, "core", "module-dir", path); |
934 | 0 | } |
935 | 0 | } |
936 | 0 | #endif |
937 | 0 | } |
938 | | |
939 | | /*if startup file was disabled, do not attempt to correct it*/ |
940 | 0 | if (gf_cfg_get_key(cfg, "core", "startup-file")==NULL) return; |
941 | | |
942 | 0 | if ( get_default_install_path(path, GF_PATH_SHARE) ) { |
943 | 0 | opt = gf_cfg_get_key(cfg, "core", "startup-file"); |
944 | 0 | if (strstr(opt, "gui.bt") && strcmp(opt, path) && strstr(path, ".app") ) { |
945 | | #if defined(__DARWIN__) || defined(__APPLE__) |
946 | | strcat(path, "/gui/gui.bt"); |
947 | | gf_cfg_set_key(cfg, "core", "startup-file", path); |
948 | | #endif |
949 | 0 | } |
950 | 0 | } |
951 | |
|
952 | 0 | #endif |
953 | 0 | } |
954 | | |
955 | | #ifdef GPAC_CONFIG_ANDROID |
956 | | |
957 | | static Bool delete_tmp_files(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info) |
958 | | { |
959 | | if (gf_file_delete(item_path) != GF_OK) { |
960 | | GF_LOG(GF_LOG_ERROR, GF_LOG_CACHE, ("[CORE] Failed to cleanup temp file %s\n", item_path)); |
961 | | } |
962 | | return GF_FALSE; |
963 | | } |
964 | | #endif |
965 | | |
966 | | static void check_default_cred_file(GF_Config *cfg, char szPath[GF_MAX_PATH]) |
967 | 0 | { |
968 | 0 | #ifndef GPAC_CONFIG_EMSCRIPTEN |
969 | 0 | char key[16]; |
970 | 0 | u64 v1, v2; |
971 | 0 | const char *opt = gf_cfg_get_key(cfg, "core", "cred"); |
972 | 0 | if (opt) return; |
973 | | //when running as service, the config file path may be unknown |
974 | 0 | if (!szPath[0] || !gf_dir_exists(szPath)) |
975 | 0 | return; |
976 | 0 | strcat(szPath, "/creds.key"); |
977 | 0 | if (gf_file_exists(szPath)) return; |
978 | | |
979 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[core] Creating default credential key in %s, use -cred=PATH/TO_FILE to overwrite\n", szPath)); |
980 | |
|
981 | 0 | v1 = gf_rand(); v1<<=32; v1 |= gf_rand(); |
982 | 0 | v2 = gf_rand(); v2<<=32; v2 |= gf_rand(); |
983 | 0 | v1 |= gf_sys_clock_high_res(); |
984 | | #ifndef GPAC_64_BITS |
985 | | v2 |= (u64) (u32) cfg; |
986 | | v2 ^= (u64) (u32) szPath; |
987 | | #else |
988 | 0 | v2 |= (u64) cfg; |
989 | 0 | v2 ^= (u64) szPath; |
990 | 0 | #endif |
991 | 0 | * ( (u64*) &key[0] ) = v1; |
992 | 0 | * ( (u64*) &key[8] ) = v2; |
993 | 0 | FILE *crd = gf_fopen(szPath, "w"); |
994 | 0 | if (!crd) { |
995 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Failed to create credential key in %s, credentials will not be stored\n", szPath)); |
996 | 0 | return; |
997 | 0 | } |
998 | 0 | fwrite(key, 16, 1, crd); |
999 | 0 | fclose(crd); |
1000 | 0 | gf_cfg_set_key(cfg, "core", "cred", szPath); |
1001 | 0 | #endif //GPAC_CONFIF_EMSCRIPTEN |
1002 | 0 | } |
1003 | | |
1004 | | /*! |
1005 | | \brief configuration file initialization |
1006 | | * |
1007 | | * Constructs a configuration file from fileName. If fileName is NULL, the default GPAC configuration file is loaded with the |
1008 | | * proper module directory, font directory and other default options. If fileName is non-NULL no configuration file is found, |
1009 | | * a "light" default configuration file is created. |
1010 | | \param profile name or path to existing config file |
1011 | | \return the configuration file object, NULL if the file could not be created |
1012 | | */ |
1013 | | #include <gpac/network.h> |
1014 | | |
1015 | | static GF_Config *gf_cfg_init(const char *profile) |
1016 | 0 | { |
1017 | 0 | GF_Config *cfg=NULL; |
1018 | 0 | u32 prof_len=0; |
1019 | 0 | Bool force_new_cfg=GF_FALSE; |
1020 | 0 | Bool fast_profile=GF_FALSE; |
1021 | 0 | char szPath[GF_MAX_PATH]; |
1022 | 0 | char *prof_opt = NULL; |
1023 | |
|
1024 | 0 | if (profile) { |
1025 | 0 | prof_len = (u32) strlen(profile); |
1026 | 0 | prof_opt = gf_url_colon_suffix(profile, 0); |
1027 | 0 | if (prof_opt) { |
1028 | 0 | prof_len -= (u32) strlen(prof_opt); |
1029 | 0 | if (strstr(prof_opt, "reload")) force_new_cfg = GF_TRUE; |
1030 | 0 | prof_opt[0] = 0; |
1031 | 0 | } |
1032 | 0 | if (!stricmp(profile, "n")) { |
1033 | 0 | fast_profile = GF_TRUE; |
1034 | 0 | cfg = create_default_config(NULL, "n"); |
1035 | 0 | goto skip_cfg; |
1036 | 0 | } |
1037 | 0 | } |
1038 | 0 | if (profile && !prof_len) |
1039 | 0 | profile = NULL; |
1040 | |
|
1041 | 0 | if (profile && (strchr(profile, '/') || strchr(profile, '\\')) ) { |
1042 | 0 | if (!gf_file_exists(profile)) { |
1043 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Config file %s does not exist\n", profile)); |
1044 | 0 | goto exit; |
1045 | 0 | } |
1046 | 0 | cfg = gf_cfg_new(NULL, profile); |
1047 | 0 | if (!cfg) { |
1048 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Failed to load existing config file %s\n", profile)); |
1049 | 0 | goto exit; |
1050 | 0 | } |
1051 | 0 | if (force_new_cfg) { |
1052 | 0 | gf_cfg_del(cfg); |
1053 | 0 | cfg = create_default_config(NULL, profile); |
1054 | 0 | } |
1055 | 0 | check_modules_dir(cfg); |
1056 | 0 | goto exit; |
1057 | 0 | } |
1058 | | |
1059 | 0 | if (!get_default_install_path(szPath, GF_PATH_CFG)) { |
1060 | 0 | if (!profile || strcmp(profile, "0")) { |
1061 | 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")); |
1062 | 0 | } |
1063 | 0 | profile="0"; |
1064 | 0 | cfg = create_default_config(szPath, profile); |
1065 | 0 | goto skip_cfg; |
1066 | 0 | } |
1067 | | |
1068 | 0 | if (profile && !strcmp(profile, "0")) { |
1069 | 0 | cfg = create_default_config(NULL, "0"); |
1070 | 0 | goto skip_cfg; |
1071 | 0 | } |
1072 | | |
1073 | 0 | if (profile) { |
1074 | 0 | strcat(szPath, "/profiles/"); |
1075 | 0 | strcat(szPath, profile); |
1076 | 0 | } |
1077 | |
|
1078 | 0 | cfg = gf_cfg_new(szPath, CFG_FILE_NAME); |
1079 | | //config file not compatible with old arch, check it: |
1080 | 0 | if (cfg) { |
1081 | 0 | const char *key; |
1082 | 0 | u32 nb_old_sec = gf_cfg_get_key_count(cfg, "Compositor"); |
1083 | 0 | nb_old_sec += gf_cfg_get_key_count(cfg, "MimeTypes"); |
1084 | 0 | nb_old_sec += gf_cfg_get_key_count(cfg, "Video"); |
1085 | 0 | nb_old_sec += gf_cfg_get_key_count(cfg, "Audio"); |
1086 | 0 | nb_old_sec += gf_cfg_get_key_count(cfg, "Systems"); |
1087 | 0 | nb_old_sec += gf_cfg_get_key_count(cfg, "General"); |
1088 | 0 | if (! gf_cfg_get_key_count(cfg, "core")) |
1089 | 0 | nb_old_sec += 1; |
1090 | | |
1091 | | //check GUI is valid, if not recreate a config |
1092 | 0 | key = gf_cfg_get_key(cfg, "core", "startup-file"); |
1093 | 0 | if (key && !gf_file_exists(key)) |
1094 | 0 | force_new_cfg = GF_TRUE; |
1095 | | |
1096 | | //check if reset flag is set in existing config |
1097 | 0 | if (gf_cfg_get_key(cfg, "core", "reset")) |
1098 | 0 | force_new_cfg = GF_TRUE; |
1099 | |
|
1100 | 0 | if (nb_old_sec || force_new_cfg) { |
1101 | 0 | if (nb_old_sec && (!profile || strcmp(profile, "0"))) { |
1102 | 0 | GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[core] Incompatible config file %s found in %s - creating new file\n", CFG_FILE_NAME, szPath )); |
1103 | 0 | } |
1104 | 0 | gf_cfg_del(cfg); |
1105 | 0 | cfg = create_default_config(szPath, profile); |
1106 | 0 | } else { |
1107 | | //check fonts are valid, if not reload fonts |
1108 | 0 | Bool rescan_fonts = GF_FALSE; |
1109 | 0 | key = gf_cfg_get_key_name(cfg, "FontCache", 0); |
1110 | 0 | if (!key) |
1111 | 0 | rescan_fonts = GF_TRUE; |
1112 | 0 | else { |
1113 | 0 | key = gf_cfg_get_key(cfg, "FontCache", key); |
1114 | 0 | if (key && !gf_file_exists(key)) |
1115 | 0 | rescan_fonts = GF_TRUE; |
1116 | 0 | } |
1117 | 0 | if (rescan_fonts) |
1118 | 0 | gf_opts_set_key("core", "rescan-fonts", "yes"); |
1119 | 0 | } |
1120 | 0 | } |
1121 | | //no config file found |
1122 | 0 | else { |
1123 | 0 | if (!profile || strcmp(profile, "0")) { |
1124 | 0 | GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[core] Config file %s not found in %s - creating new file\n", CFG_FILE_NAME, szPath )); |
1125 | 0 | } |
1126 | 0 | cfg = create_default_config(szPath, profile); |
1127 | 0 | } |
1128 | |
|
1129 | 0 | skip_cfg: |
1130 | 0 | if (!cfg) { |
1131 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Cannot create config file %s in %s directory\n", CFG_FILE_NAME, szPath)); |
1132 | 0 | goto exit; |
1133 | 0 | } |
1134 | | |
1135 | 0 | #ifndef GPAC_CONFIG_IOS |
1136 | 0 | GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[core] Using global config file in %s directory\n", szPath)); |
1137 | 0 | #endif |
1138 | |
|
1139 | 0 | if (fast_profile) goto exit; |
1140 | | |
1141 | 0 | check_modules_dir(cfg); |
1142 | 0 | if (!profile || strcmp(profile, "0")) |
1143 | 0 | check_default_cred_file(cfg, szPath); |
1144 | |
|
1145 | 0 | if (!gf_cfg_get_key(cfg, "core", "store-dir")) { |
1146 | 0 | if (profile && !strcmp(profile, "0")) { |
1147 | 0 | strcpy(szPath, gf_get_default_cache_directory_ex(GF_FALSE) ); |
1148 | 0 | strcat(szPath, "/Storage"); |
1149 | 0 | } else { |
1150 | 0 | char *sep; |
1151 | 0 | strcpy(szPath, gf_cfg_get_filename(cfg)); |
1152 | 0 | sep = strrchr(szPath, '/'); |
1153 | 0 | if (!sep) sep = strrchr(szPath, '\\'); |
1154 | 0 | if (sep) sep[0] = 0; |
1155 | 0 | strcat(szPath, "/Storage"); |
1156 | 0 | if (!gf_dir_exists(szPath)) gf_mkdir(szPath); |
1157 | 0 | } |
1158 | 0 | gf_cfg_set_key(cfg, "core", "store-dir", szPath); |
1159 | 0 | } |
1160 | |
|
1161 | 0 | exit: |
1162 | 0 | if (prof_opt) prof_opt[0] = ':'; |
1163 | | |
1164 | | //clean tmp |
1165 | | #ifdef GPAC_CONFIG_ANDROID |
1166 | | if (cfg) { |
1167 | | const char *tmp = gf_cfg_get_key(cfg, "core", "tmp"); |
1168 | | if (tmp && !strstr(tmp, "/gpac_tmp")) tmp=NULL; |
1169 | | if (tmp) { |
1170 | | gf_enum_directory(tmp, GF_FALSE, delete_tmp_files, (void*)cfg, NULL); |
1171 | | } |
1172 | | } |
1173 | | #endif |
1174 | |
|
1175 | 0 | return cfg; |
1176 | 0 | } |
1177 | | |
1178 | | |
1179 | | GF_EXPORT |
1180 | | Bool gf_opts_default_shared_directory(char *path_buffer) |
1181 | 0 | { |
1182 | 0 | return get_default_install_path(path_buffer, GF_PATH_SHARE); |
1183 | 0 | } |
1184 | | |
1185 | | void gf_modules_new(GF_Config *config); |
1186 | | void gf_modules_del(); |
1187 | | |
1188 | | GF_Config *gpac_global_config = NULL; |
1189 | | |
1190 | | void gf_init_global_config(const char *profile) |
1191 | 0 | { |
1192 | 0 | if (!gpac_global_config) { |
1193 | 0 | gpac_global_config = gf_cfg_init(profile); |
1194 | 0 | if (!gpac_global_config) { |
1195 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Fatal error: failed to initialize GPAC global configuration\n")); |
1196 | 0 | exit(1); |
1197 | 0 | } |
1198 | 0 | if (!profile || stricmp(profile, "n")) |
1199 | 0 | gf_modules_new(gpac_global_config); |
1200 | 0 | } |
1201 | 0 | } |
1202 | | |
1203 | | void gf_uninit_global_config(Bool discard_config) |
1204 | 0 | { |
1205 | 0 | if (gpac_global_config) { |
1206 | 0 | if (discard_config) gf_cfg_discard_changes(gpac_global_config); |
1207 | 0 | gf_cfg_del(gpac_global_config); |
1208 | 0 | gpac_global_config = NULL; |
1209 | 0 | gf_modules_del(); |
1210 | 0 | } |
1211 | 0 | } |
1212 | | |
1213 | | GF_Err gf_cfg_set_key_internal(GF_Config *iniFile, const char *secName, const char *keyName, const char *keyValue, Bool is_restrict); |
1214 | | |
1215 | | #ifdef GPAC_ENABLE_RESTRICT |
1216 | | void gf_cfg_load_restrict() |
1217 | | { |
1218 | | char szPath[GF_MAX_PATH]; |
1219 | | if (get_default_install_path(szPath, GF_PATH_SHARE)) { |
1220 | | strcat(szPath, "/"); |
1221 | | strcat(szPath, "restrict.cfg"); |
1222 | | if (gf_file_exists(szPath)) { |
1223 | | GF_Config *rcfg = gf_cfg_new(NULL, szPath); |
1224 | | if (rcfg) { |
1225 | | u32 i, count = gf_cfg_get_section_count(rcfg); |
1226 | | for (i=0; i<count; i++) { |
1227 | | u32 j, kcount; |
1228 | | const char *sname = gf_cfg_get_section_name(rcfg, i); |
1229 | | if (!sname) break; |
1230 | | kcount = gf_cfg_get_key_count(rcfg, sname); |
1231 | | for (j=0; j<kcount; j++) { |
1232 | | const char *kname = gf_cfg_get_key_name(rcfg, sname, j); |
1233 | | const char *kval = gf_cfg_get_key(rcfg, sname, kname); |
1234 | | gf_cfg_set_key_internal(gpac_global_config, sname, kname, kval, GF_TRUE); |
1235 | | } |
1236 | | } |
1237 | | gf_cfg_del(rcfg); |
1238 | | } |
1239 | | } |
1240 | | } |
1241 | | } |
1242 | | #endif |
1243 | | |
1244 | | GF_EXPORT |
1245 | | const char *gf_opts_get_key(const char *secName, const char *keyName) |
1246 | 939k | { |
1247 | 939k | if (!gpac_global_config) return NULL; |
1248 | | |
1249 | 0 | if (!strcmp(secName, "core")) { |
1250 | 0 | const char *opt = gf_cfg_get_key(gpac_global_config, "temp", keyName); |
1251 | 0 | if (opt) return opt; |
1252 | 0 | } |
1253 | 0 | return gf_cfg_get_key(gpac_global_config, secName, keyName); |
1254 | 0 | } |
1255 | | GF_EXPORT |
1256 | | GF_Err gf_opts_set_key(const char *secName, const char *keyName, const char *keyValue) |
1257 | 0 | { |
1258 | 0 | if (!gpac_global_config) return GF_BAD_PARAM; |
1259 | 0 | return gf_cfg_set_key(gpac_global_config, secName, keyName, keyValue); |
1260 | 0 | } |
1261 | | GF_EXPORT |
1262 | | void gf_opts_del_section(const char *secName) |
1263 | 0 | { |
1264 | 0 | if (!gpac_global_config) return; |
1265 | 0 | gf_cfg_del_section(gpac_global_config, secName); |
1266 | 0 | } |
1267 | | GF_EXPORT |
1268 | | u32 gf_opts_get_section_count() |
1269 | 0 | { |
1270 | 0 | if (!gpac_global_config) return 0; |
1271 | 0 | return gf_cfg_get_section_count(gpac_global_config); |
1272 | 0 | } |
1273 | | GF_EXPORT |
1274 | | const char *gf_opts_get_section_name(u32 secIndex) |
1275 | 0 | { |
1276 | 0 | if (!gpac_global_config) return NULL; |
1277 | 0 | return gf_cfg_get_section_name(gpac_global_config, secIndex); |
1278 | 0 | } |
1279 | | GF_EXPORT |
1280 | | u32 gf_opts_get_key_count(const char *secName) |
1281 | 0 | { |
1282 | 0 | if (!gpac_global_config) return 0; |
1283 | 0 | return gf_cfg_get_key_count(gpac_global_config, secName); |
1284 | 0 | } |
1285 | | GF_EXPORT |
1286 | | const char *gf_opts_get_key_name(const char *secName, u32 keyIndex) |
1287 | 0 | { |
1288 | 0 | if (!gpac_global_config) return NULL; |
1289 | 0 | return gf_cfg_get_key_name(gpac_global_config, secName, keyIndex); |
1290 | 0 | } |
1291 | | |
1292 | | GF_EXPORT |
1293 | | const char *gf_opts_get_key_restricted(const char *secName, const char *keyName) |
1294 | 0 | { |
1295 | 0 | const char *res = NULL; |
1296 | 0 | const char *gf_cfg_get_key_internal(GF_Config *iniFile, const char *secName, const char *keyName, Bool restricted_only); |
1297 | 0 | if (gpac_global_config) |
1298 | 0 | res = gf_cfg_get_key_internal(gpac_global_config, secName, keyName, GF_TRUE); |
1299 | 0 | return res; |
1300 | 0 | } |
1301 | | |
1302 | | GF_EXPORT |
1303 | | const char *gf_opts_get_filename() |
1304 | 0 | { |
1305 | 0 | return gf_cfg_get_filename(gpac_global_config); |
1306 | 0 | } |
1307 | | GF_EXPORT |
1308 | | GF_Err gf_opts_discard_changes() |
1309 | 0 | { |
1310 | 0 | return gf_cfg_discard_changes(gpac_global_config); |
1311 | 0 | } |
1312 | | |
1313 | | GF_EXPORT |
1314 | | GF_Err gf_opts_save() |
1315 | 0 | { |
1316 | 0 | return gf_cfg_save(gpac_global_config); |
1317 | 0 | } |
1318 | | |
1319 | | #include <gpac/main.h> |
1320 | | |
1321 | | GF_GPACArg GPAC_Args[] = { |
1322 | | GF_DEF_ARG("tmp", NULL, "specify directory for temporary file creation instead of OS-default temporary file management", NULL, NULL, GF_ARG_STRING, 0), |
1323 | | GF_DEF_ARG("noprog", NULL, "disable progress messages", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_LOG), |
1324 | | GF_DEF_ARG("quiet", NULL, "disable all messages, including errors", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_LOG), |
1325 | | GF_DEF_ARG("log-file", "lf", "set output log file", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_LOG), |
1326 | | GF_DEF_ARG("log-clock", "lc", "log time in micro sec since start time of GPAC before each log line except for `app` tool", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_LOG), |
1327 | | GF_DEF_ARG("log-utc", "lu", "log UTC time in ms before each log line except for `app` tool", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_LOG), |
1328 | | GF_DEF_ARG("logs", NULL, "set log tools and levels. \n" |
1329 | | " \n" |
1330 | | "You can independently log different tools involved in a session. \n" |
1331 | | "log_args is formatted as a colon (':') separated list of `toolX[:toolZ]@levelX` \n" |
1332 | | "`levelX` can be one of:\n" |
1333 | | "- quiet: skip logs\n" |
1334 | | "- error: logs only error messages\n" |
1335 | | "- warning: logs error+warning messages\n" |
1336 | | "- info: logs error+warning+info messages\n" |
1337 | | "- debug: logs all messages\n" |
1338 | | "\n`toolX` can be one of:\n" |
1339 | | "- core: libgpac core\n" |
1340 | | "- mutex: log all mutex calls\n" |
1341 | | "- mem: GPAC memory tracker\n" |
1342 | | "- module: GPAC modules (av out, font engine, 2D rasterizer)\n" |
1343 | | "- filter: filter session debugging\n" |
1344 | | "- sched: filter session scheduler debugging\n" |
1345 | | "- codec: codec messages (used by encoder and decoder filters)\n" |
1346 | | "- coding: bitstream formats (audio, video, scene)\n" |
1347 | | "- container: container formats (ISO File, MPEG-2 TS, AVI, ...) and multiplexer/demultiplexer filters\n" |
1348 | | "- network: TCP/UDP sockets and TLS\n" |
1349 | | "- http: HTTP traffic\n" |
1350 | | "- cache: HTTP cache subsystem\n" |
1351 | | "- rtp: RTP traffic\n" |
1352 | | "- dash: HTTP streaming logs\n" |
1353 | | "- route: ROUTE (ATSC3) debugging\n" |
1354 | | "- media: messages from generic filters and reframer/rewriter filters\n" |
1355 | | "- parser: textual parsers (svg, xmt, bt, ...)\n" |
1356 | | "- mmio: I/O management (AV devices, file, pipes, OpenGL)\n" |
1357 | | "- audio: audio renderer/mixer/output\n" |
1358 | | "- script: script engine except console log\n" |
1359 | | "- console: script console log\n" |
1360 | | "- scene: scene graph and scene manager\n" |
1361 | | "- compose: composition engine (2D, 3D, etc)\n" |
1362 | | "- ctime: media and SMIL timing info from composition engine\n" |
1363 | | "- interact: interaction messages (UI events and triggered DOM events and VRML route)\n" |
1364 | | "- rti: run-time stats of compositor\n" |
1365 | | "- all: all tools logged - other tools can be specified afterwards. \n" |
1366 | | "The special keyword `ncl` can be set to disable color logs. \n" |
1367 | | "The special keyword `strict` can be set to exit at first error. \n" |
1368 | | "\nEX -logs=all@info:dash@debug:ncl\n" |
1369 | | "This moves all log to info level, dash to debug level and disable color logs" |
1370 | | , NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_LOG), |
1371 | | 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), |
1372 | | GF_DEF_ARG("log-dual", "ld", "output to both file and stderr", NULL, NULL, GF_ARG_BOOL, GF_ARG_SUBSYS_LOG), |
1373 | | |
1374 | | 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), |
1375 | | GF_DEF_ARG("store-dir", NULL, "set storage directory", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_CORE), |
1376 | | 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), |
1377 | | GF_DEF_ARG("js-dirs", NULL, "set javascript directories", NULL, NULL, GF_ARG_STRINGS, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1378 | | GF_DEF_ARG("no-js-mods", NULL, "disable javascript module loading", NULL, NULL, GF_ARG_STRINGS, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1379 | | GF_DEF_ARG("ifce", NULL, "set default multicast interface (default is ANY), either an IP address or a device name as listed by `gpac -h net`. Prefix '+' will force using IPv6 for dual interface", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_CORE), |
1380 | | GF_DEF_ARG("lang", NULL, "set preferred language", NULL, NULL, GF_ARG_STRING, GF_ARG_SUBSYS_CORE), |
1381 | | GF_DEF_ARG("cfg", "opt", "get or set configuration file value. The string parameter can be formatted as:\n" |
1382 | | "- `section:key=val`: set the key to a new value\n" |
1383 | | "- `section:key=null`, `section:key`: remove the key\n" |
1384 | | "- `section=null`: remove the section\n" |
1385 | | "- no argument: print the entire configuration file\n" |
1386 | | "- `section`: print the given section\n" |
1387 | | "- `section:key`: print the given `key` in `section` (section can be set to `*`)" |
1388 | | "- `*:key`: print the given `key` in all sections" |
1389 | | , NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_CORE), |
1390 | | 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), |
1391 | | 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), |
1392 | | 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), |
1393 | | 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), |
1394 | | 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), |
1395 | | 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), |
1396 | | GF_DEF_ARG("devclass", NULL, "set device class\n" |
1397 | | "- ios: iOS-based mobile device\n" |
1398 | | "- android: Android-based mobile device\n" |
1399 | | "- desktop: desktop device", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_HIDE|GF_ARG_SUBSYS_CORE), |
1400 | | |
1401 | | 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), |
1402 | | GF_DEF_ARG("no-check", NULL, "disable compliance 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), |
1403 | | GF_DEF_ARG("unhandled-rejection", NULL, "dump unhandled promise rejections", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1404 | | GF_DEF_ARG("startup-file", NULL, "startup file of compositor in GUI mode", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1405 | | GF_DEF_ARG("docs-dir", NULL, "default documents directory (for GUI on iOS and Android)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1406 | | GF_DEF_ARG("last-dir", NULL, "last working directory (for GUI)", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1407 | | #ifdef GPAC_HAS_POLL |
1408 | | GF_DEF_ARG("no-poll", NULL, "disable poll and use select for socket groups", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1409 | | #endif |
1410 | | GF_DEF_ARG("no-tls-rcfg", NULL, "disable automatic TCP to TLS reconfiguration", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1411 | | GF_DEF_ARG("no-fd", NULL, "use buffered IO instead of file descriptor for read/write - this can speed up operations on small files", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1412 | | GF_DEF_ARG("no-mx", NULL, "disable all mutexes, threads and semaphores (do not use if unsure about threading used)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1413 | | #ifndef GPAC_DISABLE_NETCAP |
1414 | | GF_DEF_ARG("netcap-dst", NULL, "output packets to indicated file", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1415 | | GF_DEF_ARG("netcap-src", NULL, "read packets from indicated file, as produced by -netcap-dst or a pcap or pcapng file", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1416 | | GF_DEF_ARG("netcap-nrt", NULL, "ignore real-time regulation when reading packet from capture file", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1417 | | GF_DEF_ARG("netcap-loop", NULL, "set number of loops of capture file, -1 means forever", NULL, NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1418 | | GF_DEF_ARG("net-filter", NULL, "set packet filtering rules (live or from file). Value is a list of `{OPT,OPT2...}` with OPT in:\n" |
1419 | | "- m=N: set rule mode - `N` can be `r` for reception only (default), `w` for send only or `rw` for both\n" |
1420 | | "- s=N: set packet start range to `N`\n" |
1421 | | "- e=N: set packet end range to `N` (only used for `r` and `f` rules)\n" |
1422 | | "- n=N: set number of packets to drop to `N`, 0 or 1 means single packet\n" |
1423 | | "- r=N: random drop one packet every `N`\n" |
1424 | | "- f=N: drop first packet every `N`\n" |
1425 | | "- p=P: local port number to filter, if not set the rule applies to all packets\n" |
1426 | | "- o=N: patch packet instead of droping (always true for TCP), replacing byte at offset `N` (0 is first byte, <0 for random)\n" |
1427 | | "- v=N: set patch byte value to `N` (hexa) or negative value for random (default)\n" |
1428 | | "\nEX {p=1234,s=100,n=20}{r=200,s=500,o=10,v=FE}\n" |
1429 | | "This will drop packets 100 to 119 on port 1234 and patch one random packet every 200 starting from packet 500, setting byte 10 to FE", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_CORE), |
1430 | | #endif |
1431 | | |
1432 | | GF_DEF_ARG("cache", NULL, "cache directory location", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1433 | | GF_DEF_ARG("proxy-on", NULL, "enable HTTP proxy", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1434 | | GF_DEF_ARG("proxy-name", NULL, "set HTTP proxy address", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1435 | | GF_DEF_ARG("proxy-port", NULL, "set HTTP proxy port", "80", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1436 | | 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), |
1437 | | GF_DEF_ARG("no-cache", NULL, "disable HTTP caching", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1438 | | GF_DEF_ARG("offline-cache", NULL, "enable offline HTTP caching (no re-validation of existing resource in cache)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1439 | | 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), |
1440 | | GF_DEF_ARG("cache-size", NULL, "specify cache size in bytes", "100M", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_HTTP), |
1441 | | GF_DEF_ARG("tcp-timeout", NULL, "time in milliseconds to wait for HTTP/RTSP connect before error", "5000", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1442 | | GF_DEF_ARG("req-timeout", NULL, "time in milliseconds to wait on HTTP/RTSP request before error (0 disables timeout)", "10000", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1443 | | GF_DEF_ARG("no-timeout", NULL, "ignore HTTP 1.1 timeout in keep-alive", "false", NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1444 | | GF_DEF_ARG("broken-cert", NULL, "enable accepting broken SSL certificates", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1445 | | 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), |
1446 | | 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), |
1447 | | 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), |
1448 | | 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), |
1449 | | 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), |
1450 | | 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), |
1451 | | GF_DEF_ARG("cred", NULL, "path to 128 bits key for credential storage", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1452 | | |
1453 | | #ifdef GPAC_HAS_HTTP2 |
1454 | | GF_DEF_ARG("no-h2", NULL, "disable HTTP2", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HTTP), |
1455 | | 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), |
1456 | | 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), |
1457 | | #endif |
1458 | | |
1459 | | 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), |
1460 | | 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), |
1461 | | GF_DEF_ARG("no-dynf", NULL, "disable dynamically loaded filters", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_FILTERS), |
1462 | | |
1463 | | GF_DEF_ARG("no-block", NULL, "disable blocking mode of filters\n" |
1464 | | "- no: enable blocking mode\n" |
1465 | | "- fanout: disable blocking on fan-out, unblocking the PID as soon as one of its destinations requires a packet\n" |
1466 | | "- all: disable blocking", "no", "no|fanout|all", GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS), |
1467 | | 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), |
1468 | | 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), |
1469 | | GF_DEF_ARG("sched", NULL, "set scheduler mode\n" |
1470 | | "- free: lock-free queues except for task list (default)\n" |
1471 | | "- lock: mutexes for queues when several threads\n" |
1472 | | "- freex: lock-free queues including for task lists (experimental)\n" |
1473 | | "- flock: mutexes for queues even when no thread (debug mode)\n" |
1474 | | "- 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), |
1475 | | GF_DEF_ARG("max-chain", NULL, "set maximum chain length when resolving filter links. Default value covers for __[ in -> ] dmx -> reframe -> decode -> encode -> reframe -> mx [ -> out]__. Filter chains loaded for adaptation (e.g. 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), |
1476 | | 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), |
1477 | | |
1478 | | 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), |
1479 | | 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), |
1480 | | 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), |
1481 | | GF_DEF_ARG("blacklist", NULL, "blacklist the filters listed in the given string (comma-separated list). If first character is '-', this is a whitelist, i.e. only filters listed in the given string will be allowed", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS), |
1482 | | 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), |
1483 | | 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), |
1484 | | GF_DEF_ARG("buffer-gen", NULL, "default buffer size in microseconds for generic pids", "1000", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS), |
1485 | | GF_DEF_ARG("buffer-dec", NULL, "default buffer size in microseconds for decoder input pids", "1000000", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS), |
1486 | | GF_DEF_ARG("buffer-units", NULL, "default buffer size in frames when timing is not available", "1", NULL, GF_ARG_INT, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_FILTERS), |
1487 | | |
1488 | | 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), |
1489 | | 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), |
1490 | | GF_DEF_ARG("gl-doublebuf", NULL, "enable OpenGL double buffering", "yes", NULL, GF_ARG_BOOL, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_VIDEO), |
1491 | | 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), |
1492 | | GF_DEF_ARG("video-output", NULL, "indicate the name of the video output module to use (see `gpac -h modules`)." |
1493 | | " The reserved name `glfbo` is used in player mode to draw in the OpenGL texture identified by [-glfbo-txid](). " |
1494 | | " In this mode, the application is responsible for sending event to the compositor", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_VIDEO), |
1495 | | |
1496 | | 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_AUDIO), |
1497 | | |
1498 | | 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), |
1499 | | 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), |
1500 | | 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), |
1501 | | 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), |
1502 | | 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), |
1503 | | GF_DEF_ARG("charset", NULL, "set charset when not recognized from input. Possible values are:\n" |
1504 | | "- utf8: force UTF-8\n" |
1505 | | "- utf16: force UTF-16 little endian\n" |
1506 | | "- utf16be: force UTF-16 big endian\n" |
1507 | | "- other: attempt to parse anyway", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_ADVANCED|GF_ARG_SUBSYS_TEXT), |
1508 | | |
1509 | | 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), |
1510 | | GF_DEF_ARG("rmt-port", NULL, "set remotery port", "17815", NULL, GF_ARG_INT, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT), |
1511 | | GF_DEF_ARG("rmt-reuse", NULL, "allow remotery to reuse port", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT), |
1512 | | 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), |
1513 | | 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), |
1514 | | 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), |
1515 | | 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), |
1516 | | 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), |
1517 | | GF_DEF_ARG("rmt-ogl", NULL, "make remotery sample opengl calls", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_RMT), |
1518 | | |
1519 | | 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), |
1520 | | 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), |
1521 | | GF_DEF_ARG("vvdec-annexb", NULL, "hack for old vvdec+libavcodec supporting only annexB format", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HACKS), |
1522 | | GF_DEF_ARG("heif-hevc-urn", NULL, "use HEVC URN for alpha and depth in HEIF instead of MPEG-B URN (HEIF first edition)", NULL, NULL, GF_ARG_BOOL, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HACKS), |
1523 | | GF_DEF_ARG("boxdir", NULL, "use box definitions in the given directory for XML dump", NULL, NULL, GF_ARG_STRING, GF_ARG_HINT_EXPERT|GF_ARG_SUBSYS_HACKS), |
1524 | | |
1525 | | |
1526 | | {0} |
1527 | | }; |
1528 | | |
1529 | | |
1530 | | const GF_Config *gf_sys_get_lang_file(); |
1531 | | |
1532 | | GF_EXPORT |
1533 | | const GF_GPACArg *gf_sys_get_options() |
1534 | 0 | { |
1535 | 0 | return GPAC_Args; |
1536 | 0 | } |
1537 | | |
1538 | | static const char *gpac_opt_default(const char *argname) |
1539 | 411k | { |
1540 | 411k | const GF_GPACArg *arg = NULL; |
1541 | 411k | u32 i=0; |
1542 | 10.8M | while (GPAC_Args[i].name) { |
1543 | 10.8M | arg = &GPAC_Args[i]; |
1544 | 10.8M | i++; |
1545 | 10.8M | if (!strcmp(arg->name, argname)) break; |
1546 | 10.4M | arg = NULL; |
1547 | 10.4M | } |
1548 | 411k | if (!arg) return NULL; |
1549 | 411k | return arg->val; |
1550 | 411k | } |
1551 | | |
1552 | | GF_EXPORT |
1553 | | Bool gf_opts_get_bool(const char *secName, const char *keyName) |
1554 | 382k | { |
1555 | 382k | const char *opt = gf_opts_get_key(secName, keyName); |
1556 | | |
1557 | 382k | if (!opt && !strcmp(secName, "core")) { |
1558 | 382k | opt = gpac_opt_default(keyName); |
1559 | 382k | } |
1560 | | |
1561 | 382k | if (!opt) return GF_FALSE; |
1562 | 0 | if (!strcmp(opt, "yes")) return GF_TRUE; |
1563 | 0 | if (!strcmp(opt, "true")) return GF_TRUE; |
1564 | 0 | if (!strcmp(opt, "1")) return GF_TRUE; |
1565 | 0 | return GF_FALSE; |
1566 | 0 | } |
1567 | | GF_EXPORT |
1568 | | u32 gf_opts_get_int(const char *secName, const char *keyName) |
1569 | 28.3k | { |
1570 | 28.3k | u32 times=1, val; |
1571 | 28.3k | char *opt = (char *) gf_opts_get_key(secName, keyName); |
1572 | | |
1573 | 28.3k | if (!opt && !strcmp(secName, "core")) { |
1574 | 28.3k | opt = (char *) gpac_opt_default(keyName); |
1575 | 28.3k | } |
1576 | 28.3k | if (!opt || !opt[0]) return 0; |
1577 | 28.3k | val = (u32) strlen(opt); |
1578 | 28.3k | char c = opt[val-1]; |
1579 | 28.3k | switch (c) { |
1580 | 0 | case 'k': |
1581 | 0 | case 'K': |
1582 | 0 | times=1000; |
1583 | 0 | break; |
1584 | 0 | case 'm': |
1585 | 0 | case 'M': |
1586 | 0 | times=1000000; |
1587 | 0 | break; |
1588 | 28.3k | } |
1589 | 28.3k | val = atoi(opt); |
1590 | 28.3k | return val*times; |
1591 | 28.3k | } |
1592 | | |
1593 | | GF_EXPORT |
1594 | | Bool gf_sys_set_cfg_option(const char *opt_string) |
1595 | 0 | { |
1596 | 0 | size_t sepIdx; |
1597 | 0 | char *sep, *sep2, szSec[1024], szKey[1024], szVal[1024]; |
1598 | 0 | sep = strchr(opt_string, ':'); |
1599 | 0 | if (!sep) { |
1600 | 0 | sep = strchr(opt_string, '='); |
1601 | 0 | if (sep && !stricmp(sep, "=null")) { |
1602 | 0 | sepIdx = sep - opt_string; |
1603 | 0 | if (sepIdx>=1024) sepIdx = 1023; |
1604 | 0 | strncpy(szSec, opt_string, sepIdx); |
1605 | 0 | szSec[sepIdx] = 0; |
1606 | 0 | gf_opts_del_section(szSec); |
1607 | 0 | return GF_TRUE; |
1608 | 0 | } |
1609 | | |
1610 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CoreArgs] Badly formatted option %s - expected Section:Name=Value\n", opt_string ) ); |
1611 | 0 | return GF_FALSE; |
1612 | 0 | } |
1613 | | |
1614 | 0 | sepIdx = sep - opt_string; |
1615 | 0 | if (sepIdx>=1024) |
1616 | 0 | sepIdx = 1023; |
1617 | 0 | strncpy(szSec, opt_string, sepIdx); |
1618 | 0 | szSec[sepIdx] = 0; |
1619 | |
|
1620 | 0 | sep ++; |
1621 | 0 | sep2 = strchr(sep, '='); |
1622 | 0 | if (!sep2) { |
1623 | 0 | gf_opts_set_key(szSec, sep, NULL); |
1624 | 0 | return GF_TRUE; |
1625 | 0 | } |
1626 | | |
1627 | 0 | sepIdx = sep2 - sep; |
1628 | 0 | if (sepIdx>=1024) |
1629 | 0 | sepIdx = 1023; |
1630 | 0 | strncpy(szKey, sep, sepIdx); |
1631 | 0 | szKey[sepIdx] = 0; |
1632 | |
|
1633 | 0 | sepIdx = strlen(sep2+1); |
1634 | 0 | if (sepIdx>=1024) |
1635 | 0 | sepIdx = 1023; |
1636 | 0 | memcpy(szVal, sep2+1, sepIdx); |
1637 | 0 | szVal[sepIdx] = 0; |
1638 | |
|
1639 | 0 | if (!stricmp(szKey, "*")) { |
1640 | 0 | if (stricmp(szVal, "null")) { |
1641 | 0 | GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[CoreArgs] Badly formatted option %s - expected Section:*=null\n", opt_string)); |
1642 | 0 | return GF_FALSE; |
1643 | 0 | } |
1644 | 0 | gf_opts_del_section(szSec); |
1645 | 0 | return GF_TRUE; |
1646 | 0 | } |
1647 | | |
1648 | 0 | if (!stricmp(szVal, "null")) { |
1649 | 0 | szVal[0]=0; |
1650 | 0 | } |
1651 | 0 | gf_opts_set_key(szSec, szKey, szVal[0] ? szVal : NULL); |
1652 | |
|
1653 | 0 | if (!strcmp(szSec, "core") || !strcmp(szSec, "temp")) { |
1654 | 0 | if (!strcmp(szKey, "noprog") && (!strcmp(szVal, "yes")||!strcmp(szVal, "true")||!strcmp(szVal, "1")) ) { |
1655 | 0 | void gpac_disable_progress(); |
1656 | |
|
1657 | 0 | gpac_disable_progress(); |
1658 | 0 | } |
1659 | 0 | } |
1660 | 0 | return GF_TRUE; |
1661 | 0 | } |
1662 | | |
1663 | | void gf_module_reload_dirs(); |
1664 | | |
1665 | | Bool gf_opts_load_option(const char *arg_name, const char *val, Bool *consumed_next, GF_Err *e) |
1666 | 0 | { |
1667 | 0 | const GF_GPACArg *arg = NULL; |
1668 | 0 | u32 i=0; |
1669 | 0 | *e = GF_OK; |
1670 | 0 | *consumed_next = GF_FALSE; |
1671 | 0 | arg_name = arg_name+1; |
1672 | 0 | while (GPAC_Args[i].name) { |
1673 | 0 | arg = &GPAC_Args[i]; |
1674 | 0 | i++; |
1675 | 0 | if (!strcmp(arg->name, arg_name)) break; |
1676 | 0 | if (arg->altname && !strcmp(arg->altname, arg_name)) break; |
1677 | | |
1678 | 0 | arg = NULL; |
1679 | 0 | } |
1680 | 0 | if (!arg) return GF_FALSE; |
1681 | | |
1682 | 0 | if (!strcmp(arg->name, "cfg")) { |
1683 | 0 | *consumed_next = GF_TRUE; |
1684 | 0 | if (val && strchr(val, '=')) { |
1685 | 0 | if (! gf_sys_set_cfg_option(val)) *e = GF_BAD_PARAM; |
1686 | 0 | } else { |
1687 | 0 | u32 sec_len = 0; |
1688 | 0 | char *sep = val ? strchr(val, ':') : NULL; |
1689 | 0 | u32 sec_count = gf_opts_get_section_count(); |
1690 | 0 | if (sep) { |
1691 | 0 | sec_len = (u32) (sep - val - 1); |
1692 | 0 | sep++; |
1693 | 0 | } else if (val) { |
1694 | 0 | sec_len = (u32) strlen(val); |
1695 | 0 | } |
1696 | 0 | for (i=0; i<sec_count; i++) { |
1697 | 0 | u32 k, key_count; |
1698 | 0 | Bool sec_hdr_done = GF_FALSE; |
1699 | 0 | const char *sname = gf_opts_get_section_name(i); |
1700 | 0 | key_count = sname ? gf_opts_get_key_count(sname) : 0; |
1701 | 0 | if (!key_count) continue; |
1702 | | |
1703 | 0 | if (sec_len) { |
1704 | 0 | if (!strncmp(val, "*", sec_len) || !strncmp(val, "@", sec_len)) { |
1705 | 0 | } else if (strncmp(val, sname, sec_len) || (sec_len != (u32) strlen(sname) ) ) { |
1706 | 0 | continue; |
1707 | 0 | } |
1708 | 0 | } |
1709 | 0 | for (k=0; k<key_count; k++) { |
1710 | 0 | const char *kname = gf_opts_get_key_name(sname, k); |
1711 | 0 | const char *kval = kname ? gf_opts_get_key(sname, kname) : NULL; |
1712 | 0 | if (!kval) continue; |
1713 | 0 | if (sep && strcmp(sep, kname)) continue; |
1714 | | |
1715 | 0 | if (!sec_hdr_done) { |
1716 | 0 | sec_hdr_done = GF_TRUE; |
1717 | 0 | fprintf(stdout, "[%s]\n", sname); |
1718 | 0 | } |
1719 | 0 | fprintf(stdout, "%s=%s\n", kname, kval); |
1720 | 0 | } |
1721 | 0 | if (sec_hdr_done) |
1722 | 0 | fprintf(stdout, "\n"); |
1723 | 0 | } |
1724 | 0 | } |
1725 | 0 | return GF_TRUE; |
1726 | 0 | } |
1727 | 0 | if (!strcmp(arg->name, "strict-error")) { |
1728 | 0 | gf_log_set_strict_error(1); |
1729 | 0 | return GF_TRUE; |
1730 | 0 | } |
1731 | | |
1732 | 0 | if (arg->type==GF_ARG_BOOL) { |
1733 | 0 | if (!val) gf_opts_set_key("temp", arg->name, "yes"); |
1734 | 0 | else { |
1735 | 0 | if (!strcmp(val, "yes") || !strcmp(val, "true") || !strcmp(val, "1")) { |
1736 | 0 | *consumed_next = GF_TRUE; |
1737 | 0 | gf_opts_set_key("temp", arg->name, "yes"); |
1738 | 0 | } else { |
1739 | 0 | if (!strcmp(val, "no") || !strcmp(val, "false") || !strcmp(val, "0")) { |
1740 | 0 | *consumed_next = GF_TRUE; |
1741 | 0 | gf_opts_set_key("temp", arg->name, "no"); |
1742 | 0 | } else { |
1743 | 0 | gf_opts_set_key("temp", arg->name, "yes"); |
1744 | 0 | } |
1745 | 0 | } |
1746 | 0 | } |
1747 | 0 | } else { |
1748 | 0 | *consumed_next = GF_TRUE; |
1749 | 0 | if (!val && (arg->type==GF_ARG_BOOL)) |
1750 | 0 | gf_opts_set_key("temp", arg->name, "true"); |
1751 | 0 | else { |
1752 | 0 | gf_opts_set_key("temp", arg->name, val); |
1753 | 0 | if (!strcmp(arg->name, "mod-dirs")) { |
1754 | 0 | gf_module_reload_dirs(); |
1755 | 0 | } |
1756 | 0 | } |
1757 | 0 | } |
1758 | 0 | return GF_TRUE; |
1759 | 0 | } |
1760 | | |
1761 | | GF_EXPORT |
1762 | | u32 gf_sys_is_gpac_arg(const char *arg_name) |
1763 | 0 | { |
1764 | 0 | char *argsep; |
1765 | 0 | u32 arglen; |
1766 | 0 | const GF_GPACArg *arg = NULL; |
1767 | 0 | u32 i=0; |
1768 | 0 | arg_name = arg_name+1; |
1769 | 0 | if (arg_name[0]=='-') |
1770 | 0 | return 1; |
1771 | 0 | if (arg_name[0]=='+') |
1772 | 0 | return 1; |
1773 | | |
1774 | 0 | argsep = strchr(arg_name, '='); |
1775 | 0 | if (argsep) arglen = (u32) (argsep - arg_name); |
1776 | 0 | else arglen = (u32) strlen(arg_name); |
1777 | |
|
1778 | 0 | while (GPAC_Args[i].name) { |
1779 | 0 | arg = &GPAC_Args[i]; |
1780 | 0 | i++; |
1781 | 0 | if ((strlen(arg->name) == arglen) && !strncmp(arg->name, arg_name, arglen)) break; |
1782 | 0 | if (arg->altname) { |
1783 | 0 | char *alt = strstr(arg->altname, arg_name); |
1784 | 0 | if (alt) { |
1785 | 0 | char c = alt[strlen(arg_name)]; |
1786 | 0 | if (!c || (c==' ')) break; |
1787 | 0 | } |
1788 | 0 | } |
1789 | 0 | arg = NULL; |
1790 | 0 | } |
1791 | 0 | if (!arg) return 0; |
1792 | 0 | if (arg->type==GF_ARG_BOOL) return 1; |
1793 | 0 | if (argsep) return 1; |
1794 | 0 | return 2; |
1795 | 0 | } |
1796 | | |
1797 | | |
1798 | | GF_EXPORT |
1799 | | void gf_sys_print_arg(FILE *helpout, GF_SysPrintArgFlags flags, const GF_GPACArg *arg, const char *arg_subsystem) |
1800 | 0 | { |
1801 | 0 | u32 gen_doc = 0; |
1802 | 0 | if (flags & GF_PRINTARG_MD) |
1803 | 0 | gen_doc = 1; |
1804 | 0 | if (!helpout) helpout = stderr; |
1805 | | |
1806 | | //#ifdef GPAC_ENABLE_COVERAGE |
1807 | 0 | #if 1 |
1808 | 0 | if ((arg->name[0]>='A') && (arg->name[0]<='Z')) { |
1809 | 0 | if ((arg->name[1]<'A') || (arg->name[1]>'Z')) { |
1810 | 0 | fprintf(stderr, "\nWARNING: arg %s bad name format, should use lowercase\n", arg->name); |
1811 | 0 | exit(1); |
1812 | 0 | } |
1813 | 0 | } |
1814 | 0 | if (arg->description) { |
1815 | 0 | char *sep; |
1816 | |
|
1817 | 0 | if ((arg->description[0]>='A') && (arg->description[0]<='Z')) { |
1818 | 0 | if ((arg->description[1]<'A') || (arg->description[1]>'Z')) { |
1819 | 0 | fprintf(stderr, "\nWARNING: arg %s bad name format \"%s\", should use lowercase\n", arg->name, arg->description); |
1820 | 0 | exit(1); |
1821 | 0 | } |
1822 | 0 | } |
1823 | 0 | if (strchr(arg->description, '\t')) { |
1824 | 0 | fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not use tab\n", arg->name, arg->description); |
1825 | 0 | exit(1); |
1826 | 0 | } |
1827 | | |
1828 | 0 | u8 achar = arg->description[strlen(arg->description)-1]; |
1829 | 0 | if (achar == '.') { |
1830 | 0 | fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not end with .\n", arg->name, arg->description); |
1831 | 0 | exit(1); |
1832 | 0 | } |
1833 | 0 | sep = strstr(arg->description, ".\n"); |
1834 | 0 | if (sep) { |
1835 | 0 | fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should not contain .\\n \n", arg->name, arg->description); |
1836 | 0 | exit(1); |
1837 | 0 | } |
1838 | 0 | sep = strstr(arg->description, "- "); |
1839 | 0 | if (sep && (sep[-1]!='\n') && !strcmp(sep, "- see")) { |
1840 | 0 | fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should have \\n before first bullet\n", arg->name, arg->description); |
1841 | 0 | exit(1); |
1842 | 0 | } |
1843 | | |
1844 | 0 | sep = strchr(arg->description, ' '); |
1845 | 0 | if (sep && (sep>arg->description)) { |
1846 | 0 | sep--; |
1847 | 0 | if ((sep[0] == 's') && (sep[-1] != 's')) { |
1848 | 0 | fprintf(stderr, "\nWARNING: arg %s bad description format \"%s\", should use infintive\n", arg->name, arg->description); |
1849 | 0 | exit(1); |
1850 | 0 | } |
1851 | 0 | } |
1852 | 0 | } |
1853 | 0 | #endif |
1854 | | |
1855 | 0 | if (arg->flags & GF_ARG_HINT_HIDE) |
1856 | 0 | return; |
1857 | | |
1858 | 0 | const char *syntax=strchr(arg->name, ' '); |
1859 | 0 | char *arg_name=NULL; |
1860 | 0 | if (syntax) { |
1861 | 0 | arg_name = gf_strdup(arg->name); |
1862 | 0 | char *sep = strchr(arg_name, ' '); |
1863 | 0 | sep[0]=0; |
1864 | 0 | } |
1865 | |
|
1866 | 0 | if (flags & GF_PRINTARG_MAN) { |
1867 | 0 | fprintf(helpout, ".TP\n.B %s%s", (flags&GF_PRINTARG_NO_DASH) ? "" : "\\-", arg_name ? arg_name : arg->name); |
1868 | 0 | } |
1869 | 0 | else if (gen_doc==1) { |
1870 | 0 | if (flags&GF_PRINTARG_NO_DASH) { |
1871 | 0 | gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s", arg_name ? arg_name : arg->name); |
1872 | 0 | } else { |
1873 | 0 | gf_sys_format_help(helpout, flags, "<a id=\"%s\">", arg_name ? arg_name : arg->name); |
1874 | 0 | gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "-%s", arg_name ? arg_name : arg->name); |
1875 | 0 | gf_sys_format_help(helpout, flags, "</a>"); |
1876 | 0 | } |
1877 | 0 | } else { |
1878 | 0 | gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s%s%s", |
1879 | 0 | (flags&GF_PRINTARG_ADD_DASH) ? "-" : "", |
1880 | 0 | (flags&GF_PRINTARG_NO_DASH) ? "" : ((flags&GF_PRINTARG_COLON) ? ":" : "-"), |
1881 | 0 | arg_name ? arg_name : arg->name |
1882 | 0 | ); |
1883 | 0 | } |
1884 | 0 | if (arg->altname) { |
1885 | 0 | gf_sys_format_help(helpout, flags, ","); |
1886 | 0 | gf_sys_format_help(helpout, flags | GF_PRINTARG_HIGHLIGHT_FIRST, "%s-%s", (flags&GF_PRINTARG_ADD_DASH) ? "-" : "", arg->altname); |
1887 | 0 | } |
1888 | 0 | if (syntax) { |
1889 | 0 | gf_sys_format_help(helpout, flags, " %s", syntax); |
1890 | 0 | gf_free(arg_name); |
1891 | 0 | } |
1892 | |
|
1893 | 0 | if (arg->type==GF_ARG_CUSTOM) { |
1894 | 0 | if (arg->val) |
1895 | 0 | gf_sys_format_help(helpout, flags, " `%s`", arg->val); |
1896 | 0 | } else if (arg->type==GF_ARG_INT && arg->values && strchr(arg->values, '|')) { |
1897 | 0 | gf_sys_format_help(helpout, flags, " (Enum"); |
1898 | 0 | if (arg->val) |
1899 | 0 | gf_sys_format_help(helpout, flags, ", default: **%s**", arg->val); |
1900 | 0 | gf_sys_format_help(helpout, flags, ")"); |
1901 | 0 | } else if (arg->type != GF_ARG_BOOL) { |
1902 | 0 | gf_sys_format_help(helpout, flags, " ("); |
1903 | 0 | switch (arg->type) { |
1904 | 0 | case GF_ARG_BOOL: gf_sys_format_help(helpout, flags, "boolean"); break; |
1905 | 0 | case GF_ARG_INT: gf_sys_format_help(helpout, flags, "int"); break; |
1906 | 0 | case GF_ARG_DOUBLE: gf_sys_format_help(helpout, flags, "number"); break; |
1907 | 0 | case GF_ARG_STRING: gf_sys_format_help(helpout, flags, "string"); break; |
1908 | 0 | case GF_ARG_STRINGS: gf_sys_format_help(helpout, flags, "string list"); break; |
1909 | 0 | case GF_ARG_4CC: gf_sys_format_help(helpout, flags, "4CC"); break; |
1910 | 0 | case GF_ARG_4CCS: gf_sys_format_help(helpout, flags, "4CC list"); break; |
1911 | 0 | default: break; |
1912 | 0 | } |
1913 | 0 | if (arg->val) |
1914 | 0 | gf_sys_format_help(helpout, flags, ", default: **%s**", arg->val); |
1915 | 0 | if (arg->values) |
1916 | 0 | gf_sys_format_help(helpout, flags, ", values: __%s__", arg->values); |
1917 | 0 | gf_sys_format_help(helpout, flags, ")"); |
1918 | 0 | } |
1919 | | |
1920 | 0 | if (flags & GF_PRINTARG_MAN) { |
1921 | 0 | gf_sys_format_help(helpout, flags, "\n%s\n", gf_sys_localized(arg_subsystem, arg->name, arg->description) ); |
1922 | 0 | } else { |
1923 | 0 | if (arg->description) { |
1924 | 0 | gf_sys_format_help(helpout, flags | GF_PRINTARG_OPT_DESC, ": %s", gf_sys_localized(arg_subsystem, arg->name, arg->description) ); |
1925 | 0 | } |
1926 | 0 | gf_sys_format_help(helpout, flags, "\n"); |
1927 | 0 | } |
1928 | |
|
1929 | 0 | if ((gen_doc==1) && arg->description && strstr(arg->description, "- ")) |
1930 | 0 | gf_sys_format_help(helpout, flags, "\n"); |
1931 | 0 | } |
1932 | | |
1933 | | |
1934 | | GF_EXPORT |
1935 | | void gf_sys_print_core_help(FILE *helpout, GF_SysPrintArgFlags flags, GF_SysArgMode mode, u32 subsystem_flags) |
1936 | 0 | { |
1937 | 0 | u32 i=0; |
1938 | 0 | const GF_GPACArg *args = gf_sys_get_options(); |
1939 | |
|
1940 | 0 | while (args[i].name) { |
1941 | 0 | const GF_GPACArg *arg = &args[i]; |
1942 | 0 | i++; |
1943 | 0 | if (arg->flags & GF_ARG_HINT_HIDE) continue; |
1944 | | |
1945 | 0 | if (subsystem_flags && !(arg->flags & subsystem_flags)) { |
1946 | 0 | continue; |
1947 | 0 | } |
1948 | 0 | if (mode != GF_ARGMODE_ALL) { |
1949 | 0 | if ((mode==GF_ARGMODE_EXPERT) && !(arg->flags & GF_ARG_HINT_EXPERT)) continue; |
1950 | 0 | else if ((mode==GF_ARGMODE_ADVANCED) && !(arg->flags & GF_ARG_HINT_ADVANCED)) continue; |
1951 | 0 | else if ((mode==GF_ARGMODE_BASE) && (arg->flags & (GF_ARG_HINT_ADVANCED|GF_ARG_HINT_EXPERT) )) continue; |
1952 | 0 | } |
1953 | 0 | gf_sys_print_arg(helpout, flags, arg, "core"); |
1954 | 0 | } |
1955 | 0 | } |
1956 | | |
1957 | | |
1958 | 0 | #define LINE_OFFSET_DESCR 30 |
1959 | | |
1960 | | static char *help_buf = NULL; |
1961 | | static u32 help_buf_size=0; |
1962 | | |
1963 | | void gf_sys_cleanup_help() |
1964 | 0 | { |
1965 | 0 | if (help_buf) { |
1966 | 0 | gf_free(help_buf); |
1967 | 0 | help_buf = NULL; |
1968 | 0 | help_buf_size = 0; |
1969 | 0 | } |
1970 | 0 | } |
1971 | | |
1972 | | |
1973 | | enum |
1974 | | { |
1975 | | TOK_CODE, |
1976 | | TOK_BOLD, |
1977 | | TOK_ITALIC, |
1978 | | TOK_STRIKE, |
1979 | | TOK_OPTLINK, |
1980 | | TOK_LINKSTART, |
1981 | | }; |
1982 | | struct _token { |
1983 | | char *tok; |
1984 | | GF_ConsoleCodes cmd_type; |
1985 | | } Tokens[] = |
1986 | | { |
1987 | | {"`", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC}, |
1988 | | {"**", GF_CONSOLE_BOLD}, |
1989 | | {"__", GF_CONSOLE_ITALIC}, |
1990 | | {"~~", GF_CONSOLE_STRIKE}, |
1991 | | {"[-", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC}, |
1992 | | {"[", GF_CONSOLE_YELLOW|GF_CONSOLE_ITALIC}, |
1993 | | }; |
1994 | | static u32 nb_tokens = sizeof(Tokens) / sizeof(struct _token); |
1995 | | |
1996 | | static u32 line_pos = 0; |
1997 | | |
1998 | | //#define CHECK_BALANCED_SEPS |
1999 | | |
2000 | | #ifdef CHECK_BALANCED_SEPS |
2001 | | static void check_char_balanced(char *buf, char c) |
2002 | | { |
2003 | | char *txt = buf; |
2004 | | while (txt) { |
2005 | | char *bquote_next; |
2006 | | char *bquote = strchr(txt, c); |
2007 | | if (!bquote) break; |
2008 | | if (c=='\'') { |
2009 | | if ((bquote[1]=='s') && (bquote[2]==' ')) { |
2010 | | txt = bquote + 1; |
2011 | | continue; |
2012 | | } |
2013 | | } |
2014 | | bquote_next = strchr(bquote+1, c); |
2015 | | if (!bquote_next) { |
2016 | | fprintf(stderr, "Missing closing %c after %s\n", c, bquote); |
2017 | | exit(1); |
2018 | | } |
2019 | | switch (bquote_next[1] ) { |
2020 | | case 0: |
2021 | | case '\n': |
2022 | | case ' ': |
2023 | | case ',': |
2024 | | case '.': |
2025 | | case ')': |
2026 | | case ']': |
2027 | | case ':': |
2028 | | break; |
2029 | | default: |
2030 | | if (c=='\'') { |
2031 | | if ((bquote_next[1]>='A') && (bquote_next[1]<='Z')) |
2032 | | break; |
2033 | | } |
2034 | | fprintf(stderr, "Missing space after closing %c %s\n", c, bquote_next); |
2035 | | exit(1); |
2036 | | } |
2037 | | txt = bquote_next + 1; |
2038 | | } |
2039 | | } |
2040 | | #endif |
2041 | | |
2042 | | GF_EXPORT |
2043 | | void gf_sys_format_help(FILE *helpout, GF_SysPrintArgFlags flags, const char *fmt, ...) |
2044 | 0 | { |
2045 | 0 | char *line; |
2046 | 0 | u32 len; |
2047 | 0 | va_list vlist; |
2048 | 0 | Bool escape_xml = GF_FALSE; |
2049 | 0 | Bool escape_pipe = GF_FALSE; |
2050 | 0 | Bool prev_was_example = GF_FALSE; |
2051 | 0 | Bool prev_has_line_after = GF_FALSE; |
2052 | 0 | u32 gen_doc = 0; |
2053 | 0 | u32 is_app_opts = 0; |
2054 | 0 | if (flags & GF_PRINTARG_MD) { |
2055 | 0 | gen_doc = 1; |
2056 | 0 | if (flags & GF_PRINTARG_ESCAPE_XML) |
2057 | 0 | escape_xml = GF_TRUE; |
2058 | 0 | if (flags & GF_PRINTARG_ESCAPE_PIPE) |
2059 | 0 | escape_pipe = GF_TRUE; |
2060 | 0 | } |
2061 | 0 | if (flags & GF_PRINTARG_MAN) |
2062 | 0 | gen_doc = 2; |
2063 | 0 | if (flags & GF_PRINTARG_IS_APP) |
2064 | 0 | is_app_opts = 1; |
2065 | 0 | if (!helpout) helpout = stderr; |
2066 | |
|
2067 | 0 | va_start(vlist, fmt); |
2068 | 0 | len=vsnprintf(NULL, 0, fmt, vlist); |
2069 | 0 | va_end(vlist); |
2070 | 0 | if (help_buf_size < len+2) { |
2071 | 0 | help_buf_size = len+2; |
2072 | 0 | help_buf = gf_realloc(help_buf, help_buf_size); |
2073 | 0 | } |
2074 | 0 | va_start(vlist, fmt); |
2075 | 0 | vsprintf(help_buf, fmt, vlist); |
2076 | 0 | va_end(vlist); |
2077 | |
|
2078 | | #ifdef CHECK_BALANCED_SEPS |
2079 | | if (gen_doc) { |
2080 | | check_char_balanced(help_buf, '`'); |
2081 | | check_char_balanced(help_buf, '\''); |
2082 | | } |
2083 | | #endif |
2084 | | |
2085 | | /*#ifdef GPAC_CONFIG_ANDROID |
2086 | | //on android use logs for help print |
2087 | | if (!gen_doc) { |
2088 | | GF_LOG(GF_LOG_INFO, GF_LOG_APP, ("%s", help_buf)); |
2089 | | return; |
2090 | | } |
2091 | | #endif |
2092 | | */ |
2093 | |
|
2094 | 0 | line = help_buf; |
2095 | 0 | while (line[0]) { |
2096 | 0 | u32 att_len = 0; |
2097 | 0 | char *tok_sep = NULL; |
2098 | 0 | GF_ConsoleCodes console_code = GF_CONSOLE_RESET; |
2099 | 0 | Bool line_before = GF_FALSE; |
2100 | 0 | Bool line_after = GF_FALSE; |
2101 | 0 | const char *footer_string = NULL; |
2102 | 0 | const char *header_string = NULL; |
2103 | 0 | char *next_line = strchr(line, '\n'); |
2104 | 0 | Bool has_token=GF_FALSE; |
2105 | |
|
2106 | 0 | if (next_line) next_line[0]=0; |
2107 | |
|
2108 | 0 | if (prev_has_line_after && !strlen(line)) { |
2109 | 0 | if (!next_line) break; |
2110 | 0 | line = next_line+1; |
2111 | 0 | line_pos=0; |
2112 | 0 | continue; |
2113 | 0 | } |
2114 | | |
2115 | 0 | if ((line[0]=='#') && (line[1]==' ')) { |
2116 | 0 | if (!gen_doc) |
2117 | 0 | line+=2; |
2118 | 0 | else if (gen_doc==2) { |
2119 | 0 | header_string = ".SH "; |
2120 | 0 | footer_string = "\n.LP"; |
2121 | 0 | line+=2; |
2122 | 0 | } |
2123 | |
|
2124 | 0 | console_code = GF_CONSOLE_GREEN; |
2125 | 0 | line_after = line_before = GF_TRUE; |
2126 | 0 | } else if ((line[0]=='#') && (line[1]=='#') && (line[2]==' ')) { |
2127 | 0 | if (!gen_doc) |
2128 | 0 | line+=3; |
2129 | 0 | else if (gen_doc==2) { |
2130 | 0 | line+=3; |
2131 | 0 | header_string = ".SS "; |
2132 | 0 | } |
2133 | |
|
2134 | 0 | console_code = GF_CONSOLE_MAGENTA; |
2135 | 0 | line_before = GF_TRUE; |
2136 | 0 | } else if ((line[0]=='#') && (line[1]=='#') && (line[2]=='#') && (line[3]==' ')) { |
2137 | 0 | if (!gen_doc) |
2138 | 0 | line+=4; |
2139 | 0 | else if (gen_doc==2) { |
2140 | 0 | line+=4; |
2141 | 0 | header_string = ".P\n.B\n"; |
2142 | 0 | } |
2143 | |
|
2144 | 0 | console_code = GF_CONSOLE_CYAN; |
2145 | 0 | line_after = GF_TRUE; |
2146 | 0 | } else if ((line[0]=='E') && (line[1]=='X') && (line[2]==' ')) { |
2147 | 0 | line+=3; |
2148 | 0 | console_code = GF_CONSOLE_YELLOW; |
2149 | |
|
2150 | 0 | if (gen_doc==1) { |
2151 | 0 | header_string = "Example\n```\n"; |
2152 | 0 | footer_string = "\n```"; |
2153 | 0 | } else if (gen_doc==2) { |
2154 | 0 | header_string = "Example\n.br\n"; |
2155 | 0 | footer_string = "\n.br\n"; |
2156 | 0 | } else { |
2157 | 0 | header_string = "Example:\n"; |
2158 | 0 | } |
2159 | |
|
2160 | 0 | if (prev_was_example) { |
2161 | 0 | header_string = NULL; |
2162 | 0 | } |
2163 | |
|
2164 | 0 | if (next_line && (next_line[1]=='E') && (next_line[2]=='X') && (next_line[3]==' ')) { |
2165 | 0 | prev_was_example = GF_TRUE; |
2166 | 0 | footer_string = NULL; |
2167 | 0 | } else { |
2168 | 0 | prev_was_example = GF_FALSE; |
2169 | 0 | } |
2170 | 0 | } else if (!strncmp(line, "Note: ", 6)) { |
2171 | 0 | console_code = GF_CONSOLE_CYAN | GF_CONSOLE_ITALIC; |
2172 | 0 | } else if (!strncmp(line, "Warning: ", 9)) { |
2173 | 0 | line_after = line_before = GF_TRUE; |
2174 | 0 | console_code = GF_CONSOLE_RED | GF_CONSOLE_BOLD; |
2175 | 0 | } else if ( ( |
2176 | 0 | ((line[0]=='-') && (line[1]==' ')) |
2177 | 0 | || ((line[0]==' ') && (line[1]=='-') && (line[2]==' ')) |
2178 | 0 | || ((line[0]==' ') && (line[1]==' ') && (line[2]=='-') && (line[3]==' ')) |
2179 | 0 | ) |
2180 | | |
2181 | | //look for ": " |
2182 | 0 | && ((tok_sep=strstr(line, ": ")) != NULL ) |
2183 | 0 | ) { |
2184 | 0 | if (!gen_doc) |
2185 | 0 | fprintf(helpout, "\t"); |
2186 | 0 | while (line[0] != '-') { |
2187 | 0 | fprintf(helpout, " "); |
2188 | 0 | line++; |
2189 | 0 | line_pos++; |
2190 | |
|
2191 | 0 | } |
2192 | 0 | fprintf(helpout, "* "); |
2193 | 0 | line_pos+=2; |
2194 | 0 | if (!gen_doc) |
2195 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_YELLOW); |
2196 | 0 | tok_sep[0] = 0; |
2197 | 0 | fprintf(helpout, "%s", line+2); |
2198 | 0 | line_pos += (u32) strlen(line+2); |
2199 | 0 | tok_sep[0] = ':'; |
2200 | 0 | line = tok_sep; |
2201 | 0 | if (!gen_doc) |
2202 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2203 | 0 | } else if (flags & (GF_PRINTARG_HIGHLIGHT_FIRST | GF_PRINTARG_OPT_DESC)) { |
2204 | 0 | char *sep = strchr(line, ' '); |
2205 | |
|
2206 | 0 | if (sep) sep[0] = 0; |
2207 | |
|
2208 | 0 | if (!gen_doc && !(flags & GF_PRINTARG_OPT_DESC) ) |
2209 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_GREEN); |
2210 | |
|
2211 | 0 | if ((gen_doc==1) && !(flags & GF_PRINTARG_OPT_DESC) ) { |
2212 | 0 | fprintf(helpout, "__%s__", line); |
2213 | 0 | line_pos += 4+ (u32) strlen(line); |
2214 | 0 | } else { |
2215 | 0 | fprintf(helpout, "%s", line); |
2216 | 0 | line_pos += (u32) strlen(line); |
2217 | 0 | } |
2218 | |
|
2219 | 0 | if (!gen_doc && !(flags & GF_PRINTARG_OPT_DESC) ) |
2220 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2221 | |
|
2222 | 0 | if (flags & GF_PRINTARG_OPT_DESC) { |
2223 | 0 | flags = 0; |
2224 | 0 | att_len = line_pos; |
2225 | 0 | } |
2226 | | |
2227 | |
|
2228 | 0 | if (sep) { |
2229 | 0 | sep[0] = ' '; |
2230 | 0 | line = sep; |
2231 | 0 | } else { |
2232 | 0 | line = NULL; |
2233 | 0 | } |
2234 | 0 | } |
2235 | 0 | if (!line) break; |
2236 | 0 | if (gen_doc==2) { |
2237 | 0 | line_before = line_after = GF_FALSE; |
2238 | 0 | } |
2239 | |
|
2240 | 0 | if (prev_has_line_after) line_before = GF_FALSE; |
2241 | 0 | prev_has_line_after = GF_FALSE; |
2242 | 0 | if (!strlen(line)) |
2243 | 0 | prev_has_line_after = GF_TRUE; |
2244 | |
|
2245 | 0 | if (line_before) { |
2246 | 0 | fprintf(helpout, "\n"); |
2247 | 0 | line_pos=0; |
2248 | 0 | } |
2249 | |
|
2250 | 0 | if (console_code != GF_CONSOLE_RESET) { |
2251 | 0 | if (gen_doc==1) { |
2252 | 0 | if (console_code & GF_CONSOLE_BOLD) { |
2253 | 0 | fprintf(helpout, "__"); |
2254 | 0 | line_pos+=2; |
2255 | 0 | } |
2256 | 0 | else if (console_code & GF_CONSOLE_ITALIC) { |
2257 | 0 | fprintf(helpout, "_"); |
2258 | 0 | line_pos++; |
2259 | 0 | } |
2260 | 0 | } else if (!gen_doc) { |
2261 | 0 | gf_sys_set_console_code(helpout, console_code); |
2262 | 0 | } |
2263 | 0 | } |
2264 | |
|
2265 | 0 | if (att_len) { |
2266 | 0 | while (att_len < LINE_OFFSET_DESCR) { |
2267 | 0 | fprintf(helpout, " "); |
2268 | 0 | att_len++; |
2269 | 0 | line_pos++; |
2270 | 0 | } |
2271 | 0 | } |
2272 | | |
2273 | |
|
2274 | 0 | if (header_string) { |
2275 | 0 | fprintf(helpout, "%s", header_string); |
2276 | 0 | line_pos += (u32) strlen(header_string); |
2277 | 0 | } |
2278 | |
|
2279 | 0 | while (line) { |
2280 | 0 | char *skip_url = NULL; |
2281 | 0 | char *link_start = NULL; |
2282 | 0 | u32 tid=0, i; |
2283 | 0 | char *next_token = NULL; |
2284 | 0 | for (i=0; i<nb_tokens; i++) { |
2285 | 0 | char *tok = strstr(line, Tokens[i].tok); |
2286 | 0 | if (!tok) continue; |
2287 | 0 | if (next_token && ((next_token-line) < (tok-line)) ) continue; |
2288 | | //check we have an end of token, otherwise consider this regular text |
2289 | 0 | if ((i == TOK_LINKSTART) || (i == TOK_OPTLINK)) { |
2290 | 0 | char *end_tok = strstr(tok, "]("); |
2291 | 0 | if (!end_tok) continue; |
2292 | 0 | } |
2293 | | |
2294 | 0 | if (i == TOK_LINKSTART) { |
2295 | 0 | if (tid == TOK_OPTLINK) continue; |
2296 | 0 | if (gen_doc!=1) { |
2297 | 0 | char *link_end; |
2298 | 0 | skip_url = strstr(tok, "]("); |
2299 | 0 | link_end = skip_url; |
2300 | 0 | if (skip_url) skip_url = strstr(skip_url, ")"); |
2301 | 0 | if (skip_url) skip_url ++; |
2302 | |
|
2303 | 0 | if (!skip_url) continue; |
2304 | 0 | link_start = tok+1; |
2305 | 0 | link_end[0] = 0; |
2306 | 0 | } else { |
2307 | 0 | continue; |
2308 | 0 | } |
2309 | 0 | } |
2310 | 0 | next_token=tok; |
2311 | 0 | tid=i; |
2312 | 0 | } |
2313 | 0 | if (next_token) { |
2314 | 0 | next_token[0]=0; |
2315 | 0 | } |
2316 | 0 | if ((gen_doc==1) && has_token) { |
2317 | 0 | if (tid==TOK_CODE) { |
2318 | 0 | fprintf(helpout, "`%s`", line); |
2319 | 0 | line_pos+=2; |
2320 | 0 | } else if (tid==TOK_ITALIC) { |
2321 | 0 | fprintf(helpout, "_%s_", line); |
2322 | 0 | line_pos+=2; |
2323 | 0 | } else if (tid==TOK_BOLD) { |
2324 | 0 | fprintf(helpout, "__%s__", line); |
2325 | 0 | line_pos+=4; |
2326 | 0 | } else { |
2327 | 0 | fprintf(helpout, "%s", line); |
2328 | 0 | } |
2329 | 0 | } else if (escape_xml) { |
2330 | 0 | char *xml_line = line; |
2331 | 0 | while (xml_line) { |
2332 | 0 | char *xml_start = strchr(xml_line, '<'); |
2333 | 0 | char *xml_end = strchr(xml_line, '>'); |
2334 | |
|
2335 | 0 | if (xml_end && (xml_start > xml_end)) xml_start = xml_end; |
2336 | 0 | else if (!xml_start && xml_end) xml_start = xml_end; |
2337 | 0 | else if (xml_start && xml_end) xml_end = NULL; |
2338 | |
|
2339 | 0 | if (xml_start) { |
2340 | 0 | u8 c = xml_start[0]; |
2341 | 0 | xml_start[0] = 0; |
2342 | 0 | fprintf(helpout, "%s", xml_line); |
2343 | 0 | fprintf(helpout, xml_end ? ">" : "<"); |
2344 | 0 | xml_start[0] = c; |
2345 | 0 | xml_line = xml_start+1; |
2346 | 0 | } else { |
2347 | 0 | fprintf(helpout, "%s", xml_line); |
2348 | 0 | break; |
2349 | 0 | } |
2350 | 0 | } |
2351 | 0 | } else if (escape_pipe) { |
2352 | 0 | char *src_line = line; |
2353 | 0 | while (src_line) { |
2354 | 0 | char *pipe_start = strchr(src_line, '|'); |
2355 | 0 | if (pipe_start && (pipe_start[1]==' ')) |
2356 | 0 | pipe_start = NULL; |
2357 | |
|
2358 | 0 | if (pipe_start) { |
2359 | 0 | pipe_start[0] = 0; |
2360 | 0 | fprintf(helpout, "%s ", src_line); |
2361 | 0 | pipe_start[0] = '|'; |
2362 | 0 | src_line = pipe_start+1; |
2363 | 0 | } else { |
2364 | 0 | fprintf(helpout, "%s", src_line); |
2365 | 0 | break; |
2366 | 0 | } |
2367 | 0 | } |
2368 | 0 | } else { |
2369 | 0 | fprintf(helpout, "%s", line); |
2370 | 0 | } |
2371 | 0 | line_pos+=(u32) strlen(line); |
2372 | |
|
2373 | 0 | if (!next_token) break; |
2374 | 0 | has_token = !has_token; |
2375 | |
|
2376 | 0 | if (!gen_doc) { |
2377 | 0 | if (has_token) { |
2378 | 0 | u32 cmd; |
2379 | 0 | if (Tokens[tid].cmd_type & 0xFFFF) { |
2380 | 0 | cmd = Tokens[tid].cmd_type; |
2381 | 0 | } else { |
2382 | 0 | cmd = Tokens[tid].cmd_type | console_code; |
2383 | 0 | } |
2384 | |
|
2385 | 0 | if (console_code&GF_CONSOLE_ITALIC) { |
2386 | 0 | if (Tokens[tid].cmd_type & GF_CONSOLE_ITALIC) { |
2387 | 0 | cmd &= ~GF_CONSOLE_ITALIC; |
2388 | 0 | cmd |= GF_CONSOLE_BOLD; |
2389 | 0 | } |
2390 | 0 | } |
2391 | 0 | else if (console_code&GF_CONSOLE_BOLD) { |
2392 | 0 | if (Tokens[tid].cmd_type & GF_CONSOLE_BOLD) { |
2393 | 0 | cmd &= ~GF_CONSOLE_BOLD; |
2394 | 0 | cmd |= GF_CONSOLE_ITALIC; |
2395 | 0 | } |
2396 | 0 | } |
2397 | 0 | gf_sys_set_console_code(helpout, cmd); |
2398 | 0 | } else { |
2399 | 0 | gf_sys_set_console_code(helpout, console_code); |
2400 | 0 | } |
2401 | 0 | } |
2402 | 0 | line = next_token + (u32) strlen(Tokens[tid].tok); |
2403 | |
|
2404 | 0 | if (skip_url) { |
2405 | 0 | if (link_start) |
2406 | 0 | fprintf(helpout, "%s", link_start); |
2407 | 0 | if (!gen_doc) |
2408 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2409 | 0 | has_token = GF_FALSE; |
2410 | 0 | line = skip_url; |
2411 | |
|
2412 | 0 | } |
2413 | |
|
2414 | 0 | if (has_token && tid==TOK_OPTLINK) { |
2415 | 0 | char *link = strchr(line, '('); |
2416 | 0 | assert(link); |
2417 | 0 | link++; |
2418 | 0 | char *end_link = strchr(line, ')'); |
2419 | 0 | if (end_link) end_link[0] = 0; |
2420 | 0 | char *end_tok = strchr(line, ']'); |
2421 | 0 | if (end_tok) end_tok[0] = 0; |
2422 | |
|
2423 | 0 | if (gen_doc==1) { |
2424 | 0 | if (!strncmp(link, "GPAC", 4)) { |
2425 | 0 | fprintf(helpout, "[-%s](gpac_general/#%s)", line, line); |
2426 | 0 | line_pos+=7 + 2*(u32)strlen(line) + (u32)strlen("gpac_general"); |
2427 | 0 | } else if (!strncmp(link, "LOG", 3)) { |
2428 | 0 | fprintf(helpout, "[-%s](core_logs/#%s)", line, line); |
2429 | 0 | line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("core_logs"); |
2430 | 0 | } else if (!strncmp(link, "CORE", 4)) { |
2431 | 0 | fprintf(helpout, "[-%s](core_options/#%s)", line, line); |
2432 | 0 | line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("core_options"); |
2433 | 0 | } else if (!strncmp(link, "CFG", 3)) { |
2434 | 0 | fprintf(helpout, "[-%s](core_config/#%s)", line, line); |
2435 | 0 | line_pos+=7 + 2*(u32)strlen(line) + (u32)strlen("core_config"); |
2436 | 0 | } else if (!strncmp(link, "MP4B_GEN", 8)) { |
2437 | 0 | fprintf(helpout, "[-%s](mp4box-gen-opts/#%s)", line, line); |
2438 | 0 | line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen("mp4box-gen-opts"); |
2439 | 0 | } else if (strlen(link)) { |
2440 | 0 | fprintf(helpout, "[-%s](%s/#%s)", line, link, line); |
2441 | 0 | line_pos+=7 + 2* (u32)strlen(line) + (u32)strlen(link); |
2442 | 0 | } else if (is_app_opts || !strcmp(line, "i") || !strcmp(line, "o") || !strcmp(line, "h")) { |
2443 | 0 | fprintf(helpout, "[-%s](#%s)", line, line); |
2444 | 0 | line_pos+=6 + 2* (u32)strlen(line); |
2445 | 0 | } else { |
2446 | | //this is a filter opt, don't print '-' |
2447 | 0 | fprintf(helpout, "[%s](#%s)", line, line); |
2448 | 0 | line_pos+=5 + 2* (u32)strlen(line); |
2449 | 0 | } |
2450 | 0 | } else { |
2451 | 0 | if (gen_doc==2) |
2452 | 0 | fprintf(helpout, ".I "); |
2453 | |
|
2454 | 0 | if (!strncmp(link, "GPAC", 4) |
2455 | 0 | || !strncmp(link, "LOG", 3) |
2456 | 0 | || !strncmp(link, "CORE", 4) |
2457 | 0 | || strlen(link) |
2458 | 0 | || !strcmp(line, "i") || !strcmp(line, "o") || !strcmp(line, "h") |
2459 | 0 | ) { |
2460 | 0 | fprintf(helpout, "-%s", line); |
2461 | 0 | line_pos+=1+ (u32)strlen(line); |
2462 | 0 | } else { |
2463 | 0 | fprintf(helpout, "%s", line); |
2464 | 0 | line_pos+= (u32)strlen(line); |
2465 | 0 | } |
2466 | 0 | if (!gen_doc) |
2467 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2468 | 0 | } |
2469 | 0 | if (!end_link) break; |
2470 | 0 | line = end_link+1; |
2471 | 0 | has_token = GF_FALSE; |
2472 | 0 | } |
2473 | 0 | } |
2474 | |
|
2475 | 0 | if (has_token && !gen_doc) |
2476 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2477 | |
|
2478 | 0 | if (footer_string) { |
2479 | 0 | fprintf(helpout, "%s", footer_string); |
2480 | 0 | line_pos += (u32) strlen(footer_string); |
2481 | 0 | } |
2482 | 0 | if (console_code != GF_CONSOLE_RESET) { |
2483 | 0 | if (gen_doc==1) { |
2484 | 0 | if (console_code & GF_CONSOLE_BOLD) { |
2485 | 0 | fprintf(helpout, "__"); |
2486 | 0 | line_pos+=2; |
2487 | 0 | } else if (console_code & GF_CONSOLE_ITALIC) { |
2488 | 0 | fprintf(helpout, "_"); |
2489 | 0 | line_pos++; |
2490 | 0 | } |
2491 | 0 | } else if (!gen_doc) { |
2492 | 0 | gf_sys_set_console_code(helpout, GF_CONSOLE_RESET); |
2493 | 0 | } |
2494 | 0 | } |
2495 | |
|
2496 | 0 | if (line_after) { |
2497 | 0 | if (gen_doc==1) fprintf(helpout, " "); |
2498 | 0 | fprintf(helpout, (flags & GF_PRINTARG_NL_TO_BR) ? "<br/>" : "\n"); |
2499 | 0 | line_pos=0; |
2500 | 0 | prev_has_line_after = GF_TRUE; |
2501 | 0 | } |
2502 | |
|
2503 | 0 | if (!next_line) break; |
2504 | 0 | next_line[0]=0; |
2505 | 0 | if (gen_doc==1) fprintf(helpout, " "); |
2506 | 0 | line = next_line+1; |
2507 | 0 | if (gen_doc==2) { |
2508 | 0 | if (line[0] != '.') |
2509 | 0 | fprintf(helpout, "\n.br\n"); |
2510 | 0 | else |
2511 | 0 | fprintf(helpout, "\n"); |
2512 | 0 | } else |
2513 | 0 | fprintf(helpout, (line[0] && (flags & GF_PRINTARG_NL_TO_BR)) ? "<br/>" : "\n"); |
2514 | 0 | line_pos=0; |
2515 | 0 | } |
2516 | 0 | } |
2517 | | |
2518 | | GF_EXPORT |
2519 | | Bool gf_strnistr(const char *text, const char *subtext, u32 subtext_len) |
2520 | 0 | { |
2521 | 0 | if (!*text || !subtext || !subtext_len) |
2522 | 0 | return GF_FALSE; |
2523 | | |
2524 | 0 | while (*text) { |
2525 | 0 | if (tolower(*text) == *subtext) { |
2526 | 0 | if (!strnicmp(text, subtext, subtext_len)) |
2527 | 0 | return GF_TRUE; |
2528 | |
|
2529 | 0 | } |
2530 | 0 | text++; |
2531 | 0 | } |
2532 | 0 | return GF_FALSE; |
2533 | 0 | } |
2534 | | |
2535 | | GF_EXPORT |
2536 | | Bool gf_sys_word_match(const char *orig, const char *dst) |
2537 | 0 | { |
2538 | 0 | s32 dist = 0; |
2539 | 0 | u32 match = 0; |
2540 | 0 | u32 i; |
2541 | 0 | u32 olen = (u32) strlen(orig); |
2542 | 0 | u32 dlen = (u32) strlen(dst); |
2543 | 0 | u32 *run; |
2544 | |
|
2545 | 0 | if ((olen>=3) && (olen<dlen) && !strncmp(orig, dst, olen)) |
2546 | 0 | return GF_TRUE; |
2547 | 0 | if ((dlen>=3) && (dlen<olen) && !strncmp(orig, dst, dlen)) |
2548 | 0 | return GF_TRUE; |
2549 | | |
2550 | 0 | if (olen*2 < dlen) { |
2551 | 0 | char *s1 = strchr(orig, ':'); |
2552 | 0 | char *s2 = strchr(dst, ':'); |
2553 | 0 | if (s1 && !s2) return GF_FALSE; |
2554 | 0 | if (!s1 && s2) return GF_FALSE; |
2555 | | |
2556 | 0 | if (gf_strnistr(dst, orig, MIN(olen, dlen))) |
2557 | 0 | return GF_TRUE; |
2558 | 0 | return GF_FALSE; |
2559 | 0 | } |
2560 | | |
2561 | 0 | if ((dlen>=3) && gf_strnistr(orig, dst, dlen)) |
2562 | 0 | return GF_TRUE; |
2563 | 0 | if ((olen>=3) && gf_strnistr(dst, orig, olen)) |
2564 | 0 | return GF_TRUE; |
2565 | | |
2566 | 0 | run = gf_malloc(sizeof(u32) * olen); |
2567 | 0 | memset(run, 0, sizeof(u32) * olen); |
2568 | |
|
2569 | 0 | for (i=0; i<dlen; i++) { |
2570 | 0 | u32 dist_char; |
2571 | 0 | u32 offset=0; |
2572 | 0 | char *pos; |
2573 | |
|
2574 | 0 | retry_char: |
2575 | 0 | pos = strchr(orig+offset, dst[i]); |
2576 | 0 | if (!pos) continue; |
2577 | 0 | dist_char = (u32) (pos - orig); |
2578 | 0 | if (!run[dist_char]) { |
2579 | 0 | run[dist_char] = i+1; |
2580 | 0 | match++; |
2581 | 0 | } else if (run[dist_char] > i) { |
2582 | 0 | run[dist_char] = i+1; |
2583 | 0 | match++; |
2584 | 0 | } else { |
2585 | | //this can be a repeated character |
2586 | 0 | offset++; |
2587 | 0 | goto retry_char; |
2588 | |
|
2589 | 0 | } |
2590 | 0 | } |
2591 | 0 | if (match*2<olen) { |
2592 | 0 | gf_free(run); |
2593 | 0 | return GF_FALSE; |
2594 | 0 | } |
2595 | | /* |
2596 | | //if 4/5 of characters are matched, suggest it |
2597 | | if (match * 5 >= 4 * dlen ) { |
2598 | | gf_free(run); |
2599 | | return GF_TRUE; |
2600 | | } |
2601 | | if ((olen<=4) && (match>=3) && (dlen*2<olen*3) ) { |
2602 | | gf_free(run); |
2603 | | return GF_TRUE; |
2604 | | } |
2605 | | */ |
2606 | 0 | for (i=0; i<olen; i++) { |
2607 | 0 | if (!i) { |
2608 | 0 | if (run[0]==1) |
2609 | 0 | dist++; |
2610 | 0 | } else if (run[i-1] + 1 == run[i]) { |
2611 | 0 | dist++; |
2612 | 0 | } |
2613 | 0 | } |
2614 | 0 | gf_free(run); |
2615 | | //if half the characters are in order, consider a match |
2616 | | //if arg is small only check dst |
2617 | 0 | if ((olen<=4) && (dist >= 2)) |
2618 | 0 | return GF_TRUE; |
2619 | 0 | if ((dist*2 >= (s32) olen) && (dist*2 >= (s32) dlen)) |
2620 | 0 | return GF_TRUE; |
2621 | 0 | return GF_FALSE; |
2622 | 0 | } |