~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to source/Irrlicht/CFileSystem.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
 
2
// This file is part of the "Irrlicht Engine".
 
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
 
4
 
 
5
#include "IrrCompileConfig.h"
 
6
 
 
7
#include "CFileSystem.h"
 
8
#include "IReadFile.h"
 
9
#include "IWriteFile.h"
 
10
#include "CZipReader.h"
 
11
#include "CMountPointReader.h"
 
12
#include "CPakReader.h"
 
13
#include "CNPKReader.h"
 
14
#include "CTarReader.h"
 
15
#include "CWADReader.h"
 
16
#include "CFileList.h"
 
17
#include "CXMLReader.h"
 
18
#include "CXMLWriter.h"
 
19
#include "stdio.h"
 
20
#include "os.h"
 
21
#include "CAttributes.h"
 
22
#include "CMemoryFile.h"
 
23
#include "CLimitReadFile.h"
 
24
#include "irrList.h"
 
25
 
 
26
#if defined (_IRR_WINDOWS_API_)
 
27
        #if !defined ( _WIN32_WCE )
 
28
                #include <direct.h> // for _chdir
 
29
                #include <io.h> // for _access
 
30
                #include <tchar.h>
 
31
        #endif
 
32
#else
 
33
        #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
 
34
                #include <stdio.h>
 
35
                #include <stdlib.h>
 
36
                #include <string.h>
 
37
                #include <limits.h>
 
38
                #include <sys/types.h>
 
39
                #include <dirent.h>
 
40
                #include <sys/stat.h>
 
41
                #include <unistd.h>
 
42
        #endif
 
43
#endif
 
44
 
 
45
namespace irr
 
46
{
 
47
namespace io
 
48
{
 
49
 
 
50
//! constructor
 
51
CFileSystem::CFileSystem()
 
52
{
 
53
        #ifdef _DEBUG
 
54
        setDebugName("CFileSystem");
 
55
        #endif
 
56
 
 
57
        setFileListSystem(FILESYSTEM_NATIVE);
 
58
        //! reset current working directory
 
59
        getWorkingDirectory();
 
60
 
 
61
#ifdef __IRR_COMPILE_WITH_PAK_ARCHIVE_LOADER_
 
62
        ArchiveLoader.push_back(new CArchiveLoaderPAK(this));
 
63
#endif
 
64
 
 
65
#ifdef __IRR_COMPILE_WITH_NPK_ARCHIVE_LOADER_
 
66
        ArchiveLoader.push_back(new CArchiveLoaderNPK(this));
 
67
#endif
 
68
 
 
69
#ifdef __IRR_COMPILE_WITH_TAR_ARCHIVE_LOADER_
 
70
        ArchiveLoader.push_back(new CArchiveLoaderTAR(this));
 
71
#endif
 
72
 
 
73
#ifdef __IRR_COMPILE_WITH_WAD_ARCHIVE_LOADER_
 
74
        ArchiveLoader.push_back(new CArchiveLoaderWAD(this));
 
75
#endif
 
76
 
 
77
#ifdef __IRR_COMPILE_WITH_MOUNT_ARCHIVE_LOADER_
 
78
        ArchiveLoader.push_back(new CArchiveLoaderMount(this));
 
79
#endif
 
80
 
 
81
#ifdef __IRR_COMPILE_WITH_ZIP_ARCHIVE_LOADER_
 
82
        ArchiveLoader.push_back(new CArchiveLoaderZIP(this));
 
83
#endif
 
84
 
 
85
}
 
86
 
 
87
 
 
88
//! destructor
 
89
CFileSystem::~CFileSystem()
 
90
{
 
91
        u32 i;
 
92
 
 
93
        for ( i=0; i < FileArchives.size(); ++i)
 
94
        {
 
95
                FileArchives[i]->drop();
 
96
        }
 
97
 
 
98
        for ( i=0; i < ArchiveLoader.size(); ++i)
 
99
        {
 
100
                ArchiveLoader[i]->drop();
 
101
        }
 
102
}
 
103
 
 
104
 
 
105
//! opens a file for read access
 
106
IReadFile* CFileSystem::createAndOpenFile(const io::path& filename)
 
107
{
 
108
        IReadFile* file = 0;
 
109
        u32 i;
 
110
 
 
111
        for (i=0; i< FileArchives.size(); ++i)
 
112
        {
 
113
                file = FileArchives[i]->createAndOpenFile(filename);
 
114
                if (file)
 
115
                        return file;
 
116
        }
 
117
 
 
118
        // Create the file using an absolute path so that it matches
 
119
        // the scheme used by CNullDriver::getTexture().
 
120
        return createReadFile(getAbsolutePath(filename));
 
121
}
 
122
 
 
123
 
 
124
//! Creates an IReadFile interface for treating memory like a file.
 
125
IReadFile* CFileSystem::createMemoryReadFile(void* memory, s32 len,
 
126
                const io::path& fileName, bool deleteMemoryWhenDropped)
 
127
{
 
128
        if (!memory)
 
129
                return 0;
 
130
        else
 
131
                return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped);
 
132
                        }
 
133
 
 
134
 
 
135
//! Creates an IReadFile interface for reading files inside files
 
136
IReadFile* CFileSystem::createLimitReadFile(const io::path& fileName,
 
137
                IReadFile* alreadyOpenedFile, long pos, long areaSize)
 
138
{
 
139
        if (!alreadyOpenedFile)
 
140
                return 0;
 
141
        else
 
142
                return new CLimitReadFile(alreadyOpenedFile, pos, areaSize, fileName);
 
143
}
 
144
 
 
145
 
 
146
//! Creates an IReadFile interface for treating memory like a file.
 
147
IWriteFile* CFileSystem::createMemoryWriteFile(void* memory, s32 len,
 
148
                const io::path& fileName, bool deleteMemoryWhenDropped)
 
149
{
 
150
        if (!memory)
 
151
                return 0;
 
152
        else
 
153
                return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped);
 
154
}
 
