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"
38 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
46 struct _finddata_t c_file
;
51 char d_name
[_MAX_PATH
];
54 // buffer which readdir returns
57 DIR* opendir(const char* filename
)
59 DIR* dirp
= ( DIR* ) malloc( sizeof( DIR ) );
62 sprintf( dirp
->path
, "%s%s*.*", filename
, SPathDelimiter
);
63 //if((hFile = (long)_findfirst(Path, &c_file)) == -1L) //If there is no file matching our search
68 dirent
* readdir(DIR* dirp
)
70 struct _finddata_t c_file
;
74 dirp
->hFile
= ( long ) _findfirst( dirp
->path
, &c_file
);
75 if (dirp
->hFile
== -1L)
78 if (( long ) _findnext( dirp
->hFile
, &c_file
) != 0) {
83 strcpy( de
.d_name
, c_file
.name
);
88 void closedir(DIR* dirp
)
90 _findclose( dirp
->hFile
);
95 _FILE
* _fopen(const char* filename
, const char* mode
)
98 DWORD AccessFlags
= 0;
102 if (( *mode
== 'w' ) || ( *mode
== 'W' )) {
103 OpenFlags
|= OPEN_ALWAYS
;
104 AccessFlags
|= GENERIC_WRITE
;
105 ShareFlags
|= FILE_SHARE_READ
;
106 } else if (( *mode
== 'r' ) || ( *mode
== 'R' )) {
107 OpenFlags
|= OPEN_EXISTING
;
108 AccessFlags
|= GENERIC_READ
;
109 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
110 } else if (( *mode
== 'a' ) || ( *mode
== 'A' )) {
111 OpenFlags
|= OPEN_ALWAYS
;
112 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
113 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
114 } else if (*mode
== '+') {
115 AccessFlags
|= GENERIC_READ
|GENERIC_WRITE
;
116 ShareFlags
|= FILE_SHARE_READ
|FILE_SHARE_WRITE
;
120 HANDLE hFile
= CreateFile( filename
, AccessFlags
, ShareFlags
, NULL
,
121 OpenFlags
, FILE_ATTRIBUTE_NORMAL
, NULL
);
122 if (hFile
== INVALID_HANDLE_VALUE
) {
125 _FILE
* ret
= ( _FILE
* ) malloc( sizeof( _FILE
) );
130 size_t _fread(void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
136 if (!ReadFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
), &read
,
140 return ( size_t ) read
;
143 size_t _fwrite(const void* ptr
, size_t size
, size_t n
, _FILE
* stream
)
149 if (!WriteFile( stream
->hFile
, ptr
, ( unsigned long ) ( size
* n
),
153 return ( size_t ) wrote
;
156 size_t _fseek(_FILE
* stream
, long offset
, int whence
)
161 unsigned long method
;
167 method
= FILE_CURRENT
;
175 if (SetFilePointer( stream
->hFile
, offset
, NULL
, method
) == 0xffffffff) {
181 int _fgetc(_FILE
* stream
)
188 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
190 if (bResult
&& read
) {
196 long int _ftell(_FILE
* stream
)
201 unsigned long pos
= SetFilePointer( stream
->hFile
, 0, NULL
, FILE_CURRENT
);
202 if (pos
== 0xffffffff) {
205 return ( long int ) pos
;
208 int _feof(_FILE
* stream
)
215 BOOL bResult
= ReadFile( stream
->hFile
, &tmp
, ( unsigned long ) 1, &read
,
217 if (bResult
&& ( read
== 0 )) {
220 bResult
= SetFilePointer( stream
->hFile
, -1, NULL
, FILE_CURRENT
);
224 int _fclose(_FILE
* stream
)
229 if (!CloseHandle( stream
->hFile
)) {
239 /** Returns true if path is an existing directory */
240 bool dir_exists(const char* path
)
246 return S_ISDIR( buf
.st_mode
) != 0;
252 * Appends dir 'dir' to path 'target' and returns 'target'.
253 * It takes care of inserting PathDelimiter ('/' or '\\') if needed
255 char* PathAppend (char* target
, const char* dir
)
257 if (target
[0] != 0 && target
[strlen( target
) - 1] != PathDelimiter
)
258 strncat( target
, SPathDelimiter
, _MAX_PATH
);
259 strncat( target
, dir
, _MAX_PATH
);
265 bool FindInDir(const char* Dir
, char *Filename
)
267 // First test if there's a Filename with exactly same name
268 // and if yes, return it and do not search in the Dir
269 char TempFilePath
[_MAX_PATH
];
270 strcpy(TempFilePath
, Dir
);
271 PathAppend( TempFilePath
, Filename
);
273 if (!access( TempFilePath
, R_OK
)) {
277 if (!core
->CaseSensitive
) {
281 DirectoryIterator
dir(Dir
);
286 // Exact match not found, so try to search for Filename
287 // with different case
289 const char *name
= dir
.GetName();
290 if (stricmp( name
, Filename
) == 0) {
291 strcpy( Filename
, name
);
298 bool PathJoin (char *target
, const char *base
, ...)
308 strcpy(target
, base
);
310 while (char *source
= va_arg(ap
, char*)) {
313 char filename
[_MAX_PATH
] = { '\0' };
314 slash
= strchr(source
, PathDelimiter
);
315 if (slash
== source
) {
319 strncat(filename
, source
, slash
-source
);
321 strcpy(filename
, source
);
323 if (!FindInDir(target
, filename
)) {
324 PathAppend(target
, source
);
327 PathAppend(target
, filename
);
334 while (char *source
= va_arg(ap
, char*)) {
335 PathAppend(target
, source
);
341 bool PathJoinExt (char* target
, const char* dir
, const char* base
, const char* ext
)
343 char file
[_MAX_PATH
];
347 return PathJoin(target
, dir
, file
, NULL
);
350 /** Fixes path delimiter character (slash).
351 * needslash = true : we add a slash
352 * needslash = false: we remove the slash
354 void FixPath (char *path
, bool needslash
)
356 size_t i
= strlen( path
) - 1;
359 if (path
[i
] == PathDelimiter
) return;
361 // if path is already too long, don't do anything
362 if (i
>= _MAX_PATH
- 2) return;
364 path
[i
++] = PathDelimiter
;
367 if (path
[i
] != PathDelimiter
) return;
372 int strmatch(const char *string
, const char *mask
)
376 if (tolower(*mask
)!=tolower(*string
)) {
386 bool FileGlob(char* target
, const char* Dir
, const char *glob
)
388 DirectoryIterator
dir(Dir
);
394 const char *name
= dir
.GetName();
395 if (strmatch( name
, glob
) == 0) {
396 strcpy( target
, name
);
406 void ResolveFilePath(char* FilePath
)
408 char TempFilePath
[_MAX_PATH
];
410 if (FilePath
[0]=='~') {
411 const char *home
= getenv("HOME");
413 strcpy(TempFilePath
, FilePath
+1);
414 PathJoin(FilePath
, home
, TempFilePath
, NULL
);
419 if (core
&& !core
->CaseSensitive
) {
422 strcpy(TempFilePath
, FilePath
);
423 PathJoin(FilePath
, TempFilePath
[0]==PathDelimiter
?SPathDelimiter
:"", TempFilePath
, NULL
);
426 void ResolveFilePath(std::string
& FilePath
)
428 char TempFilePath
[_MAX_PATH
];
430 if (FilePath
[0]=='~') {
431 const char *home
= getenv("HOME");
433 PathJoin(TempFilePath
, home
, FilePath
.c_str()+1, NULL
);
434 FilePath
= TempFilePath
;
439 if (core
&& !core
->CaseSensitive
) {
442 PathJoin(TempFilePath
, FilePath
[0]==PathDelimiter
?SPathDelimiter
:"", FilePath
.c_str(), NULL
);
443 FilePath
= TempFilePath
;
448 void ExtractFileFromPath(char *file
, const char *full_path
)
451 if ((p
= strrchr (full_path
, PathDelimiter
)))
453 else if ((p
= strchr (full_path
, ':')))
456 strcpy(file
, full_path
);
459 DirectoryIterator::DirectoryIterator(const char *path
)
460 : Directory(), Entry(), Path(path
)
465 DirectoryIterator::~DirectoryIterator()
468 closedir(static_cast<DIR*>(Directory
));
471 bool DirectoryIterator::IsDirectory()
473 char dtmp
[_MAX_PATH
];
477 return S_ISDIR( fst
.st_mode
);
480 char* DirectoryIterator::GetName()
482 return static_cast<dirent
*>(Entry
)->d_name
;
485 void DirectoryIterator::GetFullPath(char *name
)
487 snprintf(name
, _MAX_PATH
, "%s%s%s", Path
, SPathDelimiter
, static_cast<dirent
*>(Entry
)->d_name
);
490 DirectoryIterator
& DirectoryIterator::operator++()
492 Entry
= readdir(static_cast<DIR*>(Directory
));
496 void DirectoryIterator::Rewind()
499 closedir(static_cast<DIR*>(Directory
));
500 Directory
= opendir(Path
);
501 if (Directory
== NULL
)
504 Entry
= readdir(static_cast<DIR*>(Directory
));