LCOV - code coverage report
Current view: top level - utils - os_file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 425 516 82.4 %
Date: 2021-04-29 23:48:07 Functions: 58 60 96.7 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre - Copyright (c) Telecom ParisTech 2000-2020
       5             :  *                               Romain Bouqueau - Copyright (c) Romain Bouqueau 2015
       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/tools.h>
      27             : #include <gpac/utf.h>
      28             : 
      29             : #if defined(_WIN32_WCE)
      30             : 
      31             : #include <winbase.h>
      32             : #include <tlhelp32.h>
      33             : 
      34             : #elif defined(WIN32)
      35             : 
      36             : #include <windows.h>
      37             : #include <process.h>
      38             : #include <direct.h>
      39             : #include <sys/stat.h>
      40             : #include <share.h>
      41             : 
      42             : #else
      43             : 
      44             : #include <sys/stat.h>
      45             : #include <unistd.h>
      46             : #include <dirent.h>
      47             : #include <sys/time.h>
      48             : 
      49             : #ifndef __BEOS__
      50             : #include <errno.h>
      51             : #endif
      52             : 
      53             : #endif
      54             : 
      55             : 
      56             : GF_EXPORT
      57           3 : GF_Err gf_rmdir(const char *DirPathName)
      58             : {
      59             : #if defined (_WIN32_WCE)
      60             :         TCHAR swzName[MAX_PATH];
      61             :         BOOL res;
      62             :         CE_CharToWide(DirPathName, swzName);
      63             :         res = RemoveDirectory(swzName);
      64             :         if (! res) {
      65             :                 int err = GetLastError();
      66             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory \"%s\": last error %d\n", DirPathName, err ));
      67             :         }
      68             : #elif defined (WIN32)
      69             :         int res;
      70             :         wchar_t* wcsDirPathName = gf_utf8_to_wcs(DirPathName);
      71             :         if (!wcsDirPathName)
      72             :                 return GF_IO_ERR;
      73             :         res = _wrmdir(wcsDirPathName);
      74             :         gf_free(wcsDirPathName);
      75             :         if (res == -1) {
      76             :                 int err = GetLastError();
      77             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory \"%s\": last error %d\n", DirPathName, err ));
      78             :                 return GF_IO_ERR;
      79             :         }
      80             : #else
      81           3 :         int res = rmdir(DirPathName);
      82           3 :         if (res==-1) {
      83           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory \"%s\": last error %d\n", DirPathName, errno  ));
      84             :                 return GF_IO_ERR;
      85             :         }
      86             : #endif
      87             :         return GF_OK;
      88             : }
      89             : 
      90             : GF_EXPORT
      91          63 : GF_Err gf_mkdir(const char* DirPathName)
      92             : {
      93             : #if defined (_WIN32_WCE)
      94             :         TCHAR swzName[MAX_PATH];
      95             :         BOOL res;
      96             :         CE_CharToWide(DirPathName, swzName);
      97             :         res = CreateDirectory(swzName, NULL);
      98             :         if (! res) {
      99             :                 int err = GetLastError();
     100             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory \"%s\": last error %d\n", DirPathName, err ));
     101             :         }
     102             : #elif defined (WIN32)
     103             :         int res;
     104             :         wchar_t* wcsDirPathName = gf_utf8_to_wcs(DirPathName);
     105             :         if (!wcsDirPathName)
     106             :                 return GF_IO_ERR;
     107             :         res = _wmkdir(wcsDirPathName);
     108             :         gf_free(wcsDirPathName);
     109             :         if (res==-1) {
     110             :                 int err = GetLastError();
     111             :                 if (err != 183) {
     112             :                         // don't throw error if dir already exists
     113             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory \"%s\": last error %d\n", DirPathName, err));
     114             :                 }
     115             :         }
     116             : #else
     117          63 :         int res = mkdir(DirPathName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
     118          63 :         if (res==-1) {
     119           0 :                 if(errno == 17) {
     120           0 :                         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("Cannot create directory \"%s\", it already exists: last error %d \n", DirPathName, errno ));
     121             :                         return GF_OK;
     122             :                 } else {
     123           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory \"%s\": last error %d\n", DirPathName, errno ));
     124             :                         return GF_IO_ERR;
     125             :                 }
     126             :         }
     127             : #endif
     128             :         return GF_OK;
     129             : }
     130             : 
     131             : 
     132             : GF_EXPORT
     133      147408 : Bool gf_dir_exists(const char* DirPathName)
     134             : {
     135             : #if defined (_WIN32_WCE)
     136             :         TCHAR swzName[MAX_PATH];
     137             :         DWORD att;
     138             :         CE_CharToWide(DirPathName, swzName);
     139             :         att = GetFileAttributes(swzName);
     140             :         return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE;
     141             : #elif defined (WIN32)
     142             :         DWORD att;
     143             :         wchar_t* wcsDirPathName = gf_utf8_to_wcs(DirPathName);
     144             :         if (!wcsDirPathName)
     145             :                 return GF_FALSE;
     146             :         att = GetFileAttributesW(wcsDirPathName);
     147             :         gf_free(wcsDirPathName);
     148             :         return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE;
     149             : #else
     150      147408 :         DIR* dir = opendir(DirPathName);
     151      147408 :         if (!dir) return GF_FALSE;
     152       79380 :         closedir(dir);
     153       79380 :         return GF_TRUE;
     154             : #endif
     155             :         return GF_FALSE;
     156             : }
     157           2 : static Bool delete_dir(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info)
     158             : {
     159           2 :         Bool directory_clean_mode = *(Bool*)cbck;
     160             : 
     161           2 :         if(directory_clean_mode) {
     162           1 :                 gf_dir_cleanup(item_path);
     163           1 :                 gf_rmdir(item_path);
     164             :         } else {
     165           1 :                 gf_file_delete(item_path);
     166             :         }
     167           2 :         return GF_FALSE;
     168             : }
     169             : 
     170             : GF_EXPORT
     171           3 : GF_Err gf_dir_cleanup(const char* DirPathName)
     172             : {
     173             :         Bool directory_clean_mode;
     174             : 
     175           3 :         directory_clean_mode = GF_TRUE;
     176           3 :         gf_enum_directory(DirPathName, GF_TRUE, delete_dir, &directory_clean_mode, NULL);
     177           3 :         directory_clean_mode = GF_FALSE;
     178           3 :         gf_enum_directory(DirPathName, GF_FALSE, delete_dir, &directory_clean_mode, NULL);
     179             : 
     180           3 :         return GF_OK;
     181             : }
     182             : 
     183             : GF_EXPORT
     184         305 : GF_Err gf_file_delete(const char *fileName)
     185             : {
     186         305 :         if (!fileName || !fileName[0]) {
     187           1 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("gf_file_delete with no param - ignoring\n"));
     188             :                 return GF_OK;
     189             :         }
     190             : #if defined(_WIN32_WCE)
     191             :         TCHAR swzName[MAX_PATH];
     192             :         CE_CharToWide((char*)fileName, swzName);
     193             :         return (DeleteFile(swzName)==0) ? GF_IO_ERR : GF_OK;
     194             : #elif defined(WIN32)
     195             :         /* success if != 0 */
     196             :         {
     197             :                 BOOL op_result;
     198             :                 wchar_t* wcsFileName = gf_utf8_to_wcs(fileName);
     199             :                 if (!wcsFileName)
     200             :                         return GF_IO_ERR;
     201             :                 op_result = DeleteFileW(wcsFileName);
     202             :                 gf_free(wcsFileName);
     203             :                 return (op_result==0) ? GF_IO_ERR : GF_OK;
     204             :         }
     205             : #else
     206             :         /* success is == 0 */
     207         304 :         return ( remove(fileName) == 0) ? GF_OK : GF_IO_ERR;
     208             : #endif
     209             : }
     210             : 
     211             : #ifndef WIN32
     212             : /**
     213             :  * Remove existing single-quote from a single-quoted string.
     214             :  * The caller is responsible for deallocating the returns string with gf_free()
     215             :  */
     216         158 : static char* gf_sanetize_single_quoted_string(const char *src) {
     217             :         int i, j;
     218         158 :         char *out = (char*)gf_malloc(4*strlen(src)+3);
     219         158 :         out[0] = '\'';
     220        7138 :         for (i=0, j=1; (out[j]=src[i]); ++i, ++j) {
     221        6980 :                 if (src[i]=='\'') {
     222           0 :                         out[++j]='\\';
     223           0 :                         out[++j]='\'';
     224           0 :                         out[++j]='\'';
     225             :                 }
     226             :         }
     227         158 :         out[j++] = '\'';
     228         158 :         out[j++] = 0;
     229         158 :         return out;
     230             : }
     231             : #endif
     232             : 
     233             : #if defined(GPAC_CONFIG_IOS) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
     234             : #include <spawn.h>
     235             : extern char **environ;
     236             : #endif
     237             : 
     238             : #if defined(WIN32)
     239             : #include <io.h>
     240             : #endif
     241             : 
     242             : GF_EXPORT
     243       78914 : Bool gf_file_exists_ex(const char *fileName, const char *par_name)
     244             : {
     245             :         u32 gfio_type = 0;
     246       78914 :         if (!fileName) return GF_FALSE;
     247             : 
     248       78914 :         if (!strncmp(fileName, "gfio://", 7))
     249             :                 gfio_type = 1;
     250       78914 :         else if (par_name && !strncmp(par_name, "gfio://", 7))
     251             :                 gfio_type = 2;
     252             : 
     253             :         if (gfio_type) {
     254             :                 GF_FileIO *gfio_ref;
     255             :                 GF_FileIO *new_gfio;
     256             :                 GF_Err e;
     257             :                 Bool res = GF_TRUE;
     258           0 :                 if (gfio_type==1)
     259           0 :                         gfio_ref = gf_fileio_from_url(fileName);
     260             :                 else
     261           0 :                         gfio_ref = gf_fileio_from_url(par_name);
     262             : 
     263           0 :                 if (!gfio_ref) return GF_FALSE;
     264           0 :                 new_gfio = gf_fileio_open_url(gfio_ref, fileName, "probe", &e);
     265           0 :                 if (e==GF_URL_ERROR)
     266             :                         res = GF_FALSE;
     267           0 :                 if (new_gfio)
     268           0 :                         gf_fileio_open_url(new_gfio, NULL, "r", &e);
     269             :                 return res;
     270             :         }
     271             : 
     272             : #if defined(WIN32)
     273             :         Bool res;
     274             :         wchar_t* wname = gf_utf8_to_wcs(fileName);
     275             :         if (!wname) return GF_FALSE;
     276             :         res = (_waccess(wname, 4) == -1) ? GF_FALSE : GF_TRUE;
     277             :         if (res == GF_TRUE) {
     278             :                 DWORD att;
     279             :                 att = GetFileAttributesW(wname);
     280             :                 if (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY))
     281             :                         res = GF_FALSE;
     282             :         }
     283             :         gf_free(wname);
     284             :         return res;
     285             : #elif defined(GPAC_CONFIG_LINUX)
     286       78914 :         Bool res = (access(fileName, 4) == -1) ? GF_FALSE : GF_TRUE;
     287       78914 :         if (res && gf_dir_exists(fileName))
     288             :                 res = GF_FALSE;
     289             :         return res;
     290             : #elif defined(__DARWIN__) || defined(__APPLE__)
     291             :         Bool res = (access(fileName, 4) == -1) ? GF_FALSE : GF_TRUE;
     292             :         if (res && gf_dir_exists(fileName))
     293             :                 res = GF_FALSE;
     294             :         return res;
     295             : #elif defined(GPAC_CONFIG_IOS) || defined(GPAC_CONFIG_ANDROID)
     296             :         Bool res = (access(fileName, 4) == -1) ? GF_FALSE : GF_TRUE;
     297             :         if (res && gf_dir_exists(fileName))
     298             :                 res = GF_FALSE;
     299             :         return res;
     300             : #else
     301             :         FILE *f = gf_fopen(fileName, "r");
     302             :         if (f) {
     303             :                 gf_fclose(f);
     304             :                 return GF_TRUE;
     305             :         }
     306             :         return GF_FALSE;
     307             : #endif
     308             : }
     309             : 
     310             : GF_EXPORT
     311       78858 : Bool gf_file_exists(const char *fileName)
     312             : {
     313       78858 :         return gf_file_exists_ex(fileName, NULL);
     314             : }
     315             : 
     316             : GF_EXPORT
     317          79 : GF_Err gf_file_move(const char *fileName, const char *newFileName)
     318             : {
     319             : #if defined(_WIN32_WCE)
     320             :         GF_Err e = GF_OK;
     321             :         TCHAR swzName[MAX_PATH];
     322             :         TCHAR swzNewName[MAX_PATH];
     323             :         CE_CharToWide((char*)fileName, swzName);
     324             :         CE_CharToWide((char*)newFileName, swzNewName);
     325             :         if (MoveFile(swzName, swzNewName) == 0 )
     326             :                 e = GF_IO_ERR;
     327             : #elif defined(WIN32)
     328             :         GF_Err e = GF_OK;
     329             :         /* success if != 0 */
     330             :         BOOL op_result;
     331             :         wchar_t* wcsFileName = gf_utf8_to_wcs(fileName);
     332             :         wchar_t* wcsNewFileName = gf_utf8_to_wcs(newFileName);
     333             :         if (!wcsFileName || !wcsNewFileName) {
     334             :                 if (wcsFileName) gf_free(wcsFileName);
     335             :                 if (wcsNewFileName) gf_free(wcsNewFileName);
     336             :                 e = GF_IO_ERR;
     337             :         } else {
     338             :                 op_result = MoveFileW(wcsFileName, wcsNewFileName);
     339             :                 gf_free(wcsFileName);
     340             :                 gf_free(wcsNewFileName);
     341             :                 if ( op_result == 0 )
     342             :                         e = GF_IO_ERR;
     343             :         }
     344             : #else
     345             :         GF_Err e = GF_IO_ERR;
     346             :         char cmd[1024], *arg1, *arg2;
     347          79 :         if (!fileName || !newFileName) {
     348             :                 e = GF_IO_ERR;
     349             :         } else {
     350          79 :                 arg1 = gf_sanetize_single_quoted_string(fileName);
     351          79 :                 arg2 = gf_sanetize_single_quoted_string(newFileName);
     352          79 :                 if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error;
     353             : 
     354             : #if defined(GPAC_CONFIG_IOS) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
     355             :                 {
     356             :                         pid_t pid;
     357             :                         char *argv[3];
     358             :                         argv[0] = "mv";
     359             :                         argv[1] = cmd;
     360             :                         argv[2] = NULL;
     361             :                         posix_spawn(&pid, argv[0], NULL, NULL, argv, environ);
     362             :                         waitpid(pid, NULL, 0);
     363             :                 }
     364             : #else
     365          79 :                 e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR;
     366             : #endif
     367             : 
     368          79 : error:
     369          79 :                 gf_free(arg1);
     370          79 :                 gf_free(arg2);
     371             :         }
     372             : #endif
     373             : 
     374          79 :         if (e) {
     375           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] Failed to move file %s to %s: %s\n", fileName, newFileName, gf_error_to_string(e) ));
     376             :         }
     377          79 :         return e;
     378             : }
     379             : 
     380             : GF_EXPORT
     381         357 : u64 gf_file_modification_time(const char *filename)
     382             : {
     383             : #if defined(_WIN32_WCE)
     384             :         WCHAR _file[GF_MAX_PATH];
     385             :         WIN32_FIND_DATA FindData;
     386             :         HANDLE fh;
     387             :         ULARGE_INTEGER uli;
     388             :         ULONGLONG time_ms;
     389             :         BOOL ret;
     390             :         CE_CharToWide((char *) filename, _file);
     391             :         fh = FindFirstFile(_file, &FindData);
     392             :         if (fh == INVALID_HANDLE_VALUE) return 0;
     393             :         uli.LowPart = FindData.ftLastWriteTime.dwLowDateTime;
     394             :         uli.HighPart = FindData.ftLastWriteTime.dwHighDateTime;
     395             :         ret = FindClose(fh);
     396             :         if (!ret) {
     397             :                 DWORD err = GetLastError();
     398             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_file_modification_time() returned the following error code: %d\n", err));
     399             :         }
     400             :         time_ms = uli.QuadPart/10000;
     401             :         return time_ms;
     402             : #elif defined(WIN32) && !defined(__GNUC__)
     403             :         struct _stat64 sb;
     404             :         int op_result;
     405             :         wchar_t* wcsFilename = gf_utf8_to_wcs(filename);
     406             :         if (!wcsFilename)
     407             :                 return 0;
     408             :         op_result = _wstat64(wcsFilename, &sb);
     409             :         gf_free(wcsFilename);
     410             :         if (op_result != 0) return 0;
     411             :         return sb.st_mtime;
     412             : #else
     413             :         struct stat sb;
     414         357 :         if (stat(filename, &sb) != 0) return 0;
     415         357 :         return sb.st_mtime;
     416             : #endif
     417             :         return 0;
     418             : }
     419             : 
     420             : #include <gpac/list.h>
     421             : extern int gf_mem_track_enabled;
     422             : static  GF_List * gpac_open_files = NULL;
     423             : 
     424             : typedef struct
     425             : {
     426             :         FILE *ptr;
     427             :         char *url;
     428             :         Bool is_temp;
     429             : } GF_FileHandle;
     430             : 
     431             : static u32 gpac_file_handles = 0;
     432             : 
     433             : 
     434             : 
     435             : GF_EXPORT
     436        6147 : u32 gf_file_handles_count()
     437             : {
     438             : #ifdef GPAC_MEMORY_TRACKING
     439        6147 :         if (gpac_open_files) {
     440           1 :                 return gf_list_count(gpac_open_files);
     441             :         }
     442             : #endif
     443        6146 :         return gpac_file_handles;
     444             : }
     445             : 
     446             : #ifdef GPAC_MEMORY_TRACKING
     447           2 : const char *enum_open_handles(u32 *idx)
     448             : {
     449             :         GF_FileHandle *h;
     450           2 :         u32 count = gf_list_count(gpac_open_files);
     451           2 :         if (*idx >= count) return NULL;
     452           1 :         h = gf_list_get(gpac_open_files, *idx);
     453           1 :         (*idx)++;
     454           1 :         return h->url;
     455             : }
     456             : #endif
     457             : 
     458       58620 : static void gf_register_file_handle(char *filename, FILE *ptr, Bool is_temp_file)
     459             : {
     460       58620 :         if (is_temp_file
     461             : #ifdef GPAC_MEMORY_TRACKING
     462       58620 :                 || gf_mem_track_enabled
     463             : #endif
     464             :         ) {
     465             :                 GF_FileHandle *h;
     466       58469 :                 if (!gpac_open_files) gpac_open_files = gf_list_new();
     467       58469 :                 GF_SAFEALLOC(h, GF_FileHandle);
     468       58469 :                 if (h) {
     469       58469 :                         h->ptr = ptr;
     470       58469 :                         if (is_temp_file) {
     471           0 :                                 h->is_temp = GF_TRUE;
     472           0 :                                 h->url = filename;
     473             :                         } else {
     474       58469 :                                 h->url = gf_strdup(filename);
     475             :                         }
     476       58469 :                         gf_list_add(gpac_open_files, h);
     477             :                 }
     478             :         }
     479       58620 :         gpac_file_handles++;
     480       58620 : }
     481             : 
     482             : #include <gpac/thread.h>
     483             : extern GF_Mutex *logs_mx;
     484             : 
     485       58615 : static Bool gf_unregister_file_handle(FILE *ptr)
     486             : {
     487             :         u32 i, count;
     488             :         Bool res = GF_FALSE;
     489             :         assert(gpac_file_handles);
     490       58615 :         gpac_file_handles--;
     491             : 
     492       58615 :         if (!gpac_open_files)
     493             :                 return GF_FALSE;
     494             : 
     495       58464 :         gf_mx_p(logs_mx);
     496       58464 :         count = gf_list_count(gpac_open_files);
     497      155400 :         for (i=0; i<count; i++) {
     498      155400 :                 GF_FileHandle *h = gf_list_get(gpac_open_files, i);
     499      155400 :                 if (h->ptr != ptr) continue;
     500             : 
     501       58464 :                 if (h->is_temp) {
     502             :                         GF_Err e;
     503           0 :                         fclose(h->ptr);
     504           0 :                         e = gf_file_delete(h->url);
     505           0 :                         if (e) {
     506           0 :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Core] Failed to delete temp file %s: %s\n", h->url, gf_error_to_string(e)));
     507             :                         }
     508             :                         res = GF_TRUE;
     509             :                 }
     510       58464 :                 gf_free(h->url);
     511       58464 :                 gf_free(h);
     512       58464 :                 gf_list_rem(gpac_open_files, i);
     513       58464 :                 if (!gf_list_count(gpac_open_files)) {
     514       29800 :                         gf_list_del(gpac_open_files);
     515       29800 :                         gpac_open_files = NULL;
     516             :                 }
     517             :                 break;
     518             :         }
     519       58464 :         gf_mx_v(logs_mx);
     520       58464 :         return res;
     521             : }
     522             : 
     523        2778 : static FILE *gf_file_temp_os(char ** const fileName)
     524             : {
     525             :         FILE *res;
     526             : #if defined(_WIN32_WCE)
     527             :         TCHAR pPath[MAX_PATH+1];
     528             :         TCHAR pTemp[MAX_PATH+1];
     529             :         res = NULL;
     530             :         if (!GetTempPath(MAX_PATH, pPath)) {
     531             :                 pPath[0] = '.';
     532             :                 pPath[1] = '.';
     533             :         }
     534             :         if (GetTempFileName(pPath, TEXT("git"), 0, pTemp))
     535             :                 res = _wfopen(pTemp, TEXT("w+b"));
     536             : #elif defined(WIN32)
     537             :         res = tmpfile();
     538             : 
     539             :         if (!res) {
     540             :                 wchar_t tmp[MAX_PATH];
     541             : 
     542             :                 GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Win32] system failure for tmpfile(): 0x%08x\n", GetLastError()));
     543             : 
     544             :                 /*tmpfile() may fail under vista ...*/
     545             :                 if (GetEnvironmentVariableW(L"TEMP", tmp, MAX_PATH)) {
     546             :                         wchar_t tmp2[MAX_PATH], *t_file;
     547             :                         char* mbs_t_file;
     548             :                         gf_rand_init(GF_FALSE);
     549             :                         swprintf(tmp2, MAX_PATH, L"gpac_%d_%08x_", _getpid(), gf_rand());
     550             :                         t_file = _wtempnam(tmp, tmp2);
     551             :                         mbs_t_file = gf_wcs_to_utf8(t_file);
     552             :                         if (!mbs_t_file)
     553             :                                 return 0;
     554             :                         res = gf_fopen(mbs_t_file, "w+b");
     555             :                         if (res) {
     556             :                                 gf_unregister_file_handle(res);
     557             :                                 if (fileName) {
     558             :                                         *fileName = gf_strdup(mbs_t_file);
     559             :                                 } else {
     560             :                                         GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Win32] temporary file \"%s\" won't be deleted - contact the GPAC team\n", mbs_t_file));
     561             :                                 }
     562             :                         }
     563             :                         gf_free(mbs_t_file);
     564             :                         free(t_file);
     565             :                 }
     566             :         }
     567             : #else
     568        2778 :         res = tmpfile();
     569             : #endif
     570             : 
     571        2778 :         if (res) {
     572        2778 :                 gf_register_file_handle("temp file", res, GF_FALSE);
     573             :         }
     574        2778 :         return res;
     575             : }
     576             : 
     577             : GF_EXPORT
     578        2778 : FILE *gf_file_temp(char ** const fileName)
     579             : {
     580        2778 :         const char *tmp_dir = gf_opts_get_key("core", "tmp");
     581             : 
     582        2778 :         if (tmp_dir && tmp_dir[0]) {
     583             :                 FILE *res;
     584           0 :                 char *opath=NULL, szFName[100];
     585           0 :                 u32 len = (u32) strlen(tmp_dir);
     586             : 
     587           0 :                 gf_dynstrcat(&opath, tmp_dir, NULL);
     588           0 :                 if (!strchr("/\\", tmp_dir[len-1]))
     589           0 :                         gf_dynstrcat(&opath, "/", NULL);
     590           0 :                 if (!opath) return NULL;
     591             : 
     592           0 :                 sprintf(szFName, "_libgpac_%d_%p_"LLU"_%d", gf_sys_get_process_id(), opath, gf_sys_clock_high_res(), gf_rand() );
     593           0 :                 gf_dynstrcat(&opath, szFName, NULL);
     594           0 :                 if (fileName) {
     595             :                         sprintf(szFName, "%p", fileName);
     596           0 :                         gf_dynstrcat(&opath, szFName, "_");
     597             :                 }
     598             : 
     599           0 :                 if (gf_file_exists(opath)) {
     600           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Something went wrong creating temp file path %s, file already exists !\n", opath));
     601           0 :                         gf_free(opath);
     602           0 :                         return NULL;
     603             :                 }
     604           0 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Opening new temp file %s\n", opath));
     605           0 :                 res = gf_fopen_ex(opath, "__temp_file", "w+b");
     606           0 :                 if (!res) {
     607           0 :                         gf_free(opath);
     608           0 :                         return NULL;
     609             :                 }
     610           0 :                 gf_register_file_handle(opath, res, GF_TRUE);
     611           0 :                 return res;
     612             :         }
     613        2778 :         return gf_file_temp_os(fileName);
     614             : }
     615             : 
     616             : 
     617             : /*enumerate directories*/
     618             : GF_EXPORT
     619       20106 : GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter)
     620             : {
     621             : #ifdef WIN32
     622             :         wchar_t item_path[GF_MAX_PATH];
     623             : #else
     624             :         char item_path[GF_MAX_PATH];
     625             : #endif
     626             :         GF_FileEnumInfo file_info;
     627             : 
     628             : #if defined(_WIN32_WCE)
     629             :         char _path[GF_MAX_PATH];
     630             :         unsigned short path[GF_MAX_PATH];
     631             :         unsigned short w_filter[GF_MAX_PATH];
     632             :         char file[GF_MAX_PATH];
     633             : #elif defined(WIN32)
     634             :         wchar_t path[GF_MAX_PATH], *file;
     635             :         wchar_t w_filter[GF_MAX_PATH];
     636             :         char *mbs_file, *mbs_item_path;
     637             :         char _path[GF_MAX_PATH];
     638             :         const char* tmpdir;
     639             : #else
     640             :         char path[GF_MAX_PATH], *file;
     641             : #endif
     642             : 
     643             : #ifdef WIN32
     644             :         WIN32_FIND_DATAW FindData;
     645             :         HANDLE SearchH;
     646             : #else
     647             :         DIR *the_dir;
     648             :         struct dirent* the_file;
     649             :         struct stat st;
     650             : #endif
     651             : 
     652       20106 :         if (!dir || !enum_dir_fct) return GF_BAD_PARAM;
     653             : 
     654       20106 :         if (filter && (!strcmp(filter, "*") || !filter[0])) filter=NULL;
     655             : 
     656             :         memset(&file_info, 0, sizeof(GF_FileEnumInfo) );
     657             : 
     658             :         if (!strcmp(dir, "/")) {
     659             : #if defined(WIN32) && !defined(_WIN32_WCE)
     660             :                 u32 len;
     661             :                 char *drives, *volume;
     662             :                 len = GetLogicalDriveStrings(0, NULL);
     663             :                 drives = (char*)gf_malloc(sizeof(char)*(len+1));
     664             :                 drives[0]=0;
     665             :                 GetLogicalDriveStrings(len, drives);
     666             :                 len = (u32) strlen(drives);
     667             :                 volume = drives;
     668             :                 file_info.directory = GF_TRUE;
     669             :                 file_info.drive = GF_TRUE;
     670             :                 while (len) {
     671             :                         enum_dir_fct(cbck, volume, "", &file_info);
     672             :                         volume += len+1;
     673             :                         len = (u32) strlen(volume);
     674             :                 }
     675             :                 gf_free(drives);
     676             :                 return GF_OK;
     677             : #elif defined(__SYMBIAN32__)
     678             :                 RFs iFs;
     679             :                 TDriveList aList;
     680             :                 iFs.Connect();
     681             :                 iFs.DriveList(aList);
     682             :                 for (TInt i=0; i<KMaxDrives; i++) {
     683             :                         if (aList[i]) {
     684             :                                 char szDrive[10];
     685             :                                 TChar aDrive;
     686             :                                 iFs.DriveToChar(i, aDrive);
     687             :                                 sprintf(szDrive, "%c:", (TUint)aDrive);
     688             :                                 enum_dir_fct(cbck, szDrive, "", &file_info);
     689             :                         }
     690             :                 }
     691             :                 iFs.Close();
     692             :                 FlushItemList();
     693             :                 return GF_OK;
     694             : #elif defined(GPAC_CONFIG_ANDROID)
     695             :                 dir = getenv("EXTERNAL_STORAGE");
     696             :                 if (!dir) dir = "/sdcard";
     697             : #elif defined(GPAC_CONFIG_IOS)
     698             :                 dir = (char *) gf_opts_get_key("General", "iOSDocumentsDir");
     699             : #endif
     700             :         }
     701             : 
     702             : 
     703             : #if defined (_WIN32_WCE)
     704             :         switch (dir[strlen(dir) - 1]) {
     705             :         case '/':
     706             :         case '\\':
     707             :                 sprintf(_path, "%s*", dir);
     708             :                 break;
     709             :         default:
     710             :                 sprintf(_path, "%s%c*", dir, GF_PATH_SEPARATOR);
     711             :                 break;
     712             :         }
     713             :         CE_CharToWide(_path, path);
     714             :         CE_CharToWide((char *)filter, w_filter);
     715             : #elif defined(WIN32)
     716             : 
     717             :         strcpy(_path, dir);
     718             :         switch (dir[strlen(dir)] - 1) {
     719             :         case '/':
     720             :         case '\\':
     721             :                 snprintf(_path, MAX_PATH, "%s*", dir);
     722             :                 break;
     723             :         default:
     724             :                 snprintf(_path, MAX_PATH, "%s%c*", dir, GF_PATH_SEPARATOR);
     725             :                 break;
     726             :         }
     727             : 
     728             :         tmpdir = _path;
     729             :         if (gf_utf8_mbstowcs(path, GF_MAX_PATH, &tmpdir) == (size_t)-1) {
     730             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot convert %s to UTF16: broken string\n", dir));
     731             :                 return GF_BAD_PARAM;
     732             :         }
     733             :         tmpdir  = filter;
     734             :         if (gf_utf8_mbstowcs(w_filter, sizeof(w_filter), &tmpdir) == (size_t)-1) {
     735             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot convert %s to UTF16: broken string\n", filter));
     736             :                 return GF_BAD_PARAM;
     737             :         }
     738             : 
     739             : #else
     740             :         strcpy(path, dir);
     741       20106 :         if (path[strlen(path)-1] != '/') strcat(path, "/");
     742             : #endif
     743             : 
     744             : #ifdef WIN32
     745             :         SearchH= FindFirstFileW(path, &FindData);
     746             :         if (SearchH == INVALID_HANDLE_VALUE) return GF_IO_ERR;
     747             : 
     748             : #if defined (_WIN32_WCE)
     749             :         _path[strlen(_path)-1] = 0;
     750             : #else
     751             :         path[wcslen(path)-1] = 0;
     752             : #endif
     753             : 
     754             :         while (SearchH != INVALID_HANDLE_VALUE) {
     755             : 
     756             : #else
     757             : 
     758       20106 :         the_dir = opendir(path);
     759       20106 :         if (the_dir == NULL) {
     760           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open directory \"%s\" for enumeration: %d\n", path, errno));
     761             :                 return GF_IO_ERR;
     762             :         }
     763       20106 :         the_file = readdir(the_dir);
     764      106804 :         while (the_file) {
     765             : 
     766             : #endif
     767             : 
     768             :                 memset(&file_info, 0, sizeof(GF_FileEnumInfo) );
     769             : 
     770             : 
     771             : #if defined (_WIN32_WCE)
     772             :                 if (!wcscmp(FindData.cFileName, _T(".") )) goto next;
     773             :                 if (!wcscmp(FindData.cFileName, _T("..") )) goto next;
     774             : #elif defined(WIN32)
     775             :                 if (!wcscmp(FindData.cFileName, L".")) goto next;
     776             :                 if (!wcscmp(FindData.cFileName, L"..")) goto next;
     777             : #else
     778       79044 :                 if (!strcmp(the_file->d_name, "..")) goto next;
     779       71390 :                 if (the_file->d_name[0] == '.') goto next;
     780             : #endif
     781             : 
     782             : #ifdef WIN32
     783             :                 file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE;
     784             :                 if (!enum_directory && file_info.directory) goto next;
     785             :                 if (enum_directory && !file_info.directory) goto next;
     786             : #endif
     787             : 
     788       63725 :                 if (filter) {
     789             : #if defined (_WIN32_WCE)
     790             :                         short ext[30];
     791             :                         short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.');
     792             :                         short *found_ext;
     793             :                         u32 ext_len;
     794             :                         if (!sep) goto next;
     795             :                         wcscpy(ext, sep+1);
     796             :                         wcslwr(ext);
     797             :                         ext_len = (u32) wcslen(ext);
     798             :                         found_ext = wcsstr(w_filter, ext);
     799             :                         if (!found_ext) goto next;
     800             :                         if (found_ext[ext_len] && (found_ext[ext_len] != (wchar_t) ';')) goto next;
     801             : #elif defined(WIN32)
     802             :                         wchar_t ext[30];
     803             :                         wchar_t *sep = wcsrchr(FindData.cFileName, L'.');
     804             :                         wchar_t *found_ext;
     805             :                         u32 ext_len;
     806             :                         if (!sep) goto next;
     807             :                         wcscpy(ext, sep+1);
     808             :                         wcslwr(ext);
     809             :                         ext_len = (u32) wcslen(ext);
     810             :                         found_ext = wcsstr(w_filter, ext);
     811             :                         if (!found_ext) goto next;
     812             :                         if (found_ext[ext_len] && (found_ext[ext_len] != L';')) goto next;
     813             : #else
     814             :                         char ext[30];
     815       33650 :                         char *sep = strrchr(the_file->d_name, '.');
     816             :                         char *found_ext;
     817             :                         u32 ext_len;
     818       33650 :                         if (!sep) goto next;
     819       31926 :                         strcpy(ext, sep+1);
     820       31926 :                         strlwr(ext);
     821       31926 :                         ext_len = (u32) strlen(ext);
     822       31926 :                         found_ext = strstr(filter, ext);
     823       31926 :                         if (!found_ext) goto next;
     824       31878 :                         if (found_ext[ext_len] && (found_ext[ext_len]!=';')) goto next;
     825             : #endif
     826             :                 }
     827             : 
     828             : #if defined(WIN32)
     829             :                 file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? GF_TRUE : GF_FALSE;
     830             :                 file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? GF_TRUE : GF_FALSE;
     831             :                 file_info.size = MAXDWORD;
     832             :                 file_info.size += 1;
     833             :                 file_info.size *= FindData.nFileSizeHigh;
     834             :                 file_info.size += FindData.nFileSizeLow;
     835             :                 file_info.last_modified = (u64) ((*(LONGLONG *) &FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
     836             : #endif
     837             : 
     838             : #if defined (_WIN32_WCE)
     839             :                 CE_WideToChar(FindData.cFileName, file);
     840             :                 strcpy(item_path, _path);
     841             :                 strcat(item_path, file);
     842             : #elif defined(WIN32)
     843             :                 wcscpy(item_path, path);
     844             :                 wcscat(item_path, FindData.cFileName);
     845             :                 file = FindData.cFileName;
     846             : #else
     847             :                 strcpy(item_path, path);
     848             :                 strcat(item_path, the_file->d_name);
     849       61953 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file \"%s\" for enum\n", item_path));
     850             : 
     851       61953 :                 if (stat( item_path, &st ) != 0) goto next;
     852             : 
     853       61953 :                 file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE;
     854       61953 :                 if (enum_directory && !file_info.directory) goto next;
     855       49256 :                 if (!enum_directory && file_info.directory) goto next;
     856             : 
     857       48790 :                 file_info.size = st.st_size;
     858             : 
     859             :                 {
     860       48790 :                         struct tm _t = * gf_gmtime(& st.st_mtime);
     861       48790 :                         file_info.last_modified = mktime(&_t);
     862             :                 }
     863             :                 file = the_file->d_name;
     864       48790 :                 if (file && file[0]=='.') file_info.hidden = 1;
     865             : 
     866       48790 :                 if (file_info.directory) {
     867        1774 :                         char * parent_name = strrchr(item_path, '/');
     868        1774 :                         if (!parent_name) {
     869           0 :                                 file_info.drive = GF_TRUE;
     870             :                         } else {
     871             :                                 struct stat st_parent;
     872        1774 :                                 parent_name[0] = 0;
     873        1774 :                                 if (stat(item_path, &st_parent) == 0)  {
     874        1753 :                                         if ((st.st_dev != st_parent.st_dev) || (st.st_ino == st_parent.st_ino) ) {
     875           0 :                                                 file_info.drive = GF_TRUE;
     876             :                                         }
     877             :                                 }
     878        1774 :                                 parent_name[0] = '/';
     879             :                         }
     880             :                 }
     881             : #endif
     882             : 
     883             : #ifdef WIN32
     884             :                 mbs_file = gf_wcs_to_utf8(file);
     885             :                 mbs_item_path = gf_wcs_to_utf8(item_path);
     886             :                 if (!mbs_file || !mbs_item_path)
     887             :                 {
     888             :                         if (mbs_file) gf_free(mbs_file);
     889             :                         if (mbs_item_path) gf_free(mbs_item_path);
     890             :                         return GF_IO_ERR;
     891             :                 }
     892             :                 if (enum_dir_fct(cbck, mbs_file, mbs_item_path, &file_info)) {
     893             :                         BOOL ret = FindClose(SearchH);
     894             :                         if (!ret) {
     895             :                                 DWORD err = GetLastError();
     896             :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err));
     897             :                         }
     898             : #else
     899       48790 :                 if (enum_dir_fct(cbck, file, item_path, &file_info)) {
     900             : #endif
     901             :                         break;
     902             :                 }
     903             : 
     904             : #ifdef WIN32
     905             :                 gf_free(mbs_file);
     906             :                 gf_free(mbs_item_path);
     907             : #endif
     908             : 
     909       64820 : next:
     910             : #ifdef WIN32
     911             :                 if (!FindNextFileW(SearchH, &FindData)) {
     912             :                         BOOL ret = FindClose(SearchH);
     913             :                         if (!ret) {
     914             :                                 DWORD err = GetLastError();
     915             :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err));
     916             :                         }
     917             :                         break;
     918             :                 }
     919             : #else
     920       66592 :                 the_file = readdir(the_dir);
     921             : #endif
     922             :         }
     923             : #ifndef WIN32
     924       20106 :         closedir(the_dir);
     925             : #endif
     926       20106 :         return GF_OK;
     927             : }
     928             : 
     929             : 
     930             : 
     931             : struct __gf_file_io
     932             : {
     933             :         u32 _reserved_null;
     934             :         void *__this;
     935             : 
     936             :         GF_FileIO * (*open)(GF_FileIO *fileio_ref, const char *url, const char *mode, GF_Err *out_error);
     937             :         GF_Err (*seek)(GF_FileIO *fileio, u64 offset, s32 whence);
     938             :         u32 (*read)(GF_FileIO *fileio, u8 *buffer, u32 bytes);
     939             :         u32 (*write)(GF_FileIO *fileio, u8 *buffer, u32 bytes);
     940             :         s64 (*tell)(GF_FileIO *fileio);
     941             :         Bool (*eof)(GF_FileIO *fileio);
     942             :         int (*printf)(GF_FileIO *gfio, const char *format, va_list args);
     943             : 
     944             :         char *url;
     945             :         char *res_url;
     946             :         void *udta;
     947             : 
     948             :         u64 bytes_done, file_size_plus_one;
     949             :         Bool cache_complete;
     950             :         u32 bytes_per_sec;
     951             : 
     952             :         u32 printf_alloc;
     953             :         u8* printf_buf;
     954             : };
     955             : 
     956             : GF_EXPORT
     957    17136211 : Bool gf_fileio_check(FILE *fp)
     958             : {
     959             :         GF_FileIO *fio = (GF_FileIO *)fp;
     960    17136211 :         if ((fp==stdin) || (fp==stderr) || (fp==stdout))
     961             :                 return GF_FALSE;
     962             : 
     963    16873451 :         if (fio && !fio->_reserved_null && (fio->__this==fio))
     964             :                 return GF_TRUE;
     965    16869020 :         return GF_FALSE;
     966             : }
     967             : 
     968             : typedef struct
     969             : {
     970             :         u8 *data;
     971             :         u32 size;
     972             :         u32 pos;
     973             : } GF_FileIOBlob;
     974             : 
     975          10 : static GF_FileIO *gfio_blob_open(GF_FileIO *fileio_ref, const char *url, const char *mode, GF_Err *out_error)
     976             : {
     977          10 :         GF_FileIOBlob *blob = gf_fileio_get_udta(fileio_ref);
     978          10 :         if (!url) {
     979          10 :                 gf_free(blob);
     980          10 :                 gf_fileio_del(fileio_ref);
     981             :         }
     982          10 :         return NULL;
     983             : }
     984             : 
     985          14 : static GF_Err gfio_blob_seek(GF_FileIO *fileio, u64 offset, s32 whence)
     986             : {
     987          14 :         GF_FileIOBlob *blob = gf_fileio_get_udta(fileio);
     988          14 :         if (whence==SEEK_END) blob->pos = blob->size;
     989          11 :         else if (whence==SEEK_SET) blob->pos = 0;
     990             :         else {
     991           0 :                 if (blob->pos + offset > blob->size) return GF_BAD_PARAM;
     992           0 :                 blob->pos += (u32) offset;
     993             :         }
     994             :         return GF_OK;
     995             : }
     996        1587 : static u32 gfio_blob_read(GF_FileIO *fileio, u8 *buffer, u32 bytes)
     997             : {
     998        1587 :         GF_FileIOBlob *blob = gf_fileio_get_udta(fileio);
     999        1587 :         if (bytes + blob->pos > blob->size)
    1000           4 :                 bytes = blob->size - blob->pos;
    1001        1587 :         if (bytes) {
    1002        1585 :                 memcpy(buffer, blob->data+blob->pos, bytes);
    1003        1585 :                 blob->pos += bytes;
    1004             :         }
    1005        1587 :         return bytes;
    1006             : }
    1007          29 : static s64 gfio_blob_tell(GF_FileIO *fileio)
    1008             : {
    1009          29 :         GF_FileIOBlob *blob = gf_fileio_get_udta(fileio);
    1010          29 :         return (s64) blob->pos;
    1011             : }
    1012          56 : static Bool gfio_blob_eof(GF_FileIO *fileio)
    1013             : {
    1014          56 :         GF_FileIOBlob *blob = gf_fileio_get_udta(fileio);
    1015          56 :         if (blob->pos==blob->size) return GF_TRUE;
    1016          54 :         return GF_FALSE;
    1017             : }
    1018             : 
    1019             : GF_EXPORT
    1020          37 : GF_FileIO *gf_fileio_new(char *url, void *udta,
    1021             :         gfio_open_proc open,
    1022             :         gfio_seek_proc seek,
    1023             :         gfio_read_proc read,
    1024             :         gfio_write_proc write,
    1025             :         gfio_tell_proc tell,
    1026             :         gfio_eof_proc eof,
    1027             :         gfio_printf_proc printf)
    1028             : {
    1029             :         char szURL[100];
    1030             :         GF_FileIO *tmp;
    1031             : 
    1032          37 :         if (!open || !seek || !tell || !eof) return NULL;
    1033             : 
    1034          37 :         if (!write && !read) return NULL;
    1035          37 :         GF_SAFEALLOC(tmp, GF_FileIO);
    1036          37 :         if (!tmp) return NULL;
    1037             : 
    1038          37 :         tmp->open = open;
    1039          37 :         tmp->seek = seek;
    1040          37 :         tmp->write = write;
    1041          37 :         tmp->read = read;
    1042          37 :         tmp->tell = tell;
    1043          37 :         tmp->eof = eof;
    1044          37 :         tmp->printf = printf;
    1045             : 
    1046          37 :         tmp->udta = udta;
    1047          37 :         if (url)
    1048          37 :                 tmp->res_url = gf_strdup(url);
    1049             : 
    1050             :         sprintf(szURL, "gfio://%p", tmp);
    1051          37 :         tmp->url = gf_strdup(szURL);
    1052          37 :         tmp->__this = tmp;
    1053          37 :         return tmp;
    1054             : }
    1055             : 
    1056             : GF_EXPORT
    1057          17 : const char * gf_fileio_url(GF_FileIO *gfio)
    1058             : {
    1059          17 :         return gfio ? gfio->url : NULL;
    1060             : }
    1061             : 
    1062             : GF_EXPORT
    1063          23 : const char * gf_fileio_resource_url(GF_FileIO *gfio)
    1064             : {
    1065          23 :         return gfio ? gfio->res_url : NULL;
    1066             : }
    1067             : 
    1068             : GF_EXPORT
    1069          37 : void gf_fileio_del(GF_FileIO *gfio)
    1070             : {
    1071          37 :         if (!gfio) return;
    1072          37 :         if (gfio->url) gf_free(gfio->url);
    1073          37 :         if (gfio->res_url) gf_free(gfio->res_url);
    1074          37 :         if (gfio->printf_buf) gf_free(gfio->printf_buf);
    1075          37 :         gf_free(gfio);
    1076             : }
    1077             : 
    1078             : GF_EXPORT
    1079        5931 : void *gf_fileio_get_udta(GF_FileIO *gfio)
    1080             : {
    1081        5931 :         return gfio ? gfio->udta : NULL;
    1082             : }
    1083             : 
    1084             : GF_EXPORT
    1085          72 : GF_FileIO *gf_fileio_open_url(GF_FileIO *gfio_ref, const char *url, const char *mode, GF_Err *out_err)
    1086             : {
    1087          72 :         if (!gfio_ref) {
    1088           0 :                 *out_err = GF_BAD_PARAM;
    1089           0 :                 return NULL;
    1090             :         }
    1091          72 :         if (!gfio_ref->open) {
    1092           0 :                 *out_err = url ? GF_NOT_SUPPORTED : GF_OK;
    1093           0 :                 return NULL;
    1094             :         }
    1095          72 :         return gfio_ref->open(gfio_ref, url, mode, out_err);
    1096             : }
    1097             : 
    1098             : static u32 gf_fileio_read(GF_FileIO *gfio, u8 *buffer, u32 nb_bytes)
    1099             : {
    1100        1836 :         if (!gfio) return GF_BAD_PARAM;
    1101        1836 :         if (gfio->read)
    1102        1836 :                 return gfio->read(gfio, buffer, nb_bytes);
    1103             :         return 0;
    1104             : }
    1105             : 
    1106             : static u32 gf_fileio_write(GF_FileIO *gfio, u8 *buffer, u32 nb_bytes)
    1107             : {
    1108         208 :         if (!gfio) return GF_BAD_PARAM;
    1109         208 :         if (!gfio->write) return 0;
    1110         208 :         return gfio->write(gfio, buffer, (u32) nb_bytes);
    1111             : }
    1112             : 
    1113        3545 : int gf_fileio_printf(GF_FileIO *gfio, const char *format, va_list args)
    1114             : {
    1115             :         va_list args_copy;
    1116        3545 :         if (!gfio) return -1;
    1117        3545 :         if (gfio->printf) return gfio->printf(gfio, format, args);
    1118             : 
    1119           0 :         if (!gfio->write) return -1;
    1120             : 
    1121           0 :         va_copy(args_copy, args);
    1122           0 :         u32 len=vsnprintf(NULL, 0, format, args_copy);
    1123           0 :         va_end(args_copy);
    1124             : 
    1125           0 :         if (len>=gfio->printf_alloc) {
    1126           0 :                 gfio->printf_alloc = len+1;
    1127           0 :                 gfio->printf_buf = gf_realloc(gfio->printf_buf, gfio->printf_alloc);
    1128             :         }
    1129           0 :         vsnprintf(gfio->printf_buf, len, format, args);
    1130           0 :         gfio->printf_buf[len] = 0;
    1131           0 :         return gfio->write(gfio, gfio->printf_buf, len+1);
    1132             : }
    1133             : 
    1134             : GF_EXPORT
    1135          13 : Bool gf_fileio_write_mode(GF_FileIO *gfio)
    1136             : {
    1137          13 :         return (gfio && gfio->write) ? GF_TRUE : GF_FALSE;
    1138             : }
    1139             : 
    1140             : GF_EXPORT
    1141          24 : Bool gf_fileio_read_mode(GF_FileIO *gfio)
    1142             : {
    1143          24 :         return (gfio && gfio->read) ? GF_TRUE : GF_FALSE;
    1144             : }
    1145             : 
    1146             : GF_EXPORT
    1147          92 : GF_FileIO *gf_fileio_from_url(const char *url)
    1148             : {
    1149             :         char szURL[100];
    1150          92 :         GF_FileIO *ptr=NULL;
    1151          92 :         if (!url) return NULL;
    1152             :         
    1153          92 :         sscanf(url, "gfio://%p", &ptr);
    1154          92 :         sprintf(szURL, "gfio://%p", ptr);
    1155          92 :         if (strcmp(url, szURL))
    1156             :                 return NULL;
    1157             : 
    1158          92 :         if (ptr && ptr->url && !strcmp(ptr->url, url) ) {
    1159          92 :                 return ptr;
    1160             :         }
    1161             :         return NULL;
    1162             : }
    1163             : 
    1164             : GF_EXPORT
    1165          25 : const char * gf_fileio_translate_url(const char *url)
    1166             : {
    1167          25 :         GF_FileIO *gfio = gf_fileio_from_url(url);
    1168          25 :         return gfio ? gfio->res_url : NULL;
    1169             : }
    1170             : 
    1171           0 : Bool gf_fileio_eof(GF_FileIO *fileio)
    1172             : {
    1173         101 :         if (!fileio || !fileio->tell) return GF_TRUE;
    1174         101 :         return fileio->eof(fileio);
    1175             : }
    1176             : 
    1177           0 : int gf_fileio_flush(GF_FileIO *fileio)
    1178             : {
    1179           1 :         if (!fileio || !fileio->write) return 0;
    1180           1 :         fileio->write(fileio, NULL, 0);
    1181           0 :         return 0;
    1182             : }
    1183             : 
    1184             : GF_EXPORT
    1185           1 : const char *gf_fileio_factory(GF_FileIO *gfio, const char *new_res_url)
    1186             : {
    1187             :         GF_Err e;
    1188           1 :         if (!gfio || !gfio->open) return NULL;
    1189           1 :         GF_FileIO *new_res = gfio->open(gfio, new_res_url, "url", &e);
    1190           1 :         if (e) return NULL;
    1191           1 :         return gf_fileio_url(new_res);
    1192             : }
    1193             : 
    1194             : GF_EXPORT
    1195          19 : void gf_fileio_set_stats(GF_FileIO *gfio, u64 bytes_done, u64 file_size, Bool cache_complete, u32 bytes_per_sec)
    1196             : {
    1197          19 :         if (!gfio) return;
    1198          19 :         gfio->bytes_done = bytes_done;
    1199          19 :         gfio->file_size_plus_one = file_size ? (1 + file_size) : 0;
    1200          19 :         gfio->cache_complete = cache_complete;
    1201          19 :         gfio->bytes_per_sec = bytes_per_sec;
    1202             : }
    1203             : 
    1204             : 
    1205             : GF_EXPORT
    1206           6 : Bool gf_fileio_get_stats(GF_FileIO *gfio, u64 *bytes_done, u64 *file_size, Bool *cache_complete, u32 *bytes_per_sec)
    1207             : {
    1208           6 :         if (!gf_fileio_check((FILE *)gfio))
    1209             :                 return GF_FALSE;
    1210             : 
    1211           6 :         if (bytes_done) *bytes_done = gfio->bytes_done;
    1212           6 :         if (file_size) *file_size = gfio->file_size_plus_one ? gfio->file_size_plus_one-1 : 0;
    1213           6 :         if (cache_complete) *cache_complete = gfio->cache_complete;
    1214           6 :         if (bytes_per_sec) *bytes_per_sec = gfio->bytes_per_sec;
    1215             :         return GF_TRUE;
    1216             : }
    1217             : 
    1218             : GF_EXPORT
    1219      108540 : u64 gf_ftell(FILE *fp)
    1220             : {
    1221      108540 :         if (!fp) return -1;
    1222             : 
    1223      108540 :         if (gf_fileio_check(fp)) {
    1224             :                 GF_FileIO *gfio = (GF_FileIO *)fp;
    1225          42 :                 if (!gfio->tell) return -1;
    1226          42 :                 return gfio->tell(gfio);
    1227             :         }
    1228             : 
    1229             : #if defined(_WIN32_WCE)
    1230             :         return (u64) ftell(fp);
    1231             : #elif defined(GPAC_CONFIG_WIN32) && (defined(__CYGWIN__) || defined(__MINGW32__))
    1232             : #if (_FILE_OFFSET_BITS >= 64)
    1233             :         return (u64) ftello64(fp);
    1234             : #else
    1235             :         return (u64) ftell(fp);
    1236             : #endif
    1237             : #elif defined(WIN32)
    1238             :         return (u64) _ftelli64(fp);
    1239             : #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_CONFIG_ANDROID)
    1240      108498 :         return (u64) ftello64(fp);
    1241             : #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
    1242             :         return (u64) ftello(fp);
    1243             : #else
    1244             :         return (u64) ftell(fp);
    1245             : #endif
    1246             : }
    1247             : 
    1248             : GF_EXPORT
    1249     1627225 : s32 gf_fseek(FILE *fp, s64 offset, s32 whence)
    1250             : {
    1251     1627225 :         if (!fp) return -1;
    1252     1627225 :         if (gf_fileio_check(fp)) {
    1253             :                 GF_FileIO *gfio = (GF_FileIO *)fp;
    1254          77 :                 if (gfio->seek) {
    1255          77 :                         GF_Err e = gfio->seek(gfio, offset, whence);
    1256          77 :                         if (e) return -1;
    1257          77 :                         return 0;
    1258             :                 }
    1259             :                 return -1;
    1260             :         }
    1261             : 
    1262             : #if defined(_WIN32_WCE)
    1263             :         return (u64) fseek(fp, (s32) offset, whence);
    1264             : #elif defined(GPAC_CONFIG_WIN32) && defined(__CYGWIN__) /* mingw or cygwin */
    1265             : #if (_FILE_OFFSET_BITS >= 64)
    1266             :         return (u64) fseeko64(fp, offset, whence);
    1267             : #else
    1268             :         return (u64) fseek(fp, (s32) offset, whence);
    1269             : #endif
    1270             : #elif defined(WIN32)
    1271             :         return (u64) _fseeki64(fp, offset, whence);
    1272             : #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_CONFIG_ANDROID)
    1273     1627148 :         return fseeko64(fp, (off64_t) offset, whence);
    1274             : #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
    1275             :         return fseeko(fp, (off_t) offset, whence);
    1276             : #else
    1277             :         return fseek(fp, (s32) offset, whence);
    1278             : #endif
    1279             : }
    1280             : 
    1281             : 
    1282          10 : static GF_FileIO *gf_fileio_from_blob(const char *file_name)
    1283             : {
    1284             :         u8 *blob_data;
    1285             :         u32 blob_size, flags;
    1286             :         GF_FileIOBlob *gfio_blob;
    1287          10 :         GF_Err e = gf_blob_get(file_name, &blob_data, &blob_size, &flags);
    1288          10 :         if (e || !blob_data) return NULL;
    1289          10 :     gf_blob_release(file_name);
    1290             :     
    1291          10 :     if (flags) {
    1292           0 :         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Attempt at creating a GFIO object on blob corrupted or in transfer, not supported !"));
    1293             :         return NULL;
    1294             :     }
    1295             :     
    1296          10 :         GF_SAFEALLOC(gfio_blob, GF_FileIOBlob);
    1297          10 :         if (!gfio_blob) return NULL;
    1298          10 :         gfio_blob->data = blob_data;
    1299          10 :         gfio_blob->size = blob_size;
    1300          10 :         return gf_fileio_new((char *) file_name, gfio_blob, gfio_blob_open, gfio_blob_seek, gfio_blob_read, NULL, gfio_blob_tell, gfio_blob_eof, NULL);
    1301             : }
    1302             : GF_EXPORT
    1303       62320 : FILE *gf_fopen_ex(const char *file_name, const char *parent_name, const char *mode)
    1304             : {
    1305             :         FILE *res = NULL;
    1306             :         u32 gfio_type = 0;
    1307             : 
    1308       62320 :         if (!file_name) return NULL;
    1309             : 
    1310       62320 :         if (!strncmp(file_name, "gmem://", 7)) {
    1311             :                 GF_FileIO *new_gfio;
    1312          10 :                 if (strstr(mode, "w"))
    1313             :                         return NULL;
    1314          10 :                 new_gfio = gf_fileio_from_blob(file_name);
    1315          10 :                 if (new_gfio)
    1316          10 :                         gf_register_file_handle((char *)file_name, (FILE *) new_gfio, GF_FALSE);
    1317             :                 return (FILE *) new_gfio;
    1318             : 
    1319             :         }
    1320             : 
    1321       62310 :         if (!strncmp(file_name, "gfio://", 7))
    1322             :                 gfio_type = 1;
    1323       62291 :         else if (parent_name && !strncmp(parent_name, "gfio://", 7))
    1324             :                 gfio_type = 2;
    1325             : 
    1326             :         if (gfio_type) {
    1327             :                 GF_FileIO *gfio_ref;
    1328             :                 GF_FileIO *new_gfio;
    1329             :                 GF_Err e;
    1330          27 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Open GFIO %s in mode %s\n", file_name, mode));
    1331             : 
    1332          27 :                 if (gfio_type==1)
    1333          19 :                         gfio_ref = gf_fileio_from_url(file_name);
    1334             :                 else
    1335           8 :                         gfio_ref = gf_fileio_from_url(parent_name);
    1336             : 
    1337          27 :                 if (!gfio_ref) return NULL;
    1338          27 :                 if (strchr(mode, 'r') && !gf_fileio_read_mode(gfio_ref)) {
    1339           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("FileIO %s is not read-enabled and open mode %s was requested\n", file_name, mode));
    1340             :                         return NULL;
    1341             :                 }
    1342          27 :                 if ((strchr(mode, 'w') || strchr(mode, 'a'))  && !gf_fileio_write_mode(gfio_ref)) {
    1343           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("FileIO %s is not write-enabled and open mode %s was requested\n", file_name, mode));
    1344             :                         return NULL;
    1345             :                 }
    1346          27 :                 new_gfio = gf_fileio_open_url(gfio_ref, file_name, mode, &e);
    1347          27 :                 if (e) {
    1348           1 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("FileIO %s open in mode %s failed: %s\n", file_name, mode, gf_error_to_string(e)));
    1349             :                         return NULL;
    1350             :                 }
    1351          26 :                 gf_register_file_handle((char *)file_name, (FILE *) new_gfio, GF_FALSE);
    1352          26 :                 return (FILE *) new_gfio;
    1353             :         }
    1354             : 
    1355       62283 :         GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Open file %s in mode %s\n", file_name, mode));
    1356       62283 :         if (strchr(mode, 'w')) {
    1357        7748 :                 char *fname = gf_strdup(file_name);
    1358        7748 :                 char *sep = strchr(fname, '/');
    1359        7748 :                 if (!sep) sep = strchr(fname, '\\');
    1360        7748 :                 if (file_name[0] == '/') sep = strchr(fname+1, '/');
    1361        7375 :                 else if (file_name[2] == '\\') sep = strchr(fname+3, '\\');
    1362             : 
    1363       30362 :                 while (sep) {
    1364             :                         char *n_sep;
    1365       22614 :                         char c = sep[0];
    1366       22614 :                         sep[0] = 0;
    1367       22614 :                         if (!gf_dir_exists(fname)) {
    1368          18 :                                 GF_Err e = gf_mkdir(fname);
    1369          18 :                                 if (e != GF_OK) {
    1370           0 :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Failed to create directory \"%s\": %s\n", file_name, gf_error_to_string(e) ));
    1371           0 :                                         sep[0] = c;
    1372           0 :                                         gf_free(fname);
    1373           0 :                                         return NULL;
    1374             :                                 }
    1375             :                         }
    1376       22614 :                         sep[0] = c;
    1377       22614 :                         n_sep = strchr(sep+1, '/');
    1378       22614 :                         if (!n_sep) n_sep = strchr(sep+1, '\\');
    1379             :                         sep = n_sep;
    1380             :                 }
    1381        7748 :                 gf_free(fname);
    1382             :         }
    1383             : 
    1384             : #if defined(WIN32)
    1385             :         wchar_t *wname;
    1386             :         wchar_t *wmode;
    1387             : 
    1388             :         wname = gf_utf8_to_wcs(file_name);
    1389             :         wmode = gf_utf8_to_wcs(mode);
    1390             :         if (!wname || !wmode)
    1391             :         {
    1392             :                 if (wname) gf_free(wname);
    1393             :                 if (wmode) gf_free(wmode);
    1394             :                 return NULL;
    1395             :         }
    1396             :         res = _wfsopen(wname, wmode, _SH_DENYNO);
    1397             :         gf_free(wname);
    1398             :         gf_free(wmode);
    1399             : #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_CONFIG_ANDROID)
    1400       62283 :         res = fopen64(file_name, mode);
    1401             : #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
    1402             :         res = fopen(file_name, mode);
    1403             : #else
    1404             :         res = fopen(file_name, mode);
    1405             : #endif
    1406             : 
    1407       62283 :         if (res) {
    1408       55806 :                 if (!parent_name || strcmp(parent_name, "__temp_file"))
    1409       55806 :                         gf_register_file_handle((char *)file_name, res, GF_FALSE);
    1410             : 
    1411       55806 :                 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] file \"%s\" opened in mode \"%s\" - %d file handles\n", file_name, mode, gpac_file_handles));
    1412             :         } else {
    1413        6477 :                 if (strchr(mode, 'w') || strchr(mode, 'a')) {
    1414             : #if defined(WIN32)
    1415             :                         u32 err = GetLastError();
    1416             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of \"%s\" in mode \"%s\": 0x%08x\n", file_name, mode, err));
    1417             : #else
    1418           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] system failure for file opening of \"%s\" in mode \"%s\": %d\n", file_name, mode, errno));
    1419             : #endif
    1420             :                 }
    1421             :         }
    1422             :         return res;
    1423             : }
    1424             : 
    1425             : GF_EXPORT
    1426       51929 : FILE *gf_fopen(const char *file_name, const char *mode)
    1427             : {
    1428       51929 :         return gf_fopen_ex(file_name, NULL, mode);
    1429             : }
    1430             : 
    1431             : GF_EXPORT
    1432       58615 : s32 gf_fclose(FILE *file)
    1433             : {
    1434       58615 :         if (!file)
    1435             :                 return 0;
    1436             : 
    1437       58615 :         if (gf_unregister_file_handle(file))
    1438             :                 return 0;
    1439       58615 :         if (gf_fileio_check(file)) {
    1440             :                 GF_Err e;
    1441          36 :                 gf_fileio_open_url((GF_FileIO *) file, NULL, "deref", &e);
    1442          36 :                 if (e) return -1;
    1443          27 :                 return 0;
    1444             :         }
    1445       58579 :         return fclose(file);
    1446             : }
    1447             : 
    1448             : #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) && !defined(WIN32)
    1449             : #define HAVE_STRERROR_R 1
    1450             : #endif
    1451             : 
    1452             : GF_EXPORT
    1453     2204496 : size_t gf_fwrite(const void *ptr, size_t nb_bytes, FILE *stream)
    1454             : {
    1455             :         size_t result=0;
    1456             : 
    1457     2204496 :         if (gf_fileio_check(stream)) {
    1458         416 :                 return(size_t) gf_fileio_write((GF_FileIO *)stream, (u8 *) ptr, (u32) nb_bytes);
    1459             :         }
    1460             : 
    1461     2204288 :         if (ptr)
    1462     2204288 :                 result = fwrite(ptr, 1, nb_bytes, stream);
    1463     2204288 :         if (result != nb_bytes) {
    1464             : #ifdef _WIN32_WCE
    1465             :                 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nb_bytes, result));
    1466             : #else
    1467             : #if defined WIN32 && !defined(GPAC_CONFIG_WIN32)
    1468             :                 errno_t errno_save;
    1469             :                 _get_errno(&errno_save);
    1470             : #else
    1471           0 :                 int errno_save = errno;
    1472             : #endif
    1473             :                 //if (errno_save!=0)
    1474             :                 {
    1475             : #ifdef HAVE_STRERROR_R
    1476             : #define ERRSTR_BUF_SIZE 256
    1477             :                         char errstr[ERRSTR_BUF_SIZE];
    1478           0 :                         if(strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0)
    1479             :                         {
    1480           0 :                                 strerror_r(0, errstr, ERRSTR_BUF_SIZE);
    1481             :                         }
    1482             : #else
    1483             :                         char *errstr = (char*)strerror(errno_save);
    1484             : #endif
    1485             : 
    1486             : #ifndef GPAC_DISABLE_LOG
    1487           0 :                         GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nb_bytes, result));
    1488             : #else
    1489             :                         fprintf(stderr, "Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, (u32) nb_bytes, (u32) result);
    1490             : #endif
    1491             : 
    1492             :                 }
    1493             : #endif
    1494             :         }
    1495             :         return result;
    1496             : }
    1497             : 
    1498             : GF_EXPORT
    1499     5220048 : size_t gf_fread(void *ptr, size_t nbytes, FILE *stream)
    1500             : {
    1501             :         size_t result;
    1502     5220048 :         if (gf_fileio_check(stream)) {
    1503         522 :                 return (size_t) gf_fileio_read((GF_FileIO *)stream, ptr, (u32) nbytes);
    1504             :         }
    1505             :         result = fread(ptr, 1, nbytes, stream);
    1506             :         return result;
    1507             : }
    1508             : 
    1509             : GF_EXPORT
    1510      263325 : char *gf_fgets(char *ptr, size_t size, FILE *stream)
    1511             : {
    1512      263325 :         if (gf_fileio_check(stream)) {
    1513             :                 GF_FileIO *fio = (GF_FileIO *)stream;
    1514             :                 u32 i, read, nb_read=0;
    1515        1575 :                 for (i=0; i<size; i++) {
    1516             :                         u8 buf[1];
    1517             :                         read = (u32) gf_fileio_read(fio, buf, 1);
    1518        1575 :                         if (!read) break;
    1519             : 
    1520        1573 :                         ptr[nb_read] = buf[0];
    1521        1573 :                         nb_read++;
    1522        1573 :                         if (buf[0]=='\n') break;
    1523             :                 }
    1524         120 :                 if (!nb_read) return NULL;
    1525         118 :                 return ptr;
    1526             :         }
    1527      263205 :         return fgets(ptr, (u32) size, stream);
    1528             : }
    1529             : 
    1530             : GF_EXPORT
    1531       22374 : int gf_fgetc(FILE *stream)
    1532             : {
    1533       22374 :         if (gf_fileio_check(stream)) {
    1534             :                 GF_FileIO *fio = (GF_FileIO *)stream;
    1535             :                 u8 buf[1];
    1536             :                 u32 read = gf_fileio_read(fio, buf, 1);
    1537           0 :                 if (!read) return -1;
    1538           0 :                 return buf[0];
    1539             :         }
    1540       22374 :         return fgetc(stream);
    1541             : }
    1542             : 
    1543             : GF_EXPORT
    1544          17 : int gf_fputc(int val, FILE *stream)
    1545             : {
    1546          17 :         if (gf_fileio_check(stream)) {
    1547             :                 GF_FileIO *fio = (GF_FileIO *)stream;
    1548             :                 u32 write;
    1549             :                 u8 buf[1];
    1550           0 :                 buf[0] = val;
    1551             :                 write = gf_fileio_write(fio, buf, 1);
    1552           0 :                 if (!write) return -1;
    1553           0 :                 return buf[0];
    1554             :         }
    1555          17 :         return fputc(val, stream);
    1556             : }
    1557             : 
    1558             : GF_EXPORT
    1559       25063 : int     gf_fputs(const char *buf, FILE *stream)
    1560             : {
    1561       25063 :         if (gf_fileio_check(stream)) {
    1562             :                 GF_FileIO *fio = (GF_FileIO *)stream;
    1563           0 :                 u32 write, len = (u32) strlen(buf);
    1564             :                 write = gf_fileio_write(fio, (u8 *) buf, len);
    1565           0 :                 if (write != len) return -1;
    1566           0 :                 return write;
    1567             :         }
    1568       25063 :         return fputs(buf, stream);
    1569             : }
    1570             : 
    1571             : GF_EXPORT
    1572     3977042 : int gf_fprintf(FILE *stream, const char *format, ...)
    1573             : {
    1574             :         int     res;
    1575             :         va_list args;
    1576     3977042 :         va_start(args, format);
    1577     3977042 :         if (gf_fileio_check(stream)) {
    1578        3545 :                 res = gf_fileio_printf((GF_FileIO *)stream, format, args);
    1579             :         } else {
    1580             :                 res = vfprintf(stream, format, args);
    1581             :         }
    1582     3977042 :         va_end(args);
    1583     3977042 :         return res;
    1584             : }
    1585             : 
    1586             : GF_EXPORT
    1587      201621 : int gf_fflush(FILE *stream)
    1588             : {
    1589      201621 :         if (gf_fileio_check(stream)) {
    1590             :                 return gf_fileio_flush((GF_FileIO *)stream);
    1591             :         }
    1592      201620 :         return fflush(stream);
    1593             : }
    1594             : 
    1595             : GF_EXPORT
    1596     3390743 : int gf_feof(FILE *stream)
    1597             : {
    1598     3390743 :         if (gf_fileio_check(stream)) {
    1599         101 :                 return gf_fileio_eof((GF_FileIO *)stream) ? 1 : 0;
    1600             :         }
    1601     3390642 :         return feof(stream);
    1602             : }
    1603             : 
    1604             : 
    1605             : GF_EXPORT
    1606         352 : int gf_ferror(FILE *stream)
    1607             : {
    1608         352 :         if (gf_fileio_check(stream)) {
    1609             :                 return 0;
    1610             :         }
    1611         351 :         return ferror(stream);
    1612             : }
    1613             : 
    1614             : GF_EXPORT
    1615       25457 : u64 gf_fsize(FILE *fp)
    1616             : {
    1617             :         u64 size;
    1618             : 
    1619       25457 :         if (gf_fileio_check(fp)) {
    1620             :                 GF_FileIO *gfio = (GF_FileIO *)fp;
    1621          22 :                 if (gfio->file_size_plus_one) {
    1622          19 :                         gf_fseek(fp, 0, SEEK_SET);
    1623          19 :                         return gfio->file_size_plus_one - 1;
    1624             :                 }
    1625             :                 //fall through
    1626             :         }
    1627       25438 :         gf_fseek(fp, 0, SEEK_END);
    1628       25438 :         size = gf_ftell(fp);
    1629       25438 :         gf_fseek(fp, 0, SEEK_SET);
    1630       25438 :         return size;
    1631             : }
    1632             : 
    1633             : /**
    1634             :   * Returns a pointer to the start of a filepath basename
    1635             :  **/
    1636             : GF_EXPORT
    1637       40388 : char* gf_file_basename(const char* filename)
    1638             : {
    1639             :         char* lastPathPart = NULL;
    1640       40388 :         if (filename) {
    1641       40386 :                 lastPathPart = strrchr(filename , GF_PATH_SEPARATOR);
    1642             : #if GF_PATH_SEPARATOR != '/'
    1643             :                 // windows paths can mix slashes and backslashes
    1644             :                 // so we search for the last slash that occurs after the last backslash
    1645             :                 // if it occurs before it's not relevant
    1646             :                 // if there's no backslashes we search in the whole file path
    1647             : 
    1648             :                 char* trailingSlash = strrchr(lastPathPart?lastPathPart:filename, '/');
    1649             :                 if (trailingSlash)
    1650             :                         lastPathPart = trailingSlash;
    1651             : #endif
    1652       40386 :                 if (!lastPathPart)
    1653             :                         lastPathPart = (char *)filename;
    1654             :                 else
    1655       37102 :                         lastPathPart++;
    1656             :         }
    1657       40388 :         return lastPathPart;
    1658             : }
    1659             : 
    1660             : /**
    1661             :   * Returns a pointer to the start of a filepath extension or null
    1662             :  **/
    1663             : GF_EXPORT
    1664       32577 : char* gf_file_ext_start(const char* filename)
    1665             : {
    1666             :         char* basename;
    1667             : 
    1668       32577 :         if (filename && !strncmp(filename, "gfio://", 7)) {
    1669          22 :                 GF_FileIO *gfio = gf_fileio_from_url(filename);
    1670          22 :                 filename = gf_fileio_resource_url(gfio);
    1671             :         }
    1672       32577 :         basename = gf_file_basename(filename);
    1673             : 
    1674       32577 :         if (basename) {
    1675       32577 :                 char *ext = strrchr(basename, '.');
    1676       32577 :                 if (ext && !strcmp(ext, ".gz")) {
    1677           0 :                         ext[0] = 0;
    1678           0 :                         char *ext2 = strrchr(basename, '.');
    1679           0 :                         ext[0] = '.';
    1680           0 :                         if (ext2) return ext2;
    1681             :                 }
    1682             :                 return ext;
    1683             :         }
    1684             :         return NULL;
    1685             : }
    1686             : 
    1687             : GF_EXPORT
    1688       78866 : char* gf_url_colon_suffix(const char *path)
    1689             : {
    1690       78866 :         char *sep = strchr(path, ':');
    1691       78866 :         if (!sep) return NULL;
    1692             : 
    1693             :         //handle Z:\ and Z:/
    1694       56492 :         if ((path[1]==':') && ( (path[2]=='/') || (path[2]=='\\') ) )
    1695           0 :                 return gf_url_colon_suffix(path+2);
    1696             : 
    1697       56492 :         if (!strncmp(path, "gfio://", 7) || !strncmp(path, "gmem://", 7)) {
    1698          26 :                 return strchr(path+7, ':');
    1699             :         }
    1700             :         
    1701             :         //handle PROTO://ADD:PORT/
    1702       56466 :         if ((sep[1]=='/') && (sep[2]=='/')) {
    1703             :                 char *next_colon, *next_slash;
    1704         455 :                 sep++;
    1705             :                 //skip all // (eg PROTO://////////////mytest/)
    1706        1820 :                 while (sep[0]=='/')
    1707         910 :                         sep++;
    1708         455 :                 if (!sep[0]) return NULL;
    1709             : 
    1710             :                 /*we may now have C:\ or C:/  (eg file://///C:\crazy\ or  file://///C:/crazy/)
    1711             :                         if sep[1]==':', then sep[2] is valid (0 or something else), no need to check for len
    1712             :                 */
    1713         451 :                 if ((sep[1]==':') && ( (sep[2]=='/') || (sep[2]=='\\') ) ) {
    1714           0 :                         return gf_url_colon_suffix(sep+2);
    1715             :                 }
    1716             :                 //find closest : or /, if : is before / consider this is a port or an IPv6 address and check next : after /
    1717         451 :                 next_colon = strchr(sep, ':');
    1718         451 :                 next_slash = strchr(sep, '/');
    1719         451 :                 if (next_colon && next_slash && ((next_slash - sep) > (next_colon - sep)) ) {
    1720             :                         const char *last_colon;
    1721             :                         u32 i, port, nb_colons=0, nb_dots=0, nb_non_alnums=0;
    1722         238 :                         next_slash[0] = 0;
    1723         238 :                         last_colon = strrchr(next_colon, ':');
    1724         476 :                         port = atoi(last_colon+1);
    1725        1436 :                         for (i=0; i<strlen(next_colon+1); i++) {
    1726         970 :                                 if (next_colon[i+1] == ':') nb_colons++;
    1727         955 :                                 else if (next_colon[i+1] == '.') nb_dots++;
    1728             :                                 //closing bracket of IPv6
    1729         955 :                                 else if (next_colon[i+1] == ']') {}
    1730         955 :                                 else if (!isalnum(next_colon[i+1])) {
    1731             :                                         nb_non_alnums++;
    1732             :                                         break;
    1733             :                                 }
    1734             :                         }
    1735         238 :                         next_slash[0] = '/';
    1736             :                         //if no non-alphanum, we must have either a port (ipv4) or extra colons but no dots (ipv6)
    1737         238 :                         if (!nb_non_alnums && (port || (nb_colons && !nb_dots)))
    1738         218 :                                 next_colon = strchr(next_slash, ':');
    1739             :                 }
    1740             :                 return next_colon;
    1741             :         }
    1742             :         return sep;
    1743             : }

Generated by: LCOV version 1.13