155
 
 
156
 
 
157
//! Opens a file for write access.
 
158
IWriteFile* CFileSystem::createAndWriteFile(const io::path& filename, bool append)
 
159
{
 
160
        return createWriteFile(filename, append);
 
161
}
 
162
 
 
163
 
 
164
//! Adds an external archive loader to the engine.
 
165
void CFileSystem::addArchiveLoader(IArchiveLoader* loader)
 
166
{
 
167
        if (!loader)
 
168
                return;
 
169
 
 
170
        loader->grab();
 
171
        ArchiveLoader.push_back(loader);
 
172
}
 
173
 
 
174
//! Returns the total number of archive loaders added.
 
175
u32 CFileSystem::getArchiveLoaderCount() const
 
176
{
 
177
        return ArchiveLoader.size();
 
178
}
 
179
 
 
180
//! Gets the archive loader by index.
 
181
IArchiveLoader* CFileSystem::getArchiveLoader(u32 index) const
 
182
{
 
183
        if (index < ArchiveLoader.size())
 
184
                return ArchiveLoader[index];
 
185
        else
 
186
                return 0;
 
187
}
 
188
 
 
189
//! move the hirarchy of the filesystem. moves sourceIndex relative up or down
 
190
bool CFileSystem::moveFileArchive(u32 sourceIndex, s32 relative)
 
191
{
 
192
        bool r = false;
 
193
        const s32 dest = (s32) sourceIndex + relative;
 
194
        const s32 dir = relative < 0 ? -1 : 1;
 
195
        const s32 sourceEnd = ((s32) FileArchives.size() ) - 1;
 
196
        IFileArchive *t;
 
197
 
 
198
        for (s32 s = (s32) sourceIndex;s != dest; s += dir)
 
199
        {
 
200
                if (s < 0 || s > sourceEnd || s + dir < 0 || s + dir > sourceEnd)
 
201
                        continue;
 
202
 
 
203
                t = FileArchives[s + dir];
 
204
                FileArchives[s + dir] = FileArchives[s];
 
205
                FileArchives[s] = t;
 
206
                r = true;
 
207
        }
 
208
        return r;
 
209
}
 
210
 
 
211
 
 
212
//! Adds an archive to the file system.
 
213
bool CFileSystem::addFileArchive(const io::path& filename, bool ignoreCase,
 
214
                          bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType,
 
215
                          const core::stringc& password)
 
