winFileio.cpp
Engine/source/platformWin32/winFileio.cpp
Public Functions
bool
dFileDelete(const char * name)
bool
dFileRename(const char * oldName, const char * newName)
bool
dFileTouch(const char * name)
bool
recurseDumpDirectories(const char * basePath, const char * subPath, Vector< StringTableEntry > & directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)
bool
recurseDumpPath(const char * path, const char * pattern, Vector< Platform::FileInfo > & fileVector, S32 recurseDepth)
Detailed Description
Public Functions
dFileDelete(const char * name)
dFileRename(const char * oldName, const char * newName)
dFileTouch(const char * name)
dPathCopy(const char * fromName, const char * toName, bool nooverwrite)
osGetTemporaryDirectory()
recurseDumpDirectories(const char * basePath, const char * subPath, Vector< StringTableEntry > & directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath)
recurseDumpPath(const char * path, const char * pattern, Vector< Platform::FileInfo > & fileVector, S32 recurseDepth)
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "core/strings/stringFunctions.h" 25#include "platformWin32/platformWin32.h" 26#include "core/fileio.h" 27#include "core/util/tVector.h" 28#include "core/stringTable.h" 29#include "console/console.h" 30#include "core/strings/unicode.h" 31#include "util/tempAlloc.h" 32#include "core/util/safeDelete.h" 33#include "core/volume.h" 34 35// Microsoft VC++ has this POSIX header in the wrong directory 36#if defined(TORQUE_COMPILER_VISUALC) 37#include <sys/utime.h> 38#elif defined (TORQUE_COMPILER_GCC) 39#include <time.h> 40#include <sys/utime.h> 41#else 42#include <utime.h> 43#endif 44 45StringTableEntry Platform::createPlatformFriendlyFilename( const char *filename ) 46{ 47 return StringTable->insert( filename ); 48} 49 50//----------------------------------------------------------------------------- 51bool dFileDelete(const char * name) 52{ 53 AssertFatal( name != NULL, "dFileDelete - NULL file name" ); 54 55 TempAlloc< TCHAR> buf( dStrlen( name ) + 1 ); 56 57#ifdef UNICODE 58 convertUTF8toUTF16N( name, buf, buf.size ); 59#else 60 dStrcpy( buf, name, buf.size ); 61#endif 62 63 backslash( buf ); 64 if( Platform::isFile( name ) ) 65 return DeleteFile( buf ); 66 else 67 return RemoveDirectory( buf ); 68} 69 70bool Platform::fileDelete(const char * name) 71{ 72 if (!name || (dStrlen(name) >= MAX_PATH)) 73 return(false); 74 //return(::DeleteFile(name)); 75 if (Platform::isFile(name)) 76 return(remove(name) == 0); 77 else 78 return ::RemoveDirectoryA(name) != 0; 79} 80 81bool dFileRename(const char *oldName, const char *newName) 82{ 83 AssertFatal( oldName != NULL && newName != NULL, "dFileRename - NULL file name" ); 84 85 TempAlloc< TCHAR> oldf( dStrlen( oldName ) + 1 ); 86 TempAlloc< TCHAR> newf( dStrlen( newName ) + 1 ); 87 88#ifdef UNICODE 89 convertUTF8toUTF16N( oldName, oldf, oldf.size ); 90 convertUTF8toUTF16N( newName, newf, newf.size ); 91#else 92 dStrcpy(oldf, oldName, oldf.size); 93 dStrcpy(newf, newName, newf.size); 94#endif 95 backslash(oldf); 96 backslash(newf); 97 98 return MoveFile( oldf, newf ); 99} 100 101bool dFileTouch(const char * name) 102{ 103 AssertFatal( name != NULL, "dFileTouch - NULL file name" ); 104 105 TempAlloc< TCHAR> buf( dStrlen( name ) + 1 ); 106 107#ifdef UNICODE 108 convertUTF8toUTF16N( name, buf, buf.size ); 109#else 110 dStrcpy( buf, name, buf.size ); 111#endif 112 113 backslash( buf ); 114 FILETIME ftime; 115 GetSystemTimeAsFileTime( &ftime ); 116 HANDLE handle = CreateFile( buf, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 117 NULL, OPEN_EXISTING, 0, NULL ); 118 if( handle == INVALID_HANDLE_VALUE ) 119 return false; 120 bool result = SetFileTime( handle, NULL, NULL, &ftime ); 121 CloseHandle( handle ); 122 123 return result; 124}; 125 126bool dPathCopy(const char *fromName, const char *toName, bool nooverwrite) 127{ 128 AssertFatal( fromName != NULL && toName != NULL, "dPathCopy - NULL file name" ); 129 130 TempAlloc< TCHAR> from( dStrlen( fromName ) + 1 ); 131 TempAlloc< TCHAR> to( dStrlen( toName ) + 1 ); 132 133#ifdef UNICODE 134 convertUTF8toUTF16N( fromName, from, from.size ); 135 convertUTF8toUTF16N( toName, to, to.size ); 136#else 137 dStrcpy( from, fromName, from.size ); 138 dStrcpy( to, toName, to.size ); 139#endif 140 141 backslash( from ); 142 backslash( to ); 143 144 // Copy File 145 if (Platform::isFile(fromName)) 146 return CopyFile( from, to, nooverwrite ); 147 // Copy Path 148 else if (Platform::isDirectory(fromName)) 149 { 150 // If the destination path exists and we don't want to overwrite, return. 151 if ((Platform::isDirectory(toName) || Platform::isFile(toName)) && nooverwrite) 152 return false; 153 154 Vector<StringTableEntry> directoryInfo; 155 Platform::dumpDirectories(fromName, directoryInfo, -1); 156 157 Vector<Platform::FileInfo> fileInfo; 158 Platform::dumpPath(fromName, fileInfo); 159 160 Platform::clearExcludedDirectories(); 161 162 TempAlloc< char> tempBuf( to.size * 3 + MAX_PATH * 3 ); 163 164 // Create all the directories. 165 for (S32 i = 0; i < directoryInfo.size(); i++) 166 { 167 const char* fromDir = directoryInfo[i]; 168 169 char* toDir = tempBuf; 170 Platform::makeFullPathName(fromDir + dStrlen(fromName) + (dStricmp(fromDir, fromName) ? 1 : 0), tempBuf, tempBuf.size, toName); 171 if(*(toDir + dStrlen(toDir) - 1) != '/') 172 dStrcat(toDir, "/", tempBuf.size); 173 forwardslash(toDir); 174 175 if (!Platform::createPath(toDir)) 176 { 177 //TODO: New directory should be deleted here. 178 return false; 179 } 180 } 181 182 TempAlloc< char> tempBuf1( from.size * 3 + MAX_PATH * 3 ); 183#ifdef UNICODE 184 TempAlloc< WCHAR> wtempBuf( tempBuf.size / 3 ); 185 TempAlloc< WCHAR> wtempBuf1( tempBuf1.size / 3 ); 186#endif 187 188 for (S32 i = 0; i < fileInfo.size(); i++) 189 { 190 char* fromFile = tempBuf1; 191 dSprintf( tempBuf1, tempBuf1.size, "%s/%s", fileInfo[i].pFullPath, fileInfo[i].pFileName); 192 193 char* toFile = tempBuf; 194 Platform::makeFullPathName(fileInfo[i].pFullPath + dStrlen(fromName) + (dStricmp(fileInfo[i].pFullPath, fromName) ? 1 : 0), tempBuf, tempBuf.size, toName); 195 dStrcat(toFile, "/", tempBuf.size); 196 dStrcat(toFile, fileInfo[i].pFileName, tempBuf.size); 197 198 backslash(fromFile); 199 backslash(toFile); 200 201#ifdef UNICODE 202 convertUTF8toUTF16N( tempBuf, wtempBuf, wtempBuf.size ); 203 convertUTF8toUTF16N( tempBuf1, wtempBuf1, wtempBuf1.size ); 204 WCHAR* f = wtempBuf1; 205 WCHAR* t = wtempBuf; 206#else 207 char *f = (char*)fromFile; 208 char *t = (char*)toFile; 209#endif 210 211 if (!::CopyFile(f, t, nooverwrite)) 212 { 213 // New directory should be deleted here. 214 return false; 215 } 216 217 } 218 219 return true; 220 } 221 222 return false; 223} 224 225//----------------------------------------------------------------------------- 226// Constructors & Destructor 227//----------------------------------------------------------------------------- 228 229//----------------------------------------------------------------------------- 230// After construction, the currentStatus will be Closed and the capabilities 231// will be 0. 232//----------------------------------------------------------------------------- 233File::File() 234: currentStatus(Closed), capability(0) 235{ 236 AssertFatal(sizeof(HANDLE) == sizeof(void *), "File::File: cannot cast void* to HANDLE"); 237 238 handle = (void *)INVALID_HANDLE_VALUE; 239} 240 241//----------------------------------------------------------------------------- 242// insert a copy constructor here... (currently disabled) 243//----------------------------------------------------------------------------- 244 245//----------------------------------------------------------------------------- 246// Destructor 247//----------------------------------------------------------------------------- 248File::~File() 249{ 250 close(); 251 handle = (void *)INVALID_HANDLE_VALUE; 252} 253 254 255//----------------------------------------------------------------------------- 256// Open a file in the mode specified by openMode (Read, Write, or ReadWrite). 257// Truncate the file if the mode is either Write or ReadWrite and truncate is 258// true. 259// 260// Sets capability appropriate to the openMode. 261// Returns the currentStatus of the file. 262//----------------------------------------------------------------------------- 263File::FileStatus File::open(const char *filename, const AccessMode openMode) 264{ 265 AssertFatal(NULL != filename, "File::open: NULL fname"); 266 AssertWarn(INVALID_HANDLE_VALUE == (HANDLE)handle, "File::open: handle already valid"); 267 268 TempAlloc< TCHAR> fname( dStrlen( filename ) + 1 ); 269 270#ifdef UNICODE 271 convertUTF8toUTF16N( filename, fname, fname.size ); 272#else 273 dStrcpy(fname, filename, fname.size); 274#endif 275 backslash( fname ); 276 277 // Close the file if it was already open... 278 if (Closed != currentStatus) 279 close(); 280 281 // create the appropriate type of file... 282 switch (openMode) 283 { 284 case Read: 285 handle = (void *)CreateFile(fname, 286 GENERIC_READ, 287 FILE_SHARE_READ, 288 NULL, 289 OPEN_EXISTING, 290 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 291 NULL); 292 break; 293 case Write: 294 handle = (void *)CreateFile(fname, 295 GENERIC_WRITE, 296 0, 297 NULL, 298 CREATE_ALWAYS, 299 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 300 NULL); 301 break; 302 case ReadWrite: 303 handle = (void *)CreateFile(fname, 304 GENERIC_WRITE | GENERIC_READ, 305 0, 306 NULL, 307 OPEN_ALWAYS, 308 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 309 NULL); 310 break; 311 case WriteAppend: 312 handle = (void *)CreateFile(fname, 313 GENERIC_WRITE, 314 0, 315 NULL, 316 OPEN_ALWAYS, 317 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 318 NULL); 319 break; 320 321 default: 322 AssertFatal(false, "File::open: bad access mode"); // impossible 323 } 324 325 if (INVALID_HANDLE_VALUE == (HANDLE)handle) // handle not created successfully 326 { 327 return setStatus(); 328 } 329 else 330 { 331 // successfully created file, so set the file capabilities... 332 switch (openMode) 333 { 334 case Read: 335 capability = U32(FileRead); 336 break; 337 case Write: 338 case WriteAppend: 339 capability = U32(FileWrite); 340 break; 341 case ReadWrite: 342 capability = U32(FileRead) | 343 U32(FileWrite); 344 break; 345 default: 346 AssertFatal(false, "File::open: bad access mode"); 347 } 348 return currentStatus = Ok; // success! 349 } 350} 351 352//----------------------------------------------------------------------------- 353// Get the current position of the file pointer. 354//----------------------------------------------------------------------------- 355U32 File::getPosition() const 356{ 357 AssertFatal(Closed != currentStatus, "File::getPosition: file closed"); 358 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::getPosition: invalid file handle"); 359 360 return SetFilePointer((HANDLE)handle, 361 0, // how far to move 362 NULL, // pointer to high word 363 FILE_CURRENT); // from what point 364} 365 366//----------------------------------------------------------------------------- 367// Set the position of the file pointer. 368// Absolute and relative positioning is supported via the absolutePos 369// parameter. 370// 371// If positioning absolutely, position MUST be positive - an IOError results if 372// position is negative. 373// Position can be negative if positioning relatively, however positioning 374// before the start of the file is an IOError. 375// 376// Returns the currentStatus of the file. 377//----------------------------------------------------------------------------- 378File::FileStatus File::setPosition(S32 position, bool absolutePos) 379{ 380 AssertFatal(Closed != currentStatus, "File::setPosition: file closed"); 381 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::setPosition: invalid file handle"); 382 383 if (Ok != currentStatus && EOS != currentStatus) 384 return currentStatus; 385 386 U32 finalPos; 387 if (absolutePos) 388 { 389 AssertFatal(0 <= position, "File::setPosition: negative absolute position"); 390 391 // position beyond EOS is OK 392 finalPos = SetFilePointer((HANDLE)handle, 393 position, 394 NULL, 395 FILE_BEGIN); 396 } 397 else 398 { 399 AssertFatal((getPosition() >= (U32)abs(position) && 0 > position) || 0 <= position, "File::setPosition: negative relative position"); 400 401 // position beyond EOS is OK 402 finalPos = SetFilePointer((HANDLE)handle, 403 position, 404 NULL, 405 FILE_CURRENT); 406 } 407 408 if (0xffffffff == finalPos) 409 return setStatus(); // unsuccessful 410 else if (finalPos >= getSize()) 411 return currentStatus = EOS; // success, at end of file 412 else 413 return currentStatus = Ok; // success! 414} 415 416//----------------------------------------------------------------------------- 417// Get the size of the file in bytes. 418// It is an error to query the file size for a Closed file, or for one with an 419// error status. 420//----------------------------------------------------------------------------- 421U32 File::getSize() const 422{ 423 AssertWarn(Closed != currentStatus, "File::getSize: file closed"); 424 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::getSize: invalid file handle"); 425 426 if (Ok == currentStatus || EOS == currentStatus) 427 { 428 DWORD high; 429 return GetFileSize((HANDLE)handle, &high); // success! 430 } 431 else 432 return 0; // unsuccessful 433} 434 435//----------------------------------------------------------------------------- 436// Flush the file. 437// It is an error to flush a read-only file. 438// Returns the currentStatus of the file. 439//----------------------------------------------------------------------------- 440File::FileStatus File::flush() 441{ 442 AssertFatal(Closed != currentStatus, "File::flush: file closed"); 443 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::flush: invalid file handle"); 444 AssertFatal(true == hasCapability(FileWrite), "File::flush: cannot flush a read-only file"); 445 446 if (0 != FlushFileBuffers((HANDLE)handle)) 447 return setStatus(); // unsuccessful 448 else 449 return currentStatus = Ok; // success! 450} 451 452//----------------------------------------------------------------------------- 453// Close the File. 454// 455// Returns the currentStatus 456//----------------------------------------------------------------------------- 457File::FileStatus File::close() 458{ 459 // check if it's already closed... 460 if (Closed == currentStatus) 461 return currentStatus; 462 463 // it's not, so close it... 464 if (INVALID_HANDLE_VALUE != (HANDLE)handle) 465 { 466 if (0 == CloseHandle((HANDLE)handle)) 467 return setStatus(); // unsuccessful 468 } 469 handle = (void *)INVALID_HANDLE_VALUE; 470 return currentStatus = Closed; 471} 472 473//----------------------------------------------------------------------------- 474// Self-explanatory. 475//----------------------------------------------------------------------------- 476File::FileStatus File::getStatus() const 477{ 478 return currentStatus; 479} 480 481//----------------------------------------------------------------------------- 482// Sets and returns the currentStatus when an error has been encountered. 483//----------------------------------------------------------------------------- 484File::FileStatus File::setStatus() 485{ 486 switch (GetLastError()) 487 { 488 case ERROR_INVALID_HANDLE: 489 case ERROR_INVALID_ACCESS: 490 case ERROR_TOO_MANY_OPEN_FILES: 491 case ERROR_FILE_NOT_FOUND: 492 case ERROR_SHARING_VIOLATION: 493 case ERROR_HANDLE_DISK_FULL: 494 return currentStatus = IOError; 495 496 default: 497 return currentStatus = UnknownError; 498 } 499} 500 501//----------------------------------------------------------------------------- 502// Sets and returns the currentStatus to status. 503//----------------------------------------------------------------------------- 504File::FileStatus File::setStatus(File::FileStatus status) 505{ 506 return currentStatus = status; 507} 508 509//----------------------------------------------------------------------------- 510// Read from a file. 511// The number of bytes to read is passed in size, the data is returned in src. 512// The number of bytes read is available in bytesRead if a non-Null pointer is 513// provided. 514//----------------------------------------------------------------------------- 515File::FileStatus File::read(U32 size, char *dst, U32 *bytesRead) 516{ 517 AssertFatal(Closed != currentStatus, "File::read: file closed"); 518 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::read: invalid file handle"); 519 AssertFatal(NULL != dst, "File::read: NULL destination pointer"); 520 AssertFatal(true == hasCapability(FileRead), "File::read: file lacks capability"); 521 AssertWarn(0 != size, "File::read: size of zero"); 522 523 if (Ok != currentStatus || 0 == size) 524 return currentStatus; 525 else 526 { 527 DWORD lastBytes; 528 DWORD *bytes = (NULL == bytesRead) ? &lastBytes : (DWORD *)bytesRead; 529 if (0 != ReadFile((HANDLE)handle, dst, size, bytes, NULL)) 530 { 531 if(*((U32 *)bytes) != size) 532 return currentStatus = EOS; // end of stream 533 } 534 else 535 return setStatus(); // unsuccessful 536 } 537 return currentStatus = Ok; // successfully read size bytes 538} 539 540//----------------------------------------------------------------------------- 541// Write to a file. 542// The number of bytes to write is passed in size, the data is passed in src. 543// The number of bytes written is available in bytesWritten if a non-Null 544// pointer is provided. 545//----------------------------------------------------------------------------- 546File::FileStatus File::write(U32 size, const char *src, U32 *bytesWritten) 547{ 548 AssertFatal(Closed != currentStatus, "File::write: file closed"); 549 AssertFatal(INVALID_HANDLE_VALUE != (HANDLE)handle, "File::write: invalid file handle"); 550 AssertFatal(NULL != src, "File::write: NULL source pointer"); 551 AssertFatal(true == hasCapability(FileWrite), "File::write: file lacks capability"); 552 AssertWarn(0 != size, "File::write: size of zero"); 553 554 if ((Ok != currentStatus && EOS != currentStatus) || 0 == size) 555 return currentStatus; 556 else 557 { 558 DWORD lastBytes; 559 DWORD *bytes = (NULL == bytesWritten) ? &lastBytes : (DWORD *)bytesWritten; 560 if (0 != WriteFile((HANDLE)handle, src, size, bytes, NULL)) 561 return currentStatus = Ok; // success! 562 else 563 return setStatus(); // unsuccessful 564 } 565} 566 567//----------------------------------------------------------------------------- 568// Self-explanatory. 569//----------------------------------------------------------------------------- 570bool File::hasCapability(Capability cap) const 571{ 572 return (0 != (U32(cap) & capability)); 573} 574 575S32 Platform::compareFileTimes(const FileTime &a, const FileTime &b) 576{ 577 if(a.v2 > b.v2) 578 return 1; 579 if(a.v2 < b.v2) 580 return -1; 581 if(a.v1 > b.v1) 582 return 1; 583 if(a.v1 < b.v1) 584 return -1; 585 return 0; 586} 587 588static bool recurseDumpPath(const char *path, const char *pattern, Vector<Platform::FileInfo> &fileVector, S32 recurseDepth ) 589{ 590 WIN32_FIND_DATA findData; 591 592 TempAlloc< char> fullPath( dStrlen( path ) * 3 + MAX_PATH * 3 + 1 ); 593 Platform::makeFullPathName( path, fullPath, fullPath.size ); 594 595 U32 lenFullPath = dStrlen( fullPath ); 596 TempAlloc< char> buf( lenFullPath + MAX_PATH * 3 + 2 ); 597 dSprintf( buf, buf.size, "%s/%s", fullPath.ptr, pattern ); 598 599#ifdef UNICODE 600 TempAlloc< WCHAR> searchBuf( buf.size ); 601 convertUTF8toUTF16N( buf, searchBuf, searchBuf.size ); 602 WCHAR* search = searchBuf; 603#else 604 char *search = buf; 605#endif 606 607 backslash( search ); 608 609 HANDLE handle = FindFirstFile(search, &findData); 610 if (handle == INVALID_HANDLE_VALUE) 611 return false; 612 613 do 614 { 615#ifdef UNICODE 616 convertUTF16toUTF8N( findData.cFileName, buf, buf.size ); 617 char* fnbuf = buf; 618#else 619 char *fnbuf = findData.cFileName; 620#endif 621 622 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 623 { 624 // make sure it is a directory 625 if (findData.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_SYSTEM) ) 626 continue; 627 628 // skip . and .. directories 629 if (String::compare( findData.cFileName, TEXT( "." ) ) == 0 || String::compare( findData.cFileName, TEXT( ".." ) ) == 0) 630 continue; 631 632 // Skip excluded directores 633 if(Platform::isExcludedDirectory(fnbuf)) 634 continue; 635 636 dSprintf( fullPath, fullPath.size, "%s/%s", path, fnbuf); 637 char* child = fullPath; 638 if( recurseDepth > 0 ) 639 recurseDumpPath(child, pattern, fileVector, recurseDepth - 1); 640 else if (recurseDepth == -1) 641 recurseDumpPath(child, pattern, fileVector, -1); 642 } 643 else 644 { 645 // make sure it is the kind of file we're looking for 646 if (findData.dwFileAttributes & 647 (FILE_ATTRIBUTE_DIRECTORY| 648 FILE_ATTRIBUTE_OFFLINE| 649 FILE_ATTRIBUTE_SYSTEM| 650 FILE_ATTRIBUTE_TEMPORARY) ) 651 continue; 652 653 // add it to the list 654 fileVector.increment(); 655 Platform::FileInfo& rInfo = fileVector.last(); 656 657 forwardslash( fnbuf ); 658 659 rInfo.pFullPath = StringTable->insert(path); 660 rInfo.pFileName = StringTable->insert(fnbuf); 661 rInfo.fileSize = findData.nFileSizeLow; 662 } 663 664 }while(FindNextFile(handle, &findData)); 665 666 FindClose(handle); 667 return true; 668} 669 670 671//-------------------------------------- 672 673bool Platform::getFileTimes(const char *filePath, FileTime *createTime, FileTime *modifyTime) 674{ 675 WIN32_FIND_DATA findData; 676 677 TempAlloc< TCHAR> fp( dStrlen( filePath ) + 1 ); 678 679#ifdef UNICODE 680 convertUTF8toUTF16N( filePath, fp, fp.size ); 681#else 682 dStrcpy( fp, filePath, fp.size ); 683#endif 684 685 backslash( fp ); 686 687 HANDLE h = FindFirstFile(fp, &findData); 688 if(h == INVALID_HANDLE_VALUE) 689 return false; 690 691 if(createTime) 692 { 693 createTime->v1 = findData.ftCreationTime.dwLowDateTime; 694 createTime->v2 = findData.ftCreationTime.dwHighDateTime; 695 } 696 if(modifyTime) 697 { 698 modifyTime->v1 = findData.ftLastWriteTime.dwLowDateTime; 699 modifyTime->v2 = findData.ftLastWriteTime.dwHighDateTime; 700 } 701 FindClose(h); 702 return true; 703} 704 705//-------------------------------------- 706bool Platform::createPath(const char *file) 707{ 708 TempAlloc< TCHAR> pathbuf( dStrlen( file ) + 1 ); 709 710#ifdef UNICODE 711 TempAlloc< WCHAR> fileBuf( pathbuf.size ); 712 convertUTF8toUTF16N( file, fileBuf, fileBuf.size ); 713 const WCHAR* fileName = fileBuf; 714 const WCHAR* dir; 715#else 716 const char* fileName = file; 717 const char* dir; 718#endif 719 720 pathbuf[ 0 ] = 0; 721 U32 pathLen = 0; 722 723 while((dir = dStrchr(fileName, '/')) != NULL) 724 { 725 TCHAR* pathptr = pathbuf; 726 dMemcpy( pathptr + pathLen, fileName, ( dir - fileName ) * sizeof( TCHAR ) ); 727 pathbuf[pathLen + dir-fileName] = 0; 728 729 // ignore return value because we are fine with already existing directory 730 CreateDirectory(pathbuf, NULL); 731 732 pathLen += dir - fileName; 733 pathbuf[pathLen++] = '\\'; 734 fileName = dir + 1; 735 } 736 return true; 737} 738 739// [rene, 04/05/2008] Not used currently so did not bother updating. 740#if 0 741// [tom, 7/12/2005] Rather then converting this to unicode, just using the ANSI 742// versions of the Win32 API as its quicker for testing. 743bool S32 serialNum) 744{ 745 if (!filePath || !filePath[0]) 746 return true; 747 748 //first find the CD device... 749 char fileBuf[1024]; 750 char drivesBuf[256]; 751 S32 length = GetLogicalDriveStringsA(256, drivesBuf); 752 char *drivePtr = drivesBuf; 753 while (S32(drivePtr - drivesBuf) < length) 754 { 755 char driveVolume[256], driveFileSystem[256]; 756 U32 driveSerial, driveFNLength, driveFlags; 757 if ((dStricmp(drivePtr, "B:\\") != 0) && 758 GetVolumeInformationA((const char*)drivePtr, &driveVolume[0], (unsigned long)255, 759 (unsigned long*)&driveSerial, (unsigned long*)&driveFNLength, 760 (unsigned long*)&driveFlags, &driveFileSystem[0], (unsigned long)255)) 761 { 762#if defined (TORQUE_DEBUG) || !defined (TORQUE_SHIPPING) 763 Con::printf("Found Drive: %s, vol: %s, serial: %d", drivePtr, driveVolume, driveSerial); 764#endif 765 //see if the volume and serial number match 766 if (!dStricmp(volumeName, driveVolume) && (!serialNum || (serialNum == driveSerial))) 767 { 768 //see if the file exists on this volume 769 if(dStrlen(drivePtr) == 3 && drivePtr[2] == '\\' && filePath[0] == '\\') 770 dSprintf(fileBuf, sizeof(fileBuf), "%s%s", drivePtr, filePath + 1); 771 else 772 dSprintf(fileBuf, sizeof(fileBuf), "%s%s", drivePtr, filePath); 773#if defined (TORQUE_DEBUG) || !defined (TORQUE_SHIPPING) 774 Con::printf("Looking for file: %s on %s", fileBuf, driveVolume); 775#endif 776 WIN32_FIND_DATAA findData; 777 HANDLE h = FindFirstFileA(fileBuf, &findData); 778 if(h != INVALID_HANDLE_VALUE) 779 { 780 FindClose(h); 781 return true; 782 } 783 FindClose(h); 784 } 785 } 786 787 //check the next drive 788 drivePtr += dStrlen(drivePtr) + 1; 789 } 790 791 return false; 792} 793#endif 794 795//-------------------------------------- 796bool Platform::dumpPath(const char *path, Vector<Platform::FileInfo> &fileVector, S32 recurseDepth) 797{ 798 return recurseDumpPath(path, "*", fileVector, recurseDepth ); 799} 800 801 802//-------------------------------------- 803 804//StringTableEntry Platform::getWorkingDirectory() 805//{ 806// return getCurrentDirectory(); 807//} 808 809StringTableEntry Platform::getCurrentDirectory() 810{ 811 TempAlloc< TCHAR> buf( 2048 ); 812 813 GetCurrentDirectory( buf.size, buf ); 814 forwardslash( buf ); 815 816#ifdef UNICODE 817 char* utf8 = createUTF8string( buf ); 818 StringTableEntry result = StringTable->insert( utf8 ); 819 SAFE_DELETE_ARRAY( utf8 ); 820 return result; 821#else 822 return StringTable->insert( buf ); 823#endif 824} 825 826bool Platform::setCurrentDirectory(StringTableEntry newDir) 827{ 828 829 if (Platform::getWebDeployment()) 830 return true; 831 832 TempAlloc< TCHAR> buf( dStrlen( newDir ) + 2 ); 833 834#ifdef UNICODE 835 convertUTF8toUTF16N( newDir, buf, buf.size - 1 ); 836#else 837 dStrcpy( buf, newDir, buf.size ); 838#endif 839 840 backslash( buf ); 841 return SetCurrentDirectory( buf ); 842} 843 844#ifdef UNICODE 845static void getExecutableInfo( StringTableEntry* path, StringTableEntry* exe ) 846{ 847 static StringTableEntry pathEntry = NULL; 848 static StringTableEntry exeEntry = NULL; 849 850 if( !pathEntry ) 851 { 852 if (!Platform::getWebDeployment()) 853 { 854 WCHAR cen_buf[ 2048 ]; 855 GetModuleFileNameW( NULL, cen_buf, sizeof( cen_buf ) / sizeof( cen_buf[ 0 ] ) ); 856 forwardslash( cen_buf ); 857 858 WCHAR* delimiter = dStrrchr( cen_buf, '/' ); 859 if( delimiter ) 860 *delimiter = '\0'; 861 862 char* pathBuf = createUTF8string( cen_buf ); 863 char* exeBuf = createUTF8string( delimiter + 1 ); 864 865 pathEntry = StringTable->insert( pathBuf ); 866 exeEntry = StringTable->insert( exeBuf ); 867 868 SAFE_DELETE_ARRAY( pathBuf ); 869 SAFE_DELETE_ARRAY( exeBuf ); 870 } 871 else 872 { 873 char cdir[4096]; 874 GetCurrentDirectoryA(4096, cdir); 875 pathEntry = StringTable->insert(cdir); 876 exeEntry = StringTable->insert("WebGameCtrl.exe"); 877 } 878 } 879 880 if( path ) 881 *path = pathEntry; 882 if( exe ) 883 *exe = exeEntry; 884} 885#endif 886 887StringTableEntry Platform::getExecutableName() 888{ 889#ifdef UNICODE 890 StringTableEntry exe; 891 getExecutableInfo( NULL, &exe ); 892 return exe; 893#else 894 static StringTableEntry cen = NULL; 895 if (!cen) 896 { 897 char cen_buf[2048]; 898 GetModuleFileNameA( NULL, cen_buf, 2047); 899 forwardslash(cen_buf); 900 901 char *delimiter = dStrrchr( cen_buf, '/' ); 902 903 if( delimiter != NULL ) 904 { 905 *delimiter = 0x00; 906 delimiter++; 907 cen = StringTable->insert(delimiter); 908 } 909 else 910 cen = StringTable->insert(cen_buf); 911 } 912 return cen; 913#endif 914} 915 916StringTableEntry Platform::getExecutablePath() 917{ 918#ifdef UNICODE 919 StringTableEntry path; 920 getExecutableInfo( &path, NULL ); 921 return path; 922#else 923 static StringTableEntry cen = NULL; 924 if (!cen) 925 { 926 char cen_buf[2048]; 927 GetModuleFileNameA( NULL, cen_buf, 2047); 928 forwardslash(cen_buf); 929 930 char *delimiter = dStrrchr( cen_buf, '/' ); 931 932 if( delimiter != NULL ) 933 *delimiter = 0x00; 934 935 cen = StringTable->insert(cen_buf); 936 } 937 return cen; 938#endif 939} 940 941//-------------------------------------- 942bool Platform::isFile(const char *pFilePath) 943{ 944 if (!pFilePath || !*pFilePath) 945 return false; 946 947 TempAlloc< TCHAR> buf( dStrlen( pFilePath ) + 1 ); 948 949#ifdef UNICODE 950 convertUTF8toUTF16N( pFilePath, buf, buf.size ); 951#else 952 dStrcpy( buf, pFilePath, buf.size ); 953#endif 954 backslash( buf ); 955 956 // Get file info 957 WIN32_FIND_DATA findData; 958 HANDLE handle = FindFirstFile(buf, &findData); 959 FindClose(handle); 960 961 if(handle == INVALID_HANDLE_VALUE) 962 { 963 964 // Since file does not exist on disk see if it exists in a zip file loaded 965 return Torque::FS::IsFile(pFilePath); 966 } 967 968 // if the file is a Directory, Offline, System or Temporary then FALSE 969 if (findData.dwFileAttributes & 970 (FILE_ATTRIBUTE_DIRECTORY| 971 FILE_ATTRIBUTE_OFFLINE| 972 FILE_ATTRIBUTE_SYSTEM| 973 FILE_ATTRIBUTE_TEMPORARY) ) 974 return false; 975 976 // must be a real file then 977 return true; 978} 979 980//-------------------------------------- 981S32 Platform::getFileSize(const char *pFilePath) 982{ 983 if (!pFilePath || !*pFilePath) 984 return -1; 985 986 TempAlloc< TCHAR> buf( dStrlen( pFilePath ) + 1 ); 987 988#ifdef UNICODE 989 convertUTF8toUTF16N( pFilePath, buf, buf.size ); 990#else 991 dStrcpy( buf, pFilePath, buf.size ); 992#endif 993 backslash( buf ); 994 995 // Get file info 996 WIN32_FIND_DATA findData; 997 HANDLE handle = FindFirstFile(buf, &findData); 998 999 if(handle == INVALID_HANDLE_VALUE) 1000 return -1; 1001 1002 FindClose(handle); 1003 1004 // if the file is a Directory, Offline, System or Temporary then FALSE 1005 if (findData.dwFileAttributes & 1006 (FILE_ATTRIBUTE_DIRECTORY| 1007 FILE_ATTRIBUTE_OFFLINE| 1008 FILE_ATTRIBUTE_SYSTEM| 1009 FILE_ATTRIBUTE_TEMPORARY) ) 1010 return -1; 1011 1012 // must be a real file then 1013 return ((findData.nFileSizeHigh * (MAXDWORD+1)) + findData.nFileSizeLow); 1014} 1015 1016 1017//-------------------------------------- 1018bool Platform::isDirectory(const char *pDirPath) 1019{ 1020 if (!pDirPath || !*pDirPath) 1021 return false; 1022 1023 TempAlloc< TCHAR> buf( dStrlen( pDirPath ) + 1 ); 1024 1025#ifdef UNICODE 1026 convertUTF8toUTF16N( pDirPath, buf, buf.size ); 1027#else 1028 dStrcpy( buf, pDirPath, buf.size ); 1029#endif 1030 backslash( buf ); 1031 1032 // Get file info 1033 WIN32_FIND_DATA findData; 1034 HANDLE handle = FindFirstFile(buf, &findData); 1035 1036 // [neo, 5/15/2007] 1037 // This check was AFTER FindClose for some reason - this is most probably the 1038 // original intent. 1039 if(handle == INVALID_HANDLE_VALUE) 1040 return false; 1041 1042 FindClose(handle); 1043 1044 // if the file is a Directory, Offline, System or Temporary then FALSE 1045 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1046 { 1047 // make sure it's a valid game directory 1048 if (findData.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE|FILE_ATTRIBUTE_SYSTEM) ) 1049 return false; 1050 1051 // must be a directory 1052 return true; 1053 } 1054 1055 return false; 1056} 1057 1058 1059 1060//-------------------------------------- 1061bool Platform::isSubDirectory(const char *pParent, const char *pDir) 1062{ 1063 if (!pParent || !*pDir) 1064 return false; 1065 1066 const char* fileName = avar("%s/*", pParent); 1067 1068 TempAlloc< TCHAR> file( dStrlen( fileName ) + 1 ); 1069 TempAlloc< TCHAR> dir( dStrlen( pDir ) + 1 ); 1070 1071#ifdef UNICODE 1072 convertUTF8toUTF16N( fileName, file, file.size ); 1073 convertUTF8toUTF16N( pDir, dir, dir.size ); 1074#else 1075 dStrcpy( file, fileName, file.size ); 1076 dStrcpy( dir, pDir, dir.size ); 1077#endif 1078 1079 backslash( file ); 1080 backslash( dir ); 1081 1082 // this is somewhat of a brute force method but we need to be 100% sure 1083 // that the user cannot enter things like ../dir or /dir etc,... 1084 WIN32_FIND_DATA findData; 1085 HANDLE handle = FindFirstFile(file, &findData); 1086 if (handle == INVALID_HANDLE_VALUE) 1087 return false; 1088 do 1089 { 1090 // if it is a directory... 1091 if (findData.dwFileAttributes & 1092 (FILE_ATTRIBUTE_DIRECTORY| 1093 FILE_ATTRIBUTE_OFFLINE| 1094 FILE_ATTRIBUTE_SYSTEM| 1095 FILE_ATTRIBUTE_TEMPORARY) ) 1096 { 1097 //FIXME: this has to be dStrcasecmp but there's no implementation for Unicode 1098 1099 // and the names match 1100 if (String::compare(dir, findData.cFileName ) == 0) 1101 { 1102 // then we have a real sub directory 1103 FindClose(handle); 1104 return true; 1105 } 1106 } 1107 }while(FindNextFile(handle, &findData)); 1108 1109 FindClose(handle); 1110 return false; 1111} 1112 1113//------------------------------------------------------------------------------ 1114 1115bool Platform::fileTimeToString(FileTime * time, char * string, U32 strLen) 1116{ 1117 if(!time || !string) 1118 return(false); 1119 1120 dSprintf(string, strLen, "%d:%d", time->v2, time->v1); 1121 return(true); 1122} 1123 1124bool Platform::stringToFileTime(const char * string, FileTime * time) 1125{ 1126 if(!time || !string) 1127 return(false); 1128 1129 char buf[80]; 1130 dSprintf(buf, sizeof(buf), (char *)string); 1131 1132 char * sep = (char *)dStrstr((const char *)buf, (const char *)":"); 1133 if(!sep) 1134 return(false); 1135 1136 *sep = 0; 1137 sep++; 1138 1139 time->v2 = dAtoi(buf); 1140 time->v1 = dAtoi(sep); 1141 1142 return(true); 1143} 1144 1145// Volume Functions 1146 1147void Platform::getVolumeNamesList( Vector<const char*>& out_rNameVector, bool bOnlyFixedDrives ) 1148{ 1149 DWORD dwDrives = GetLogicalDrives(); 1150 DWORD dwMask = 1; 1151 char driveLetter[12]; 1152 1153 out_rNameVector.clear(); 1154 1155 for(S32 i = 0; i < 32; i++ ) 1156 { 1157 dMemset(driveLetter,0,12); 1158 if( dwDrives & dwMask ) 1159 { 1160 dSprintf(driveLetter, 12, "%c:", (i + 'A')); 1161 1162 if( bOnlyFixedDrives && GetDriveTypeA(driveLetter) == DRIVE_FIXED ) 1163 out_rNameVector.push_back( StringTable->insert( driveLetter ) ); 1164 else if ( !bOnlyFixedDrives ) 1165 out_rNameVector.push_back( StringTable->insert( driveLetter ) ); 1166 } 1167 dwMask <<= 1; 1168 } 1169} 1170 1171void Platform::getVolumeInformationList( Vector<VolumeInformation>& out_rVolumeInfoVector, bool bOnlyFixedDrives ) 1172{ 1173 Vector<const char*> drives; 1174 1175 getVolumeNamesList( drives, bOnlyFixedDrives ); 1176 1177 if( ! drives.empty() ) 1178 { 1179 Vector<StringTableEntry>::iterator i; 1180 for( i = drives.begin(); i != drives.end(); i++ ) 1181 { 1182 VolumeInformation info; 1183 TCHAR lpszVolumeName[ 256 ]; 1184 TCHAR lpszFileSystem[ 256 ]; 1185 DWORD dwSerial = 0; 1186 DWORD dwMaxComponentLength = 0; 1187 DWORD dwFileSystemFlags = 0; 1188 1189 dMemset( lpszVolumeName, 0, sizeof( lpszVolumeName ) ); 1190 dMemset( lpszFileSystem, 0, sizeof( lpszFileSystem ) ); 1191 dMemset( &info, 0, sizeof( VolumeInformation ) ); 1192 1193 // More volume information 1194 UINT uDriveType = GetDriveTypeA( (*i) ); 1195 if( uDriveType == DRIVE_UNKNOWN ) 1196 info.Type = DRIVETYPE_UNKNOWN; 1197 else if( uDriveType == DRIVE_REMOVABLE ) 1198 info.Type = DRIVETYPE_REMOVABLE; 1199 else if( uDriveType == DRIVE_FIXED ) 1200 info.Type = DRIVETYPE_FIXED; 1201 else if( uDriveType == DRIVE_CDROM ) 1202 info.Type = DRIVETYPE_CDROM; 1203 else if( uDriveType == DRIVE_RAMDISK ) 1204 info.Type = DRIVETYPE_RAMDISK; 1205 else if( uDriveType == DRIVE_REMOTE ) 1206 info.Type = DRIVETYPE_REMOTE; 1207 1208 info.RootPath = StringTable->insert( (*i) ); 1209 1210 // We don't retrieve drive volume info for removable drives, because it's loud :( 1211 if( info.Type != DRIVETYPE_REMOVABLE ) 1212 { 1213#ifdef UNICODE 1214 WCHAR ibuf[ 3 ]; 1215 ibuf[ 0 ] = ( *i )[ 0 ]; 1216 ibuf[ 1 ] = ':'; 1217 ibuf[ 2 ] = '\0'; 1218#else 1219 char* ibuf = *i; 1220#endif 1221 // Standard volume information 1222 GetVolumeInformation( ibuf, lpszVolumeName, sizeof( lpszVolumeName ) / sizeof( lpszVolumeName[ 0 ] ), 1223 &dwSerial, &dwMaxComponentLength, &dwFileSystemFlags, lpszFileSystem, 1224 sizeof( lpszFileSystem ) / sizeof( lpszFileSystem[ 0 ] ) ); 1225 1226#ifdef UNICODE 1227 char buf[ sizeof( lpszFileSystem ) / sizeof( lpszFileSystem[ 0 ] ) * 3 + 1 ]; 1228 convertUTF16toUTF8( lpszFileSystem, buf ); 1229 info.FileSystem = StringTable->insert( buf ); 1230 1231 convertUTF16toUTF8( lpszVolumeName, buf ); 1232 info.Name = StringTable->insert( buf ); 1233#else 1234 info.FileSystem = StringTable->insert( lpszFileSystem ); 1235 info.Name = StringTable->insert( lpszVolumeName ); 1236#endif 1237 info.SerialNumber = dwSerial; 1238 // Won't compile on something prior to XP. 1239 info.ReadOnly = dwFileSystemFlags & FILE_READ_ONLY_VOLUME; 1240 } 1241 out_rVolumeInfoVector.push_back( info ); 1242 1243 // I opted not to get free disk space because of the overhead of the calculations required for it 1244 1245 } 1246 } 1247} 1248 1249 1250bool Platform::hasSubDirectory(const char *pPath) 1251{ 1252 if( !pPath ) 1253 return false; 1254 1255 char searchBuf[1024]; 1256 1257 // Compose our search string - Format : ([path]/[subpath]/*) 1258 char trail = pPath[ dStrlen(pPath) - 1 ]; 1259 if( trail == '/' ) 1260 dStrcpy( searchBuf, pPath, 1024 ); 1261 else 1262 dSprintf(searchBuf, 1024, "%s/*", pPath ); 1263 1264#ifdef UNICODE 1265 WCHAR buf[ 1024 ]; 1266 convertUTF8toUTF16( searchBuf, buf ); 1267 WCHAR* search = buf; 1268#else 1269 char* search = searchBuf; 1270#endif 1271 1272 backslash( search ); 1273 1274 // See if we get any hits 1275 WIN32_FIND_DATA findData; 1276 HANDLE handle = FindFirstFile(search, &findData); 1277 if (handle == INVALID_HANDLE_VALUE) 1278 return false; 1279 1280 bool result = false; 1281 do 1282 { 1283 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1284 { 1285 // skip . and .. directories 1286 if (String::compare(findData.cFileName, TEXT( "." ) ) == 0 || String::compare(findData.cFileName, TEXT( ".." ) ) == 0) 1287 continue; 1288 1289#ifdef UNICODE 1290 char fileName[ 1024 ]; 1291 convertUTF16toUTF8( findData.cFileName, fileName ); 1292#else 1293 char* fileName = findData.cFileName; 1294#endif 1295 1296 if( Platform::isExcludedDirectory( fileName ) ) 1297 continue; 1298 1299 result = true; 1300 break; 1301 } 1302 } 1303 while(FindNextFile(handle, &findData)); 1304 1305 FindClose(handle); 1306 1307 Platform::clearExcludedDirectories(); 1308 1309 return result; 1310} 1311 1312 1313static bool recurseDumpDirectories(const char *basePath, const char *subPath, Vector<StringTableEntry> &directoryVector, S32 currentDepth, S32 recurseDepth, bool noBasePath) 1314{ 1315 TempAlloc< char> search( 1024 ); 1316 1317 //----------------------------------------------------------------------------- 1318 // Compose our search string - Format : ([path]/[subpath]/*) 1319 //----------------------------------------------------------------------------- 1320 1321 dsize_t trLen = basePath ? dStrlen(basePath) : 0; 1322 dsize_t subtrLen = subPath ? dStrlen(subPath) : 0; 1323 char trail = trLen > 0 ? basePath[ trLen - 1 ] : '\0'; 1324 char subTrail = subtrLen > 0 ? subPath[ subtrLen - 1 ] : '\0'; 1325 char subLead = subtrLen > 0 ? subPath[0] : '\0'; 1326 1327 if( trail == '/' ) 1328 { 1329 // we have a sub path and it's not an empty string 1330 if( subPath && ( dStrncmp( subPath, "", 1 ) != 0 ) ) 1331 { 1332 if( subTrail == '/' ) 1333 dSprintf(search, search.size, "%s%s*", basePath,subPath ); 1334 else 1335 dSprintf(search, search.size, "%s%s/*", basePath,subPath ); 1336 } 1337 else 1338 dSprintf( search, search.size, "%s*", basePath ); 1339 } 1340 else 1341 { 1342 if( subPath && ( dStrncmp( subPath, "", 1 ) != 0 ) ) 1343 if( subTrail == '/' ) 1344 dSprintf(search, search.size, "%s%s*", basePath,subPath ); 1345 else 1346 dSprintf(search, search.size, "%s%s/*", basePath,subPath ); 1347 else 1348 dSprintf(search, search.size, "%s/*", basePath ); 1349 } 1350 1351#ifdef UNICODE 1352 TempAlloc< WCHAR> searchStr( dStrlen( search ) + 1 ); 1353 convertUTF8toUTF16N( search, searchStr, searchStr.size ); 1354#else 1355 char* searchStr = search; 1356#endif 1357 1358 backslash( searchStr ); 1359 1360 //----------------------------------------------------------------------------- 1361 // See if we get any hits 1362 //----------------------------------------------------------------------------- 1363 1364 WIN32_FIND_DATA findData; 1365 HANDLE handle = FindFirstFile(searchStr, &findData); 1366 if (handle == INVALID_HANDLE_VALUE) 1367 return false; 1368 1369 //----------------------------------------------------------------------------- 1370 // add path to our return list ( provided it is valid ) 1371 //----------------------------------------------------------------------------- 1372 if( !Platform::isExcludedDirectory( subPath ) ) 1373 { 1374 1375 if( noBasePath ) 1376 { 1377 // We have a path and it's not an empty string or an excluded directory 1378 if( ( subPath && ( dStrncmp( subPath, "", 1 ) != 0 ) ) ) 1379 directoryVector.push_back( StringTable->insert( subPath ) ); 1380 } 1381 else 1382 { 1383 if( ( subPath && ( dStrncmp( subPath, "", 1 ) != 0 ) ) ) 1384 { 1385 char szPath[1024]; 1386 dMemset(szPath, 0, 1024); 1387 if (trail == '/') 1388 { 1389 if (subLead == '/') 1390 dSprintf(szPath, 1024, "%s%s", basePath, &subPath[1]); 1391 else 1392 dSprintf(szPath, 1024, "%s%s", basePath, subPath); 1393 } 1394 else 1395 { 1396 if (subLead == '/') 1397 dSprintf(szPath, 1024, "%s%s", basePath, subPath); 1398 else 1399 dSprintf(szPath, 1024, "%s/%s", basePath, subPath); 1400 } 1401 directoryVector.push_back(StringTable->insert(szPath)); 1402 } 1403 else 1404 directoryVector.push_back( StringTable->insert( basePath ) ); 1405 } 1406 } 1407 1408 //----------------------------------------------------------------------------- 1409 // Iterate through and grab valid directories 1410 //----------------------------------------------------------------------------- 1411 1412#ifdef UNICODE 1413 TempAlloc< char> fileName( 1024 ); 1414#endif 1415 1416 do 1417 { 1418 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 1419 { 1420 // skip . and .. directories 1421 if (String::compare(findData.cFileName, TEXT( "." )) == 0 || String::compare(findData.cFileName, TEXT( ".." )) == 0) 1422 continue; 1423 1424#ifdef UNICODE 1425 convertUTF16toUTF8N( findData.cFileName, fileName, fileName.size ); 1426#else 1427 char* fileName = findData.cFileName; 1428#endif 1429 1430 // skip excluded directories 1431 if( Platform::isExcludedDirectory( fileName ) ) 1432 continue; 1433 1434 if( ( subPath && ( dStrncmp( subPath, "", 1 ) != 0 ) )) 1435 { 1436 if( subTrail == '/' ) 1437 dSprintf(search, search.size, "%s%s", subPath, fileName.ptr); 1438 else 1439 dSprintf(search, search.size, "%s/%s", subPath, fileName.ptr); 1440 char* child = search; 1441 1442 if( currentDepth < recurseDepth || recurseDepth == -1 ) 1443 recurseDumpDirectories(basePath, child, directoryVector, currentDepth+1, recurseDepth, noBasePath ); 1444 1445 } 1446 else 1447 { 1448 char* child; 1449 if( trail == '/' ) 1450 child = fileName; 1451 else 1452 { 1453 dSprintf(search, search.size, "/%s", fileName.ptr); 1454 child = search; 1455 } 1456 1457 if( currentDepth < recurseDepth || recurseDepth == -1 ) 1458 recurseDumpDirectories(basePath, child, directoryVector, currentDepth+1, recurseDepth, noBasePath ); 1459 } 1460 } 1461 } 1462 while(FindNextFile(handle, &findData)); 1463 1464 FindClose(handle); 1465 return true; 1466} 1467 1468bool Platform::dumpDirectories( const char *path, Vector<StringTableEntry> &directoryVector, S32 depth, bool noBasePath ) 1469{ 1470 bool retVal = recurseDumpDirectories( path, "", directoryVector, -1, depth, noBasePath ); 1471 1472 clearExcludedDirectories(); 1473 1474 return retVal; 1475} 1476 1477//----------------------------------------------------------------------------- 1478 1479StringTableEntry osGetTemporaryDirectory() 1480{ 1481 TCHAR buf[ 1024 ]; 1482 const U32 bufSize = sizeof( buf ) / sizeof( buf[ 0 ] ); 1483 DWORD len = GetTempPath( sizeof( buf ) / sizeof( buf[ 0 ] ), buf ); 1484 1485 TempAlloc< TCHAR> temp; 1486 TCHAR* buffer = buf; 1487 if( len > bufSize - 1 ) 1488 { 1489 temp = TempAlloc< TCHAR>( len + 1 ); 1490 buffer = temp; 1491 GetTempPath( len + 1, buffer ); 1492 } 1493 1494 // Remove the trailing slash 1495 buffer[len-1] = 0; 1496 1497#ifdef UNICODE 1498 TempAlloc< char> dirBuffer( len * 3 + 1 ); 1499 char* dir = dirBuffer; 1500 convertUTF16toUTF8N( buffer, dir, dirBuffer.size ); 1501#else 1502 char* dir = buf; 1503#endif 1504 1505 forwardslash(dir); 1506 return StringTable->insert(dir); 1507} 1508