MercuryFiles.cpp

Go to the documentation of this file.
00001 #include "MercuryFiles.h"
00002 #include "MercuryTheme.h"
00003 
00004 #include "ezSockets.h"
00005 
00006 //For the store compression on zips
00007 #include <zlib.h>
00008 
00009 #if !defined(WIN32)
00010 #include <dirent.h>
00011 
00012 #include <sys/types.h>
00013 #include <sys/stat.h>
00014 #include <unistd.h>
00015 #endif
00016 
00017 #if defined(_EE)
00018 #define FSHEADER "host:"
00019 #else
00020 #define FSHEADER ""
00021 #endif
00022 
00023 MercuryFileManager FILEMAN;
00024 
00025 const MString PackagePrefix = "Packages/";
00026 const MString MemoryFileName = "memory.zip";
00027 
00028 
00029 /********************FILE DRIVER NET**********************/
00030 
00031 MercuryFileObjectNet::~MercuryFileObjectNet()
00032 {
00033     if( m_Buffer )
00034         delete m_Buffer;
00035     if( m_pSocket )
00036         delete ((ezSockets*)m_pSocket);
00037 }
00038 
00039 bool MercuryFileObjectNet::Init( const MString & fName, FilePermission p )
00040 {
00041     MercuryFile::Init(fName, p);
00042 
00043     ezSockets * s = new ezSockets;
00044 
00045     //EXPECT "http://" then "[host]" then "[document]"
00046     int iDist = BytesUntil( fName.c_str(), "/", 8, fName.length(), 2 );
00047     MString sHost = fName.substr( 7, iDist + 1 );
00048     MString sDocument = fName.substr( iDist + 8 );
00049 
00050     s->bBlocking = true;
00051     s->mode = ezSockets::skGeneral;
00052     s->Create( );
00053     if( !s->Connect( sHost, 80 ) )
00054     {
00055         SAFE_DELETE( s );
00056         return false;
00057     }
00058     MString sRequest = "GET " + sDocument + " HTTP/1.1\r\n";
00059     sRequest += "User-Agent: Mercury Game Engine (http://sf.net/projects/hgengine)\r\n";
00060     sRequest += "Host:" + sHost + "\r\n\r\n";
00061     s->SendData( sRequest.c_str(), sRequest.length() );
00062     MString str;
00063 
00064     bool bNotBreak = true;
00065     while( bNotBreak )
00066     {
00067         if( !s->ReadLine( str ) )
00068             return false;
00069         if( str.substr( 0, 14 ) == "Content-Length" )
00070             m_size = atoi( str.substr( 15 ).c_str() );
00071         else if( str.length() == 0 )
00072             bNotBreak = false;
00073     }
00074 
00075     if( m_size == 0 )
00076         return false;
00077 
00078     m_Buffer = (char*)malloc( m_size );
00079     if( !s->ReadData( m_Buffer, m_size ) )
00080     {
00081         SAFE_FREE( m_Buffer );
00082         return false;
00083     }
00084 
00085     m_location = 0;
00086     s->Close();
00087     m_pSocket = s;
00088 
00089     return true;
00090 }
00091 
00092 bool MercuryFileObjectNet::Seek( unsigned long position ) 
00093 {
00094     if ( position < m_size ) 
00095     { 
00096         m_location = position;
00097         return true;
00098     } 
00099     else 
00100         return false;
00101 }
00102 
00103 void MercuryFileObjectNet::Close()
00104 {
00105 }
00106 
00107 unsigned long MercuryFileObjectNet::Tell()
00108 {
00109     return m_location;
00110 }
00111 
00112 unsigned long MercuryFileObjectNet::Length()
00113 {
00114     return m_size;
00115 }
00116 
00117 unsigned long MercuryFileObjectNet::Read( void * data, unsigned long length )
00118 {
00119     unsigned int iRead;
00120     if( length >= m_size - m_location )
00121         iRead = m_size - m_location - 1;
00122     else
00123         iRead = length;
00124     memcpy( data, m_Buffer + m_location, length );
00125     m_location += iRead;
00126     return iRead;
00127 }
00128 
00129 bool MercuryFileObjectNet::Check()
00130 {
00131     return m_size > 0;
00132 }
00133 
00134 bool MercuryFileObjectNet::Eof()
00135 {
00136     return m_location < m_size;
00137 }
00138 
00139 
00140 
00141 MercuryFile * MercuryFileDriverNet::GetFileHandle( const MString & sPath, FilePermission p  )
00142 {
00143     if( sPath.substr( 0, 7 ) == "http://" )
00144     {
00145         MercuryFileObjectNet * fNew = new MercuryFileObjectNet;
00146         if( fNew->Init( sPath, p ) )
00147             return fNew;
00148         else
00149             return 0;
00150     }
00151     return 0;
00152 }
00153 
00154 void MercuryFileDriverNet::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
00155 {
00156     //Do nothing, since we can't inquire as to folders on the internet.
00157 }
00158 
00159 
00160 /********************FILE DRIVER DIRECT*******************/
00161 //Core base only.
00162 MercuryFile::MercuryFile()
00163 {
00164     //No code
00165 }
00166 
00167 MercuryFile::~MercuryFile()
00168 {
00169     //No code
00170 }
00171 
00172 bool MercuryFile::Init( const MString &sPath, FilePermission p )
00173 {
00174     m_sPath = sPath;
00175     m_p = p;
00176     return true;
00177 }
00178 
00179 bool MercuryFile::ReadLine( MString & data )
00180 {
00181     data = "";
00182     char b1[1];
00183     bool Success;
00184     while ( Success = ( Read( b1, 1 ) > 0 ) )
00185     {
00186         if ( ( b1[0] == '\r' ) || ( b1[0] == '\n' ) )
00187             break;
00188         data += b1[0];
00189     }
00190 
00191     //We're using windows, check to make sure we don't have an extra \n.
00192     if ( b1[0] == '\r' )
00193     {
00194         unsigned long loc = Tell();
00195         Read( b1, 1 );
00196         if ( b1[0] != '\n' )
00197             Seek(loc);
00198     }
00199 
00200     return Success;
00201 }
00202 
00203 MercuryFileObjectDirect::MercuryFileObjectDirect( ):
00204     MercuryFile( )
00205 {
00206     m_fF = NULL;
00207 }
00208 
00209 MercuryFileObjectDirect::~MercuryFileObjectDirect()
00210 {
00211     if ( m_fF != NULL )
00212     {
00213         fclose ( m_fF );
00214         m_fF = NULL;
00215     }
00216 }
00217 
00218 void MercuryFileObjectDirect::Close()
00219 {
00220     if ( m_fF != NULL )
00221     {
00222         fclose ( m_fF );
00223         m_fF = NULL;
00224     }
00225     delete this;
00226 }
00227 
00228 bool MercuryFileObjectDirect::Init( const MString & fName, FilePermission p )
00229 {
00230     MercuryFile::Init( fName, p );
00231     if ( m_fF != NULL )
00232         SAFE_DELETE( m_fF );
00233 
00234     switch ( p )
00235     {
00236     case MFP_READ_ONLY:
00237         m_fF = fopen( (FSHEADER+fName).c_str(), "rb" );
00238         break;
00239     case MFP_WRITE_ONLY:
00240         m_fF = fopen( (FSHEADER+fName).c_str(), "wb" );
00241         break;
00242     case MFP_READ_AND_WRITE:
00243         m_fF = fopen( (FSHEADER+fName).c_str(), "wb+" );
00244         break;
00245     case MFP_APPEND:
00246         m_fF = fopen( (FSHEADER+fName).c_str(), "a" );
00247         break;
00248     default:
00249         m_fF = NULL;
00250         break;
00251     }
00252 
00253     return ( m_fF != NULL );
00254 }
00255 
00256 bool MercuryFileObjectDirect::Seek( unsigned long position )
00257 {
00258     if ( m_fF == NULL )
00259         return false;
00260     return ( fseek( m_fF, position, SEEK_SET ) == 0 );
00261 }
00262 
00263 unsigned long MercuryFileObjectDirect::Tell()
00264 {
00265     if ( m_fF == NULL )
00266         return false;
00267     return ftell( m_fF );
00268 }
00269 
00270 unsigned long MercuryFileObjectDirect::Length()
00271 {
00272     if ( m_fF == NULL )
00273       return false;
00274     unsigned long prev = ftell( m_fF );
00275     fseek( m_fF, 0, SEEK_END );
00276     unsigned long ret = ftell( m_fF );
00277     fseek( m_fF, prev, SEEK_SET );
00278     return ret;
00279 }
00280 
00281 bool MercuryFileObjectDirect::Write( void * data, unsigned long length )
00282 {
00283     if ( m_fF == NULL )
00284         return false;
00285     return ( fwrite( data, length, 1, m_fF ) > 0 );
00286 }
00287 
00288 unsigned long MercuryFileObjectDirect::Read( void * data, unsigned long length )
00289 {
00290     if ( m_fF == NULL )
00291         return false;
00292     return ( fread( data, 1, length, m_fF) );
00293 }
00294 
00295 bool MercuryFileObjectDirect::Check()
00296 {
00297     if ( m_fF == NULL )
00298         return true;
00299     return (ferror( m_fF )!=0);
00300 }
00301 
00302 bool MercuryFileObjectDirect::Eof()
00303 {
00304     if ( m_fF == NULL )
00305         return false;
00306     return (feof( m_fF )!=0);
00307 }
00308 
00309 unsigned long MercuryFileObjectDirect::GetModTime()
00310 {
00311     if( !m_fF )
00312         return 0;
00313 #if defined(WIN32)
00314     HANDLE hFile = CreateFile( m_sPath.c_str(), GENERIC_READ, FILE_SHARE_READ, 
00315         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL );
00316     if( !hFile )
00317         return 0;
00318     FILETIME Tcreate,Taccess,Twrite;
00319     if( !GetFileTime( hFile, &Tcreate, &Taccess, &Twrite ) )
00320     {
00321         CloseHandle( hFile );
00322         return 0;
00323     }
00324     else
00325     {
00326         CloseHandle( hFile );
00327         //Windows does time based on 100ns  intervals from Jan 1 1601 AD.  So, we have t
00328         return (Twrite.dwHighDateTime - 27636147) * 400 + (Twrite.dwLowDateTime/10000000);
00329     }
00330 #else
00331     //Pot shot... does this even compile in linux?
00332     struct stat sb;
00333     if ( stat( m_sPath.c_str(), &sb ) )
00334         return 0;
00335     else
00336         return sb.st_mtime;
00337 #endif
00338 }
00339 
00340 MercuryFile * MercuryFileDirverDirect::GetFileHandle( const MString & sPath, FilePermission p )
00341 {
00342     MercuryFile * ret = new MercuryFileObjectDirect;
00343     if ( ret->Init( sPath, p ) )
00344         return ret;
00345 
00346     SAFE_DELETE(ret);
00347 
00348     return NULL;
00349 }
00350 
00351 #if defined(WIN32)
00352 #include <windows.h>
00353 #endif
00354 
00355 void MercuryFileDirverDirect::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
00356 {
00357 #if defined(WIN32)
00358     WIN32_FIND_DATA fd;
00359     HANDLE hFind = ::FindFirstFile( sPath, &fd );
00360     if( INVALID_HANDLE_VALUE == hFind )     // no files found
00361         return;
00362     do
00363     {
00364         if( bDirsOnly  &&  !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
00365             continue;   // skip
00366 
00367         if( (!bDirsOnly)  &&  (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
00368             continue;   // skip
00369 
00370         MString sDirName( fd.cFileName );
00371 
00372         if( sDirName == "."  ||  sDirName == ".." )
00373             continue;
00374 
00375         output.push_back( sDirName );
00376     } while( ::FindNextFile( hFind, &fd ) );
00377     ::FindClose( hFind );
00378 #elif !defined(_EE)
00379     DIR * pDe = opendir( "./" + sPath );
00380     if ( pDe == NULL )
00381         return;
00382 
00383     dirent * pEnt;
00384 
00385     while ( (pEnt = readdir( pDe )) )
00386     {
00387         if ( ( pEnt->d_type & DT_DIR ) && !bDirsOnly )
00388             continue;
00389         if ( !( pEnt->d_type & DT_DIR ) && bDirsOnly )
00390             continue;
00391 
00392         if ( strcmp( pEnt->d_name, "." ) == 0 )
00393             continue;
00394 
00395         if ( strcmp( pEnt->d_name, ".." ) == 0 )
00396             continue;
00397 
00398         output.push_back( pEnt->d_name );
00399     }
00400 
00401     closedir( pDe );
00402 #endif
00403 }
00404 
00405 /********************FILE DRIVER PACKAGE*******************/
00406 
00407 MercuryFileObjectPacked::~MercuryFileObjectPacked()
00408 {
00409     Close();
00410 }
00411 
00412 bool MercuryFileObjectPacked::Init( const MString & fName, 
00413     FilePermission p, const MString & base, unsigned offset, 
00414     unsigned size )
00415 {
00416     MercuryFile::Init(fName, p);
00417 
00418     if ( p == MFP_APPEND )
00419         return false;           //Not supported.
00420 
00421 //  m_sPath = fName;
00422 //  m_p = p;
00423     m_base = FILEMAN.Open( base, p );
00424     if ( m_base->Check() )
00425         return false;
00426     m_offset = offset;
00427     m_size = size;
00428     m_location = 0;
00429 
00430     return m_base->Seek( m_offset );
00431 }
00432 
00433 bool MercuryFileObjectPacked::Seek( unsigned long position )
00434 {
00435     if ( position >= m_size )
00436         return false;
00437     m_location = position;
00438     return m_base->Seek( m_location + m_offset );
00439 }
00440 
00441 unsigned long MercuryFileObjectPacked::Tell()
00442 {
00443     return m_location;
00444 }
00445 
00446 unsigned long MercuryFileObjectPacked::Length()
00447 {
00448     return m_size;
00449 }
00450 
00451 bool MercuryFileObjectPacked::Write( void * data, unsigned long length )
00452 {
00453     //First make sure we won't over-write good data.
00454     if ( length >= ( m_size - m_location ) )
00455         return false;
00456 
00457     bool ret = m_base->Write( data, length );
00458     if ( ret )
00459         m_location += length;
00460     return ret;
00461 }
00462 
00463 unsigned long MercuryFileObjectPacked::Read( void * data, unsigned long length )
00464 {
00465     int readable = m_size - m_location;
00466     if ( (unsigned)readable < length )
00467     {
00468         int ret = m_base->Read( data, readable );
00469         m_location += ret;
00470         return ret;
00471     }
00472     else 
00473     {
00474         int ret = m_base->Read( data, length );
00475         m_location += ret;
00476         return ret;
00477     }
00478 }
00479 
00480 bool MercuryFileObjectPacked::Check()
00481 {
00482     return ( m_base != 0 );
00483 }
00484 
00485 bool MercuryFileObjectPacked::Eof()
00486 {
00487     return m_location >= m_size;
00488 }
00489 
00490 void MercuryFileObjectPacked::Close()
00491 {
00492     SAFE_DELETE( m_base );
00493 }
00494 
00495 inline unsigned long ToLong(char * inx)
00496 {
00497     unsigned char *in = (unsigned char*)inx;
00498     return in[0] + long(in[1])*256 + long(in[2])*65536 + long(in[3])*16777216;
00499 }
00500 
00501 void MercuryFileDriverPacked::Init()
00502 {
00503     MVector< MString > out;
00504     MercuryFileDriver::Init();
00505 
00506     FILEMAN.ListDirectory( PackagePrefix+"*.*", out, false );
00507 
00508     for ( unsigned i = 0; i < out.size(); i++ )
00509     {
00510         MercuryFile * z = FILEMAN.Open( PackagePrefix+out[i] );
00511         
00512         if ( !z )
00513             continue;
00514 
00515         unsigned long NumberOfFiles = 0;
00516         char tmp[256];
00517 
00518         if ( !z->Eof() && !z->Check() )
00519         {
00520             z->Read( tmp, 4 );
00521             if ( strncmp( tmp, "HGPK", 4 ) != 0 )
00522                 continue;
00523             z->Read( tmp, 128 );
00524             z->Read( tmp, 4 );
00525             NumberOfFiles = ToLong( tmp );
00526         }
00527 
00528         for ( unsigned j = 0; j < NumberOfFiles; j++ )
00529         {
00530             MString basename;
00531             MString path;
00532             MString name;
00533             unsigned long filesize;
00534             unsigned long namelen;
00535             unsigned long offset;
00536             if ( z->Eof() || z->Check() )
00537                 break;
00538             z->Read( tmp, 4 );
00539             filesize = ToLong( tmp );
00540             z->Read( tmp, 4 );
00541             offset = ToLong( tmp );
00542             z->Read( tmp, 4 );
00543             namelen = ToLong( tmp );
00544             z->Read( tmp, namelen );
00545             tmp[namelen] = '\0';
00546             name = tmp;
00547             //First, strip out folders.
00548             MString LastFolder;
00549             MString CurrentElement;
00550             for ( int k = 0; (unsigned)k < namelen; k++ )
00551             {
00552                 if( tmp[k] == '/' )
00553                 {
00554                     PckFileEntry y;
00555                     y.m_bFolder = true;
00556                     //Other values don't apply.
00557                     m_mFileFolders[LastFolder][CurrentElement] = y;
00558                     LastFolder += CurrentElement + "/";
00559                     CurrentElement = "";
00560                 }
00561                 else
00562                     CurrentElement+=tmp[k];
00563             }
00564             PckFileEntry y;
00565             y.m_bFolder = false;
00566             y.m_sPackageName = PackagePrefix+out[i];
00567             y.m_iOffset = offset;
00568             y.m_iSize = filesize;
00569             m_mFileFolders[LastFolder][CurrentElement] = y;
00570         }
00571 
00572         z->Close();
00573         SAFE_DELETE( z );
00574     }
00575 }
00576 
00577 MercuryFile * MercuryFileDriverPacked::GetFileHandle( const MString & sPath, FilePermission p )
00578 {
00579     if ( sPath.length() == 0 )
00580         return NULL;
00581 
00582     //First break up 
00583     const char * sp = sPath.c_str();
00584     unsigned int i;
00585     for ( i = sPath.length()-1; i > 0; i-- )
00586         if ( sp[i] == '/' )
00587             break;
00588 
00589     MString ActualName;
00590     if (i >0)
00591         ActualName = sPath.substr(i+1);
00592     else
00593         ActualName = sPath;
00594 
00595     MString Path;
00596     if (i>0)
00597       Path = sPath.substr(0,i+1);
00598     else
00599       Path = "";
00600 
00601     if ( m_mFileFolders.find( Path ) == m_mFileFolders.end() )
00602         return NULL;
00603 
00604     if ( m_mFileFolders[Path].find( ActualName ) == m_mFileFolders[Path].end() )
00605         return NULL;
00606 
00607     PckFileEntry z = m_mFileFolders[Path][ActualName];
00608 
00609     if ( z.m_bFolder )
00610         return NULL;
00611 
00612     MercuryFileObjectPacked * ret = new MercuryFileObjectPacked();
00613 
00614     bool success = ret->Init( ActualName, p, z.m_sPackageName, z.m_iOffset, z.m_iSize );
00615     if ( !success )
00616     {
00617         SAFE_DELETE( ret );
00618         return NULL;
00619     }
00620     return ret;
00621 }
00622 
00623 bool FileMatch( const MString & file, const MString & regex )
00624 {
00625     const char * rx = regex.c_str();
00626     unsigned j = 0;
00627     const char * fe = file.c_str();
00628     unsigned i;
00629     for ( i = 0; i < regex.length() && j < file.length(); i++ )
00630     {
00631         switch ( rx[i] )
00632         {
00633         case '*':
00634             {
00635                 i++;
00636                 if ( i == regex.length() )
00637                     return true;
00638 
00639                 while ( ( j < file.length() ) && 
00640                     ( fe[j] != rx[i] ) )
00641                     j++;
00642 
00643                 j++;
00644                 if ( j == file.length() )
00645                     return false;
00646             }
00647             break;
00648         case '?':
00649             j++;
00650             break;
00651         default:
00652 
00653             if ( fe[j] != rx[i] )
00654                 return false;
00655             j++;
00656             break;
00657         }
00658     }
00659     if ( ( j >= file.length() ) && !( i >= regex.length() ) )
00660         return false;
00661     return true;
00662 }
00663 
00664 void MercuryFileDriverPacked::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
00665 {
00666     const char * sp = sPath.c_str();
00667     unsigned i;
00668     for (i = sPath.length()-1; i > 0; i-- )
00669         if ( sp[i] == '/' )
00670             break;
00671 
00672     MString ActualName;
00673     if (i>0)
00674         ActualName = sPath.substr( i+1 );
00675     else
00676         ActualName = sPath;
00677 
00678     MString Path;
00679     if(i>0)
00680         Path = sPath.substr( 0, i+1 );
00681 
00682     if ( m_mFileFolders.find( Path ) == m_mFileFolders.end() )
00683         return;
00684 
00685     std::map< MString, PckFileEntry > * cDir = &m_mFileFolders[Path];
00686 
00687     std::map< MString, PckFileEntry >::iterator iter, end;
00688     end = cDir->end();
00689     for ( iter = cDir->begin(); iter != end; iter++ )
00690     {
00691         MString fName = iter->first;
00692         PckFileEntry z = iter->second;
00693         if ( bDirsOnly && !z.m_bFolder )
00694             continue;
00695         if ( !bDirsOnly && z.m_bFolder )
00696             continue;
00697 
00698         if ( FileMatch( fName, ActualName ) )
00699             output.push_back( fName );
00700     }
00701 }
00702 
00703 /********************FILE DRIVER MEMORY********************/
00704 
00705 #if defined ( USE_MEMFILE )
00706 extern unsigned char MemFileData[];
00707 #endif
00708 
00709 void MercuryFileDriverMem::Init()
00710 {
00711     MercuryFileDriver::Init();
00712 #if defined ( USE_MEMFILE )
00713     m_iFileSize = MemFileData[0] + MemFileData[1] * 0x100 + MemFileData[2] * 0x10000 + MemFileData[3] * 0x1000000;
00714 #endif
00715 }
00716 
00717 MercuryFile * MercuryFileDriverMem::GetFileHandle( const MString & sPath, enum FilePermission p )
00718 {
00719 #if defined ( USE_MEMFILE )
00720     if ( sPath == MemoryFileName && p == MFP_READ_ONLY )
00721     {
00722         MercuryFileObjectZipped * ret = new MercuryFileObjectZipped;
00723         ret->MemFileInit( MemoryFileName, (const char *)(&MemFileData[0]) + 4, m_iFileSize );
00724         return ret;
00725     }
00726     else
00727 #endif
00728         return NULL;
00729 }
00730 
00731 void MercuryFileDriverMem::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
00732 {
00733 #if defined ( USE_MEMFILE )
00734     if ( !bDirsOnly && sPath == "*.*" || sPath == "*.zip" || sPath == MemoryFileName )
00735         output.push_back( MemoryFileName );
00736 #endif
00737 }
00738 
00739 /********************FILE DRIVER ZIPPED*******************/
00740 
00741 MercuryFileObjectZipped::~MercuryFileObjectZipped()
00742 {
00743     Close();
00744 }
00745 
00746 bool MercuryFileObjectZipped::Init( const MString & fName, 
00747     FilePermission p, const MString & base, unsigned offset, 
00748     unsigned size, unsigned packedsize, unsigned decompID )
00749 {
00750     if ( p == MFP_APPEND )
00751         return false;           //Not supported.
00752 
00753     //NOTE: While we don't actually support a file opened for writing,
00754     //      we shouldn't fail if write permissions are requested.
00755 
00756     m_sPath = fName;
00757     m_p = p;
00758     MercuryFile * m_base = FILEMAN.Open( base, p );
00759 
00760     //Seek to the beginning of the actual data
00761     m_base->Seek( offset );
00762 
00763     char * inbuff = (char*)malloc( packedsize + 258 );
00764     m_Buffer = (char*)malloc( size );
00765 
00766     m_base->Read( inbuff + 2, packedsize + 2 );
00767     m_base->Close();
00768 
00769     z_stream_s stream;
00770     memset( &stream, 0, sizeof(stream) );
00771     stream.avail_out = size;
00772     stream.total_out = 0;
00773     stream.next_out = (unsigned char*)m_Buffer;
00774     stream.total_in = packedsize+2;
00775     stream.avail_in = packedsize+2;
00776     stream.next_in = (unsigned char*)inbuff;
00777 
00778     //Compression type 8 (Always) (These really are magic numbers here)
00779     inbuff[0] = 0x78;
00780     inbuff[1] = 0x01;
00781 
00782     int err = inflateInit(&stream);
00783 
00784     if ( err )
00785     {
00786         inflateEnd(&stream);
00787         free( inbuff );
00788         free( m_Buffer );
00789         m_Buffer = 0;
00790         return false;
00791     }
00792 
00793     err = inflate( &stream, Z_NO_FLUSH );
00794 
00795     if ( err < 0 )
00796     {
00797         inflateEnd(&stream);
00798         free( inbuff );
00799         free( m_Buffer );
00800         m_Buffer = 0;
00801         return false;
00802     }
00803     
00804     inflateEnd(&stream);
00805 
00806     free( inbuff );
00807 
00808     m_size = size;
00809     m_location = 0;
00810     m_bIsDummy = false;
00811 
00812     return true;
00813 }
00814 
00815 bool MercuryFileObjectZipped::MemFileInit( const MString & sName, const char * pData, unsigned long iSize )
00816 {
00817     m_bIsDummy = true;
00818     //Yuck, but we're read only anyways! :)
00819     m_Buffer = (char*)pData;
00820     m_size = iSize;
00821     m_sPath = sName;
00822     m_location = 0;
00823     m_p = MFP_READ_ONLY;
00824     return true;
00825 }
00826 
00827 bool MercuryFileObjectZipped::Seek( unsigned long position )
00828 {
00829     if ( position >= m_size )
00830         return false;
00831     m_location = position;
00832     return true;
00833 }
00834 
00835 unsigned long MercuryFileObjectZipped::Tell()
00836 {
00837     return m_location;
00838 }
00839 
00840 unsigned long MercuryFileObjectZipped::Length()
00841 {
00842     return m_size;
00843 }
00844 
00845 bool MercuryFileObjectZipped::Write( void * data, unsigned long length )
00846 {
00847     //You cannot write to a zipped file in the store form.
00848     return false;
00849 }
00850 
00851 unsigned long MercuryFileObjectZipped::Read( void * data, unsigned long length )
00852 {
00853     int readable = m_size - m_location;
00854     int ret;
00855     if ( (unsigned)readable < length )
00856         ret = readable;
00857     else 
00858         ret = length;
00859     memcpy( data, m_Buffer + m_location, ret );
00860     m_location += ret;
00861     return ret;
00862 }
00863 
00864 bool MercuryFileObjectZipped::Check()
00865 {
00866     if ( m_Buffer )
00867         return 0;
00868     else
00869         return 1;
00870 }
00871 
00872 bool MercuryFileObjectZipped::Eof()
00873 {
00874     return m_location >= m_size;
00875 }
00876 
00877 void MercuryFileObjectZipped::Close()
00878 {
00879     if ( !m_bIsDummy )
00880         SAFE_DELETE( m_Buffer );
00881 }
00882 
00883 inline unsigned long ZIPToLong(char * inx)
00884 {
00885     unsigned char *in = (unsigned char*)inx;
00886     return in[0] + long(in[1])*256 + long(in[2])*65536 + long(in[3])*16777216;
00887 }
00888 
00889 void MercuryFileDriverZipped::Init()
00890 {
00891     unsigned i;
00892     MVector< MString > out;
00893 
00894     MercuryFileDriver::Init();
00895 
00896     FILEMAN.ListDirectory( PackagePrefix+"*.zip", out, false );
00897     for ( i = 0; i < out.size(); i++ )
00898         out[i] = PackagePrefix + out[i];
00899 
00900     FILEMAN.ListDirectory( "*.zip", out, false );
00901     for ( i = 0; i < out.size(); i++ )
00902     {
00903         MercuryFile * z = FILEMAN.Open( out[i] );
00904         
00905 //      unsigned long NumberOfFiles = 0;
00906         char tmp[512];
00907 
00908         while ( !z->Check() && !z->Eof() )
00909         {
00910             MString basename;
00911             MString path;
00912             MString name;
00913 
00914             unsigned long filesize;
00915             unsigned long namelen;
00916             unsigned long packed;
00917             unsigned long PK;
00918             unsigned long PK2;
00919 
00920             z->Read( tmp, 2 );
00921             if ( tmp[0] != 'P' || tmp[1] != 'K' )
00922                 break;
00923 
00924             z->Read( tmp, 4 );
00925             PK = ZIPToLong( tmp );
00926 
00927             //If we are not reading a normal entry, we don't know how to continue
00928             if ( ( PK % 0x10000 ) != 0x0403 )
00929                 break;
00930 
00931             z->Read( tmp, 4 );
00932             PK2 = ZIPToLong( tmp );
00933 
00934             z->Read( tmp, 4 ); //Time (Throw out)
00935             z->Read( tmp, 4 ); //CRC32 (Throw out)
00936 
00937             z->Read( tmp, 4 );
00938             packed = ZIPToLong( tmp );
00939 
00940             z->Read( tmp, 4 );
00941             filesize = ZIPToLong( tmp );
00942 
00943             z->Read( tmp, 4 );
00944             namelen = ZIPToLong( tmp );
00945 
00946             z->Read( tmp, namelen );
00947             tmp[namelen] = '\0';
00948             name = tmp;
00949 
00950             ZipFileEntry e;
00951 
00952             if ( name.length() > 0 )
00953                 if ( name.c_str()[name.length()-1] == '/' )
00954                     continue;   //Ignore folder entries
00955 
00956             //First, strip out folders.
00957             MString LastFolder;
00958             MString CurrentElement;
00959             for ( int k = 0; (unsigned)k < namelen; k++ )
00960             {
00961                 if( tmp[k] == '/' )
00962                 {
00963                     ZipFileEntry y;
00964                     y.m_bFolder = true;
00965                     //Other values don't apply.
00966                     m_mFileFolders[LastFolder][CurrentElement] = y;
00967                     LastFolder += CurrentElement + "/";
00968                     CurrentElement = "";
00969                 }
00970                 else
00971                     CurrentElement+=tmp[k];
00972             }
00973             ZipFileEntry y;
00974             y.m_bFolder = false;
00975             y.m_sPackageName = out[i];
00976             y.m_iOffset = z->Tell();
00977             y.m_iSize = filesize;
00978             y.m_iPackedSize = packed;
00979             y.m_pkID = PK;
00980             y.m_pkID2 = PK2;
00981             m_mFileFolders[LastFolder][CurrentElement] = y;
00982 
00983             z->Seek( z->Tell() + packed );
00984         }
00985 
00986         SAFE_DELETE( z );
00987     }
00988 }
00989 
00990 MercuryFile * MercuryFileDriverZipped::GetFileHandle( const MString & sPath, FilePermission p )
00991 {
00992     if ( sPath.length() == 0 )
00993         return NULL;
00994 
00995     //First break up 
00996     const char * sp = sPath.c_str();
00997     unsigned int i;
00998     for ( i = sPath.length()-1; i > 0; i-- )
00999         if ( sp[i] == '/' )
01000             break;
01001 
01002     MString ActualName;
01003     if (i > 0)
01004         ActualName = sPath.substr(i+1);
01005     else
01006         ActualName = sPath;
01007 
01008     MString Path;
01009     if (i>0)
01010       Path = sPath.substr(0,i+1);
01011     else
01012       Path = "";
01013 
01014     if ( m_mFileFolders.find( Path ) == m_mFileFolders.end() )
01015         return NULL;
01016 
01017     if ( m_mFileFolders[Path].find( ActualName ) == m_mFileFolders[Path].end() )
01018         return NULL;
01019 
01020     ZipFileEntry z = m_mFileFolders[Path][ActualName];
01021 
01022     if ( z.m_bFolder )
01023         return NULL;
01024 
01025     bool success;
01026 
01027     MercuryFile * ret = NULL;
01028 
01029     //Zero indicates we're not actually doing compression
01030     if ( z.m_pkID2 / 65536 == 0 )
01031     {
01032         MercuryFileObjectPacked * tmp = new MercuryFileObjectPacked();
01033         success = tmp->Init( ActualName, p, z.m_sPackageName, z.m_iOffset, z.m_iSize );
01034         ret = tmp;
01035     }
01036     else
01037     {
01038         MercuryFileObjectZipped * tmp = new MercuryFileObjectZipped();
01039         success = tmp->Init( ActualName, p, z.m_sPackageName, z.m_iOffset, z.m_iSize, z.m_iPackedSize, z.m_pkID2 );
01040         ret = tmp;
01041     }
01042 
01043     if ( !success )
01044     {
01045         SAFE_DELETE( ret );
01046         return NULL;
01047     }
01048     return ret;
01049 }
01050 
01051 void MercuryFileDriverZipped::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
01052 {
01053     const char * sp = sPath.c_str();
01054     unsigned i;
01055     for (i = sPath.length()-1; i > 0; i-- )
01056         if ( sp[i] == '/' )
01057             break;
01058 
01059     MString ActualName;
01060     if (i>0)
01061         ActualName = sPath.substr( i+1 );
01062     else
01063         ActualName = sPath;
01064 
01065     MString Path;
01066     if(i>0)
01067         Path = sPath.substr( 0, i+1 );
01068 
01069     if ( m_mFileFolders.find( Path ) == m_mFileFolders.end() )
01070         return;
01071 
01072     std::map< MString, ZipFileEntry > * cDir = &m_mFileFolders[Path];
01073 
01074     std::map< MString, ZipFileEntry >::iterator iter, end;
01075     end = cDir->end();
01076     for ( iter = cDir->begin(); iter != end; iter++ )
01077     {
01078         MString fName = iter->first;
01079         ZipFileEntry z = iter->second;
01080         if ( bDirsOnly && !z.m_bFolder )
01081             continue;
01082         if ( !bDirsOnly && z.m_bFolder )
01083             continue;
01084 
01085         if ( FileMatch( fName, ActualName ) )
01086             output.push_back( fName );
01087     }
01088 }
01089 
01090 /********************FILE MANAGER**************************/
01091 
01092 void MercuryFileManager::Init()
01093 {
01094     
01095     m_bInit = true;
01096 
01097     m_Drivers = new MVector< MercuryFileDriver * >;
01098 
01099     //Careful!  The order here ACTUALLY MATTERS
01100     m_Drivers->push_back( new MercuryFileDirverDirect );
01101 
01102     MercuryFileDriver * Mem = new MercuryFileDriverMem;
01103     Mem->Init();
01104     m_Drivers->push_back( Mem );
01105     
01106     MercuryFileDriver * Packed = new MercuryFileDriverPacked;
01107     Packed->Init();
01108     m_Drivers->push_back( Packed );
01109 
01110     MercuryFileDriver * Zipped = new MercuryFileDriverZipped;
01111     Zipped->Init();
01112     m_Drivers->push_back( Zipped );
01113 
01114     MercuryFileDriver * Net = new MercuryFileDriverNet;
01115     Net->Init();
01116     m_Drivers->push_back( Net );
01117 }
01118 
01119 MercuryFile * MercuryFileManager::Open( const MString & sPath, FilePermission p )
01120 {
01121     if( sPath.empty() )
01122         return NULL;
01123     //First check to see if we are using an associated FS
01124     //Currently these are only theme supported.
01125     if ( sPath.find( "GRAPHIC:" ) == 0 )
01126         return Open( THEME.GetPathToGraphic( sPath.substr( 8 ) ) );
01127     if ( sPath.find( "MODEL:" ) == 0 )
01128         return Open( THEME.GetPathToModel( sPath.substr( 6 ) ) );
01129     if ( sPath.find( "FILE:" ) == 0 )
01130         return Open( THEME.GetPathToFile( sPath.substr( 5 ) ) );
01131     CheckInit();
01132 
01133     MercuryFile * ret;
01134     for ( unsigned int i = 0; i < m_Drivers->size(); i++ )
01135     {
01136         ret = m_Drivers->at(i)->GetFileHandle( sPath, p );
01137         if ( ret != NULL )
01138             return ret;
01139     }
01140     return NULL;
01141 }
01142 
01143 void MercuryFileManager::ListDirectory( const MString & sPath, MVector< MString > & output, bool bDirsOnly )
01144 {
01145     CheckInit();
01146     for ( unsigned int i = 0; i < m_Drivers->size(); i++ )
01147     {
01148         if ( sPath.substr(0,1).compare("/") )
01149             m_Drivers->at(i)->ListDirectory( sPath, output, bDirsOnly );
01150         else
01151             m_Drivers->at(i)->ListDirectory( sPath.substr(1), output, bDirsOnly );
01152     }
01153 
01154 }
01155 
01156 
01157 /* 
01158  * Copyright (c) 2005-2006, Charles Lohr
01159  * All rights reserved.
01160  *
01161  * Redistribution and use in source and binary forms, with or
01162  * without modification, are permitted provided that the following
01163  * conditions are met:
01164  *  -   Redistributions of source code must retain the above
01165  *      copyright notice, this list of conditions and the following disclaimer.
01166  *  -   Redistributions in binary form must reproduce the above copyright
01167  *      notice, this list of conditions and the following disclaimer in
01168  *      the documentation and/or other materials provided with the distribution.
01169  *  -   Neither the name of the Mercury Engine nor the names of its
01170  *      contributors may be used to endorse or promote products derived from
01171  *      this software without specific prior written permission.
01172  *
01173  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
01174  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
01175  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
01176  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
01177  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
01178  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
01179  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
01180  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
01181  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
01182  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
01183  */
01184 

Hosted by SourceForge.net Logo