00001 #include "MercuryFiles.h"
00002 #include "MercuryTheme.h"
00003
00004 #include "ezSockets.h"
00005
00006
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
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
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
00157 }
00158
00159
00160
00161
00162 MercuryFile::MercuryFile()
00163 {
00164
00165 }
00166
00167 MercuryFile::~MercuryFile()
00168 {
00169
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
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
00328 return (Twrite.dwHighDateTime - 27636147) * 400 + (Twrite.dwLowDateTime/10000000);
00329 }
00330 #else
00331
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 )
00361 return;
00362 do
00363 {
00364 if( bDirsOnly && !(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
00365 continue;
00366
00367 if( (!bDirsOnly) && (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) )
00368 continue;
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
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;
00420
00421
00422
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
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
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
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
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
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
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;
00752
00753
00754
00755
00756 m_sPath = fName;
00757 m_p = p;
00758 MercuryFile * m_base = FILEMAN.Open( base, p );
00759
00760
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
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
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
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
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
00928 if ( ( PK % 0x10000 ) != 0x0403 )
00929 break;
00930
00931 z->Read( tmp, 4 );
00932 PK2 = ZIPToLong( tmp );
00933
00934 z->Read( tmp, 4 );
00935 z->Read( tmp, 4 );
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;
00955
00956
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
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
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
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
01091
01092 void MercuryFileManager::Init()
01093 {
01094
01095 m_bInit = true;
01096
01097 m_Drivers = new MVector< MercuryFileDriver * >;
01098
01099
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
01124
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
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01184