GameScript: Move initialization out of constructor.
[gemrb.git] / gemrb / core / VFS.cpp
blob93bd9651d4e41d5b7fb680d57a04bca31909337a
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 <stdarg.h>
25 #include <sys/stat.h>
26 #include <cstring>
27 #include "globals.h"
28 #include "VFS.h"
29 #include "Interface.h"
31 #ifdef WIN32
33 // buffer which readdir returns
34 static dirent de;
37 DIR* opendir(const char* filename)
39 DIR* dirp = ( DIR* ) malloc( sizeof( DIR ) );
40 dirp->is_first = 1;
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
45 return dirp;
48 dirent* readdir(DIR* dirp)
50 struct _finddata_t c_file;
52 if (dirp->is_first) {
53 dirp->is_first = 0;
54 dirp->hFile = ( long ) _findfirst( dirp->path, &c_file );
55 if (dirp->hFile == -1L)
56 return NULL;
57 } else {
58 if (( long ) _findnext( dirp->hFile, &c_file ) != 0) {
59 return NULL;
63 strcpy( de.d_name, c_file.name );
65 return &de;
68 void closedir(DIR* dirp)
70 _findclose( dirp->hFile );
71 free( dirp );
75 _FILE* _fopen(const char* filename, const char* mode)
77 DWORD OpenFlags = 0;
78 DWORD AccessFlags = 0;
79 DWORD ShareFlags = 0;
81 while (*mode) {
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;
98 mode++;
100 HANDLE hFile = CreateFile( filename, AccessFlags, ShareFlags, NULL,
101 OpenFlags, FILE_ATTRIBUTE_NORMAL, NULL );
102 if (hFile == INVALID_HANDLE_VALUE) {
103 return NULL;
105 _FILE* ret = ( _FILE* ) malloc( sizeof( _FILE ) );
106 ret->hFile = hFile;
107 return ret;
110 size_t _fread(void* ptr, size_t size, size_t n, _FILE* stream)
112 if (!stream) {
113 return ( size_t ) 0;
115 unsigned long read;
116 if (!ReadFile( stream->hFile, ptr, ( unsigned long ) ( size * n ), &read,
117 NULL )) {
118 return ( size_t ) 0;
120 return ( size_t ) read;
123 size_t _fwrite(const void* ptr, size_t size, size_t n, _FILE* stream)
125 if (!stream) {
126 return ( size_t ) 0;
128 unsigned long wrote;
129 if (!WriteFile( stream->hFile, ptr, ( unsigned long ) ( size * n ),
130 &wrote, NULL )) {
131 return ( size_t ) 0;
133 return ( size_t ) wrote;
136 size_t _fseek(_FILE* stream, long offset, int whence)
138 if (!stream) {
139 return ( size_t ) 1;
141 unsigned long method;
142 switch (whence) {
143 case SEEK_SET:
144 method = FILE_BEGIN;
145 break;
146 case SEEK_CUR:
147 method = FILE_CURRENT;
148 break;
149 case SEEK_END:
150 method = FILE_END;
151 break;
152 default:
153 return ( size_t ) 1;
155 if (SetFilePointer( stream->hFile, offset, NULL, method ) == 0xffffffff) {
156 return ( size_t ) 1;
158 return ( size_t ) 0;
161 int _fgetc(_FILE* stream)
163 if (!stream) {
164 return 0;
166 unsigned char tmp;
167 unsigned long read;
168 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
169 NULL );
170 if (bResult && read) {
171 return ( int ) tmp;
173 return EOF;
176 long int _ftell(_FILE* stream)
178 if (!stream) {
179 return EOF;
181 unsigned long pos = SetFilePointer( stream->hFile, 0, NULL, FILE_CURRENT );
182 if (pos == 0xffffffff) {
183 return -1L;
185 return ( long int ) pos;
188 int _feof(_FILE* stream)
190 if (!stream) {
191 return 0;
193 unsigned char tmp;
194 unsigned long read;
195 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
196 NULL );
197 if (bResult && ( read == 0 )) {
198 return 1;
199 } //EOF
200 bResult = SetFilePointer( stream->hFile, -1, NULL, FILE_CURRENT );
201 return 0;
204 int _fclose(_FILE* stream)
206 if (!stream) {
207 return EOF;
209 if (!CloseHandle( stream->hFile )) {
210 return EOF;
212 free( stream );
213 return 0;
216 #endif // WIN32
219 /** Returns true if path is an existing directory */
220 bool dir_exists(const char* path)
222 struct stat buf;
224 buf.st_mode = 0;
225 stat( path, &buf );
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 );
241 return target;
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 )) {
254 return true;
257 if (!core->CaseSensitive) {
258 return false;
261 DIR* dir = opendir( Dir );
262 if (dir == NULL) {
263 return false;
266 // Exact match not found, so try to search for Filename
267 // with different case
268 struct dirent* de = readdir( dir );
269 if (de == NULL) {
270 closedir( dir );
271 return false;
273 do {
274 if (stricmp( de->d_name, Filename ) == 0) {
275 strcpy( Filename, de->d_name );
276 closedir(dir);
277 return true;
279 } while (( de = readdir( dir ) ) != NULL);
280 closedir( dir ); //No other files in the directory, close it
281 return false;
284 bool PathJoin (char *target, const char *base, ...)
286 va_list ap;
287 va_start(ap, base);
289 if (base == NULL) {
290 target[0] = '\0';
291 return false;
294 strcpy(target, base);
296 while (char *source = va_arg(ap, char*)) {
297 char *slash;
298 do {
299 char filename[_MAX_PATH] = { '\0' };
300 slash = strchr(source, PathDelimiter);
301 if (slash == source) {
302 ++source;
303 continue;
304 } else if (slash) {
305 strncat(filename, source, slash-source);
306 } else {
307 strcpy(filename, source);
309 if (!FindInDir(target, filename)) {
310 PathAppend(target, source);
311 goto finish;
313 PathAppend(target, filename);
314 source = slash + 1;
315 } while (slash);
317 va_end( ap );
318 return true;
319 finish:
320 while (char *source = va_arg(ap, char*)) {
321 PathAppend(target, source);
323 va_end( ap );
324 return false;
327 bool PathJoinExt (char* target, const char* dir, const char* base, const char* ext)
329 char file[_MAX_PATH];
330 strcpy(file, base);
331 strcat(file, ".");
332 strcat(file, ext);
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;
344 if (needslash) {
345 if (path[i] == PathDelimiter) return;
347 // if path is already too long, don't do anything
348 if (i >= _MAX_PATH - 2) return;
349 i++;
350 path[i++] = PathDelimiter;
352 else {
353 if (path[i] != PathDelimiter) return;
355 path[i] = 0;
358 int strmatch(const char *string, const char *mask)
360 while(*mask) {
361 if (*mask!='?') {
362 if (tolower(*mask)!=tolower(*string)) {
363 return 1;
366 mask++;
367 string++;
369 return 0;
372 bool FileGlob(char* target, const char* Dir, const char *glob)
374 DIR* dir = opendir( Dir );
375 if (dir == NULL) {
376 return false;
379 struct dirent* de = readdir( dir );
380 if (de == NULL) {
381 closedir( dir );
382 return false;
384 do {
385 if (strmatch( de->d_name, glob ) == 0) {
386 strcpy( target, de->d_name );
387 closedir(dir);
388 return true;
390 } while (( de = readdir( dir ) ) != NULL);
391 closedir( dir ); //No other files in the directory, close it
392 return false;
396 #ifndef WIN32
398 void ResolveFilePath(char* FilePath)
400 char TempFilePath[_MAX_PATH];
402 if (FilePath[0]=='~') {
403 const char *home = getenv("HOME");
404 if (home) {
405 strcpy(TempFilePath, FilePath+1);
406 PathJoin(FilePath, home, TempFilePath, NULL);
407 return;
411 if (core && !core->CaseSensitive) {
412 return;
414 strcpy(TempFilePath, FilePath);
415 PathJoin(FilePath, "/", TempFilePath, NULL);
418 #endif
420 void ExtractFileFromPath(char *file, const char *full_path)
422 const char *p;
423 if ((p = strrchr (full_path, PathDelimiter)))
424 strcpy(file, p+1);
425 else if ((p = strchr (full_path, ':')))
426 strcpy(file, p+1);
427 else
428 strcpy(file, full_path);