# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

path.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
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 // Macros
00058 //
00059 
00060 // Use this define if you want to display info about the CPath.
00061 //#define       NL_DEBUG_PATH
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 // Variables
00076 //
00077 
00078 CPath *CPath::_Instance = NULL;
00079 
00080 
00081 //
00082 // Functions
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                 // remove the mapping from the mapping list
00147                 sint n = inst->findExtension (ext1lwr, ext2lwr);
00148                 nlassert (n != -1);
00149                 inst->_Extensions.erase (inst->_Extensions.begin() + n);
00150 
00151                 // remove mapping in the map
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                 // adding mapping into the mapping list
00175                 inst->_Extensions.push_back (make_pair (ext1lwr, ext2lwr));
00176 
00177                 // adding mapping into the map
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                                 // find if already exist
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 // TODO perhaps a problem because I insert in the current map that i parcours
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         // Try to find in the current directory
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         // If the file already contains a @, it means that a lookup already proceed and returning a big file, do nothing
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         // Try to find in the map directories
00218         CPath *inst = CPath::getInstance();
00219         string str = strlwr (filename);
00220 
00221         // Remove end spaces
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         // If found in the map, returns it
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         // Try to find in the alternative directories
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                 // try with the remapping
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         // Not found
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         // Try to find in the map directories
00277         CPath *inst = CPath::getInstance();
00278         string str = strlwr (filename);
00279 
00280         // Remove end spaces
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         // If found in the map, returns it
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         // check empty path
00301         if (path.empty()) return "";
00302 
00303         // don't transform the first \\ for windows network path
00304 /*      if (path.size() >= 2 && path[0] == '\\' && path[1] == '\\')
00305         {
00306                 newPath += "\\\\";
00307                 i = 2;
00308         }
00309 */      
00310         for (uint i = 0; i < path.size(); i++)
00311         {
00312                 // don't transform the first \\ for windows network path
00313                 if (path[i] == '\\')
00314                         newPath += '/';
00315                 else
00316                         newPath += path[i];
00317         }
00318 
00319         // add terminal slash
00320         if (addFinalSlash && newPath[path.size()-1] != '/')
00321                 newPath += '/';
00322 
00323         return newPath;
00324 }
00325 
00326 // remplace / wiht \ and put all in lower case
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                 // Yoyo: supress toLower. Not usefull!?!
00336                 /*else if (isupper(path[i]))
00337                         newPath += tolower(path[i]);*/
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         // current path
00366         if (path.empty())
00367         {
00368                 return currentPath;
00369         }
00370 
00371         // windows full path
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         // from root
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         // default case
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                 // failed
00420                 sDirBackup[0] = 0;
00421                 return NULL;
00422         }
00423 
00424 
00425         if (!CFile::isDirectory(path))
00426         {
00427                 // failed
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         // set the current path
00450         nlassert (!sDir.empty());
00451         if (SetCurrentDirectory (sDir.c_str()) == 0)
00452         {
00453                 // failed
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         // restore the current path
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         //nlinfo ("isdirectory filename %s -> 0x%08x", de->d_name, de->d_type);
00491         // we can't use "de->d_type & DT_DIR" because it s always NULL on libc2.1
00492         //return (de->d_type & DT_DIR) != 0;
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         // we can't use "de->d_type & DT_DIR" because it s always NULL on libc2.1
00506         //return (de->d_type & DT_DIR) == 0;
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         // contains path that we have to recurs into
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                 // skip . and ..
00552                 if (fn == "." || fn == "..")
00553                         continue;
00554 
00555                 if (isdirectory(de))
00556                 {
00557                         // skip CVS directory
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 /*                      int lastSep = CFile::getLastSeparator(path);
00586                         #ifdef NL_OS_WINDOWS
00587                                 char sep = lastSep == std::string::npos ? '\\'
00588                                                                                                             : path[lastSep];
00589                         #else
00590                                 char sep = lastSep == std::string::npos ? '/'
00591                                                                                                                 : path[lastSep];
00592                         #endif
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         // let s recurse
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         // check empty directory
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         // check if it s a directory
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         // check if it s a directory
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                 // add the current path
00662                 pathsToProcess.push_back (newPath);
00663 
00664                 if (recurse)
00665                 {
00666                         // find all path and subpath
00667                         getPathContent (newPath, recurse, true, false, pathsToProcess);
00668                 }
00669 
00670                 for (uint p = 0; p < pathsToProcess.size(); p++)
00671                 {
00672                         // check if the path not already in the vector
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                                 // add them in the alternative directory
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                 // find all files in the path and subpaths
00695                 getPathContent (newPath, recurse, false, true, filesToProcess);
00696 
00697                 // add them in the map
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 //                      insertFileInMap (filename, filepath, false, CFile::getExtension(filename));
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         // check empty file
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         // check if the file exists
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         // check if it s a file
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         // check if it s a big file
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                 // now, we have to see extension and insert in the map the remapped files
00761                 for (uint i = 0; i < inst->_Extensions.size (); i++)
00762                 {
00763                         if (inst->_Extensions[i].first == strlwr(ext))
00764                         {
00765                                 // need to remap
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         // check empty file
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         // check if the file exists
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         // check if it s a file
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         // TODO lire le fichier et ajouter les fichiers qui sont dedans
00796 
00797 }
00798 
00799 // WARNING : recurse is not used
00800 void CPath::addSearchBigFile (const string &sBigFilename, bool recurse, bool alternative)
00801 {
00802         // Check if filename is not empty
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         // Check if the file exists
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         // Check if it s a file
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         // Open and read the big file header
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         // add the link with the CBigFile singleton
00831         CBigFile::getInstance().add (sBigFilename, BF_ALWAYS_OPENED | BF_CACHE_FILE_ON_OPEN);
00832 
00833         // parse the big file to add file in the map
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                                 // need to remap
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         // find if the file already exist
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                         // if there's a file in a big file and a file in a path, the file in path wins
00892                         // remplace with the new one
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 // \warning doesn't work with big file
01055 uint32  CFile::getFileSize (const std::string &filename)
01056 {
01057 /*      FILE *fp = fopen (filename.c_str(), "rb");
01058         if (fp == NULL) return 0;
01059         fseek (fp, 0, SEEK_END);
01060         uint32 size = ftell (fp);
01061         fclose (fp);
01062         return size;*/
01063 
01064 /*      const char *s = filename.c_str();
01065         int h = _open (s, _O_RDONLY | _O_BINARY);
01066         _lseek (h, 0, SEEK_END);
01067         uint32 size = _tell (h);
01068         _close (h);
01069         return size;
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                                 // need to reload it
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; // not implemented yet
01190         return false;
01191 #endif  
01192 }
01193 
01194 bool CFile::copyFile(const char *dest, const char *src, bool failIfExists /*=false*/)
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         // Set full permissions....
01211         return mkdir(filename.c_str(), 0xFFFF)==0;
01212 #endif
01213 }
01214 
01215 
01216 } // NLMISC