216
{
 
217
        IFileArchive* archive = 0;
 
218
        bool ret = false;
 
219
 
 
220
        // see if archive is already added
 
221
        if (changeArchivePassword(filename, password))
 
222
                return true;
 
223
 
 
224
        s32 i;
 
225
 
 
226
        // do we know what type it should be?
 
227
        if (archiveType == EFAT_UNKNOWN || archiveType == EFAT_FOLDER)
 
228
        {
 
229
                // try to load archive based on file name
 
230
                for (i = ArchiveLoader.size()-1; i >=0 ; --i)
 
231
                {
 
232
                        if (ArchiveLoader[i]->isALoadableFileFormat(filename))
 
233
                        {
 
234
                                archive = ArchiveLoader[i]->createArchive(filename, ignoreCase, ignorePaths);
 
235
                                if (archive)
 
236
                                        break;
 
237
                        }
 
238
                }
 
239
 
 
240
                // try to load archive based on content
 
241
                if (!archive)
 
242
                {
 
243
                        io::IReadFile* file = createAndOpenFile(filename);
 
244
                        if (file)
 
245
                        {
 
246
                                for (i = ArchiveLoader.size()-1; i >= 0; --i)
 
247
                                {
 
248
                                        file->seek(0);
 
249
                                        if (ArchiveLoader[i]->isALoadableFileFormat(file))
 
250
                                        {
 
251
                                                file->seek(0);
 
252
                                                archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
 
253
                                                if (archive)
 
254
                                                        break;
 
255
                                        }
 
256
                                }
 
257
                                file->drop();
 
258
                        }
 
259
                }
 
260
        }
 
261
        else
 
262
        {
 
263
                // try to open archive based on archive loader type
 
264
 
 
265
                io::IReadFile* file = 0;
 
266
 
 
267
                for (i = ArchiveLoader.size()-1; i >= 0; --i)
 
268
                {
 
269
                        if (ArchiveLoader[i]->isALoadableFileFormat(archiveType))
 
270
                        {
 
271
                                // attempt to open file
 
272
                                if (!file)
 
273
                                        file = createAndOpenFile(filename);
 
274
 
 
275
                                // is the file open?
 
276
                                if (file)
 
277
                                {
 
278
                                        // attempt to open archive
 
279
                                        file->seek(0);
 
280
                                        if (ArchiveLoader[i]->isALoadableFileFormat(file))
 
281
                                        {
 
282
                                                file->seek(0);
 
283
                                                archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
 
284
                                                if (archive)
 
285
                                                        break;
 
286
                                        }
 
287
                                }
 
288
                                else
 
289
                                {
 
290
                                        // couldn't open file
 
291
                                        break;
 
292
                                }
 
293
                        }
 
294
                }
 
295
 
 
296
                // if open, close the file
 
297
                if (file)
 
298
                        file->drop();
 
299
        }
 
300
 
 
301
        if (archive)
 
302
        {
 
303
                FileArchives.push_back(archive);
 
304
                if (password.size())
 
305
                        archive->Password=password;
 
306
                ret = true;
 
307
        }
 
308
        else
 
309
        {
 
310
                os::Printer::log("Could not create archive for", filename, ELL_ERROR);
 
311
        }
 
312
 
 
313
        _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
 
314
        return ret;
 
315
}
 
316
 
 
317
// don't expose!
 
318
bool CFileSystem::changeArchivePassword(const path& filename, const core::stringc& password)
 
319
{
 
320
        for (s32 idx = 0; idx < (s32)FileArchives.size(); ++idx)
 
321
        {
 
322
                // TODO: This should go into a path normalization method
 
323
                // We need to check for directory names with trailing slash and without
 
324
                const path absPath = getAbsolutePath(filename);
 
325
                const path arcPath = FileArchives[idx]->getFileList()->getPath();
 
326
                if ((absPath == arcPath) || ((absPath+_IRR_TEXT("/")) == arcPath))
 
327
                {
 
328
                        if (password.size())
 
329
                                FileArchives[idx]->Password=password;
 
330
                        return true;
 
331
                }
 
332
        }
 
333
 
 
334
        return false;
 
335
}
 
336
 
 
337
bool CFileSystem::addFileArchive(IReadFile* file, bool ignoreCase, bool ignorePaths,
 
338
                        E_FILE_ARCHIVE_TYPE archiveType, const core::stringc& password)
 
339
{
 
340
        if (!file || archiveType == EFAT_FOLDER)
 
341
                return false;
 
342
 
 
343
        if (file)
 
344
        {
 
345
                if (changeArchivePassword(file->getFileName(), password))
 
346
                        return true;
 
347
 
 
348
                IFileArchive* archive = 0;
 
349
                s32 i;
 
350
 
 
351
                if (archiveType == EFAT_UNKNOWN)
 
352
                {
 
353
                        // try to load archive based on file name
 
354
                        for (i = ArchiveLoader.size()-1; i >=0 ; --i)
 
355
                        {
 
356
                                if (ArchiveLoader[i]->isALoadableFileFormat(file->getFileName()))
 
357
                                {
 
358
                                        archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
 
359
                                        if (archive)
 
360
                                                break;
 
361
                                }
 
362
                        }
 
363
 
 
364
                        // try to load archive based on content
 
365
                        if (!archive)
 
366
                        {
 
367
                                for (i = ArchiveLoader.size()-1; i >= 0; --i)
 
368
                                {
 
369
                                        file->seek(0);
 
370
                                        if (ArchiveLoader[i]->isALoadableFileFormat(file))
 
371
                                        {
 
372
                                                file->seek(0);
 
373
                                                archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
 
374
                                                if (archive)
 
375
                                                        break;
 
376
                                        }
 
377
                                }
 
378
                        }
 
379
                }
 
380
                else
 
381
                {
 
382
                        // try to open archive based on archive loader type
 
383
                        for (i = ArchiveLoader.size()-1; i >= 0; --i)
 
384
                        {
 
385
                                if (ArchiveLoader[i]->isALoadableFileFormat(archiveType))
 
386
                                {
 
387
                                        // attempt to open archive
 
388
                                        file->seek(0);
 
389
                                        if (ArchiveLoader[i]->isALoadableFileFormat(file))
 
390
                                        {
 
391
                                                file->seek(0);
 
392
                                                archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths);
 
393
                                                if (archive)
 
394
                                                        break;
 
395
                                        }
 
396
                                }
 
397
                        }
 
398
                }
 
399
 
 
400
                if (archive)
 
401
                {
 
402
                        FileArchives.push_back(archive);
 
403
                        if (password.size())
 
404
                                archive->Password=password;
 
405
                        return true;
 
406
                }
 
407
                else
 
408
                {
 
409
                        os::Printer::log("Could not create archive for", file->getFileName(), ELL_ERROR);
 
410
                }
 
411
        }
 
