GUIScript: Make LoadSymbol return an object.
[gemrb.git] / gemrb / core / VFS.cpp
blobdc2c52cd0aa89f3e215f08ac034e266fa068dad4
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>
33 #ifndef WIN32
34 #include <dirent.h>
35 #endif
37 #ifndef S_ISDIR
38 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
39 #endif
41 #ifdef WIN32
43 struct DIR {
44 char path[_MAX_PATH];
45 bool is_first;
46 struct _finddata_t c_file;
47 long hFile;
50 struct dirent {
51 char d_name[_MAX_PATH];
54 // buffer which readdir returns
55 static dirent de;
57 DIR* opendir(const char* filename)
59 DIR* dirp = ( DIR* ) malloc( sizeof( DIR ) );
60 dirp->is_first = 1;
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
65 return dirp;
68 dirent* readdir(DIR* dirp)
70 struct _finddata_t c_file;
72 if (dirp->is_first) {
73 dirp->is_first = 0;
74 dirp->hFile = ( long ) _findfirst( dirp->path, &c_file );
75 if (dirp->hFile == -1L)
76 return NULL;
77 } else {
78 if (( long ) _findnext( dirp->hFile, &c_file ) != 0) {
79 return NULL;
83 strcpy( de.d_name, c_file.name );
85 return &de;
88 void closedir(DIR* dirp)
90 _findclose( dirp->hFile );
91 free( dirp );
95 _FILE* _fopen(const char* filename, const char* mode)
97 DWORD OpenFlags = 0;
98 DWORD AccessFlags = 0;
99 DWORD ShareFlags = 0;
101 while (*mode) {
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;
118 mode++;
120 HANDLE hFile = CreateFile( filename, AccessFlags, ShareFlags, NULL,
121 OpenFlags, FILE_ATTRIBUTE_NORMAL, NULL );
122 if (hFile == INVALID_HANDLE_VALUE) {
123 return NULL;
125 _FILE* ret = ( _FILE* ) malloc( sizeof( _FILE ) );
126 ret->hFile = hFile;
127 return ret;
130 size_t _fread(void* ptr, size_t size, size_t n, _FILE* stream)
132 if (!stream) {
133 return ( size_t ) 0;
135 unsigned long read;
136 if (!ReadFile( stream->hFile, ptr, ( unsigned long ) ( size * n ), &read,
137 NULL )) {
138 return ( size_t ) 0;
140 return ( size_t ) read;
143 size_t _fwrite(const void* ptr, size_t size, size_t n, _FILE* stream)
145 if (!stream) {
146 return ( size_t ) 0;
148 unsigned long wrote;
149 if (!WriteFile( stream->hFile, ptr, ( unsigned long ) ( size * n ),
150 &wrote, NULL )) {
151 return ( size_t ) 0;
153 return ( size_t ) wrote;
156 size_t _fseek(_FILE* stream, long offset, int whence)
158 if (!stream) {
159 return ( size_t ) 1;
161 unsigned long method;
162 switch (whence) {
163 case SEEK_SET:
164 method = FILE_BEGIN;
165 break;
166 case SEEK_CUR:
167 method = FILE_CURRENT;
168 break;
169 case SEEK_END:
170 method = FILE_END;
171 break;
172 default:
173 return ( size_t ) 1;
175 if (SetFilePointer( stream->hFile, offset, NULL, method ) == 0xffffffff) {
176 return ( size_t ) 1;
178 return ( size_t ) 0;
181 int _fgetc(_FILE* stream)
183 if (!stream) {
184 return 0;
186 unsigned char tmp;
187 unsigned long read;
188 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
189 NULL );
190 if (bResult && read) {
191 return ( int ) tmp;
193 return EOF;
196 long int _ftell(_FILE* stream)
198 if (!stream) {
199 return EOF;
201 unsigned long pos = SetFilePointer( stream->hFile, 0, NULL, FILE_CURRENT );
202 if (pos == 0xffffffff) {
203 return -1L;
205 return ( long int ) pos;
208 int _feof(_FILE* stream)
210 if (!stream) {
211 return 0;
213 unsigned char tmp;
214 unsigned long read;
215 BOOL bResult = ReadFile( stream->hFile, &tmp, ( unsigned long ) 1, &read,
216 NULL );
217 if (bResult && ( read == 0 )) {
218 return 1;
219 } //EOF
220 bResult = SetFilePointer( stream->hFile, -1, NULL, FILE_CURRENT );
221 return 0;
224 int _fclose(_FILE* stream)
226 if (!stream) {
227 return EOF;
229 if (!CloseHandle( stream->hFile )) {
230 return EOF;
232 free( stream );
233 return 0;
236 #endif // WIN32
239 /** Returns true if path is an existing directory */
240 bool dir_exists(const char* path)
242 struct stat buf;
244 buf.st_mode = 0;
245 stat( path, &buf );
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 );
261 return target;
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 )) {
274 return true;
277 if (!core->CaseSensitive) {
278 return false;
281 DirectoryIterator dir(Dir);
282 if (!dir) {
283 return false;
286 // Exact match not found, so try to search for Filename
287 // with different case
288 do {
289 const char *name = dir.GetName();
290 if (stricmp( name, Filename ) == 0) {
291 strcpy( Filename, name );
292 return true;
294 } while (++dir);
295 return false;
298 bool PathJoin (char *target, const char *base, ...)
300 va_list ap;
301 va_start(ap, base);
303 if (base == NULL) {
304 target[0] = '\0';
305 return false;
308 strcpy(target, base);
310 while (char *source = va_arg(ap, char*)) {
311 char *slash;
312 do {
313 char filename[_MAX_PATH] = { '\0' };
314 slash = strchr(source, PathDelimiter);
315 if (slash == source) {
316 ++source;
317 continue;
318 } else if (slash) {
319 strncat(filename, source, slash-source);
320 } else {
321 strcpy(filename, source);
323 if (!FindInDir(target, filename)) {
324 PathAppend(target, source);
325 goto finish;
327 PathAppend(target, filename);
328 source = slash + 1;
329 } while (slash);
331 va_end( ap );
332 return true;
333 finish:
334 while (char *source = va_arg(ap, char*)) {
335 PathAppend(target, source);
337 va_end( ap );
338 return false;
341 bool PathJoinExt (char* target, const char* dir, const char* base, const char* ext)
343 char file[_MAX_PATH];
344 strcpy(file, base);
345 strcat(file, ".");
346 strcat(file, ext);
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;
358 if (needslash) {
359 if (path[i] == PathDelimiter) return;
361 // if path is already too long, don't do anything
362 if (i >= _MAX_PATH - 2) return;
363 i++;
364 path[i++] = PathDelimiter;
366 else {
367 if (path[i] != PathDelimiter) return;
369 path[i] = 0;
372 int strmatch(const char *string, const char *mask)
374 while(*mask) {
375 if (*mask!='?') {
376 if (tolower(*mask)!=tolower(*string)) {
377 return 1;
380 mask++;
381 string++;
383 return 0;
386 bool FileGlob(char* target, const char* Dir, const char *glob)
388 DirectoryIterator dir(Dir);
389 if (!dir) {
390 return false;
393 do {
394 const char *name = dir.GetName();
395 if (strmatch( name, glob ) == 0) {
396 strcpy( target, name );
397 return true;
399 } while (++dir);
400 return false;
404 #ifndef WIN32
406 void ResolveFilePath(char* FilePath)
408 char TempFilePath[_MAX_PATH];
410 if (FilePath[0]=='~') {
411 const char *home = getenv("HOME");
412 if (home) {
413 strcpy(TempFilePath, FilePath+1);
414 PathJoin(FilePath, home, TempFilePath, NULL);
415 return;
419 if (core && !core->CaseSensitive) {
420 return;
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");
432 if (home) {
433 PathJoin(TempFilePath, home, FilePath.c_str()+1, NULL);
434 FilePath = TempFilePath;
435 return;
439 if (core && !core->CaseSensitive) {
440 return;
442 PathJoin(TempFilePath, FilePath[0]==PathDelimiter?SPathDelimiter:"", FilePath.c_str(), NULL);
443 FilePath = TempFilePath;
446 #endif
448 void ExtractFileFromPath(char *file, const char *full_path)
450 const char *p;
451 if ((p = strrchr (full_path, PathDelimiter)))
452 strcpy(file, p+1);
453 else if ((p = strchr (full_path, ':')))
454 strcpy(file, p+1);
455 else
456 strcpy(file, full_path);
459 DirectoryIterator::DirectoryIterator(const char *path)
460 : Directory(), Entry(), Path(path)
462 Rewind();
465 DirectoryIterator::~DirectoryIterator()
467 if (Directory)
468 closedir(static_cast<DIR*>(Directory));
471 bool DirectoryIterator::IsDirectory()
473 char dtmp[_MAX_PATH];
474 struct stat fst;
475 GetFullPath(dtmp);
476 stat( dtmp, &fst );
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));
493 return *this;
496 void DirectoryIterator::Rewind()
498 if (Directory)
499 closedir(static_cast<DIR*>(Directory));
500 Directory = opendir(Path);
501 if (Directory == NULL)
502 Entry = NULL;
503 else
504 Entry = readdir(static_cast<DIR*>(Directory));