CodingStyle: Document header include order.
[gemrb.git] / gemrb / core / VFS.cpp
blobc2c6f51dc6d39e657c2f115d9997fc2177f9b946
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 "VFS.h"
26 #include "globals.h"
28 #include "Interface.h"
30 #include <cstdarg>
31 #include <cstring>
32 #include <sys/stat.h>
34 #ifdef WIN32
36 // buffer which readdir returns
37 static dirent de;
40 DIR* opendir(const char* filename)
42 DIR* dirp = ( DIR* ) malloc( sizeof( DIR ) );
43 dirp->is_first = 1;
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
48 return dirp;
51 dirent* readdir(DIR* dirp)
53 struct _finddata_t c_file;
55 if (dirp->is_first) {
56 dirp->is_first = 0;
57 dirp->hFile = ( long ) _findfirst( dirp->path, &c_file );
58 if (dirp->hFile == -1L)
59 return NULL;
60 } else {
61 if (( long ) _findnext( dirp->hFile, &c_file ) != 0) {
62 return NULL;
66 strcpy( de.d_name, c_file.name );
68 return &de;
71 void closedir(DIR* dirp)
73 _findclose( dirp->hFile );
74 free( dirp );
78 _FILE* _fopen(const char* filename, const char* mode)
80 DWORD OpenFlags = 0;
81 DWORD AccessFlags = 0;
82 DWORD ShareFlags = 0;
84 while (*mode) {
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;
101 mode++;
103 HANDLE hFile = CreateFile( filename, AccessFlags, ShareFlags, NULL,
104 OpenFlags, FILE_ATTRIBUTE_NORMAL, NULL );
105 if (hFile == INVALID_HANDLE_VALUE) {
106 return NULL;
108 _FILE* ret = ( _FILE* ) malloc( sizeof( _FILE ) );
109 ret->hFile = hFile;
110 return ret;
113 size_t _fread(void* ptr, size_t size, size_t n, _FILE* stream)
115 if (!stream) {
116 return ( size_t ) 0;
118 unsigned long read;
119 if (!ReadFile( stream->hFile, ptr, ( unsigned long ) ( size * n ), &read,
120 NULL )) {
121 return ( size_t ) 0;
123 return ( size_t ) read;
126 size_t _fwrite(const void* ptr, size_t size, size_t n, _FILE* stream)
128 if (!stream) {
129 return ( size_t ) 0;
131 unsigned long wrote;
132 if (!WriteFile( stream->hFile, ptr, ( unsigned long ) ( size * n ),
133 &wrote, NULL )) {
134 return ( size_t ) 0;
136 return ( size_t ) wrote;
139 size_t _fseek(_FILE* stream, long offset, int whence)
141 if (!stream) {
142 return ( size_t ) 1;
144 unsigned long method;
145 switch (whence) {
146 case SEEK_SET:
147 method = FILE_BEGIN;
148 break;
149 case SEEK_CUR:
150 method = FILE_CURRENT;
151 break;
152 case SEEK_END:
153 method = FILE_END;
154 break;
155 default:
156 return ( size_t ) 1;
158 if (SetFilePointer( stream->hFile, offset, NULL, method ) == 0xffffffff) {
159 return ( size_t ) 1;
161 return ( size_t ) 0;
164 int _fgetc(_FILE* stream)
166 if (!stream) {
167 return 0;
169 unsigned char tmp;
170 unsigned long read;
171 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
172 NULL );
173 if (bResult && read) {
174 return ( int ) tmp;
176 return EOF;
179 long int _ftell(_FILE* stream)
181 if (!stream) {
182 return EOF;
184 unsigned long pos = SetFilePointer( stream->hFile, 0, NULL, FILE_CURRENT );
185 if (pos == 0xffffffff) {
186 return -1L;
188 return ( long int ) pos;
191 int _feof(_FILE* stream)
193 if (!stream) {
194 return 0;
196 unsigned char tmp;
197 unsigned long read;
198 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
199 NULL );
200 if (bResult && ( read == 0 )) {
201 return 1;
202 } //EOF
203 bResult = SetFilePointer( stream->hFile, -1, NULL, FILE_CURRENT );
204 return 0;
207 int _fclose(_FILE* stream)
209 if (!stream) {
210 return EOF;
212 if (!CloseHandle( stream->hFile )) {
213 return EOF;
215 free( stream );
216 return 0;
219 #endif // WIN32
222 /** Returns true if path is an existing directory */
223 bool dir_exists(const char* path)
225 struct stat buf;
227 buf.st_mode = 0;
228 stat( path, &buf );
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 );
244 return target;
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 )) {
257 return true;
260 if (!core->CaseSensitive) {
261 return false;
264 DIR* dir = opendir( Dir );
265 if (dir == NULL) {
266 return false;
269 // Exact match not found, so try to search for Filename
270 // with different case
271 struct dirent* de = readdir( dir );
272 if (de == NULL) {
273 closedir( dir );
274 return false;
276 do {
277 if (stricmp( de->d_name, Filename ) == 0) {
278 strcpy( Filename, de->d_name );
279 closedir(dir);
280 return true;
282 } while (( de = readdir( dir ) ) != NULL);
283 closedir( dir ); //No other files in the directory, close it
284 return false;
287 bool PathJoin (char *target, const char *base, ...)
289 va_list ap;
290 va_start(ap, base);
292 if (base == NULL) {
293 target[0] = '\0';
294 return false;
297 strcpy(target, base);
299 while (char *source = va_arg(ap, char*)) {
300 char *slash;
301 do {
302 char filename[_MAX_PATH] = { '\0' };
303 slash = strchr(source, PathDelimiter);
304 if (slash == source) {
305 ++source;
306 continue;
307 } else if (slash) {
308 strncat(filename, source, slash-source);
309 } else {
310 strcpy(filename, source);
312 if (!FindInDir(target, filename)) {
313 PathAppend(target, source);
314 goto finish;
316 PathAppend(target, filename);
317 source = slash + 1;
318 } while (slash);
320 va_end( ap );
321 return true;
322 finish:
323 while (char *source = va_arg(ap, char*)) {
324 PathAppend(target, source);
326 va_end( ap );
327 return false;
330 bool PathJoinExt (char* target, const char* dir, const char* base, const char* ext)
332 char file[_MAX_PATH];
333 strcpy(file, base);
334 strcat(file, ".");
335 strcat(file, ext);
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;
347 if (needslash) {
348 if (path[i] == PathDelimiter) return;
350 // if path is already too long, don't do anything
351 if (i >= _MAX_PATH - 2) return;
352 i++;
353 path[i++] = PathDelimiter;
355 else {
356 if (path[i] != PathDelimiter) return;
358 path[i] = 0;
361 int strmatch(const char *string, const char *mask)
363 while(*mask) {
364 if (*mask!='?') {
365 if (tolower(*mask)!=tolower(*string)) {
366 return 1;
369 mask++;
370 string++;
372 return 0;
375 bool FileGlob(char* target, const char* Dir, const char *glob)
377 DIR* dir = opendir( Dir );
378 if (dir == NULL) {
379 return false;
382 struct dirent* de = readdir( dir );
383 if (de == NULL) {
384 closedir( dir );
385 return false;
387 do {
388 if (strmatch( de->d_name, glob ) == 0) {
389 strcpy( target, de->d_name );
390 closedir(dir);
391 return true;
393 } while (( de = readdir( dir ) ) != NULL);
394 closedir( dir ); //No other files in the directory, close it
395 return false;
399 #ifndef WIN32
401 void ResolveFilePath(char* FilePath)
403 char TempFilePath[_MAX_PATH];
405 if (FilePath[0]=='~') {
406 const char *home = getenv("HOME");
407 if (home) {
408 strcpy(TempFilePath, FilePath+1);
409 PathJoin(FilePath, home, TempFilePath, NULL);
410 return;
414 if (core && !core->CaseSensitive) {
415 return;
417 strcpy(TempFilePath, FilePath);
418 PathJoin(FilePath, TempFilePath[0]==PathDelimiter?SPathDelimiter:"", TempFilePath, NULL);
421 #endif
423 void ExtractFileFromPath(char *file, const char *full_path)
425 const char *p;
426 if ((p = strrchr (full_path, PathDelimiter)))
427 strcpy(file, p+1);
428 else if ((p = strchr (full_path, ':')))
429 strcpy(file, p+1);
430 else
431 strcpy(file, full_path);