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
28 #include "Interface.h"
36 // buffer which readdir returns
40 DIR* opendir(const char* filename
)
42 DIR* dirp
= ( DIR* ) malloc( sizeof( DIR ) );
45 sprintf( dirp
->path
, "%s%s*.*", filename
, SPathDelimiter
);
46 //if((hFile = (long)_findfirst(Path, &c_file)) == -1L) //If there is no file matching our search
51 dirent
* readdir(DIR* dirp
)
53 struct _finddata_t c_file
;
57 dirp
->hFile
= ( long ) _findfirst( dirp
->path
, &c_file
);
58 if (dirp
->hFile
== -1L)
61 if (( long ) _findnext( dirp
->hFile
, &c_file
) != 0) {
66 strcpy( de
.d_name
, c_file
.name
);
71 void closedir(DIR* dirp
)
73 _findclose( dirp
->hFile
);
78 _FILE
* _fopen(const char* filename
, const char* mode
)
81 DWORD AccessFlags
= 0;
85 if (( *mode
== 'w' ) || ( *mode
== 'W' )) {
86 OpenFlags
|= OPEN_ALWAYS
;
87 AccessFlags
|= GENERIC_WRITE
;
88 ShareFlags
|= FILE_SHARE_READ
;
89 } else if (( *mode
== 'r' ) || ( *mode
== 'R' )) {
90 OpenFlags
|= OPEN_EXISTING
;
91 AccessFlags
|= GENERIC_READ
;
92 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
93 } else if (( *mode
== 'a' ) || ( *mode
== 'A' )) {
94 OpenFlags
|= OPEN_ALWAYS
;
95 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
96 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
97 } else if (*mode
== '+') {
98 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
99 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
103 HANDLE hFile
= CreateFile( filename
, AccessFlags
, ShareFlags
, NULL
,
104 OpenFlags
, FILE_ATTRIBUTE_NORMAL
, NULL
);
105 if (hFile
== INVALID_HANDLE_VALUE
) {
108 _FILE
* ret
= ( _FILE
* ) malloc( sizeof( _FILE
) );
113 size_t _fread(void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
119 if (!ReadFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
), &read
,
123 return ( size_t ) read
;
126 size_t _fwrite(const void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
132 if (!WriteFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
),
136 return ( size_t ) wrote
;
139 size_t _fseek(_FILE
* stream
, long offset
, int whence
)
144 unsigned long method
;
150 method
= FILE_CURRENT
;
158 if (SetFilePointer( stream
->hFile
, offset
, NULL
, method
) == 0xffffffff) {
164 int _fgetc(_FILE
* stream
)
171 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
173 if (bResult
&& read
) {
179 long int _ftell(_FILE
* stream
)
184 unsigned long pos
= SetFilePointer( stream
->hFile
, 0, NULL
, FILE_CURRENT
);
185 if (pos
== 0xffffffff) {
188 return ( long int ) pos
;
191 int _feof(_FILE
* stream
)
198 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
200 if (bResult
&& ( read
== 0 )) {
203 bResult
= SetFilePointer( stream
->hFile
, -1, NULL
, FILE_CURRENT
);
207 int _fclose(_FILE
* stream
)
212 if (!CloseHandle( stream
->hFile
)) {
222 /** Returns true if path is an existing directory */
223 bool dir_exists(const char* path
)
229 return S_ISDIR( buf
.st_mode
) != 0;
235 * Appends dir 'dir' to path 'target' and returns 'target'.
236 * It takes care of inserting PathDelimiter ('/' or '\\') if needed
238 char* PathAppend (char* target
, const char* dir
)
240 if (target
[0] != 0 && target
[strlen( target
) - 1] != PathDelimiter
)
241 strncat( target
, SPathDelimiter
, _MAX_PATH
);
242 strncat( target
, dir
, _MAX_PATH
);
248 bool FindInDir(const char* Dir
, char *Filename
)
250 // First test if there's a Filename with exactly same name
251 // and if yes, return it and do not search in the Dir
252 char TempFilePath
[_MAX_PATH
];
253 strcpy(TempFilePath
, Dir
);
254 PathAppend( TempFilePath
, Filename
);
256 if (!access( TempFilePath
, R_OK
)) {
260 if (!core
->CaseSensitive
) {
264 DIR* dir
= opendir( Dir
);
269 // Exact match not found, so try to search for Filename
270 // with different case
271 struct dirent
* de
= readdir( dir
);
277 if (stricmp( de
->d_name
, Filename
) == 0) {
278 strcpy( Filename
, de
->d_name
);
282 } while (( de
= readdir( dir
) ) != NULL
);
283 closedir( dir
); //No other files in the directory, close it
287 bool PathJoin (char *target
, const char *base
, ...)
297 strcpy(target
, base
);
299 while (char *source
= va_arg(ap
, char*)) {
302 char filename
[_MAX_PATH
] = { '\0' };
303 slash
= strchr(source
, PathDelimiter
);
304 if (slash
== source
) {
308 strncat(filename
, source
, slash
-source
);
310 strcpy(filename
, source
);
312 if (!FindInDir(target
, filename
)) {
313 PathAppend(target
, source
);
316 PathAppend(target
, filename
);
323 while (char *source
= va_arg(ap
, char*)) {
324 PathAppend(target
, source
);
330 bool PathJoinExt (char* target
, const char* dir
, const char* base
, const char* ext
)
332 char file
[_MAX_PATH
];
336 return PathJoin(target
, dir
, file
, NULL
);
339 /** Fixes path delimiter character (slash).
340 * needslash = true : we add a slash
341 * needslash = false: we remove the slash
343 void FixPath (char *path
, bool needslash
)
345 size_t i
= strlen( path
) - 1;
348 if (path
[i
] == PathDelimiter
) return;
350 // if path is already too long, don't do anything
351 if (i
>= _MAX_PATH
- 2) return;
353 path
[i
++] = PathDelimiter
;
356 if (path
[i
] != PathDelimiter
) return;
361 int strmatch(const char *string
, const char *mask
)
365 if (tolower(*mask
)!=tolower(*string
)) {
375 bool FileGlob(char* target
, const char* Dir
, const char *glob
)
377 DIR* dir
= opendir( Dir
);
382 struct dirent
* de
= readdir( dir
);
388 if (strmatch( de
->d_name
, glob
) == 0) {
389 strcpy( target
, de
->d_name
);
393 } while (( de
= readdir( dir
) ) != NULL
);
394 closedir( dir
); //No other files in the directory, close it
401 void ResolveFilePath(char* FilePath
)
403 char TempFilePath
[_MAX_PATH
];
405 if (FilePath
[0]=='~') {
406 const char *home
= getenv("HOME");
408 strcpy(TempFilePath
, FilePath
+1);
409 PathJoin(FilePath
, home
, TempFilePath
, NULL
);
414 if (core
&& !core
->CaseSensitive
) {
417 strcpy(TempFilePath
, FilePath
);
418 PathJoin(FilePath
, TempFilePath
[0]==PathDelimiter
?SPathDelimiter
:"", TempFilePath
, NULL
);
423 void ExtractFileFromPath(char *file
, const char *full_path
)
426 if ((p
= strrchr (full_path
, PathDelimiter
)))
428 else if ((p
= strchr (full_path
, ':')))
431 strcpy(file
, full_path
);