412
 
 
413
        return false;
 
414
}
 
415
 
 
416
 
 
417
//! removes an archive from the file system.
 
418
bool CFileSystem::removeFileArchive(u32 index)
 
419
{
 
420
        bool ret = false;
 
421
        if (index < FileArchives.size())
 
422
        {
 
423
                FileArchives[index]->drop();
 
424
                FileArchives.erase(index);
 
425
                ret = true;
 
426
        }
 
427
        _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
 
428
        return ret;
 
429
}
 
430
 
 
431
 
 
432
//! removes an archive from the file system.
 
433
bool CFileSystem::removeFileArchive(const io::path& filename)
 
434
{
 
435
        for (u32 i=0; i < FileArchives.size(); ++i)
 
436
        {
 
437
                if (filename == FileArchives[i]->getFileList()->getPath())
 
438
                        return removeFileArchive(i);
 
439
        }
 
440
        _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
 
441
        return false;
 
442
}
 
443
 
 
444
 
 
445
//! gets an archive
 
446
u32 CFileSystem::getFileArchiveCount() const
 
447
{
 
448
        return FileArchives.size();
 
449
}
 
450
 
 
451
 
 
452
IFileArchive* CFileSystem::getFileArchive(u32 index)
 
453
{
 
454
        return index < getFileArchiveCount() ? FileArchives[index] : 0;
 
455
}
 
456
 
 
457
 
 
458
//! Returns the string of the current working directory
 
459
const io::path& CFileSystem::getWorkingDirectory()
 
460
{
 
461
        EFileSystemType type = FileSystemType;
 
462
 
 
463
        if (type != FILESYSTEM_NATIVE)
 
464
        {
 
465
                type = FILESYSTEM_VIRTUAL;
 
466
        }
 
467
        else
 
468
        {
 
469
                #if defined(_IRR_WINDOWS_CE_PLATFORM_)
 
470
                // does not need this
 
471
                #elif defined(_IRR_WINDOWS_API_)
 
472
                        fschar_t tmp[_MAX_PATH];
 
473
                        #if defined(_IRR_WCHAR_FILESYSTEM )
 
474
                                _wgetcwd(tmp, _MAX_PATH);
 
475
                                WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
 
476
                                WorkingDirectory[FILESYSTEM_NATIVE].replace(L'\\', L'/');
 
477
                        #else
 
478
                                _getcwd(tmp, _MAX_PATH);
 
479
                                WorkingDirectory[FILESYSTEM_NATIVE] = tmp;
 
480
                                WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/');
 
481
                        #endif
 
482
                #endif
 
483
 
 
484
                #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
 
485
 
 
486
                        // getting the CWD is rather complex as we do not know the size
 
487
                        // so try it until the call was successful
 
488
                        // Note that neither the first nor the second parameter may be 0 according to POSIX
 
489
 
 
490
                        #if defined(_IRR_WCHAR_FILESYSTEM )
 
491
                                u32 pathSize=256;
 
492
                                wchar_t *tmpPath = new wchar_t[pathSize];
 
493
                                while ((pathSize < (1<<16)) && !(wgetcwd(tmpPath,pathSize)))
 
494
                                {
 
495
                                        delete [] tmpPath;
 
496
                                        pathSize *= 2;
 
497
                                        tmpPath = new char[pathSize];
 
498
                                }
 
499
                                if (tmpPath)
 
500
                                {
 
501
                                        WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath;
 
502
                                        delete [] tmpPath;
 
503
                                }
 
504
                        #else
 
505
                                u32 pathSize=256;
 
506
                                char *tmpPath = new char[pathSize];
 
507
                                while ((pathSize < (1<<16)) && !(getcwd(tmpPath,pathSize)))
 
508
                                {
 
509
                                        delete [] tmpPath;
 
510
                                        pathSize *= 2;
 
511
                                        tmpPath = new char[pathSize];
 
512
                                }
 
513
                                if (tmpPath)
 
514
                                {
 
515
                                        WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath;
 
516
                                        delete [] tmpPath;
 
517
                                }
 
518
                        #endif
 
519
                #endif
 
520
 
 
521
                WorkingDirectory[type].validate();
 
522
        }
 
523
 
 
524
        return WorkingDirectory[type];
 
525
}
 
