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
29 #include "Interface.h"
33 // buffer which readdir returns
37 DIR* opendir(const char* filename
)
39 DIR* dirp
= ( DIR* ) malloc( sizeof( DIR ) );
42 sprintf( dirp
->path
, "%s%s*.*", filename
, SPathDelimiter
);
43 //if((hFile = (long)_findfirst(Path, &c_file)) == -1L) //If there is no file matching our search
48 dirent
* readdir(DIR* dirp
)
50 struct _finddata_t c_file
;
54 dirp
->hFile
= ( long ) _findfirst( dirp
->path
, &c_file
);
55 if (dirp
->hFile
== -1L)
58 if (( long ) _findnext( dirp
->hFile
, &c_file
) != 0) {
63 strcpy( de
.d_name
, c_file
.name
);
68 void closedir(DIR* dirp
)
70 _findclose( dirp
->hFile
);
75 _FILE
* _fopen(const char* filename
, const char* mode
)
78 DWORD AccessFlags
= 0;
82 if (( *mode
== 'w' ) || ( *mode
== 'W' )) {
83 OpenFlags
|= OPEN_ALWAYS
;
84 AccessFlags
|= GENERIC_WRITE
;
85 ShareFlags
|= FILE_SHARE_READ
;
86 } else if (( *mode
== 'r' ) || ( *mode
== 'R' )) {
87 OpenFlags
|= OPEN_EXISTING
;
88 AccessFlags
|= GENERIC_READ
;
89 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
90 } else if (( *mode
== 'a' ) || ( *mode
== 'A' )) {
91 OpenFlags
|= OPEN_ALWAYS
;
92 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
93 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
94 } else if (*mode
== '+') {
95 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
96 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
100 HANDLE hFile
= CreateFile( filename
, AccessFlags
, ShareFlags
, NULL
,
101 OpenFlags
, FILE_ATTRIBUTE_NORMAL
, NULL
);
102 if (hFile
== INVALID_HANDLE_VALUE
) {
105 _FILE
* ret
= ( _FILE
* ) malloc( sizeof( _FILE
) );
110 size_t _fread(void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
116 if (!ReadFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
), &read
,
120 return ( size_t ) read
;
123 size_t _fwrite(const void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
129 if (!WriteFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
),
133 return ( size_t ) wrote
;
136 size_t _fseek(_FILE
* stream
, long offset
, int whence
)
141 unsigned long method
;
147 method
= FILE_CURRENT
;
155 if (SetFilePointer( stream
->hFile
, offset
, NULL
, method
) == 0xffffffff) {
161 int _fgetc(_FILE
* stream
)
168 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
170 if (bResult
&& read
) {
176 long int _ftell(_FILE
* stream
)
181 unsigned long pos
= SetFilePointer( stream
->hFile
, 0, NULL
, FILE_CURRENT
);
182 if (pos
== 0xffffffff) {
185 return ( long int ) pos
;
188 int _feof(_FILE
* stream
)
195 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
197 if (bResult
&& ( read
== 0 )) {
200 bResult
= SetFilePointer( stream
->hFile
, -1, NULL
, FILE_CURRENT
);
204 int _fclose(_FILE
* stream
)
209 if (!CloseHandle( stream
->hFile
)) {
219 /** Returns true if path is an existing directory */
220 bool dir_exists(const char* path
)
226 return S_ISDIR( buf
.st_mode
) != 0;
232 * Appends dir 'dir' to path 'target' and returns 'target'.
233 * It takes care of inserting PathDelimiter ('/' or '\\') if needed
235 char* PathAppend (char* target
, const char* dir
)
237 if (target
[0] != 0 && target
[strlen( target
) - 1] != PathDelimiter
)
238 strncat( target
, SPathDelimiter
, _MAX_PATH
);
239 strncat( target
, dir
, _MAX_PATH
);
245 bool FindInDir(const char* Dir
, char *Filename
)
247 // First test if there's a Filename with exactly same name
248 // and if yes, return it and do not search in the Dir
249 char TempFilePath
[_MAX_PATH
];
250 strcpy(TempFilePath
, Dir
);
251 PathAppend( TempFilePath
, Filename
);
253 if (!access( TempFilePath
, R_OK
)) {
257 if (!core
->CaseSensitive
) {
261 DIR* dir
= opendir( Dir
);
266 // Exact match not found, so try to search for Filename
267 // with different case
268 struct dirent
* de
= readdir( dir
);
274 if (stricmp( de
->d_name
, Filename
) == 0) {
275 strcpy( Filename
, de
->d_name
);
279 } while (( de
= readdir( dir
) ) != NULL
);
280 closedir( dir
); //No other files in the directory, close it
284 bool PathJoin (char *target
, const char *base
, ...)
294 strcpy(target
, base
);
296 while (char *source
= va_arg(ap
, char*)) {
299 char filename
[_MAX_PATH
] = { '\0' };
300 slash
= strchr(source
, PathDelimiter
);
301 if (slash
== source
) {
305 strncat(filename
, source
, slash
-source
);
307 strcpy(filename
, source
);
309 if (!FindInDir(target
, filename
)) {
310 PathAppend(target
, source
);
313 PathAppend(target
, filename
);
320 while (char *source
= va_arg(ap
, char*)) {
321 PathAppend(target
, source
);
327 bool PathJoinExt (char* target
, const char* dir
, const char* base
, const char* ext
)
329 char file
[_MAX_PATH
];
333 return PathJoin(target
, dir
, file
, NULL
);
336 /** Fixes path delimiter character (slash).
337 * needslash = true : we add a slash
338 * needslash = false: we remove the slash
340 void FixPath (char *path
, bool needslash
)
342 size_t i
= strlen( path
) - 1;
345 if (path
[i
] == PathDelimiter
) return;
347 // if path is already too long, don't do anything
348 if (i
>= _MAX_PATH
- 2) return;
350 path
[i
++] = PathDelimiter
;
353 if (path
[i
] != PathDelimiter
) return;
358 int strmatch(const char *string
, const char *mask
)
362 if (tolower(*mask
)!=tolower(*string
)) {
372 bool FileGlob(char* target
, const char* Dir
, const char *glob
)
374 DIR* dir
= opendir( Dir
);
379 struct dirent
* de
= readdir( dir
);
385 if (strmatch( de
->d_name
, glob
) == 0) {
386 strcpy( target
, de
->d_name
);
390 } while (( de
= readdir( dir
) ) != NULL
);
391 closedir( dir
); //No other files in the directory, close it
398 void ResolveFilePath(char* FilePath
)
400 char TempFilePath
[_MAX_PATH
];
402 if (FilePath
[0]=='~') {
403 const char *home
= getenv("HOME");
405 strcpy(TempFilePath
, FilePath
+1);
406 PathJoin(FilePath
, home
, TempFilePath
, NULL
);
411 if (core
&& !core
->CaseSensitive
) {
414 strcpy(TempFilePath
, FilePath
);
415 PathJoin(FilePath
, "/", TempFilePath
, NULL
);
420 void ExtractFileFromPath(char *file
, const char *full_path
)
423 if ((p
= strrchr (full_path
, PathDelimiter
)))
425 else if ((p
= strchr (full_path
, ':')))
428 strcpy(file
, full_path
);