1 /* GemRB - Infinity Engine Emulator
2 * Copyright (C) 2003 The GemRB Project
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 // VFS.cpp : functions to access filesystem in os-independent way
22 // and POSIX-like compatibility layer for win
24 #include "System/VFS.h"
28 #include "Interface.h"
30 #if defined(__HAIKU__)
42 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
46 #define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
54 struct _finddata_t c_file
;
59 char d_name
[_MAX_PATH
];
62 // buffer which readdir returns
65 DIR* opendir(const char* filename
)
67 DIR* dirp
= ( DIR* ) malloc( sizeof( DIR ) );
70 sprintf( dirp
->path
, "%s%s*.*", filename
, SPathDelimiter
);
71 //if((hFile = (long)_findfirst(Path, &c_file)) == -1L) //If there is no file matching our search
76 dirent
* readdir(DIR* dirp
)
78 struct _finddata_t c_file
;
82 dirp
->hFile
= ( long ) _findfirst( dirp
->path
, &c_file
);
83 if (dirp
->hFile
== -1L)
86 if (( long ) _findnext( dirp
->hFile
, &c_file
) != 0) {
91 strcpy( de
.d_name
, c_file
.name
);
96 void closedir(DIR* dirp
)
98 _findclose( dirp
->hFile
);
103 _FILE
* _fopen(const char* filename
, const char* mode
)
106 DWORD AccessFlags
= 0;
107 DWORD ShareFlags
= 0;
110 if (( *mode
== 'w' ) || ( *mode
== 'W' )) {
111 OpenFlags
|= OPEN_ALWAYS
;
112 AccessFlags
|= GENERIC_WRITE
;
113 ShareFlags
|= FILE_SHARE_READ
;
114 } else if (( *mode
== 'r' ) || ( *mode
== 'R' )) {
115 OpenFlags
|= OPEN_EXISTING
;
116 AccessFlags
|= GENERIC_READ
;
117 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
118 } else if (( *mode
== 'a' ) || ( *mode
== 'A' )) {
119 OpenFlags
|= OPEN_ALWAYS
;
120 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
121 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
122 } else if (*mode
== '+') {
123 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
124 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
128 HANDLE hFile
= CreateFile( filename
, AccessFlags
, ShareFlags
, NULL
,
129 OpenFlags
, FILE_ATTRIBUTE_NORMAL
, NULL
);
130 if (hFile
== INVALID_HANDLE_VALUE
) {
133 _FILE
* ret
= ( _FILE
* ) malloc( sizeof( _FILE
) );
138 size_t _fread(void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
144 if (!ReadFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
), &read
,
148 return ( size_t ) read
;
151 size_t _fwrite(const void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
157 if (!WriteFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
),
161 return ( size_t ) wrote
;
164 size_t _fseek(_FILE
* stream
, long offset
, int whence
)
169 unsigned long method
;
175 method
= FILE_CURRENT
;
183 if (SetFilePointer( stream
->hFile
, offset
, NULL
, method
) == 0xffffffff) {
189 int _fgetc(_FILE
* stream
)
196 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
198 if (bResult
&& read
) {
204 long int _ftell(_FILE
* stream
)
209 unsigned long pos
= SetFilePointer( stream
->hFile
, 0, NULL
, FILE_CURRENT
);
210 if (pos
== 0xffffffff) {
213 return ( long int ) pos
;
216 int _feof(_FILE
* stream
)
223 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
225 if (bResult
&& ( read
== 0 )) {
228 bResult
= SetFilePointer( stream
->hFile
, -1, NULL
, FILE_CURRENT
);
232 int _fclose(_FILE
* stream
)
237 if (!CloseHandle( stream
->hFile
)) {
247 /** Returns true if path is an existing directory */
248 bool dir_exists(const char* path
)
253 if (stat(path
, &buf
) < 0) {
256 if (!S_ISDIR(buf
.st_mode
)) {
263 /** Returns true if path is an existing directory */
264 bool file_exists(const char* path
)
269 if (stat(path
, &buf
) < 0) {
272 if (!S_ISREG(buf
.st_mode
)) {
281 * Appends 'name' to path 'target' and returns 'target'.
282 * It takes care of inserting PathDelimiter ('/' or '\\') if needed
284 char* PathAppend (char* target
, const char* name
)
286 size_t len
= strlen(target
);
288 if (target
[0] != 0 && target
[len
-1] != PathDelimiter
&& len
+1 < _MAX_PATH
) {
289 target
[len
++] = PathDelimiter
;
292 strncat( target
+len
, name
, _MAX_PATH
- len
- 1 );
298 bool FindInDir(const char* Dir
, char *Filename
)
300 // First test if there's a Filename with exactly same name
301 // and if yes, return it and do not search in the Dir
302 char TempFilePath
[_MAX_PATH
];
303 strcpy(TempFilePath
, Dir
);
304 PathAppend( TempFilePath
, Filename
);
306 if (!access( TempFilePath
, R_OK
)) {
310 if (!core
->CaseSensitive
) {
314 DirectoryIterator
dir(Dir
);
319 // Exact match not found, so try to search for Filename
320 // with different case
322 const char *name
= dir
.GetName();
323 if (stricmp( name
, Filename
) == 0) {
324 strcpy( Filename
, name
);
331 bool PathJoin (char *target
, const char *base
, ...)
341 strcpy(target
, base
);
343 while (char *source
= va_arg(ap
, char*)) {
346 char filename
[_MAX_PATH
] = { '\0' };
347 slash
= strchr(source
, PathDelimiter
);
348 if (slash
== source
) {
352 strncat(filename
, source
, slash
-source
);
354 strcpy(filename
, source
);
356 if (!FindInDir(target
, filename
)) {
357 PathAppend(target
, source
);
360 PathAppend(target
, filename
);
367 while (char *source
= va_arg(ap
, char*)) {
368 PathAppend(target
, source
);
374 bool PathJoinExt (char* target
, const char* dir
, const char* base
, const char* ext
)
376 char file
[_MAX_PATH
];
380 return PathJoin(target
, dir
, file
, NULL
);
383 /** Fixes path delimiter character (slash).
384 * needslash = true : we add a slash
385 * needslash = false: we remove the slash
387 void FixPath (char *path
, bool needslash
)
389 size_t i
= strlen( path
) - 1;
392 if (path
[i
] == PathDelimiter
) return;
394 // if path is already too long, don't do anything
395 if (i
>= _MAX_PATH
- 2) return;
397 path
[i
++] = PathDelimiter
;
400 if (path
[i
] != PathDelimiter
) return;
405 int strmatch(const char *string
, const char *mask
)
409 if (tolower(*mask
)!=tolower(*string
)) {
419 bool FileGlob(char* target
, const char* Dir
, const char *glob
)
421 DirectoryIterator
dir(Dir
);
427 const char *name
= dir
.GetName();
428 if (strmatch( name
, glob
) == 0) {
429 strcpy( target
, name
);
439 void ResolveFilePath(char* FilePath
)
441 char TempFilePath
[_MAX_PATH
];
443 if (FilePath
[0]=='~') {
444 const char *home
= getenv("HOME");
446 strcpy(TempFilePath
, FilePath
+1);
447 PathJoin(FilePath
, home
, TempFilePath
, NULL
);
452 if (core
&& !core
->CaseSensitive
) {
455 strcpy(TempFilePath
, FilePath
);
456 PathJoin(FilePath
, TempFilePath
[0]==PathDelimiter
?SPathDelimiter
:"", TempFilePath
, NULL
);
459 void ResolveFilePath(std::string
& FilePath
)
461 char TempFilePath
[_MAX_PATH
];
463 if (FilePath
[0]=='~') {
464 const char *home
= getenv("HOME");
466 PathJoin(TempFilePath
, home
, FilePath
.c_str()+1, NULL
);
467 FilePath
= TempFilePath
;
472 if (core
&& !core
->CaseSensitive
) {
475 PathJoin(TempFilePath
, FilePath
[0]==PathDelimiter
?SPathDelimiter
:"", FilePath
.c_str(), NULL
);
476 FilePath
= TempFilePath
;
481 void ExtractFileFromPath(char *file
, const char *full_path
)
484 if ((p
= strrchr (full_path
, PathDelimiter
)))
486 else if ((p
= strchr (full_path
, ':')))
489 strcpy(file
, full_path
);
492 DirectoryIterator::DirectoryIterator(const char *path
)
493 : Directory(NULL
), Entry(NULL
), Path(path
)
498 DirectoryIterator::~DirectoryIterator()
501 closedir(static_cast<DIR*>(Directory
));
504 bool DirectoryIterator::IsDirectory()
506 char dtmp
[_MAX_PATH
];
510 return S_ISDIR( fst
.st_mode
);
513 char* DirectoryIterator::GetName()
515 return static_cast<dirent
*>(Entry
)->d_name
;
518 void DirectoryIterator::GetFullPath(char *name
)
520 snprintf(name
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, static_cast<dirent
*>(Entry
)->d_name
);
523 DirectoryIterator
& DirectoryIterator::operator++()
525 Entry
= readdir(static_cast<DIR*>(Directory
));
529 void DirectoryIterator::Rewind()
532 closedir(static_cast<DIR*>(Directory
));
533 Directory
= opendir(Path
);
534 if (Directory
== NULL
)
537 Entry
= readdir(static_cast<DIR*>(Directory
));