526
 
 
527
 
 
528
//! Changes the current Working Directory to the given string.
 
529
bool CFileSystem::changeWorkingDirectoryTo(const io::path& newDirectory)
 
530
{
 
531
        bool success=false;
 
532
 
 
533
        if (FileSystemType != FILESYSTEM_NATIVE)
 
534
        {
 
535
                WorkingDirectory[FILESYSTEM_VIRTUAL] = newDirectory;
 
536
                // is this empty string constant really intended?
 
537
                flattenFilename(WorkingDirectory[FILESYSTEM_VIRTUAL], _IRR_TEXT(""));
 
538
                success = 1;
 
539
        }
 
540
        else
 
541
        {
 
542
                WorkingDirectory[FILESYSTEM_NATIVE] = newDirectory;
 
543
 
 
544
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
 
545
                success = true;
 
546
#elif defined(_MSC_VER)
 
547
        #if defined(_IRR_WCHAR_FILESYSTEM)
 
548
                success=(_wchdir(newDirectory.c_str()) == 0);
 
549
        #else
 
550
                success=(_chdir(newDirectory.c_str()) == 0);
 
551
        #endif
 
552
#else
 
553
                success=(chdir(newDirectory.c_str()) == 0);
 
554
#endif
 
555
        }
 
556
 
 
557
        return success;
 
558
}
 
559
 
 
560
 
 
561
io::path CFileSystem::getAbsolutePath(const io::path& filename) const
 
562
{
 
563
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
 
564
        return filename;
 
565
#elif defined(_IRR_WINDOWS_API_)
 
566
        fschar_t *p=0;
 
567
        fschar_t fpath[_MAX_PATH];
 
568
        #if defined(_IRR_WCHAR_FILESYSTEM )
 
569
                p = _wfullpath(fpath, filename.c_str(), _MAX_PATH);
 
570
                core::stringw tmp(p);
 
571
                tmp.replace(L'\\', L'/');
 
572
        #else
 
573
                p = _fullpath(fpath, filename.c_str(), _MAX_PATH);
 
574
                core::stringc tmp(p);
 
575
                tmp.replace('\\', '/');
 
576
        #endif
 
577
        return tmp;
 
578
#elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
 
579
        c8* p=0;
 
580
        c8 fpath[4096];
 
581
        fpath[0]=0;
 
582
        p = realpath(filename.c_str(), fpath);
 
583
        if (!p)
 
584
        {
 
585
                // content in fpath is unclear at this point
 
586
                if (!fpath[0]) // seems like fpath wasn't altered, use our best guess
 
587
                {
 
588
                        io::path tmp(filename);
 
589
                        return flattenFilename(tmp);
 
590
                }
 
591
                else
 
592
                        return io::path(fpath);
 
593
        }
 
594
        if (filename[filename.size()-1]=='/')
 
595
                return io::path(p)+_IRR_TEXT("/");
 
596
        else
 
597
                return io::path(p);
 
598
#else
 
599
        return io::path(filename);
 
600
#endif
 
601
}
 
602
 
 
603
 
 
604
//! returns the directory part of a filename, i.e. all until the first
 
605
//! slash or backslash, excluding it. If no directory path is prefixed, a '.'
 
606
//! is returned.
 
607
io::path CFileSystem::getFileDir(const io::path& filename) const
 
608
{
 
609
        // find last forward or backslash
 
610
        s32 lastSlash = filename.findLast('/');
 
611
        const s32 lastBackSlash = filename.findLast('\\');
 
612
        lastSlash = lastSlash > lastBackSlash ? lastSlash : lastBackSlash;
 
613
 
 
614
        if ((u32)lastSlash < filename.size())
 
615
                return filename.subString(0, lastSlash);
 
616
        else
 
617
                return _IRR_TEXT(".");
 
618
}
 
619
 
 
620
 
 
621
//! returns the base part of a filename, i.e. all except for the directory
 
622
//! part. If no directory path is prefixed, the full name is returned.
 
623
io::path CFileSystem::getFileBasename(const io::path& filename, bool keepExtension) const
 
