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