# 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  

big_file.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2000, 2002 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 #include "stdmisc.h"
00027 
00028 #include "nel/misc/big_file.h"
00029 #include "nel/misc/path.h"
00030 
00031 using namespace std;
00032 
00033 namespace NLMISC {
00034 
00035 CBigFile *CBigFile::_Singleton = NULL;
00036 
00037 
00038 // ***************************************************************************
00039 CBigFile::CThreadFileArray::CThreadFileArray()
00040 {
00041         _CurrentId= 0;
00042 }
00043 // ***************************************************************************
00044 uint32                                          CBigFile::CThreadFileArray::allocate()
00045 {
00046         return _CurrentId++;
00047 }
00048 // ***************************************************************************
00049 CBigFile::CHandleFile           &CBigFile::CThreadFileArray::get(uint32 index)
00050 {
00051         // If the thread struct ptr is NULL, must allocate it.
00052         vector<CHandleFile>             *ptr= (vector<CHandleFile>*)_TDS.getPointer();
00053         if(ptr==NULL)
00054         {
00055                 ptr= new vector<CHandleFile>;
00056                 _TDS.setPointer(ptr);
00057         }
00058 
00059         // if the vector is not allocated, allocate it (empty entries filled with NULL => not opened FILE* in this thread)
00060         if(index>=ptr->size())
00061         {
00062                 ptr->resize(index+1);
00063         }
00064 
00065         return (*ptr)[index];
00066 }
00067 
00068 
00069 // ***************************************************************************
00070 CBigFile::CBigFile ()
00071 {
00072 }
00073 
00074 // ***************************************************************************
00075 CBigFile &CBigFile::getInstance ()
00076 {
00077         if (_Singleton == NULL)
00078         {
00079                 _Singleton = new CBigFile();
00080         }
00081         return *_Singleton;
00082 }
00083 
00084 // ***************************************************************************
00085 bool CBigFile::add (const std::string &sBigFileName, uint32 nOptions)
00086 {
00087         BNP bnpTmp;
00088 
00089         bnpTmp.BigFileName= sBigFileName;
00090 
00091         // Is already the same bigfile name ?
00092         string bigfilenamealone = CFile::getFilename (sBigFileName);
00093         if (_BNPs.find(bigfilenamealone) != _BNPs.end())
00094                 return false;
00095 
00096         // Allocate a new ThreadSafe FileId for this bnp.
00097         bnpTmp.ThreadFileId= _ThreadFileArray.allocate();
00098 
00099         // Get a ThreadSafe handle on the file
00100         CHandleFile             &handle= _ThreadFileArray.get(bnpTmp.ThreadFileId);
00101         // Open the big file.
00102         handle.File = fopen (sBigFileName.c_str(), "rb");
00103         if (handle.File == NULL)
00104                 return false;
00105         fseek (handle.File, 0, SEEK_END);
00106         uint32 nFileSize = ftell (handle.File);
00107         fseek (handle.File, nFileSize-4, SEEK_SET);
00108         uint32 nOffsetFromBegining;
00109         fread (&nOffsetFromBegining, sizeof(uint32), 1, handle.File);
00110         fseek (handle.File, nOffsetFromBegining, SEEK_SET);
00111         uint32 nNbFile;
00112         fread (&nNbFile, sizeof(uint32), 1, handle.File);
00113         for (uint32 i = 0; i < nNbFile; ++i)
00114         {
00115                 char FileName[256];
00116                 uint8 nStringSize;
00117                 fread (&nStringSize, 1, 1, handle.File);
00118                 fread (FileName, 1, nStringSize, handle.File);
00119                 FileName[nStringSize] = 0;
00120                 uint32 nFileSize;
00121                 fread (&nFileSize, sizeof(uint32), 1, handle.File);
00122                 uint32 nFilePos;
00123                 fread (&nFilePos, sizeof(uint32), 1, handle.File);
00124                 BNPFile bnpfTmp;
00125                 bnpfTmp.Pos = nFilePos;
00126                 bnpfTmp.Size = nFileSize;
00127                 bnpTmp.Files.insert (make_pair(strlwr(string(FileName)), bnpfTmp));
00128         }
00129         fseek (handle.File, 0, SEEK_SET);
00130 
00131         if (nOptions&BF_CACHE_FILE_ON_OPEN)
00132                 bnpTmp.CacheFileOnOpen = true;
00133         else
00134                 bnpTmp.CacheFileOnOpen = false;
00135 
00136         if (!(nOptions&BF_ALWAYS_OPENED))
00137         {
00138                 fclose (handle.File);
00139                 handle.File = NULL;
00140                 bnpTmp.AlwaysOpened = false;
00141         }
00142         else
00143         {
00144                 bnpTmp.AlwaysOpened = true;
00145         }
00146 
00147         _BNPs.insert (make_pair(strlwr(bigfilenamealone), bnpTmp));
00148 
00149         return true;
00150 }
00151 
00152 // ***************************************************************************
00153 void CBigFile::remove (const std::string &sBigFileName)
00154 {
00155         if (_BNPs.find (sBigFileName) != _BNPs.end())
00156         {
00157                 map<string, BNP>::iterator it = _BNPs.find (sBigFileName);
00158                 BNP &rbnp = it->second;
00159                 /* \todo yoyo: THERE is a MAJOR drawback here: Only the FILE * of the current (surely main) thread
00160                         is closed. other FILE* in other threads are still opened. This is not a big issue (system close the FILE* 
00161                         at the end of the process) and this is important so AsyncLoading of a currentTask can end up correclty 
00162                         (without an intermediate fclose()).
00163                 */
00164                 // Get a ThreadSafe handle on the file
00165                 CHandleFile             &handle= _ThreadFileArray.get(rbnp.ThreadFileId);
00166                 // close it if needed
00167                 if (handle.File != NULL)
00168                 {
00169                         fclose (handle.File);
00170                         handle.File= NULL;
00171                 }
00172                 _BNPs.erase (it);
00173         }
00174 }
00175 
00176 // ***************************************************************************
00177 bool CBigFile::isBigFileAdded(const std::string &sBigFileName)
00178 {
00179         // Is already the same bigfile name ?
00180         string bigfilenamealone = CFile::getFilename (sBigFileName);
00181         return _BNPs.find(bigfilenamealone) != _BNPs.end();
00182 }
00183 
00184 // ***************************************************************************
00185 void CBigFile::list (const std::string &sBigFileName, std::vector<std::string> &vAllFiles)
00186 {
00187         string lwrFileName = strlwr (sBigFileName);
00188         if (_BNPs.find (lwrFileName) == _BNPs.end())
00189                 return;
00190         vAllFiles.clear ();
00191         BNP &rbnp = _BNPs.find (lwrFileName)->second;
00192         map<string,BNPFile>::iterator it = rbnp.Files.begin();
00193         while (it != rbnp.Files.end())
00194         {
00195                 vAllFiles.push_back (it->first); // Add the name of the file to the return vector
00196                 ++it;
00197         }
00198 }
00199 
00200 // ***************************************************************************
00201 void CBigFile::removeAll ()
00202 {
00203         while (_BNPs.begin() != _BNPs.end())
00204         {
00205                 remove (_BNPs.begin()->first);
00206         }
00207 }
00208 
00209 // ***************************************************************************
00210 FILE* CBigFile::getFile (const std::string &sFileName, uint32 &rFileSize, 
00211                                                  uint32 &rBigFileOffset, bool &rCacheFileOnOpen, bool &rAlwaysOpened)
00212 {
00213         string zeFileName, zeBigFileName, lwrFileName = strlwr (sFileName);
00214         uint32 i, nPos = sFileName.find ('@');
00215         if (nPos == string::npos)
00216         {
00217                 nlwarning ("Couldn't load '%s'", sFileName.c_str());
00218                 return NULL;
00219         }
00220 
00221         for (i = 0; i < nPos; ++i)
00222                 zeBigFileName += lwrFileName[i];
00223         ++i; // Skip @
00224         for (; i < lwrFileName.size(); ++i)
00225                 zeFileName += lwrFileName[i];
00226 
00227         if (_BNPs.find (zeBigFileName) == _BNPs.end())
00228         {
00229                 nlwarning ("Couldn't load '%s'", sFileName.c_str());
00230                 return NULL;
00231         }
00232 
00233         BNP &rbnp = _BNPs.find (zeBigFileName)->second;
00234         if (rbnp.Files.find (zeFileName) == rbnp.Files.end())
00235         {
00236                 nlwarning ("Couldn't load '%s'", sFileName.c_str());
00237                 return NULL;
00238         }
00239 
00240         BNPFile &rbnpfile = rbnp.Files.find (zeFileName)->second;
00241 
00242         // Get a ThreadSafe handle on the file
00243         CHandleFile             &handle= _ThreadFileArray.get(rbnp.ThreadFileId);
00244         /* If not opened, open it now. There is 2 reason for it to be not opened: 
00245                 rbnp.AlwaysOpened==false, or it is a new thread which use it for the first time.
00246         */
00247         if(handle.File== NULL)
00248         {
00249                 handle.File = fopen (rbnp.BigFileName.c_str(), "rb");
00250                 if (handle.File == NULL)
00251                         return NULL;
00252         }
00253 
00254         rCacheFileOnOpen = rbnp.CacheFileOnOpen;
00255         rAlwaysOpened = rbnp.AlwaysOpened;
00256         rBigFileOffset = rbnpfile.Pos;
00257         rFileSize = rbnpfile.Size;
00258         return handle.File;
00259 }
00260 
00261 } // namespace NLMISC