624
{
 
625
        // find last forward or backslash
 
626
        s32 lastSlash = filename.findLast('/');
 
627
        const s32 lastBackSlash = filename.findLast('\\');
 
628
        lastSlash = core::max_(lastSlash, lastBackSlash);
 
629
 
 
630
        // get number of chars after last dot
 
631
        s32 end = 0;
 
632
        if (!keepExtension)
 
633
        {
 
634
                // take care to search only after last slash to check only for
 
635
                // dots in the filename
 
636
                end = filename.findLast('.');
 
637
                if (end == -1 || end < lastSlash)
 
638
                        end=0;
 
639
                else
 
640
                        end = filename.size()-end;
 
641
        }
 
642
 
 
643
        if ((u32)lastSlash < filename.size())
 
644
                return filename.subString(lastSlash+1, filename.size()-lastSlash-1-end);
 
645
        else if (end != 0)
 
646
                return filename.subString(0, filename.size()-end);
 
647
        else
 
648
                return filename;
 
649
}
 
650
 
 
651
 
 
652
//! flatten a path and file name for example: "/you/me/../." becomes "/you"
 
653
io::path& CFileSystem::flattenFilename(io::path& directory, const io::path& root) const
 
654
{
 
655
        directory.replace('\\', '/');
 
656
        if (directory.lastChar() != '/')
 
657
                directory.append('/');
 
658
 
 
659
        io::path dir;
 
660
        io::path subdir;
 
661
 
 
662
        s32 lastpos = 0;
 
663
        s32 pos = 0;
 
664
        bool lastWasRealDir=false;
 
665
 
 
666
        while ((pos = directory.findNext('/', lastpos)) >= 0)
 
667
        {
 
668
                subdir = directory.subString(lastpos, pos - lastpos + 1);
 
669
 
 
670
                if (subdir == _IRR_TEXT("../"))
 
671
                {
 
672
                        if (lastWasRealDir)
 
673
                        {
 
674
                                deletePathFromPath(dir, 2);
 
675
                                lastWasRealDir=(dir.size()!=0);
 
676
                        }
 
677
                        else
 
678
                        {
 
679
                                dir.append(subdir);
 
680
                                lastWasRealDir=false;
 
681
                        }
 
682
                }
 
683
                else if (subdir == _IRR_TEXT("/"))
 
684
                {
 
685
                        dir = root;
 
686
                }
 
687
                else if (subdir != _IRR_TEXT("./"))
 
688
                {
 
689
                        dir.append(subdir);
 
690
                        lastWasRealDir=true;
 
691
                }
 
692
 
 
693
                lastpos = pos + 1;
 
694
        }
 
695
        directory = dir;
 
696
        return directory;
 
697
}
 
698
 
 
699
 
 
700
//! Get the relative filename, relative to the given directory
 
701
path CFileSystem::getRelativeFilename(const path& filename, const path& directory) const
 
702
{
 
703
        if ( filename.empty() || directory.empty() )
 
704
                return filename;
 
705
 
 
706
        io::path path1, file, ext;
 
707
        core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext);
 
708
        io::path path2(getAbsolutePath(directory));
 
709
        core::list<io::path> list1, list2;
 
710
        path1.split(list1, _IRR_TEXT("/\\"), 2);
 
711
        path2.split(list2, _IRR_TEXT("/\\"), 2);
 
712
        u32 i=0;
 
713
        core::list<io::path>::ConstIterator it1,it2;
 
714
        it1=list1.begin();
 
715
        it2=list2.begin();
 
716
 
 
717
        #if defined (_IRR_WINDOWS_API_)
 
718
        fschar_t partition1 = 0, partition2 = 0;
 
719
        io::path prefix1, prefix2;
 
720
        if ( it1 != list1.end() )
 
721
                prefix1 = *it1;
 
722
        if ( it2 != list2.end() )
 
723
                prefix2 = *it2;
 
724
        if ( prefix1.size() > 1 && prefix1[1] == _IRR_TEXT(':') )
 
725
                partition1 = core::locale_lower(prefix1[0]);
 
726
        if ( prefix2.size() > 1 && prefix2[1] == _IRR_TEXT(':') )
 
727
                partition2 = core::locale_lower(prefix2[0]);
 
728
 
 
729
        // must have the same prefix or we can't resolve it to a relative filename
 
730
        if ( partition1 != partition2 )
 
731
        {
 
732
                return filename;
 
733
        }
 
734
        #endif
 
735
 
 
736
 
 
737
        for (; i<list1.size() && i<list2.size() 
 
738
#if defined (_IRR_WINDOWS_API_)
 
739
                && (io::path(*it1).make_lower()==io::path(*it2).make_lower())
 
740
#else
 
741
                && (*it1==*it2)
 
742
#endif
 
743
                ; ++i)
 
744
        {
 
745
                ++it1;
 
746
                ++it2;
 
747
        }
 
748
        path1=_IRR_TEXT("");
 
749
        for (; i<list2.size(); ++i)
 
750
                path1 += _IRR_TEXT("../");
 
751
        while (it1 != list1.end())
 
752
        {
 
753
                path1 += *it1++;
 
754
                path1 += _IRR_TEXT('/');
 
755
        }
 
