1 /*
2 * GPAC - Multimedia Framework C SDK
3 *
4 * Authors: Jean Le Feuvre - Copyright (c) Telecom ParisTech 2000-2012
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 <direct.h>
38 #include <sys/stat.h>
39 #include <share.h>
40
41 #else
42
43 #include <sys/stat.h>
44 #include <unistd.h>
45 #include <dirent.h>
46 #include <time.h>
47 #include <sys/time.h>
48
49 #ifndef __BEOS__
50 #include <errno.h>
51 #endif
52
53 #endif
54
55
gf_rmdir(char * DirPathName)56 GF_Err gf_rmdir(char *DirPathName)
57 {
58 #if defined (_WIN32_WCE)
59 TCHAR swzName[MAX_PATH];
60 BOOL res;
61 CE_CharToWide(DirPathName, swzName);
62 res = RemoveDirectory(swzName);
63 if (!res) {
64 int err = GetLastError();
65 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, err));
66 }
67 #elif defined (WIN32)
68 int res = rmdir(DirPathName);
69 if (res == -1) {
70 int err = GetLastError();
71 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, err));
72 return GF_IO_ERR;
73 }
74 #else
75 int res = rmdir(DirPathName);
76 if (res == -1) {
77 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot delete directory %s: last error %d\n", DirPathName, errno));
78 return GF_IO_ERR;
79 }
80 #endif
81 return GF_OK;
82 }
83
84 GF_EXPORT
gf_mkdir(char * DirPathName)85 GF_Err gf_mkdir(char* DirPathName)
86 {
87 #if defined (_WIN32_WCE)
88 TCHAR swzName[MAX_PATH];
89 BOOL res;
90 CE_CharToWide(DirPathName, swzName);
91 res = CreateDirectory(swzName, NULL);
92 if (!res) {
93 int err = GetLastError();
94 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, err));
95 }
96 #elif defined (WIN32)
97 int res = mkdir(DirPathName);
98 if (res == -1) {
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 #else
103 int res = mkdir(DirPathName, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
104 if (res == -1) {
105 if (errno == 17) {
106 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s, it already exists: last error %d \n", DirPathName, errno));
107 return GF_BAD_PARAM;
108 }
109 else {
110 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Cannot create directory %s: last error %d\n", DirPathName, errno));
111 return GF_IO_ERR;
112 }
113 }
114 #endif
115 return GF_OK;
116 }
117
118
119 GF_EXPORT
gf_dir_exists(char * DirPathName)120 Bool gf_dir_exists(char* DirPathName)
121 {
122 #if defined (_WIN32_WCE)
123 TCHAR swzName[MAX_PATH];
124 BOOL res;
125 DWORD att;
126 CE_CharToWide(DirPathName, swzName);
127 att = GetFileAttributes(swzName);
128 return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE;
129 #elif defined (WIN32)
130 DWORD att = GetFileAttributes(DirPathName);
131 return (att != INVALID_FILE_ATTRIBUTES && (att & FILE_ATTRIBUTE_DIRECTORY)) ? GF_TRUE : GF_FALSE;
132 #else
133 DIR* dir = opendir(DirPathName);
134 if (!dir) return GF_FALSE;
135 closedir(dir);
136 return GF_TRUE;
137 #endif
138 return GF_FALSE;
139 }
delete_dir(void * cbck,char * item_name,char * item_path,GF_FileEnumInfo * file_info)140 static Bool delete_dir(void *cbck, char *item_name, char *item_path, GF_FileEnumInfo *file_info)
141 {
142 Bool directory_clean_mode = *(Bool*)cbck;
143
144 if (directory_clean_mode) {
145 gf_cleanup_dir(item_path);
146 gf_rmdir(item_path);
147 }
148 else {
149 gf_delete_file(item_path);
150 }
151 return GF_FALSE;
152 }
153
gf_cleanup_dir(char * DirPathName)154 GF_Err gf_cleanup_dir(char* DirPathName)
155 {
156 Bool directory_clean_mode;
157
158 directory_clean_mode = GF_TRUE;
159 gf_enum_directory(DirPathName, GF_TRUE, delete_dir, &directory_clean_mode, NULL);
160 directory_clean_mode = GF_FALSE;
161 gf_enum_directory(DirPathName, GF_FALSE, delete_dir, &directory_clean_mode, NULL);
162
163 return GF_OK;
164 }
165
166 GF_EXPORT
gf_delete_file(const char * fileName)167 GF_Err gf_delete_file(const char *fileName)
168 {
169 if (!fileName) {
170 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("gf_delete_file deletes nothing - ignoring\n"));
171 return GF_OK;
172 }
173 #if defined(_WIN32_WCE)
174 TCHAR swzName[MAX_PATH];
175 CE_CharToWide((char*)fileName, swzName);
176 return (DeleteFile(swzName) == 0) ? GF_IO_ERR : GF_OK;
177 #elif defined(WIN32)
178 /* success if != 0 */
179 return (DeleteFile(fileName) == 0) ? GF_IO_ERR : GF_OK;
180 #else
181 /* success is == 0 */
182 return (remove(fileName) == 0) ? GF_OK : GF_IO_ERR;
183 #endif
184 }
185
186 #ifndef WIN32
187 /**
188 * Remove existing single-quote from a single-quoted string.
189 * The caller is responsible for deallocating the returns string with gf_free()
190 */
gf_sanetize_single_quoted_string(const char * src)191 static char* gf_sanetize_single_quoted_string(const char *src) {
192 int i, j;
193 char *out = (char*)gf_malloc(4 * strlen(src) + 3);
194 out[0] = '\'';
195 for (i = 0, j = 1; (out[j] = src[i]); ++i, ++j) {
196 if (src[i] == '\'') {
197 out[++j] = '\\';
198 out[++j] = '\'';
199 out[++j] = '\'';
200 }
201 }
202 out[j++] = '\'';
203 out[j++] = 0;
204 return out;
205 }
206 #endif
207
208 #if defined(GPAC_IPHONE) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
209 #include <spawn.h>
210 extern char **environ;
211 #endif
212
213 GF_EXPORT
gf_file_exists(const char * fileName)214 Bool gf_file_exists(const char *fileName)
215 {
216 FILE *f = gf_fopen(fileName, "r");
217 if (f) {
218 gf_fclose(f);
219 return GF_TRUE;
220 }
221 return GF_FALSE;
222 }
223
224 GF_EXPORT
gf_move_file(const char * fileName,const char * newFileName)225 GF_Err gf_move_file(const char *fileName, const char *newFileName)
226 {
227 #if defined(_WIN32_WCE)
228 TCHAR swzName[MAX_PATH];
229 TCHAR swzNewName[MAX_PATH];
230 CE_CharToWide((char*)fileName, swzName);
231 CE_CharToWide((char*)newFileName, swzNewName);
232 return (MoveFile(swzName, swzNewName) == 0) ? GF_IO_ERR : GF_OK;
233 #elif defined(WIN32)
234 /* success if != 0 */
235 return (MoveFile(fileName, newFileName) == 0) ? GF_IO_ERR : GF_OK;
236 #else
237 GF_Err e = GF_IO_ERR;
238 char cmd[1024], *arg1, *arg2;
239 if (!fileName || !newFileName)
240 return GF_IO_ERR;
241 arg1 = gf_sanetize_single_quoted_string(fileName);
242 arg2 = gf_sanetize_single_quoted_string(newFileName);
243 if (snprintf(cmd, sizeof cmd, "mv %s %s", arg1, arg2) >= sizeof cmd) goto error;
244
245 #if defined(GPAC_IPHONE) && (__IPHONE_OS_VERSION_MAX_ALLOWED >= 80000)
246 {
247 pid_t pid;
248 char *argv[3];
249 argv[0] = "mv";
250 argv[1] = cmd;
251 argv[2] = NULL;
252 posix_spawn(&pid, argv[0], NULL, NULL, argv, environ);
253 waitpid(pid, NULL, 0);
254 }
255 #else
256 e = (system(cmd) == 0) ? GF_OK : GF_IO_ERR;
257 #endif
258
259 error:
260 gf_free(arg1);
261 gf_free(arg2);
262 return e;
263 #endif
264 }
265
266 GF_EXPORT
gf_file_modification_time(const char * filename)267 u64 gf_file_modification_time(const char *filename)
268 {
269 #if defined(_WIN32_WCE)
270 WCHAR _file[GF_MAX_PATH];
271 WIN32_FIND_DATA FindData;
272 HANDLE fh;
273 ULARGE_INTEGER uli;
274 ULONGLONG time_ms;
275 BOOL ret;
276 CE_CharToWide((char *)filename, _file);
277 fh = FindFirstFile(_file, &FindData);
278 if (fh == INVALID_HANDLE_VALUE) return 0;
279 uli.LowPart = FindData.ftLastWriteTime.dwLowDateTime;
280 uli.HighPart = FindData.ftLastWriteTime.dwHighDateTime;
281 ret = FindClose(fh);
282 if (!ret) {
283 DWORD err = GetLastError();
284 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_file_modification_time() returned the following error code: %d\n", err));
285 }
286 time_ms = uli.QuadPart / 10000;
287 return time_ms;
288 #elif defined(WIN32) && !defined(__GNUC__)
289 struct _stat64 sb;
290 if (_stat64(filename, &sb) != 0) return 0;
291 return sb.st_mtime;
292 #else
293 struct stat sb;
294 if (stat(filename, &sb) != 0) return 0;
295 return sb.st_mtime;
296 #endif
297 return 0;
298 }
299
300 static u32 gpac_file_handles = 0;
301 GF_EXPORT
gf_file_handles_count()302 u32 gf_file_handles_count()
303 {
304 return gpac_file_handles;
305 }
306
307 GF_EXPORT
gf_temp_file_new(char ** const fileName)308 FILE *gf_temp_file_new(char ** const fileName)
309 {
310 FILE *res = NULL;
311 #if defined(_WIN32_WCE)
312 TCHAR pPath[MAX_PATH + 1];
313 TCHAR pTemp[MAX_PATH + 1];
314 if (!GetTempPath(MAX_PATH, pPath)) {
315 pPath[0] = '.';
316 pPath[1] = '.';
317 }
318 if (GetTempFileName(pPath, TEXT("git"), 0, pTemp))
319 res = _wfopen(pTemp, TEXT("w+b"));
320 #elif defined(WIN32)
321 char tmp[MAX_PATH];
322 res = tmpfile();
323 if (!res) {
324 GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Win32] system failure for tmpfile(): 0x%08x\n", GetLastError()));
325
326 /*tmpfile() may fail under vista ...*/
327 if (GetEnvironmentVariable("TEMP", tmp, MAX_PATH)) {
328 char tmp2[MAX_PATH], *t_file;
329 gf_rand_init(GF_FALSE);
330 sprintf(tmp2, "gpac_%08x_", gf_rand());
331 t_file = tempnam(tmp, tmp2);
332 res = gf_fopen(t_file, "w+b");
333 if (res) {
334 gpac_file_handles--;
335 if (fileName) {
336 *fileName = gf_strdup(t_file);
337 }
338 else {
339 GF_LOG(GF_LOG_WARNING, GF_LOG_CORE, ("[Win32] temporary file %s won't be deleted - contact the GPAC team\n", t_file));
340 }
341 }
342 free(t_file);
343 }
344 }
345 #else
346 res = tmpfile();
347 #endif
348
349 if (res) {
350 gpac_file_handles++;
351 }
352 return res;
353 }
354
355 /*enumerate directories*/
356 GF_EXPORT
gf_enum_directory(const char * dir,Bool enum_directory,gf_enum_dir_item enum_dir_fct,void * cbck,const char * filter)357 GF_Err gf_enum_directory(const char *dir, Bool enum_directory, gf_enum_dir_item enum_dir_fct, void *cbck, const char *filter)
358 {
359 char item_path[GF_MAX_PATH];
360 GF_FileEnumInfo file_info;
361
362 #if defined(_WIN32_WCE)
363 char _path[GF_MAX_PATH];
364 unsigned short path[GF_MAX_PATH];
365 unsigned short w_filter[GF_MAX_PATH];
366 char file[GF_MAX_PATH];
367 #else
368 char path[GF_MAX_PATH], *file;
369 #endif
370
371 #ifdef WIN32
372 WIN32_FIND_DATA FindData;
373 HANDLE SearchH;
374 #else
375 DIR *the_dir;
376 struct dirent* the_file;
377 struct stat st;
378 #endif
379
380 if (!dir || !enum_dir_fct) return GF_BAD_PARAM;
381
382 if (filter && (!strcmp(filter, "*") || !filter[0])) filter = NULL;
383
384 memset(&file_info, 0, sizeof(GF_FileEnumInfo));
385
386 if (!strcmp(dir, "/")) {
387 #if defined(WIN32) && !defined(_WIN32_WCE)
388 u32 len;
389 char *drives, *volume;
390 len = GetLogicalDriveStrings(0, NULL);
391 drives = (char*)gf_malloc(sizeof(char)*(len + 1));
392 drives[0] = 0;
393 GetLogicalDriveStrings(len, drives);
394 len = (u32)strlen(drives);
395 volume = drives;
396 file_info.directory = GF_TRUE;
397 file_info.drive = GF_TRUE;
398 while (len) {
399 enum_dir_fct(cbck, volume, "", &file_info);
400 volume += len + 1;
401 len = (u32)strlen(volume);
402 }
403 gf_free(drives);
404 return GF_OK;
405 #elif defined(__SYMBIAN32__)
406 RFs iFs;
407 TDriveList aList;
408 iFs.Connect();
409 iFs.DriveList(aList);
410 for (TInt i = 0; i<KMaxDrives; i++) {
411 if (aList[i]) {
412 char szDrive[10];
413 TChar aDrive;
414 iFs.DriveToChar(i, aDrive);
415 sprintf(szDrive, "%c:", (TUint)aDrive);
416 enum_dir_fct(cbck, szDrive, "", &file_info);
417 }
418 }
419 iFs.Close();
420 FlushItemList();
421 return GF_OK;
422 #endif
423 }
424
425
426 #if defined (_WIN32_WCE)
427 switch (dir[strlen(dir) - 1]) {
428 case '/':
429 case '\\':
430 sprintf(_path, "%s*", dir);
431 break;
432 default:
433 sprintf(_path, "%s%c*", dir, GF_PATH_SEPARATOR);
434 break;
435 }
436 CE_CharToWide(_path, path);
437 CE_CharToWide((char *)filter, w_filter);
438 #elif defined(WIN32)
439 switch (dir[strlen(dir) - 1]) {
440 case '/':
441 case '\\':
442 sprintf(path, "%s*", dir);
443 break;
444 default:
445 sprintf(path, "%s%c*", dir, GF_PATH_SEPARATOR);
446 break;
447 }
448 #else
449 strcpy(path, dir);
450 if (path[strlen(path) - 1] != '/') strcat(path, "/");
451 #endif
452
453 #ifdef WIN32
454 SearchH = FindFirstFile(path, &FindData);
455 if (SearchH == INVALID_HANDLE_VALUE) return GF_IO_ERR;
456
457 #if defined (_WIN32_WCE)
458 _path[strlen(_path) - 1] = 0;
459 #else
460 path[strlen(path) - 1] = 0;
461 #endif
462
463 while (SearchH != INVALID_HANDLE_VALUE) {
464
465 #else
466
467 the_dir = opendir(path);
468 if (the_dir == NULL) {
469 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[Core] Cannot open directory %s for enumeration: %d\n", path, errno));
470 return GF_IO_ERR;
471 }
472 the_file = readdir(the_dir);
473 while (the_file) {
474
475 #endif
476
477 memset(&file_info, 0, sizeof(GF_FileEnumInfo));
478
479
480 #if defined (_WIN32_WCE)
481 if (!wcscmp(FindData.cFileName, _T("."))) goto next;
482 if (!wcscmp(FindData.cFileName, _T(".."))) goto next;
483 #elif defined(WIN32)
484 if (!strcmp(FindData.cFileName, ".")) goto next;
485 if (!strcmp(FindData.cFileName, "..")) goto next;
486 #else
487 if (!strcmp(the_file->d_name, "..")) goto next;
488 if (the_file->d_name[0] == '.') goto next;
489 #endif
490
491 #ifdef WIN32
492 file_info.directory = (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? GF_TRUE : GF_FALSE;
493 if (!enum_directory && file_info.directory) goto next;
494 if (enum_directory && !file_info.directory) goto next;
495 #endif
496
497 if (filter) {
498 #if defined (_WIN32_WCE)
499 short ext[30];
500 short *sep = wcsrchr(FindData.cFileName, (wchar_t) '.');
501 if (!sep) goto next;
502 wcscpy(ext, sep + 1);
503 wcslwr(ext);
504 if (!wcsstr(w_filter, ext)) goto next;
505 #elif defined(WIN32)
506 char ext[30];
507 char *sep = strrchr(FindData.cFileName, '.');
508 if (!sep) goto next;
509 strcpy(ext, sep + 1);
510 strlwr(ext);
511 if (!strstr(filter, ext)) goto next;
512 #else
513 char ext[30];
514 char *sep = strrchr(the_file->d_name, '.');
515 if (!sep) goto next;
516 strcpy(ext, sep + 1);
517 strlwr(ext);
518 if (!strstr(filter, sep + 1)) goto next;
519 #endif
520 }
521
522 #if defined(WIN32)
523 file_info.hidden = (FindData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) ? GF_TRUE : GF_FALSE;
524 file_info.system = (FindData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) ? GF_TRUE : GF_FALSE;
525 file_info.size = MAXDWORD;
526 file_info.size += 1;
527 file_info.size *= FindData.nFileSizeHigh;
528 file_info.size += FindData.nFileSizeLow;
529 file_info.last_modified = (u64)((*(LONGLONG *)&FindData.ftLastWriteTime - TIMESPEC_TO_FILETIME_OFFSET) / 10000000);
530 #endif
531
532 #if defined (_WIN32_WCE)
533 CE_WideToChar(FindData.cFileName, file);
534 strcpy(item_path, _path);
535 strcat(item_path, file);
536 #elif defined(WIN32)
537 strcpy(item_path, path);
538 strcat(item_path, FindData.cFileName);
539 file = FindData.cFileName;
540 #else
541 strcpy(item_path, path);
542 strcat(item_path, the_file->d_name);
543 GF_LOG(GF_LOG_DEBUG, GF_LOG_CORE, ("[Core] Checking file %s for enum\n", item_path));
544
545 if (stat(item_path, &st) != 0) goto next;
546
547 file_info.directory = ((st.st_mode & S_IFMT) == S_IFDIR) ? GF_TRUE : GF_FALSE;
548 if (enum_directory && !file_info.directory) goto next;
549 if (!enum_directory && file_info.directory) goto next;
550
551 file_info.size = st.st_size;
552
553 {
554 struct tm _t = *gmtime(&st.st_mtime);
555 file_info.last_modified = mktime(&_t);
556 }
557 file = the_file->d_name;
558 if (file && file[0] == '.') file_info.hidden = 1;
559
560 if (file_info.directory) {
561 char * parent_name = strrchr(item_path, '/');
562 if (!parent_name) {
563 file_info.drive = GF_TRUE;
564 }
565 else {
566 struct stat st_parent;
567 parent_name[0] = 0;
568 if (stat(item_path, &st_parent) == 0) {
569 if ((st.st_dev != st_parent.st_dev) || ((st.st_dev == st_parent.st_dev) && (st.st_ino == st_parent.st_ino))) {
570 file_info.drive = GF_TRUE;
571 }
572 }
573 parent_name[0] = '/';
574 }
575 }
576 #endif
577 if (enum_dir_fct(cbck, file, item_path, &file_info)) {
578 #ifdef WIN32
579 BOOL ret = FindClose(SearchH);
580 if (!ret) {
581 DWORD err = GetLastError();
582 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(1) the following error code: %d\n", err));
583 }
584 #endif
585 break;
586 }
587
588 next:
589 #ifdef WIN32
590 if (!FindNextFile(SearchH, &FindData)) {
591 BOOL ret = FindClose(SearchH);
592 if (!ret) {
593 DWORD err = GetLastError();
594 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("[core] FindClose() in gf_enum_directory() returned(2) the following error code: %d\n", err));
595 }
596 break;
597 }
598 #else
599 the_file = readdir(the_dir);
600 #endif
601 }
602 #ifndef WIN32
603 closedir(the_dir);
604 #endif
605 return GF_OK;
606 }
607
608 GF_EXPORT
609 u64 gf_ftell(FILE *fp)
610 {
611 #if defined(_WIN32_WCE)
612 return (u64)ftell(fp);
613 #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */
614 #if (_FILE_OFFSET_BITS >= 64)
615 return (u64)ftello64(fp);
616 #else
617 return (u64)ftell(fp);
618 #endif
619 #elif defined(WIN32)
620 return (u64)_ftelli64(fp);
621 #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID)
622 return (u64)ftello64(fp);
623 #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
624 return (u64)ftello(fp);
625 #else
626 return (u64)ftell(fp);
627 #endif
628 }
629
630 GF_EXPORT
631 u64 gf_fseek(FILE *fp, s64 offset, s32 whence)
632 {
633 #if defined(_WIN32_WCE)
634 return (u64)fseek(fp, (s32)offset, whence);
635 #elif defined(GPAC_CONFIG_WIN32) && !defined(__CYGWIN__) /* mingw or cygwin */
636 #if (_FILE_OFFSET_BITS >= 64)
637 return (u64)fseeko64(fp, offset, whence);
638 #else
639 return (u64)fseek(fp, (s32)offset, whence);
640 #endif
641 #elif defined(WIN32)
642 return (u64)_fseeki64(fp, offset, whence);
643 #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID)
644 return fseeko64(fp, (off64_t)offset, whence);
645 #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
646 return fseeko(fp, (off_t)offset, whence);
647 #else
648 return fseek(fp, (s32)offset, whence);
649 #endif
650 }
651
652 GF_EXPORT
653 FILE *gf_fopen(const char *file_name, const char *mode)
654 {
655 FILE *res = NULL;
656
657 #if defined(WIN32)
658 Bool is_create;
659 is_create = (strchr(mode, 'w') == NULL) ? GF_FALSE : GF_TRUE;
660 if (!is_create) {
661 if (strchr(mode, 'a')) {
662 res = fopen(file_name, "rb");
663 if (res) {
664 fclose(res);
665 res = fopen(file_name, mode);
666 }
667 }
668 else {
669 res = fopen(file_name, mode);
670 }
671 }
672 if (!res) {
673 const char *str_src;
674 wchar_t *wname;
675 wchar_t *wmode;
676 size_t len;
677 size_t len_res;
678 if (!is_create) {
679 GF_LOG(GF_LOG_INFO, GF_LOG_CORE, ("[Core] Could not open file %s mode %s in UTF-8 mode, trying UTF-16\n", file_name, mode));
680 }
681 len = (strlen(file_name) + 1) * sizeof(wchar_t);
682 wname = (wchar_t *)gf_malloc(len);
683 str_src = file_name;
684 len_res = gf_utf8_mbstowcs(wname, len, &str_src);
685 if (len_res == -1) {
686 return NULL;
687 }
688 len = (strlen(mode) + 1) * sizeof(wchar_t);
689 wmode = (wchar_t *)gf_malloc(len);
690 str_src = mode;
691 len_res = gf_utf8_mbstowcs(wmode, len, &str_src);
692 if (len_res == -1) {
693 return NULL;
694 }
695
696 res = _wfsopen(wname, wmode, _SH_DENYNO);
697 gf_free(wname);
698 gf_free(wmode);
699 }
700 #elif defined(GPAC_CONFIG_LINUX) && !defined(GPAC_ANDROID)
701 res = fopen64(file_name, mode);
702 #elif (defined(GPAC_CONFIG_FREEBSD) || defined(GPAC_CONFIG_DARWIN))
703 res = fopen(file_name, mode);
704 #else
705 res = fopen(file_name, mode);
706 #endif
707
708 if (res) {
709 gpac_file_handles++;
710 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));
711 }
712 else {
713 if (strchr(mode, 'w') || strchr(mode, 'a')) {
714 #if defined(WIN32)
715 u32 err = GetLastError();
716 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));
717 #else
718 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));
719 #endif
720 }
721 }
722 return res;
723 }
724
725 GF_EXPORT
726 s32 gf_fclose(FILE *file)
727 {
728 if (file) {
729 assert(gpac_file_handles);
730 gpac_file_handles--;
731 }
732 return fclose(file);
733 }
734
735 #if (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! defined(_GNU_SOURCE) && !defined(WIN32)
736 #define HAVE_STRERROR_R 1
737 #endif
738
739 GF_EXPORT
740 size_t gf_fread(void *ptr, size_t size, size_t nmemb, FILE *stream) {
741 return fread(ptr, size, nmemb, stream);
742 }
743
744 GF_EXPORT
745 size_t gf_fwrite(const void *ptr, size_t size, size_t nmemb,
746 FILE *stream)
747 {
748 size_t result = fwrite(ptr, size, nmemb, stream);
749 if (result != nmemb) {
750 #ifdef _WIN32_WCE
751 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data: %d blocks to write but %d blocks written\n", nmemb, result));
752 #else
753 #if defined WIN32 && !defined(GPAC_CONFIG_WIN32)
754 errno_t errno_save;
755 _get_errno(&errno_save);
756 #else
757 int errno_save = errno;
758 #endif
759 //if (errno_save!=0)
760 {
761 #ifdef HAVE_STRERROR_R
762 #define ERRSTR_BUF_SIZE 256
763 char errstr[ERRSTR_BUF_SIZE];
764 if (strerror_r(errno_save, errstr, ERRSTR_BUF_SIZE) != 0)
765 {
766 strerror_r(0, errstr, ERRSTR_BUF_SIZE);
767 }
768 #else
769 char *errstr = (char*)strerror(errno_save);
770 #endif
771 GF_LOG(GF_LOG_ERROR, GF_LOG_CORE, ("Error writing data (%s): %d blocks to write but %d blocks written\n", errstr, nmemb, result));
772 }
773 #endif
774 }
775 return result;
776 }
777
778