diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CFileSystem.cpp | 1078 |
1 files changed, 1078 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CFileSystem.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CFileSystem.cpp new file mode 100644 index 0000000..0358480 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CFileSystem.cpp | |||
@@ -0,0 +1,1078 @@ | |||
1 | // Copyright (C) 2002-2012 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 | IFileArchive** retArchive) | ||
217 | { | ||
218 | IFileArchive* archive = 0; | ||
219 | bool ret = false; | ||
220 | |||
221 | // see if archive is already added | ||
222 | if (changeArchivePassword(filename, password, retArchive)) | ||
223 | return true; | ||
224 | |||
225 | s32 i; | ||
226 | |||
227 | // do we know what type it should be? | ||
228 | if (archiveType == EFAT_UNKNOWN || archiveType == EFAT_FOLDER) | ||
229 | { | ||
230 | // try to load archive based on file name | ||
231 | for (i = ArchiveLoader.size()-1; i >=0 ; --i) | ||
232 | { | ||
233 | if (ArchiveLoader[i]->isALoadableFileFormat(filename)) | ||
234 | { | ||
235 | archive = ArchiveLoader[i]->createArchive(filename, ignoreCase, ignorePaths); | ||
236 | if (archive) | ||
237 | break; | ||
238 | } | ||
239 | } | ||
240 | |||
241 | // try to load archive based on content | ||
242 | if (!archive) | ||
243 | { | ||
244 | io::IReadFile* file = createAndOpenFile(filename); | ||
245 | if (file) | ||
246 | { | ||
247 | for (i = ArchiveLoader.size()-1; i >= 0; --i) | ||
248 | { | ||
249 | file->seek(0); | ||
250 | if (ArchiveLoader[i]->isALoadableFileFormat(file)) | ||
251 | { | ||
252 | file->seek(0); | ||
253 | archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); | ||
254 | if (archive) | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | file->drop(); | ||
259 | } | ||
260 | } | ||
261 | } | ||
262 | else | ||
263 | { | ||
264 | // try to open archive based on archive loader type | ||
265 | |||
266 | io::IReadFile* file = 0; | ||
267 | |||
268 | for (i = ArchiveLoader.size()-1; i >= 0; --i) | ||
269 | { | ||
270 | if (ArchiveLoader[i]->isALoadableFileFormat(archiveType)) | ||
271 | { | ||
272 | // attempt to open file | ||
273 | if (!file) | ||
274 | file = createAndOpenFile(filename); | ||
275 | |||
276 | // is the file open? | ||
277 | if (file) | ||
278 | { | ||
279 | // attempt to open archive | ||
280 | file->seek(0); | ||
281 | if (ArchiveLoader[i]->isALoadableFileFormat(file)) | ||
282 | { | ||
283 | file->seek(0); | ||
284 | archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); | ||
285 | if (archive) | ||
286 | break; | ||
287 | } | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | // couldn't open file | ||
292 | break; | ||
293 | } | ||
294 | } | ||
295 | } | ||
296 | |||
297 | // if open, close the file | ||
298 | if (file) | ||
299 | file->drop(); | ||
300 | } | ||
301 | |||
302 | if (archive) | ||
303 | { | ||
304 | FileArchives.push_back(archive); | ||
305 | if (password.size()) | ||
306 | archive->Password=password; | ||
307 | if (retArchive) | ||
308 | *retArchive = archive; | ||
309 | ret = true; | ||
310 | } | ||
311 | else | ||
312 | { | ||
313 | os::Printer::log("Could not create archive for", filename, ELL_ERROR); | ||
314 | } | ||
315 | |||
316 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
317 | return ret; | ||
318 | } | ||
319 | |||
320 | // don't expose! | ||
321 | bool CFileSystem::changeArchivePassword(const path& filename, | ||
322 | const core::stringc& password, | ||
323 | IFileArchive** archive) | ||
324 | { | ||
325 | for (s32 idx = 0; idx < (s32)FileArchives.size(); ++idx) | ||
326 | { | ||
327 | // TODO: This should go into a path normalization method | ||
328 | // We need to check for directory names with trailing slash and without | ||
329 | const path absPath = getAbsolutePath(filename); | ||
330 | const path arcPath = FileArchives[idx]->getFileList()->getPath(); | ||
331 | if ((absPath == arcPath) || ((absPath+_IRR_TEXT("/")) == arcPath)) | ||
332 | { | ||
333 | if (password.size()) | ||
334 | FileArchives[idx]->Password=password; | ||
335 | if (archive) | ||
336 | *archive = FileArchives[idx]; | ||
337 | return true; | ||
338 | } | ||
339 | } | ||
340 | |||
341 | return false; | ||
342 | } | ||
343 | |||
344 | bool CFileSystem::addFileArchive(IReadFile* file, bool ignoreCase, | ||
345 | bool ignorePaths, E_FILE_ARCHIVE_TYPE archiveType, | ||
346 | const core::stringc& password, IFileArchive** retArchive) | ||
347 | { | ||
348 | if (!file || archiveType == EFAT_FOLDER) | ||
349 | return false; | ||
350 | |||
351 | if (file) | ||
352 | { | ||
353 | if (changeArchivePassword(file->getFileName(), password, retArchive)) | ||
354 | return true; | ||
355 | |||
356 | IFileArchive* archive = 0; | ||
357 | s32 i; | ||
358 | |||
359 | if (archiveType == EFAT_UNKNOWN) | ||
360 | { | ||
361 | // try to load archive based on file name | ||
362 | for (i = ArchiveLoader.size()-1; i >=0 ; --i) | ||
363 | { | ||
364 | if (ArchiveLoader[i]->isALoadableFileFormat(file->getFileName())) | ||
365 | { | ||
366 | archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); | ||
367 | if (archive) | ||
368 | break; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | // try to load archive based on content | ||
373 | if (!archive) | ||
374 | { | ||
375 | for (i = ArchiveLoader.size()-1; i >= 0; --i) | ||
376 | { | ||
377 | file->seek(0); | ||
378 | if (ArchiveLoader[i]->isALoadableFileFormat(file)) | ||
379 | { | ||
380 | file->seek(0); | ||
381 | archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); | ||
382 | if (archive) | ||
383 | break; | ||
384 | } | ||
385 | } | ||
386 | } | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | // try to open archive based on archive loader type | ||
391 | for (i = ArchiveLoader.size()-1; i >= 0; --i) | ||
392 | { | ||
393 | if (ArchiveLoader[i]->isALoadableFileFormat(archiveType)) | ||
394 | { | ||
395 | // attempt to open archive | ||
396 | file->seek(0); | ||
397 | if (ArchiveLoader[i]->isALoadableFileFormat(file)) | ||
398 | { | ||
399 | file->seek(0); | ||
400 | archive = ArchiveLoader[i]->createArchive(file, ignoreCase, ignorePaths); | ||
401 | if (archive) | ||
402 | break; | ||
403 | } | ||
404 | } | ||
405 | } | ||
406 | } | ||
407 | |||
408 | if (archive) | ||
409 | { | ||
410 | FileArchives.push_back(archive); | ||
411 | if (password.size()) | ||
412 | archive->Password=password; | ||
413 | if (retArchive) | ||
414 | *retArchive = archive; | ||
415 | return true; | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | os::Printer::log("Could not create archive for", file->getFileName(), ELL_ERROR); | ||
420 | } | ||
421 | } | ||
422 | |||
423 | return false; | ||
424 | } | ||
425 | |||
426 | |||
427 | //! Adds an archive to the file system. | ||
428 | bool CFileSystem::addFileArchive(IFileArchive* archive) | ||
429 | { | ||
430 | for (u32 i=0; i < FileArchives.size(); ++i) | ||
431 | { | ||
432 | if (archive == FileArchives[i]) | ||
433 | { | ||
434 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
435 | return false; | ||
436 | } | ||
437 | } | ||
438 | FileArchives.push_back(archive); | ||
439 | return true; | ||
440 | } | ||
441 | |||
442 | |||
443 | //! removes an archive from the file system. | ||
444 | bool CFileSystem::removeFileArchive(u32 index) | ||
445 | { | ||
446 | bool ret = false; | ||
447 | if (index < FileArchives.size()) | ||
448 | { | ||
449 | FileArchives[index]->drop(); | ||
450 | FileArchives.erase(index); | ||
451 | ret = true; | ||
452 | } | ||
453 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
454 | return ret; | ||
455 | } | ||
456 | |||
457 | |||
458 | //! removes an archive from the file system. | ||
459 | bool CFileSystem::removeFileArchive(const io::path& filename) | ||
460 | { | ||
461 | const path absPath = getAbsolutePath(filename); | ||
462 | for (u32 i=0; i < FileArchives.size(); ++i) | ||
463 | { | ||
464 | if (absPath == FileArchives[i]->getFileList()->getPath()) | ||
465 | return removeFileArchive(i); | ||
466 | } | ||
467 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
468 | return false; | ||
469 | } | ||
470 | |||
471 | |||
472 | //! Removes an archive from the file system. | ||
473 | bool CFileSystem::removeFileArchive(const IFileArchive* archive) | ||
474 | { | ||
475 | for (u32 i=0; i < FileArchives.size(); ++i) | ||
476 | { | ||
477 | if (archive == FileArchives[i]) | ||
478 | { | ||
479 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
480 | return removeFileArchive(i); | ||
481 | } | ||
482 | } | ||
483 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
484 | return false; | ||
485 | } | ||
486 | |||
487 | |||
488 | //! gets an archive | ||
489 | u32 CFileSystem::getFileArchiveCount() const | ||
490 | { | ||
491 | return FileArchives.size(); | ||
492 | } | ||
493 | |||
494 | |||
495 | IFileArchive* CFileSystem::getFileArchive(u32 index) | ||
496 | { | ||
497 | return index < getFileArchiveCount() ? FileArchives[index] : 0; | ||
498 | } | ||
499 | |||
500 | |||
501 | //! Returns the string of the current working directory | ||
502 | const io::path& CFileSystem::getWorkingDirectory() | ||
503 | { | ||
504 | EFileSystemType type = FileSystemType; | ||
505 | |||
506 | if (type != FILESYSTEM_NATIVE) | ||
507 | { | ||
508 | type = FILESYSTEM_VIRTUAL; | ||
509 | } | ||
510 | else | ||
511 | { | ||
512 | #if defined(_IRR_WINDOWS_CE_PLATFORM_) | ||
513 | // does not need this | ||
514 | #elif defined(_IRR_WINDOWS_API_) | ||
515 | fschar_t tmp[_MAX_PATH]; | ||
516 | #if defined(_IRR_WCHAR_FILESYSTEM ) | ||
517 | _wgetcwd(tmp, _MAX_PATH); | ||
518 | WorkingDirectory[FILESYSTEM_NATIVE] = tmp; | ||
519 | WorkingDirectory[FILESYSTEM_NATIVE].replace(L'\\', L'/'); | ||
520 | #else | ||
521 | _getcwd(tmp, _MAX_PATH); | ||
522 | WorkingDirectory[FILESYSTEM_NATIVE] = tmp; | ||
523 | WorkingDirectory[FILESYSTEM_NATIVE].replace('\\', '/'); | ||
524 | #endif | ||
525 | #endif | ||
526 | |||
527 | #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) | ||
528 | |||
529 | // getting the CWD is rather complex as we do not know the size | ||
530 | // so try it until the call was successful | ||
531 | // Note that neither the first nor the second parameter may be 0 according to POSIX | ||
532 | |||
533 | #if defined(_IRR_WCHAR_FILESYSTEM ) | ||
534 | u32 pathSize=256; | ||
535 | wchar_t *tmpPath = new wchar_t[pathSize]; | ||
536 | while ((pathSize < (1<<16)) && !(wgetcwd(tmpPath,pathSize))) | ||
537 | { | ||
538 | delete [] tmpPath; | ||
539 | pathSize *= 2; | ||
540 | tmpPath = new char[pathSize]; | ||
541 | } | ||
542 | if (tmpPath) | ||
543 | { | ||
544 | WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath; | ||
545 | delete [] tmpPath; | ||
546 | } | ||
547 | #else | ||
548 | u32 pathSize=256; | ||
549 | char *tmpPath = new char[pathSize]; | ||
550 | while ((pathSize < (1<<16)) && !(getcwd(tmpPath,pathSize))) | ||
551 | { | ||
552 | delete [] tmpPath; | ||
553 | pathSize *= 2; | ||
554 | tmpPath = new char[pathSize]; | ||
555 | } | ||
556 | if (tmpPath) | ||
557 | { | ||
558 | WorkingDirectory[FILESYSTEM_NATIVE] = tmpPath; | ||
559 | delete [] tmpPath; | ||
560 | } | ||
561 | #endif | ||
562 | #endif | ||
563 | |||
564 | WorkingDirectory[type].validate(); | ||
565 | } | ||
566 | |||
567 | return WorkingDirectory[type]; | ||
568 | } | ||
569 | |||
570 | |||
571 | //! Changes the current Working Directory to the given string. | ||
572 | bool CFileSystem::changeWorkingDirectoryTo(const io::path& newDirectory) | ||
573 | { | ||
574 | bool success=false; | ||
575 | |||
576 | if (FileSystemType != FILESYSTEM_NATIVE) | ||
577 | { | ||
578 | WorkingDirectory[FILESYSTEM_VIRTUAL] = newDirectory; | ||
579 | // is this empty string constant really intended? | ||
580 | flattenFilename(WorkingDirectory[FILESYSTEM_VIRTUAL], _IRR_TEXT("")); | ||
581 | success = true; | ||
582 | } | ||
583 | else | ||
584 | { | ||
585 | WorkingDirectory[FILESYSTEM_NATIVE] = newDirectory; | ||
586 | |||
587 | #if defined(_IRR_WINDOWS_CE_PLATFORM_) | ||
588 | success = true; | ||
589 | #elif defined(_MSC_VER) | ||
590 | #if defined(_IRR_WCHAR_FILESYSTEM) | ||
591 | success = (_wchdir(newDirectory.c_str()) == 0); | ||
592 | #else | ||
593 | success = (_chdir(newDirectory.c_str()) == 0); | ||
594 | #endif | ||
595 | #else | ||
596 | #if defined(_IRR_WCHAR_FILESYSTEM) | ||
597 | success = (_wchdir(newDirectory.c_str()) == 0); | ||
598 | #else | ||
599 | success = (chdir(newDirectory.c_str()) == 0); | ||
600 | #endif | ||
601 | #endif | ||
602 | } | ||
603 | |||
604 | return success; | ||
605 | } | ||
606 | |||
607 | |||
608 | io::path CFileSystem::getAbsolutePath(const io::path& filename) const | ||
609 | { | ||
610 | #if defined(_IRR_WINDOWS_CE_PLATFORM_) | ||
611 | return filename; | ||
612 | #elif defined(_IRR_WINDOWS_API_) | ||
613 | fschar_t *p=0; | ||
614 | fschar_t fpath[_MAX_PATH]; | ||
615 | #if defined(_IRR_WCHAR_FILESYSTEM ) | ||
616 | p = _wfullpath(fpath, filename.c_str(), _MAX_PATH); | ||
617 | core::stringw tmp(p); | ||
618 | tmp.replace(L'\\', L'/'); | ||
619 | #else | ||
620 | p = _fullpath(fpath, filename.c_str(), _MAX_PATH); | ||
621 | core::stringc tmp(p); | ||
622 | tmp.replace('\\', '/'); | ||
623 | #endif | ||
624 | return tmp; | ||
625 | #elif (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) | ||
626 | c8* p=0; | ||
627 | c8 fpath[4096]; | ||
628 | fpath[0]=0; | ||
629 | p = realpath(filename.c_str(), fpath); | ||
630 | if (!p) | ||
631 | { | ||
632 | // content in fpath is unclear at this point | ||
633 | if (!fpath[0]) // seems like fpath wasn't altered, use our best guess | ||
634 | { | ||
635 | io::path tmp(filename); | ||
636 | return flattenFilename(tmp); | ||
637 | } | ||
638 | else | ||
639 | return io::path(fpath); | ||
640 | } | ||
641 | if (filename[filename.size()-1]=='/') | ||
642 | return io::path(p)+_IRR_TEXT("/"); | ||
643 | else | ||
644 | return io::path(p); | ||
645 | #else | ||
646 | return io::path(filename); | ||
647 | #endif | ||
648 | } | ||
649 | |||
650 | |||
651 | //! returns the directory part of a filename, i.e. all until the first | ||
652 | //! slash or backslash, excluding it. If no directory path is prefixed, a '.' | ||
653 | //! is returned. | ||
654 | io::path CFileSystem::getFileDir(const io::path& filename) const | ||
655 | { | ||
656 | // find last forward or backslash | ||
657 | s32 lastSlash = filename.findLast('/'); | ||
658 | const s32 lastBackSlash = filename.findLast('\\'); | ||
659 | lastSlash = lastSlash > lastBackSlash ? lastSlash : lastBackSlash; | ||
660 | |||
661 | if ((u32)lastSlash < filename.size()) | ||
662 | return filename.subString(0, lastSlash); | ||
663 | else | ||
664 | return _IRR_TEXT("."); | ||
665 | } | ||
666 | |||
667 | |||
668 | //! returns the base part of a filename, i.e. all except for the directory | ||
669 | //! part. If no directory path is prefixed, the full name is returned. | ||
670 | io::path CFileSystem::getFileBasename(const io::path& filename, bool keepExtension) const | ||
671 | { | ||
672 | // find last forward or backslash | ||
673 | s32 lastSlash = filename.findLast('/'); | ||
674 | const s32 lastBackSlash = filename.findLast('\\'); | ||
675 | lastSlash = core::max_(lastSlash, lastBackSlash); | ||
676 | |||
677 | // get number of chars after last dot | ||
678 | s32 end = 0; | ||
679 | if (!keepExtension) | ||
680 | { | ||
681 | // take care to search only after last slash to check only for | ||
682 | // dots in the filename | ||
683 | end = filename.findLast('.'); | ||
684 | if (end == -1 || end < lastSlash) | ||
685 | end=0; | ||
686 | else | ||
687 | end = filename.size()-end; | ||
688 | } | ||
689 | |||
690 | if ((u32)lastSlash < filename.size()) | ||
691 | return filename.subString(lastSlash+1, filename.size()-lastSlash-1-end); | ||
692 | else if (end != 0) | ||
693 | return filename.subString(0, filename.size()-end); | ||
694 | else | ||
695 | return filename; | ||
696 | } | ||
697 | |||
698 | |||
699 | //! flatten a path and file name for example: "/you/me/../." becomes "/you" | ||
700 | io::path& CFileSystem::flattenFilename(io::path& directory, const io::path& root) const | ||
701 | { | ||
702 | directory.replace('\\', '/'); | ||
703 | if (directory.lastChar() != '/') | ||
704 | directory.append('/'); | ||
705 | |||
706 | io::path dir; | ||
707 | io::path subdir; | ||
708 | |||
709 | s32 lastpos = 0; | ||
710 | s32 pos = 0; | ||
711 | bool lastWasRealDir=false; | ||
712 | |||
713 | while ((pos = directory.findNext('/', lastpos)) >= 0) | ||
714 | { | ||
715 | subdir = directory.subString(lastpos, pos - lastpos + 1); | ||
716 | |||
717 | if (subdir == _IRR_TEXT("../")) | ||
718 | { | ||
719 | if (lastWasRealDir) | ||
720 | { | ||
721 | deletePathFromPath(dir, 2); | ||
722 | lastWasRealDir=(dir.size()!=0); | ||
723 | } | ||
724 | else | ||
725 | { | ||
726 | dir.append(subdir); | ||
727 | lastWasRealDir=false; | ||
728 | } | ||
729 | } | ||
730 | else if (subdir == _IRR_TEXT("/")) | ||
731 | { | ||
732 | dir = root; | ||
733 | } | ||
734 | else if (subdir != _IRR_TEXT("./")) | ||
735 | { | ||
736 | dir.append(subdir); | ||
737 | lastWasRealDir=true; | ||
738 | } | ||
739 | |||
740 | lastpos = pos + 1; | ||
741 | } | ||
742 | directory = dir; | ||
743 | return directory; | ||
744 | } | ||
745 | |||
746 | |||
747 | //! Get the relative filename, relative to the given directory | ||
748 | path CFileSystem::getRelativeFilename(const path& filename, const path& directory) const | ||
749 | { | ||
750 | if ( filename.empty() || directory.empty() ) | ||
751 | return filename; | ||
752 | |||
753 | io::path path1, file, ext; | ||
754 | core::splitFilename(getAbsolutePath(filename), &path1, &file, &ext); | ||
755 | io::path path2(getAbsolutePath(directory)); | ||
756 | core::list<io::path> list1, list2; | ||
757 | path1.split(list1, _IRR_TEXT("/\\"), 2); | ||
758 | path2.split(list2, _IRR_TEXT("/\\"), 2); | ||
759 | u32 i=0; | ||
760 | core::list<io::path>::ConstIterator it1,it2; | ||
761 | it1=list1.begin(); | ||
762 | it2=list2.begin(); | ||
763 | |||
764 | #if defined (_IRR_WINDOWS_API_) | ||
765 | fschar_t partition1 = 0, partition2 = 0; | ||
766 | io::path prefix1, prefix2; | ||
767 | if ( it1 != list1.end() ) | ||
768 | prefix1 = *it1; | ||
769 | if ( it2 != list2.end() ) | ||
770 | prefix2 = *it2; | ||
771 | if ( prefix1.size() > 1 && prefix1[1] == _IRR_TEXT(':') ) | ||
772 | partition1 = core::locale_lower(prefix1[0]); | ||
773 | if ( prefix2.size() > 1 && prefix2[1] == _IRR_TEXT(':') ) | ||
774 | partition2 = core::locale_lower(prefix2[0]); | ||
775 | |||
776 | // must have the same prefix or we can't resolve it to a relative filename | ||
777 | if ( partition1 != partition2 ) | ||
778 | { | ||
779 | return filename; | ||
780 | } | ||
781 | #endif | ||
782 | |||
783 | |||
784 | for (; i<list1.size() && i<list2.size() | ||
785 | #if defined (_IRR_WINDOWS_API_) | ||
786 | && (io::path(*it1).make_lower()==io::path(*it2).make_lower()) | ||
787 | #else | ||
788 | && (*it1==*it2) | ||
789 | #endif | ||
790 | ; ++i) | ||
791 | { | ||
792 | ++it1; | ||
793 | ++it2; | ||
794 | } | ||
795 | path1=_IRR_TEXT(""); | ||
796 | for (; i<list2.size(); ++i) | ||
797 | path1 += _IRR_TEXT("../"); | ||
798 | while (it1 != list1.end()) | ||
799 | { | ||
800 | path1 += *it1++; | ||
801 | path1 += _IRR_TEXT('/'); | ||
802 | } | ||
803 | path1 += file; | ||
804 | if (ext.size()) | ||
805 | { | ||
806 | path1 += _IRR_TEXT('.'); | ||
807 | path1 += ext; | ||
808 | } | ||
809 | return path1; | ||
810 | } | ||
811 | |||
812 | |||
813 | //! Sets the current file systen type | ||
814 | EFileSystemType CFileSystem::setFileListSystem(EFileSystemType listType) | ||
815 | { | ||
816 | EFileSystemType current = FileSystemType; | ||
817 | FileSystemType = listType; | ||
818 | return current; | ||
819 | } | ||
820 | |||
821 | |||
822 | //! Creates a list of files and directories in the current working directory | ||
823 | IFileList* CFileSystem::createFileList() | ||
824 | { | ||
825 | CFileList* r = 0; | ||
826 | io::path Path = getWorkingDirectory(); | ||
827 | Path.replace('\\', '/'); | ||
828 | if (Path.lastChar() != '/') | ||
829 | Path.append('/'); | ||
830 | |||
831 | //! Construct from native filesystem | ||
832 | if (FileSystemType == FILESYSTEM_NATIVE) | ||
833 | { | ||
834 | // -------------------------------------------- | ||
835 | //! Windows version | ||
836 | #ifdef _IRR_WINDOWS_API_ | ||
837 | #if !defined ( _WIN32_WCE ) | ||
838 | |||
839 | r = new CFileList(Path, true, false); | ||
840 | |||
841 | // TODO: Should be unified once mingw adapts the proper types | ||
842 | #if defined(__GNUC__) | ||
843 | long hFile; //mingw return type declaration | ||
844 | #else | ||
845 | intptr_t hFile; | ||
846 | #endif | ||
847 | |||
848 | struct _tfinddata_t c_file; | ||
849 | if( (hFile = _tfindfirst( _T("*"), &c_file )) != -1L ) | ||
850 | { | ||
851 | do | ||
852 | { | ||
853 | r->addItem(Path + c_file.name, 0, c_file.size, (_A_SUBDIR & c_file.attrib) != 0, 0); | ||
854 | } | ||
855 | while( _tfindnext( hFile, &c_file ) == 0 ); | ||
856 | |||
857 | _findclose( hFile ); | ||
858 | } | ||
859 | #endif | ||
860 | |||
861 | //TODO add drives | ||
862 | //entry.Name = "E:\\"; | ||
863 | //entry.isDirectory = true; | ||
864 | //Files.push_back(entry); | ||
865 | #endif | ||
866 | |||
867 | // -------------------------------------------- | ||
868 | //! Linux version | ||
869 | #if (defined(_IRR_POSIX_API_) || defined(_IRR_OSX_PLATFORM_)) | ||
870 | |||
871 | |||
872 | r = new CFileList(Path, false, false); | ||
873 | |||
874 | r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0); | ||
875 | |||
876 | //! We use the POSIX compliant methods instead of scandir | ||
877 | DIR* dirHandle=opendir(Path.c_str()); | ||
878 | if (dirHandle) | ||
879 | { | ||
880 | struct dirent *dirEntry; | ||
881 | while ((dirEntry=readdir(dirHandle))) | ||
882 | { | ||
883 | u32 size = 0; | ||
884 | bool isDirectory = false; | ||
885 | |||
886 | if((strcmp(dirEntry->d_name, ".")==0) || | ||
887 | (strcmp(dirEntry->d_name, "..")==0)) | ||
888 | { | ||
889 | continue; | ||
890 | } | ||
891 | struct stat buf; | ||
892 | if (stat(dirEntry->d_name, &buf)==0) | ||
893 | { | ||
894 | size = buf.st_size; | ||
895 | isDirectory = S_ISDIR(buf.st_mode); | ||
896 | } | ||
897 | #if !defined(_IRR_SOLARIS_PLATFORM_) && !defined(__CYGWIN__) | ||
898 | // only available on some systems | ||
899 | else | ||
900 | { | ||
901 | isDirectory = dirEntry->d_type == DT_DIR; | ||
902 | } | ||
903 | #endif | ||
904 | |||
905 | r->addItem(Path + dirEntry->d_name, 0, size, isDirectory, 0); | ||
906 | } | ||
907 | closedir(dirHandle); | ||
908 | } | ||
909 | #endif | ||
910 | } | ||
911 | else | ||
912 | { | ||
913 | //! create file list for the virtual filesystem | ||
914 | r = new CFileList(Path, false, false); | ||
915 | |||
916 | //! add relative navigation | ||
917 | SFileListEntry e2; | ||
918 | SFileListEntry e3; | ||
919 | |||
920 | //! PWD | ||
921 | r->addItem(Path + _IRR_TEXT("."), 0, 0, true, 0); | ||
922 | |||
923 | //! parent | ||
924 | r->addItem(Path + _IRR_TEXT(".."), 0, 0, true, 0); | ||
925 | |||
926 | //! merge archives | ||
927 | for (u32 i=0; i < FileArchives.size(); ++i) | ||
928 | { | ||
929 | const IFileList *merge = FileArchives[i]->getFileList(); | ||
930 | |||
931 | for (u32 j=0; j < merge->getFileCount(); ++j) | ||
932 | { | ||
933 | if (core::isInSameDirectory(Path, merge->getFullFileName(j)) == 0) | ||
934 | { | ||
935 | r->addItem(merge->getFullFileName(j), merge->getFileOffset(j), merge->getFileSize(j), merge->isDirectory(j), 0); | ||
936 | } | ||
937 | } | ||
938 | } | ||
939 | } | ||
940 | |||
941 | if (r) | ||
942 | r->sort(); | ||
943 | return r; | ||
944 | } | ||
945 | |||
946 | //! Creates an empty filelist | ||
947 | IFileList* CFileSystem::createEmptyFileList(const io::path& path, bool ignoreCase, bool ignorePaths) | ||
948 | { | ||
949 | return new CFileList(path, ignoreCase, ignorePaths); | ||
950 | } | ||
951 | |||
952 | |||
953 | //! determines if a file exists and would be able to be opened. | ||
954 | bool CFileSystem::existFile(const io::path& filename) const | ||
955 | { | ||
956 | for (u32 i=0; i < FileArchives.size(); ++i) | ||
957 | if (FileArchives[i]->getFileList()->findFile(filename)!=-1) | ||
958 | return true; | ||
959 | |||
960 | #if defined(_IRR_WINDOWS_CE_PLATFORM_) | ||
961 | #if defined(_IRR_WCHAR_FILESYSTEM) | ||
962 | HANDLE hFile = CreateFileW(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); | ||
963 | #else | ||
964 | HANDLE hFile = CreateFileW(core::stringw(filename).c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); | ||
965 | #endif | ||
966 | if (hFile == INVALID_HANDLE_VALUE) | ||
967 | return false; | ||
968 | else | ||
969 | { | ||
970 | CloseHandle(hFile); | ||
971 | return true; | ||
972 | } | ||
973 | #else | ||
974 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | ||
975 | #if defined(_MSC_VER) | ||
976 | #if defined(_IRR_WCHAR_FILESYSTEM) | ||
977 | return (_waccess(filename.c_str(), 0) != -1); | ||
978 | #else | ||
979 | return (_access(filename.c_str(), 0) != -1); | ||
980 | #endif | ||
981 | #elif defined(F_OK) | ||
982 | #if defined(_IRR_WCHAR_FILESYSTEM) | ||
983 | return (_waccess(filename.c_str(), F_OK) != -1); | ||
984 | #else | ||
985 | return (access(filename.c_str(), F_OK) != -1); | ||
986 | #endif | ||
987 | #else | ||
988 | return (access(filename.c_str(), 0) != -1); | ||
989 | #endif | ||
990 | #endif | ||
991 | } | ||
992 | |||
993 | |||
994 | //! Creates a XML Reader from a file. | ||
995 | IXMLReader* CFileSystem::createXMLReader(const io::path& filename) | ||
996 | { | ||
997 | IReadFile* file = createAndOpenFile(filename); | ||
998 | if (!file) | ||
999 | return 0; | ||
1000 | |||
1001 | IXMLReader* reader = createXMLReader(file); | ||
1002 | file->drop(); | ||
1003 | return reader; | ||
1004 | } | ||
1005 | |||
1006 | |||
1007 | //! Creates a XML Reader from a file. | ||
1008 | IXMLReader* CFileSystem::createXMLReader(IReadFile* file) | ||
1009 | { | ||
1010 | if (!file) | ||
1011 | return 0; | ||
1012 | |||
1013 | return createIXMLReader(file); | ||
1014 | } | ||
1015 | |||
1016 | |||
1017 | //! Creates a XML Reader from a file. | ||
1018 | IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(const io::path& filename) | ||
1019 | { | ||
1020 | IReadFile* file = createAndOpenFile(filename); | ||
1021 | if (!file) | ||
1022 | return 0; | ||
1023 | |||
1024 | IXMLReaderUTF8* reader = createIXMLReaderUTF8(file); | ||
1025 | file->drop(); | ||
1026 | return reader; | ||
1027 | } | ||
1028 | |||
1029 | |||
1030 | //! Creates a XML Reader from a file. | ||
1031 | IXMLReaderUTF8* CFileSystem::createXMLReaderUTF8(IReadFile* file) | ||
1032 | { | ||
1033 | if (!file) | ||
1034 | return 0; | ||
1035 | |||
1036 | return createIXMLReaderUTF8(file); | ||
1037 | } | ||
1038 | |||
1039 | |||
1040 | //! Creates a XML Writer from a file. | ||
1041 | IXMLWriter* CFileSystem::createXMLWriter(const io::path& filename) | ||
1042 | { | ||
1043 | IWriteFile* file = createAndWriteFile(filename); | ||
1044 | IXMLWriter* writer = 0; | ||
1045 | if (file) | ||
1046 | { | ||
1047 | writer = createXMLWriter(file); | ||
1048 | file->drop(); | ||
1049 | } | ||
1050 | return writer; | ||
1051 | } | ||
1052 | |||
1053 | |||
1054 | //! Creates a XML Writer from a file. | ||
1055 | IXMLWriter* CFileSystem::createXMLWriter(IWriteFile* file) | ||
1056 | { | ||
1057 | return new CXMLWriter(file); | ||
1058 | } | ||
1059 | |||
1060 | |||
1061 | //! creates a filesystem which is able to open files from the ordinary file system, | ||
1062 | //! and out of zipfiles, which are able to be added to the filesystem. | ||
1063 | IFileSystem* createFileSystem() | ||
1064 | { | ||
1065 | return new CFileSystem(); | ||
1066 | } | ||
1067 | |||
1068 | |||
1069 | //! Creates a new empty collection of attributes, usable for serialization and more. | ||
1070 | IAttributes* CFileSystem::createEmptyAttributes(video::IVideoDriver* driver) | ||
1071 | { | ||
1072 | return new CAttributes(driver); | ||
1073 | } | ||
1074 | |||
1075 | |||
1076 | } // end namespace irr | ||
1077 | } // end namespace io | ||
1078 | |||