756
        path1 += file;
 
757
        if (ext.size())
 
758
        {
 
759
                path1 += _IRR_TEXT('.');
 
760
                path1 += ext;
 
761
        }
 
762
        return path1;
 
763
}
 
764
 
 
765
 
 
766
//! Sets the current file systen type
 
767
EFileSystemType CFileSystem::setFileListSystem(EFileSystemType listType)
 
768
{
 
769
        EFileSystemType current = FileSystemType;
 
770
        FileSystemType = listType;
 
771
        return current;
 
772
}
 
773
 
 
774
 
 
775
//! Creates a list of files and directories in the current working directory
 
776
IFileList* CFileSystem::createFileList()
 
777
{
 
778
        CFileList* r = 0;
 
779
        io::path Path = getWorkingDirectory();
 
780
        Path.replace('\\', '/');
 
781
        if (Path.lastChar() != '/')
 
782
                Path.append('/');
 
783
 
 
784
        //! Construct from native filesystem
 
785
        if (FileSystemType == FILESYSTEM_NATIVE)
 
786
        {
 
787
                // --------------------------------------------
 
788
                //! Windows version
 
789
                #ifdef _IRR_WINDOWS_API_
 
790
                #if !defined ( _WIN32_WCE )
 
791
 
 
792
                r = new CFileList(Path, true, false);
 
793
 
 
794
                struct _tfinddata_t c_file;
 
795
                long hFile;
 
796
 
 
797
                if( (hFile = _tfindfirst( _T("*"), &c_file )) != -1L )
 
798
                {
 
799
                        do
 
800
                        {
 
801
                                r->addItem(Path + c_file.name, 0, c_file.size, (_A_SUBDIR & c_file.attrib) != 0, 0);
 
802
                        }
 
803
                        while( _tfindnext( hFile, &c_file ) == 0 );
 
804
 
 
805
                        _findclose( hFile );
 
806
                }
 
807
                #endif
 
808
 
 
809
                //TODO add drives
 
810
                //entry.Name = "E:\\";
 
811
                //entry.isDirectory = true;
 
812
                //Files.push_back(entry);
 
813
                #endif
 
814
 
 
815
                // --------------------------------------------
 
816
                //! Linux version
 
817
                #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_))
 
818
 
 
819
 
 
820
                r = new CFileList(Path, false, false);
 
821
 
 
822
                r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0);
 
823
 
 
824
                //! We use the POSIX compliant methods instead of scandir
 
825
                DIR* dirHandle=opendir(Path.c_str());
 
826
                if (dirHandle)
 
827
                {
 
828
                        struct dirent *dirEntry;
 
829
                        while ((dirEntry=readdir(dirHandle)))
 
830
                        {
 
831
                                u32 size = 0;
 
832
                                bool isDirectory = false;
 
833
 
 
834
                                if((strcmp(dirEntry->d_name, ".")==0) ||
 
835
                                   (strcmp(dirEntry->d_name, "..")==0))
 
836
                                {
 
837
                                        continue;
 
838
                                }
 
839
                                struct stat buf;
 
840
                                if (stat(dirEntry->d_name, &buf)==0)
 
841
                                {
 
842
                                        size = buf.st_size;
 
843
                                        isDirectory = S_ISDIR(buf.st_mode);
 
844
                                }
 
845
                                #if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__)
 
846
                                // only available on some systems
 
847
                                else
 
848
                                {
 
849
                                        isDirectory = dirEntry->d_type == DT_DIR;
 
850
                                }
 
851
                                #endif
 
852
 
 
853
                                r->addItem(Path + dirEntry->d_name, 0, size, isDirectory, 0);
 
854
                        }
 
855
                        closedir(dirHandle);
 
856
                }
 
857
                #endif
 
858
        }
 
859
        else
 
860
        {
 
861
                //! create file list for the virtual filesystem
 
862
                r = new CFileList(Path, false, false);
 
863
 
 
864
                //! add relative navigation
 
865
                SFileListEntry e2;
 
866
                SFileListEntry e3;
 
867
 
 
868
                //! PWD
 
869
                r->addItem(Path + _IRR_TEXT("."), 0, 0, true, 0);
 
870
 
 
871
                //! parent
 
872
                r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0);
 
873
 
 
874
                //! merge archives
 
875
                for (u32 i=0; i < FileArchives.size(); ++i)
 
876
                {
 
877
                        const IFileList *merge = FileArchives[i]->getFileList();
 
878
 
 
879
                        for (u32 j=0; j < merge->getFileCount(); ++j)
 
880
                        {
 
881
                                if (core::isInSameDirectory(Path, merge->getFullFileName(j)) == 0)
 
882
                                {
 
883
                                        r->addItem(merge->getFullFileName(j), merge->getFileOffset(j), merge->getFileSize(j), merge->isDirectory(j), 0);
 
884
                                }
 
885
                        }
 
886
                }
 
