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