00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdmisc.h"
00028
00029 #include <fstream>
00030
00031 #include "nel/misc/big_file.h"
00032 #include "nel/misc/path.h"
00033 #include "nel/misc/hierarchical_timer.h"
00034
00035 #ifdef NL_OS_WINDOWS
00036 # include <windows.h>
00037 # include <sys/types.h>
00038 # include <sys/stat.h>
00039 # include <direct.h>
00040 # include <io.h>
00041 # include <fcntl.h>
00042 # include <sys/types.h>
00043 # include <sys/stat.h>
00044 #else
00045 # include <sys/types.h>
00046 # include <sys/stat.h>
00047 # include <dirent.h>
00048 # include <unistd.h>
00049 # include <errno.h>
00050 #endif // NL_OS_WINDOWS
00051
00052 using namespace std;
00053
00054 namespace NLMISC {
00055
00056
00057
00058
00059
00060
00061
00062
00063 #ifdef NL_DEBUG_PATH
00064 #define NL_DISPLAY_PATH nlinfo
00065 #else
00066 #ifdef __GNUC__
00067 #define NL_DISPLAY_PATH(format, args...)
00068 #else // __GNUC__
00069 #define NL_DISPLAY_PATH if(false)
00070 #endif // __GNUC__
00071 #endif
00072
00073
00074
00075
00076
00077
00078 CPath *CPath::_Instance = NULL;
00079
00080
00081
00082
00083
00084
00085 void CPath::getFileList(const std::string &extension, std::vector<std::string> &filenames)
00086 {
00087 std::map<std::string, CFileEntry>::iterator first(getInstance()->_Files.begin()), last(getInstance()->_Files.end());
00088
00089 for (; first != last; ++ first)
00090 {
00091 if (first->second.Extension == extension)
00092 {
00093 filenames.push_back(first->first);
00094 }
00095 }
00096 }
00097
00098 CPath *CPath::getInstance ()
00099 {
00100 if (_Instance == NULL)
00101 {
00102 _Instance = new CPath;
00103 }
00104 return _Instance;
00105 }
00106
00107 void CPath::clearMap ()
00108 {
00109 CPath *inst = CPath::getInstance();
00110 inst->_Files.clear ();
00111 NL_DISPLAY_PATH("CPath::clearMap(): map directory cleared");
00112 }
00113
00114 sint CPath::findExtension (const string &ext1, const string &ext2)
00115 {
00116 CPath *inst = CPath::getInstance();
00117 for (uint i = 0; i < inst->_Extensions.size (); i++)
00118 {
00119 if (inst->_Extensions[i].first == ext1 && inst->_Extensions[i].second == ext2)
00120 {
00121 return i;
00122 }
00123 }
00124 return -1;
00125 }
00126
00127 void CPath::remapExtension (const string &ext1, const string &ext2, bool substitute)
00128 {
00129 CPath *inst = CPath::getInstance();
00130
00131 string ext1lwr = strlwr (ext1);
00132 string ext2lwr = strlwr (ext2);
00133
00134 if (ext1lwr.empty() || ext2lwr.empty())
00135 {
00136 nlwarning ("CPath::remapExtension(%s, %s, %d): can't remap empty extension", ext1lwr.c_str(), ext2lwr.c_str(), substitute);
00137 }
00138
00139 if (ext1lwr == "bnp" || ext2lwr == "bnp")
00140 {
00141 nlwarning ("CPath::remapExtension(%s, %s, %d): you can't remap a big file", ext1lwr.c_str(), ext2lwr.c_str(), substitute);
00142 }
00143
00144 if (!substitute)
00145 {
00146
00147 sint n = inst->findExtension (ext1lwr, ext2lwr);
00148 nlassert (n != -1);
00149 inst->_Extensions.erase (inst->_Extensions.begin() + n);
00150
00151
00152 map<string, CFileEntry>::iterator it = inst->_Files.begin();
00153 map<string, CFileEntry>::iterator nit = it;
00154 while (it != inst->_Files.end ())
00155 {
00156 nit++;
00157 if ((*it).second.Remapped && (*it).second.Extension == ext2lwr)
00158 {
00159 inst->_Files.erase (it);
00160 }
00161 it = nit;
00162 }
00163 NL_DISPLAY_PATH("CPath::remapExtension(%s, %s, %d): extension removed", ext1lwr.c_str(), ext2lwr.c_str(), substitute);
00164 }
00165 else
00166 {
00167 sint n = inst->findExtension (ext1lwr, ext2lwr);
00168 if (n != -1)
00169 {
00170 nlwarning ("CPath::remapExtension(%s, %s, %d): remapping already set", ext1lwr.c_str(), ext2lwr.c_str(), substitute);
00171 return;
00172 }
00173
00174
00175 inst->_Extensions.push_back (make_pair (ext1lwr, ext2lwr));
00176
00177
00178 vector<string> newFiles;
00179 map<string, CFileEntry>::iterator it = inst->_Files.begin();
00180 while (it != inst->_Files.end ())
00181 {
00182 if (!(*it).second.Remapped && (*it).second.Extension == ext1lwr)
00183 {
00184
00185 uint32 pos = (*it).first.find_last_of (".");
00186 if (pos != string::npos)
00187 {
00188 string file = (*it).first.substr (0, pos + 1);
00189 file += ext2lwr;
00190
00191
00192 insertFileInMap (file, (*it).second.Path, true, ext2lwr);
00193 }
00194 }
00195 it++;
00196 }
00197 NL_DISPLAY_PATH("CPath::remapExtension(%s, %s, %d): extension added", ext1lwr.c_str(), ext2lwr.c_str(), substitute);
00198 }
00199 }
00200
00201 string CPath::lookup (const string &filename, bool throwException, bool displayWarning, bool lookupInLocalDirectory)
00202 {
00203
00204 if ( lookupInLocalDirectory && CFile::fileExists(filename) )
00205 {
00206 NL_DISPLAY_PATH("CPath::lookup(%s): found in the current directory: '%s'", filename.c_str(), filename.c_str());
00207 return filename;
00208 }
00209
00210
00211 if (filename.find ("@") != string::npos)
00212 {
00213 NL_DISPLAY_PATH("CPath::lookup(%s): already found", filename.c_str());
00214 return filename;
00215 }
00216
00217
00218 CPath *inst = CPath::getInstance();
00219 string str = strlwr (filename);
00220
00221
00222 while ((!str.empty()) && (str[str.size()-1] == ' '))
00223 {
00224 str.resize (str.size()-1);
00225 }
00226
00227 map<string, CFileEntry>::iterator it = inst->_Files.find (str);
00228
00229 if (it != inst->_Files.end())
00230 {
00231 NL_DISPLAY_PATH("CPath::lookup(%s): found in the map directory: '%s'", filename.c_str(), (*it).second.Path.c_str());
00232 return (*it).second.Path;
00233 }
00234
00235
00236
00237 for (uint i = 0; i < inst->_AlternativePaths.size(); i++)
00238 {
00239 string s = inst->_AlternativePaths[i] + filename;
00240 if ( CFile::fileExists(s) )
00241 {
00242 NL_DISPLAY_PATH("CPath::lookup(%s): found in the alternative directory: '%s'", filename.c_str(), s.c_str());
00243 return s;
00244 }
00245
00246
00247 for (uint j = 0; j < inst->_Extensions.size(); j++)
00248 {
00249 if (strlwr(CFile::getExtension (filename)) == inst->_Extensions[j].second)
00250 {
00251 string rs = inst->_AlternativePaths[i] + CFile::getFilenameWithoutExtension (filename) + "." + inst->_Extensions[j].first;
00252 if ( CFile::fileExists(rs) )
00253 {
00254 NL_DISPLAY_PATH("CPath::lookup(%s): found in the alternative directory: '%s'", filename.c_str(), rs.c_str());
00255 return rs;
00256 }
00257 }
00258 }
00259 }
00260
00261
00262
00263 if (displayWarning)
00264 {
00265 nlwarning ("CPath::lookup(%s): file not found", filename.c_str());
00266 }
00267
00268 if (throwException)
00269 throw EPathNotFound (filename);
00270
00271 return "";
00272 }
00273
00274 bool CPath::exists (const std::string &filename)
00275 {
00276
00277 CPath *inst = CPath::getInstance();
00278 string str = strlwr (filename);
00279
00280
00281 while ((!str.empty()) && (str[str.size()-1] == ' '))
00282 {
00283 str.resize (str.size()-1);
00284 }
00285
00286 map<string, CFileEntry>::iterator it = inst->_Files.find (str);
00287
00288 if (it != inst->_Files.end())
00289 {
00290 return true;
00291 }
00292
00293 return false;
00294 }
00295
00296 string CPath::standardizePath (const string &path, bool addFinalSlash)
00297 {
00298 string newPath;
00299
00300
00301 if (path.empty()) return "";
00302
00303
00304
00305
00306
00307
00308
00309
00310 for (uint i = 0; i < path.size(); i++)
00311 {
00312
00313 if (path[i] == '\\')
00314 newPath += '/';
00315 else
00316 newPath += path[i];
00317 }
00318
00319
00320 if (addFinalSlash && newPath[path.size()-1] != '/')
00321 newPath += '/';
00322
00323 return newPath;
00324 }
00325
00326
00327 std::string CPath::standardizeDosPath (const std::string &path)
00328 {
00329 string newPath;
00330
00331 for (uint i = 0; i < path.size(); i++)
00332 {
00333 if (path[i] == '/')
00334 newPath += '\\';
00335
00336
00337
00338 else
00339 newPath += path[i];
00340 }
00341
00342 if (CFile::isExists(path) && CFile::isDirectory(path) && newPath[newPath.size()-1] != '\\')
00343 newPath += '\\';
00344
00345 return newPath;
00346 }
00347
00348
00349 std::string CPath::getCurrentPath ()
00350 {
00351 char buffer [10000];
00352
00353 #ifdef NL_OS_WINDOWS
00354 return _getcwd(buffer, 10000);
00355 #else
00356 return getcwd(buffer, 10000);
00357 #endif
00358 }
00359
00360 std::string CPath::getFullPath (const std::string &path, bool addFinalSlash)
00361 {
00362 string currentPath = standardizePath (getCurrentPath ());
00363 string sPath = standardizePath (path, addFinalSlash);
00364
00365
00366 if (path.empty())
00367 {
00368 return currentPath;
00369 }
00370
00371
00372 if (path.size() >= 2 && path[1] == ':')
00373 {
00374 return sPath;
00375 }
00376
00377 if (path.size() >= 2 && (path[0] == '/' || path[0] == '\\') && (path[1] == '/' || path[1] == '\\'))
00378 {
00379 return sPath;
00380 }
00381
00382
00383
00384 if (path [0] == '/' || path[0] == '\\')
00385 {
00386 if (currentPath.size() > 2 && currentPath[1] == ':')
00387 {
00388 return currentPath.substr(0,3) + sPath.substr(1);
00389 }
00390 else
00391 {
00392 return sPath;
00393 }
00394 }
00395
00396
00397 return currentPath + sPath;
00398 }
00399
00400
00401
00402 #ifdef NL_OS_WINDOWS
00403 # define dirent WIN32_FIND_DATA
00404 # define DIR void
00405
00406 static string sDir;
00407 static char sDirBackup[512];
00408 static WIN32_FIND_DATA findData;
00409 static HANDLE hFind;
00410
00411 DIR *opendir (const char *path)
00412 {
00413 nlassert (path != NULL);
00414 nlassert (path[0] != '\0');
00415
00416 nlassert (sDirBackup[0] == '\0');
00417 if (GetCurrentDirectory (512, sDirBackup) == 0)
00418 {
00419
00420 sDirBackup[0] = 0;
00421 return NULL;
00422 }
00423
00424
00425 if (!CFile::isDirectory(path))
00426 {
00427
00428 sDirBackup[0] = 0;
00429 return NULL;
00430 }
00431
00432 sDir = path;
00433
00434 hFind = NULL;
00435
00436 return (void *)1;
00437 }
00438
00439 int closedir (DIR *dir)
00440 {
00441 nlassert (sDirBackup[0] != '\0');
00442 FindClose(hFind);
00443 sDirBackup[0] = '\0';
00444 return 0;
00445 }
00446
00447 dirent *readdir (DIR *dir)
00448 {
00449
00450 nlassert (!sDir.empty());
00451 if (SetCurrentDirectory (sDir.c_str()) == 0)
00452 {
00453
00454 return NULL;
00455 }
00456
00457 if (hFind == NULL)
00458 {
00459 hFind = FindFirstFile ("*", &findData);
00460 }
00461 else
00462 {
00463 if (!FindNextFile (hFind, &findData))
00464 {
00465 nlassert (sDirBackup[0] != '\0');
00466 SetCurrentDirectory (sDirBackup);
00467 return NULL;
00468 }
00469 }
00470
00471
00472 nlassert (sDirBackup[0] != '\0');
00473 SetCurrentDirectory (sDirBackup);
00474
00475 return &findData;
00476 }
00477
00478 #endif // NL_OS_WINDOWS
00479
00480 #ifndef NL_OS_WINDOWS
00481 string BasePathgetPathContent;
00482 #endif
00483
00484 bool isdirectory (dirent *de)
00485 {
00486 nlassert (de != NULL);
00487 #ifdef NL_OS_WINDOWS
00488 return ((de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) && ((de->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0);
00489 #else
00490
00491
00492
00493
00494 return CFile::isDirectory (BasePathgetPathContent + de->d_name);
00495
00496 #endif // NL_OS_WINDOWS
00497 }
00498
00499 bool isfile (dirent *de)
00500 {
00501 nlassert (de != NULL);
00502 #ifdef NL_OS_WINDOWS
00503 return ((de->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) && ((de->dwFileAttributes & FILE_ATTRIBUTE_SYSTEM) == 0);
00504 #else
00505
00506
00507
00508 return !CFile::isDirectory (BasePathgetPathContent + de->d_name);
00509
00510 #endif // NL_OS_WINDOWS
00511 }
00512
00513 string getname (dirent *de)
00514 {
00515 nlassert (de != NULL);
00516 #ifdef NL_OS_WINDOWS
00517 return de->cFileName;
00518 #else
00519 return de->d_name;
00520 #endif // NL_OS_WINDOWS
00521 }
00522
00523 void CPath::getPathContent (const string &path, bool recurse, bool wantDir, bool wantFile, vector<string> &result)
00524 {
00525 #ifndef NL_OS_WINDOWS
00526 BasePathgetPathContent = CPath::standardizePath (path);
00527 #endif
00528
00529 DIR *dir = opendir (path.c_str());
00530
00531 if (dir == NULL)
00532 {
00533 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): could not open the directory", path.c_str(), recurse, wantDir, wantFile);
00534 return;
00535 }
00536
00537
00538 vector<string> recursPath;
00539
00540 while (true)
00541 {
00542 dirent *de = readdir(dir);
00543 if (de == NULL)
00544 {
00545 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): end of directory", path.c_str(), recurse, wantDir, wantFile);
00546 break;
00547 }
00548
00549 string fn = getname (de);
00550
00551
00552 if (fn == "." || fn == "..")
00553 continue;
00554
00555 if (isdirectory(de))
00556 {
00557
00558 if (fn == "CVS")
00559 {
00560 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): skip CVS directory", path.c_str(), recurse, wantDir, wantFile);
00561 continue;
00562 }
00563
00564 string stdName = standardizePath(standardizePath(path) + fn);
00565 if (recurse)
00566 {
00567 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): need to recurse into '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00568 recursPath.push_back (stdName);
00569 }
00570
00571 if (wantDir)
00572 {
00573 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): adding path '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00574 result.push_back (stdName);
00575 }
00576 }
00577 if (wantFile && isfile(de))
00578 {
00579 if (fn.size() >= 4 && fn.substr (fn.size()-4) == ".log")
00580 {
00581 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): skip *.log files (%s)", path.c_str(), recurse, wantDir, wantFile, fn.c_str());
00582 continue;
00583 }
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594 string stdName = standardizePath(path) + getname(de);
00595
00596
00597 NL_DISPLAY_PATH("CPath::getPathContent(%s, %d, %d, %d): adding file '%s'", path.c_str(), recurse, wantDir, wantFile, stdName.c_str());
00598 result.push_back (stdName);
00599 }
00600 }
00601
00602 closedir (dir);
00603
00604 #ifndef NL_OS_WINDOWS
00605 BasePathgetPathContent = "";
00606 #endif
00607
00608
00609 for (uint i = 0; i < recursPath.size (); i++)
00610 {
00611 getPathContent (recursPath[i], recurse, wantDir, wantFile, result);
00612 }
00613 }
00614
00615 void CPath::removeAllAlternativeSearchPath ()
00616 {
00617 CPath *inst = CPath::getInstance();
00618 inst->_AlternativePaths.clear ();
00619 NL_DISPLAY_PATH("CPath::RemoveAllAternativeSearchPath(): removed");
00620 }
00621
00622
00623 void CPath::addSearchPath (const string &path, bool recurse, bool alternative)
00624 {
00625 H_AUTO_INST(addSearchPath);
00626
00627 CPath *inst = CPath::getInstance();
00628
00629
00630 if (path.empty())
00631 {
00632 nlwarning ("CPath::addSearchPath(%s, %d, %d): can't add empty directory, skip it", path.c_str(), recurse, alternative);
00633 return;
00634 }
00635
00636
00637 if (!CFile::isDirectory (path))
00638 {
00639 nlinfo ("CPath::addSearchPath(%s, %d, %d): '%s' is not a directory, I'll call addSearchFile()", path.c_str(), recurse, alternative, path.c_str());
00640 addSearchFile (path);
00641 return;
00642 }
00643
00644 string newPath = standardizePath(path);
00645
00646
00647 if (!CFile::isExists (newPath))
00648 {
00649 nlwarning ("CPath::addSearchPath(%s, %d, %d): '%s' is not found, skip it", path.c_str(), recurse, alternative, newPath.c_str());
00650 return;
00651 }
00652
00653 nlinfo ("CPath::addSearchPath(%s, %d, %d): adding the path '%s'", path.c_str(), recurse, alternative, newPath.c_str());
00654
00655 NL_DISPLAY_PATH("CPath::addSearchPath(%s, %d, %d): try to add '%s'", path.c_str(), recurse, alternative, newPath.c_str());
00656
00657 if (alternative)
00658 {
00659 vector<string> pathsToProcess;
00660
00661
00662 pathsToProcess.push_back (newPath);
00663
00664 if (recurse)
00665 {
00666
00667 getPathContent (newPath, recurse, true, false, pathsToProcess);
00668 }
00669
00670 for (uint p = 0; p < pathsToProcess.size(); p++)
00671 {
00672
00673 uint i;
00674 for (i = 0; i < inst->_AlternativePaths.size(); i++)
00675 {
00676 if (inst->_AlternativePaths[i] == pathsToProcess[p])
00677 break;
00678 }
00679 if (i == inst->_AlternativePaths.size())
00680 {
00681
00682 inst->_AlternativePaths.push_back (pathsToProcess[p]);
00683 NL_DISPLAY_PATH("CPath::addSearchPath(%s, %d, %d): path '%s' added", newPath.c_str(), recurse, alternative, pathsToProcess[p].c_str());
00684 }
00685 else
00686 {
00687 nlwarning ("CPath::addSearchPath(%s, %d, %d): path '%s' already added", newPath.c_str(), recurse, alternative, pathsToProcess[p].c_str());
00688 }
00689 }
00690 }
00691 else
00692 {
00693 vector<string> filesToProcess;
00694
00695 getPathContent (newPath, recurse, false, true, filesToProcess);
00696
00697
00698 for (uint f = 0; f < filesToProcess.size(); f++)
00699 {
00700 string filename = CFile::getFilename (filesToProcess[f]);
00701 string filepath = CFile::getPath (filesToProcess[f]);
00702
00703 addSearchFile (filesToProcess[f]);
00704 }
00705 }
00706 }
00707
00708 void CPath::addSearchFile (const string &file, bool remap, const string &virtual_ext)
00709 {
00710 CPath *inst = CPath::getInstance();
00711 string newFile = standardizePath(file, false);
00712
00713
00714 if (newFile.empty())
00715 {
00716 nlwarning ("CPath::addSearchFile(%s, %d, %s): can't add empty file, skip it", file.c_str(), remap, virtual_ext.c_str());
00717 return;
00718 }
00719
00720
00721 if (!CFile::isExists (newFile))
00722 {
00723 nlwarning ("CPath::addSearchFile(%s, %d, %s): '%s' is not found, skip it", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());
00724 return;
00725 }
00726
00727
00728 if (CFile::isDirectory (newFile))
00729 {
00730 nlwarning ("CPath::addSearchFile(%s, %d, %s): '%s' is not a file, skip it", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());
00731 return;
00732 }
00733
00734
00735 if (CFile::getExtension(newFile) == "bnp")
00736 {
00737 NL_DISPLAY_PATH ("CPath::addSearchFile(%s, %d, %s): '%s' is a big file, add it", file.c_str(), remap, virtual_ext.c_str(), newFile.c_str());
00738 addSearchBigFile(file, false, false);
00739 return;
00740 }
00741
00742 string filenamewoext = CFile::getFilenameWithoutExtension (newFile);
00743 string filename, ext;
00744
00745 if (virtual_ext.empty())
00746 {
00747 filename = CFile::getFilename (newFile);
00748 ext = CFile::getExtension (filename);
00749 }
00750 else
00751 {
00752 filename = filenamewoext + "." + virtual_ext;
00753 ext = virtual_ext;
00754 }
00755
00756 insertFileInMap (filename, newFile, remap, ext);
00757
00758 if (!remap && !ext.empty())
00759 {
00760
00761 for (uint i = 0; i < inst->_Extensions.size (); i++)
00762 {
00763 if (inst->_Extensions[i].first == strlwr(ext))
00764 {
00765
00766 addSearchFile (newFile, true, inst->_Extensions[i].second);
00767 }
00768 }
00769 }
00770 }
00771
00772 void CPath::addSearchListFile (const string &filename, bool recurse, bool alternative)
00773 {
00774
00775 if (filename.empty())
00776 {
00777 nlwarning ("CPath::addSearchListFile(%s, %d, %d): can't add empty file, skip it", filename.c_str(), recurse, alternative);
00778 return;
00779 }
00780
00781
00782 if (!CFile::isExists (filename))
00783 {
00784 nlwarning ("CPath::addSearchListFile(%s, %d, %d): '%s' is not found, skip it", filename.c_str(), recurse, alternative, filename.c_str());
00785 return;
00786 }
00787
00788
00789 if (CFile::isDirectory (filename))
00790 {
00791 nlwarning ("CPath::addSearchListFile(%s, %d, %d): '%s' is not a file, skip it", filename.c_str(), recurse, alternative, filename.c_str());
00792 return;
00793 }
00794
00795
00796
00797 }
00798
00799
00800 void CPath::addSearchBigFile (const string &sBigFilename, bool recurse, bool alternative)
00801 {
00802
00803 if (sBigFilename.empty())
00804 {
00805 nlwarning ("CPath::addSearchBigFile(%s, %d, %d): can't add empty file, skip it", sBigFilename.c_str(), recurse, alternative);
00806 return;
00807 }
00808
00809 if (!CFile::isExists (sBigFilename))
00810 {
00811 nlwarning ("CPath::addSearchBigFile(%s, %d, %d): '%s' is not found, skip it", sBigFilename.c_str(), recurse, alternative, sBigFilename.c_str());
00812 return;
00813 }
00814
00815 if (CFile::isDirectory (sBigFilename))
00816 {
00817 nlwarning ("CPath::addSearchBigFile(%s, %d, %d): '%s' is not a file, skip it", sBigFilename.c_str(), recurse, alternative, sBigFilename.c_str());
00818 return;
00819 }
00820
00821 CPath *inst = CPath::getInstance();
00822
00823 FILE *Handle = fopen (sBigFilename.c_str(), "rb");
00824 if (Handle == NULL)
00825 {
00826 nlwarning ("CPath::addSearchBigFile(%s, %d, %d): can't open file, skip it", sBigFilename.c_str(), recurse, alternative);
00827 return;
00828 }
00829
00830
00831 CBigFile::getInstance().add (sBigFilename, BF_ALWAYS_OPENED | BF_CACHE_FILE_ON_OPEN);
00832
00833
00834 fseek (Handle, 0, SEEK_END);
00835 uint32 nFileSize = ftell (Handle);
00836 fseek (Handle, nFileSize-4, SEEK_SET);
00837 uint32 nOffsetFromBegining;
00838 fread (&nOffsetFromBegining, sizeof(uint32), 1, Handle);
00839 fseek (Handle, nOffsetFromBegining, SEEK_SET);
00840 uint32 nNbFile;
00841 fread (&nNbFile, sizeof(uint32), 1, Handle);
00842 for (uint32 i = 0; i < nNbFile; ++i)
00843 {
00844 char FileName[256];
00845 uint8 nStringSize;
00846 fread (&nStringSize, 1, 1, Handle);
00847 fread (FileName, 1, nStringSize, Handle);
00848 FileName[nStringSize] = 0;
00849 uint32 nFileSize;
00850 fread (&nFileSize, sizeof(uint32), 1, Handle);
00851 uint32 nFilePos;
00852 fread (&nFilePos, sizeof(uint32), 1, Handle);
00853 string sTmp = strlwr(string(FileName));
00854 if (sTmp.empty())
00855 {
00856 nlwarning ("CPath::addSearchBigFile(%s, %d, %d): can't add empty file, skip it", sBigFilename.c_str(), recurse, alternative);
00857 continue;
00858 }
00859 string bigfilenamealone = CFile::getFilename (sBigFilename);
00860 string filenamewoext = CFile::getFilenameWithoutExtension (sTmp);
00861 string ext = strlwr(CFile::getExtension(sTmp));
00862
00863 insertFileInMap (sTmp, bigfilenamealone + "@" + sTmp, false, ext);
00864
00865 for (uint j = 0; j < inst->_Extensions.size (); j++)
00866 {
00867 if (inst->_Extensions[j].first == ext)
00868 {
00869
00870 insertFileInMap (filenamewoext+"."+inst->_Extensions[j].second,
00871 bigfilenamealone + "@" + sTmp,
00872 true,
00873 inst->_Extensions[j].second);
00874 }
00875 }
00876
00877 }
00878 fclose (Handle);
00879 }
00880
00881 void CPath::insertFileInMap (const string &filename, const string &filepath, bool remap, const string &extension)
00882 {
00883 CPath *inst = CPath::getInstance();
00884
00885
00886 map<string, CFileEntry>::iterator it = inst->_Files.find (strlwr(filename));
00887 if (it != inst->_Files.end ())
00888 {
00889 if ((*it).second.Path.find("@") != string::npos && filepath.find("@") == string::npos)
00890 {
00891
00892
00893 nlinfo ("CPath::insertFileInMap(%s, %s, %d, %s): already inserted from '%s' but special case so overide it", filename.c_str(), filepath.c_str(), remap, extension.c_str(), (*it).second.Path.c_str());
00894 (*it).second.Path = filepath;
00895 (*it).second.Remapped = remap;
00896 (*it).second.Extension = extension;
00897 }
00898 else
00899 {
00900 nlwarning ("CPath::insertFileInMap(%s, %s, %d, %s): already inserted from '%s', skip it", filename.c_str(), filepath.c_str(), remap, extension.c_str(), (*it).second.Path.c_str());
00901 }
00902 }
00903 else
00904 {
00905 inst->_Files.insert (make_pair (strlwr(filename), CFileEntry (filepath, remap, strlwr(extension))));
00906 NL_DISPLAY_PATH("CPath::insertFileInMap(%s, %s, %d, %s): added", strlwr(filename).c_str(), filepath.c_str(), remap, strlwr(extension).c_str());
00907 }
00908 }
00909
00910 void CPath::display ()
00911 {
00912 CPath *inst = CPath::getInstance ();
00913 nlinfo ("Contents of the map:");
00914 nlinfo ("%-25s %-5s %-5s %s", "filename", "ext", "remap", "full path");
00915 nlinfo ("----------------------------------------------------");
00916 for (map<string, CFileEntry>::iterator it = inst->_Files.begin(); it != inst->_Files.end (); it++)
00917 {
00918 nlinfo ("%-25s %-5s %-5d %s", (*it).first.c_str(), (*it).second.Extension.c_str(), (*it).second.Remapped, (*it).second.Path.c_str());
00919 }
00920 nlinfo ("");
00921 nlinfo ("Contents of the alternative directory:");
00922 for (uint i = 0; i < inst->_AlternativePaths.size(); i++)
00923 {
00924 nlinfo ("'%s'", inst->_AlternativePaths[i].c_str ());
00925 }
00926 nlinfo ("");
00927 nlinfo ("Contents of the remapped entension table:");
00928 for (uint j = 0; j < inst->_Extensions.size(); j++)
00929 {
00930 nlinfo ("'%s' -> '%s'", inst->_Extensions[j].first.c_str (), inst->_Extensions[j].second.c_str ());
00931 }
00932 nlinfo ("End of display");
00933 }
00934
00940
00941 int CFile::getLastSeparator (const string &filename)
00942 {
00943 uint32 pos = filename.find_last_of ('/');
00944 if (pos == string::npos)
00945 {
00946 pos = filename.find_last_of ('\\');
00947 if (pos == string::npos)
00948 {
00949 pos = filename.find_last_of ('@');
00950 }
00951 }
00952 return pos;
00953 }
00954
00955 string CFile::getFilename (const string &filename)
00956 {
00957 uint32 pos = CFile::getLastSeparator(filename);
00958 if (pos != string::npos)
00959 return filename.substr (pos + 1);
00960 else
00961 return filename;
00962 }
00963
00964 string CFile::getFilenameWithoutExtension (const string &filename)
00965 {
00966 string filename2 = getFilename (filename);
00967 uint32 pos = filename2.find_last_of ('.');
00968 if (pos == string::npos)
00969 return filename2;
00970 else
00971 return filename2.substr (0, pos);
00972 }
00973
00974 string CFile::getExtension (const string &filename)
00975 {
00976 uint32 pos = filename.find_last_of ('.');
00977 if (pos == string::npos)
00978 return "";
00979 else
00980 return filename.substr (pos + 1);
00981 }
00982
00983 string CFile::getPath (const string &filename)
00984 {
00985 uint32 pos = CFile::getLastSeparator(filename);
00986 if (pos != string::npos)
00987 return filename.substr (0, pos + 1);
00988 else
00989 return "";
00990 }
00991
00992 bool CFile::isDirectory (const string &filename)
00993 {
00994 #ifdef NL_OS_WINDOWS
00995 DWORD res = GetFileAttributes(filename.c_str());
00996 if (res == -1)
00997 {
00998 nlwarning ("%s is not a valid file / directory name", filename);
00999 return false;
01000 }
01001 return (res & FILE_ATTRIBUTE_DIRECTORY) != 0;
01002 #else // NL_OS_WINDOWS
01003 struct stat buf;
01004 int res = stat (filename.c_str (), &buf);
01005 if (res == -1)
01006 {
01007 nlwarning ("can't stat '%s' error %d '%s'", filename.c_str(), errno, strerror(errno));
01008 return false;
01009 }
01010 return (buf.st_mode & S_IFDIR) != 0;
01011 #endif // NL_OS_WINDOWS
01012 }
01013
01014 bool CFile::isExists (const string &filename)
01015 {
01016 #ifdef NL_OS_WINDOWS
01017 return (GetFileAttributes(filename.c_str()) != -1);
01018 #else // NL_OS_WINDOWS
01019 struct stat buf;
01020 return stat (filename.c_str (), &buf) == 0;
01021 #endif // NL_OS_WINDOWS
01022 }
01023
01024 bool CFile::fileExists (const string& filename)
01025 {
01026 return ! ! fstream( filename.c_str(), ios::in );
01027 }
01028
01029
01030 string CFile::findNewFile (const string &filename)
01031 {
01032 uint32 pos = filename.find_last_of ('.');
01033 if (pos == string::npos)
01034 return filename;
01035
01036 string start = filename.substr (0, pos);
01037 string end = filename.substr (pos);
01038
01039 uint num = 0;
01040 char numchar[4];
01041 string npath;
01042 do
01043 {
01044 npath = start;
01045 smprintf(numchar,4,"%03d",num++);
01046 npath += numchar;
01047 npath += end;
01048 if (!CFile::fileExists(npath)) break;
01049 }
01050 while (num<999);
01051 return npath;
01052 }
01053
01054
01055 uint32 CFile::getFileSize (const std::string &filename)
01056 {
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072 #if defined (NL_OS_WINDOWS)
01073 struct _stat buf;
01074 int result = _stat (filename.c_str (), &buf);
01075 #elif defined (NL_OS_UNIX)
01076 struct stat buf;
01077 int result = stat (filename.c_str (), &buf);
01078 #endif
01079 if (result != 0) return 0;
01080 else return buf.st_size;
01081
01082 }
01083
01084 uint32 CFile::getFileModificationDate(const std::string &filename)
01085 {
01086 uint pos;
01087 string fn;
01088 if ((pos=filename.find('@')) != string::npos)
01089 {
01090 fn = filename.substr (0, pos);
01091 }
01092 else
01093 {
01094 fn = filename;
01095 }
01096
01097 #if defined (NL_OS_WINDOWS)
01098 struct _stat buf;
01099 int result = _stat (fn.c_str (), &buf);
01100 #elif defined (NL_OS_UNIX)
01101 struct stat buf;
01102 int result = stat (fn.c_str (), &buf);
01103 #endif
01104
01105 if (result != 0) return 0;
01106 else return buf.st_mtime;
01107 }
01108
01109
01110 uint32 CFile::getFileCreationDate(const std::string &filename)
01111 {
01112 uint pos;
01113 string fn;
01114 if ((pos=filename.find('@')) != string::npos)
01115 {
01116 fn = filename.substr (0, pos);
01117 }
01118 else
01119 {
01120 fn = filename;
01121 }
01122
01123 #if defined (NL_OS_WINDOWS)
01124 struct _stat buf;
01125 int result = _stat (fn.c_str (), &buf);
01126 #elif defined (NL_OS_UNIX)
01127 struct stat buf;
01128 int result = stat (fn.c_str (), &buf);
01129 #endif
01130
01131 if (result != 0) return 0;
01132 else return buf.st_ctime;
01133 }
01134
01135 struct CFileEntry
01136 {
01137 CFileEntry (const string &filename, void (*callback)(const string &filename)) : FileName (filename), Callback (callback)
01138 {
01139 LastModified = CFile::getFileModificationDate(filename);
01140 }
01141 string FileName;
01142 void (*Callback)(const string &filename);
01143 uint32 LastModified;
01144 };
01145
01146 static vector <CFileEntry> FileToCheck;
01147
01148
01149 void CFile::addFileChangeCallback (const std::string &filename, void (*cb)(const string &filename))
01150 {
01151 nlinfo ("CFile::addFileChangeCallback: I'll check the modification date for this file '%s'", CPath::lookup(filename).c_str());
01152 FileToCheck.push_back(CFileEntry(CPath::lookup(filename), cb));
01153 }
01154
01155 void CFile::checkFileChange (TTime frequency)
01156 {
01157 static TTime lastChecked = CTime::getLocalTime();
01158
01159 if (CTime::getLocalTime() > lastChecked + frequency)
01160 {
01161 for (uint i = 0; i < FileToCheck.size(); i++)
01162 {
01163 if(CFile::getFileModificationDate(FileToCheck[i].FileName) != FileToCheck[i].LastModified)
01164 {
01165
01166 if(FileToCheck[i].Callback != NULL)
01167 FileToCheck[i].Callback(FileToCheck[i].FileName);
01168
01169 FileToCheck[i].LastModified = CFile::getFileModificationDate(FileToCheck[i].FileName);
01170 }
01171 }
01172
01173 lastChecked = CTime::getLocalTime();
01174 }
01175 }
01176
01177
01178 static bool CopyMoveFile(const char *dest, const char *src, bool copyFile, bool failIfExists = false)
01179 {
01180 if (!dest || !src) return false;
01181 if (!strlen(dest) || !strlen(src)) return false;
01182 #ifdef NL_OS_WINDOWS
01183 std::string dosdest = CPath::standardizeDosPath(dest);
01184 std::string dossrc = CPath::standardizeDosPath(src);
01185
01186 return copyFile ? CopyFile(dossrc.c_str(), dosdest.c_str(), failIfExists) != FALSE
01187 : MoveFile(dossrc.c_str(), dosdest.c_str()) != FALSE;
01188 #else
01189 nlstop;
01190 return false;
01191 #endif
01192 }
01193
01194 bool CFile::copyFile(const char *dest, const char *src, bool failIfExists )
01195 {
01196 return CopyMoveFile(dest, src, true, failIfExists);
01197 }
01198
01199 bool CFile::moveFile(const char *dest,const char *src)
01200 {
01201 return CopyMoveFile(dest, src, false);
01202 }
01203
01204
01205 bool CFile::createDirectory(const std::string &filename)
01206 {
01207 #ifdef NL_OS_WINDOWS
01208 return _mkdir(filename.c_str())==0;
01209 #else
01210
01211 return mkdir(filename.c_str(), 0xFFFF)==0;
01212 #endif
01213 }
01214
01215
01216 }