887
        }
 
888
 
 
889
        if (r)
 
890
                r->sort();
 
891
        return r;
 
892
}
 
893
 
 
894
//! Creates an empty filelist
 
895
IFileList* CFileSystem::createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths)
 
896
{
 
897
        return new CFileList(path, ignoreCase, ignorePaths);
 
898
}
 
899
 
 
900
 
 
901
//! determines if a file exists and would be able to be opened.
 
902
bool CFileSystem::existFile(const io::path& filename) const
 
903
{
 
904
        for (u32 i=0; i < FileArchives.size(); ++i)
 
905
                if (FileArchives[i]->getFileList()->findFile(filename)!=-1)
 
906
                        return true;
 
907
 
 
908
#if defined(_IRR_WINDOWS_CE_PLATFORM_)
 
909
#if defined(_IRR_WCHAR_FILESYSTEM)
 
910
        HANDLE hFile = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
 
911
#else
 
912
        HANDLE hFile = CreateFileW(core::stringw(filename).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
 
913
#endif
 
914
        if (hFile == INVALID_HANDLE_VALUE)
 
915
                return false;
 
916
        else
 
917
        {
 
918
                CloseHandle(hFile);
 
919
                return true;
 
920
        }
 
921
#else
 
922
        _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
 
923
#if defined(_MSC_VER)
 
924
#if defined(_IRR_WCHAR_FILESYSTEM)
 
925
        return (_waccess(filename.c_str(), 0) != -1);
 
926
#else
 
927
        return (_access(filename.c_str(), 0) != -1);
 
928
#endif
 
929
#elif defined(F_OK)
 
930
        return (access(filename.c_str(), F_OK) != -1);
 
931
#else
 
932
    return (access(filename.c_str(), 0) != -1);
 
933
#endif
 
934
#endif
 
935
}
 
936
 
 
937
 
 
938
//! Creates a XML Reader from a file.
 
939
IXMLReader* CFileSystem::createXMLReader(const io::path& filename)
 
940
{
 
941
        IReadFile* file = createAndOpenFile(filename);
 
942
        if (!file)
 
943
                return 0;
 
944
 
 
945
        IXMLReader* reader = createXMLReader(file);
 
946
        file->drop();
 
947
        return reader;
 
948
}
 
949
 
 
950
 
 
951
//! Creates a XML Reader from a file.
 
952
IXMLReader* CFileSystem::createXMLReader(IReadFile* file)
 
953
{
 
954
        if (!file)
 
955
                return 0;
 
956
 
 
957
        return createIXMLReader(file);
 
958
}
 
959
 
 
960
 
 
961
//! Creates a XML Reader from a file.
 
962
IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(const io::path& filename)
 
963
{
 
964
        IReadFile* file = createAndOpenFile(filename);
 
965
        if (!file)
 
966
                return 0;
 
967
 
 
968
        IXMLReaderUTF8* reader = createIXMLReaderUTF8(file);
 
969
        file->drop();
 
970
        return reader;
 
971
}
 
972
 
 
973
 
 
974
//! Creates a XML Reader from a file.
 
975
IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(IReadFile* file)
 
976
{
 
977
        if (!file)
 
978
                return 0;
 
979
 
 
980
        return createIXMLReaderUTF8(file);
 
981
}
 
982
 
 
983
 
 
984
//! Creates a XML Writer from a file.
 
985
IXMLWriter* CFileSystem::createXMLWriter(const io::path& filename)
 
986
{
 
987
        IWriteFile* file = createAndWriteFile(filename);
 
988
        IXMLWriter* writer = 0;
 
989
        if (file)
 
990
        {
 
991
                writer = createXMLWriter(file);
 
992
                file->drop();
 
993
        }
 
994
        return writer;
 
995
}
 
996
 
 
997
 
 
998
//! Creates a XML Writer from a file.
 
999
IXMLWriter* CFileSystem::createXMLWriter(IWriteFile* file)
 
1000
{
 
1001
        return new CXMLWriter(file);
 
1002
}
 
1003
 
 
1004
 
 
1005
//! creates a filesystem which is able to open files from the ordinary file system,
 
1006
//! and out of zipfiles, which are able to be added to the filesystem.
 
1007
IFileSystem* createFileSystem()
 
1008
{
 
1009
        return new CFileSystem();
 
1010
}
 
1011
 
 
1012
 
 
1013
//! Creates a new empty collection of attributes, usable for serialization and more.
 
1014
IAttributes* CFileSystem::createEmptyAttributes(video::IVideoDriver* driver)
 
1015
{
 
1016
        return new CAttributes(driver);
 
1017
}
 
1018
 
 
1019
 
 
1020
} // end namespace irr
 
1021
} // end namespace io
 
1022