00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 #include "OSDLEmbeddedFile.h"
00029 
00030 #ifdef OSDL_USES_CONFIG_H
00031 #include "OSDLConfig.h"              
00032 #endif // OSDL_USES_CONFIG_H
00033 
00034 
00035 #if OSDL_ARCH_NINTENDO_DS
00036 #include "OSDLConfigForNintendoDS.h" 
00037 #endif // OSDL_ARCH_NINTENDO_DS
00038 
00039 
00040 #if OSDL_USES_PHYSICSFS
00041 #include "physfs.h"                  
00042 #endif // OSDL_USES_PHYSICSFS
00043 
00044 
00045 
00046 #include "OSDLEmbeddedFileSystemManager.h" 
00047 
00048 
00049 #include "Ceylan.h"                  
00050 
00051 
00052 #include <cstring>                   
00053 
00054 
00055 
00056 
00057 
00058 
00059 
00060 
00061 
00062 
00063 
00064 
00065 
00066 
00067 
00068 
00069 
00070 
00071 
00072 
00073 
00074 
00075 
00076 using std::string ;
00077 
00078 using namespace Ceylan::System ;
00079 using namespace Ceylan::Log ;
00080 
00081 using namespace OSDL ;
00082 
00083 
00084 
00085 
00086 EmbeddedFileException::EmbeddedFileException( const string & reason ) :
00087   FileException( reason )
00088 {
00089 
00090 }
00091 
00092 
00093 
00094 EmbeddedFileException::~EmbeddedFileException() throw()
00095 {
00096 
00097 }
00098 
00099 
00100 
00101 
00102 
00103 
00104 
00105 
00106 
00107 EmbeddedFile::~EmbeddedFile() throw()
00108 {
00109 
00110   
00111   
00112 
00113   if ( isOpen() )
00114   {
00115 
00116     try
00117     {
00118       close() ;
00119     }
00120     catch( const Stream::CloseException & e )
00121     {
00122       LogPlug::error( "EmbeddedFile destructor: close failed: "
00123         + e.toString() ) ;
00124     }
00125 
00126   }
00127 
00128 }
00129 
00130 
00131 
00132 
00133 
00134 
00135 
00136 
00137 
00138 
00139 
00140 
00141 
00142 bool EmbeddedFile::isOpen() const
00143 {
00144 
00145 #if OSDL_USES_PHYSICSFS
00146 
00147   return ( _physfsHandle != 0 ) ;
00148 
00149 #else // OSDL_USES_PHYSICSFS
00150 
00151   return false ;
00152 
00153 #endif // OSDL_USES_PHYSICSFS
00154 
00155 }
00156 
00157 
00158 
00159 bool EmbeddedFile::close()
00160 {
00161 
00162   if ( ! isOpen() )
00163   {
00164 
00165     LogPlug::warning( "EmbeddedFile::close: file '" +  _name
00166       + "' does not seem to have been already opened." ) ;
00167 
00168     return false ;
00169 
00170   }
00171   else
00172   {
00173 
00174     
00175 
00176 #if OSDL_USES_PHYSICSFS
00177 
00178     if ( PHYSFS_close( _physfsHandle ) == 0 )
00179       throw Stream::CloseException( "EmbeddedFile::close failed: "
00180         + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00181 
00182     _physfsHandle = 0 ;
00183 
00184     return true ;
00185 
00186 #else // OSDL_USES_PHYSICSFS
00187 
00188     throw Stream::CloseException( "EmbeddedFile::close failed: "
00189       "no PhysicsFS support available." ) ;
00190 
00191 #endif // OSDL_USES_PHYSICSFS
00192 
00193   }
00194 
00195 }
00196 
00197 
00198 
00199 void EmbeddedFile::saveAs( const string & newName )
00200 {
00201 
00202 #if OSDL_USES_PHYSICSFS
00203 
00204   
00205   EmbeddedFile & f = EmbeddedFile::Create( newName ) ;
00206   serialize( *f._physfsHandle ) ;
00207   delete &f ;
00208 
00209 #else // OSDL_USES_PHYSICSFS
00210 
00211   throw FileException(
00212     "EmbeddedFile::saveAs: not implemented on this platform." ) ;
00213 
00214 #endif // OSDL_USES_PHYSICSFS
00215 
00216 }
00217 
00218 
00219 
00220 
00221 
00222 
00223 
00224 
00232 void EmbeddedFile::lockForReading() const
00233 {
00234 
00235   throw FileReadLockingFailed( "EmbeddedFile::lockForReading: "
00236     "lock feature not available" ) ;
00237 
00238 }
00239 
00240 
00241 
00242 void EmbeddedFile::unlockForReading() const
00243 {
00244 
00245   throw FileReadUnlockingFailed(
00246     "EmbeddedFile::unlockForReading: lock feature not available" ) ;
00247 
00248 }
00249 
00250 
00251 
00252 void EmbeddedFile::lockForWriting() const
00253 {
00254 
00255   throw FileWriteLockingFailed( "EmbeddedFile::lockForWriting: "
00256     "lock feature not available" ) ;
00257 
00258 }
00259 
00260 
00261 
00262 void EmbeddedFile::unlockForWriting() const
00263 {
00264 
00265   throw FileWriteUnlockingFailed( "EmbeddedFile::unlockForWriting: "
00266     "lock feature not available" ) ;
00267 
00268 }
00269 
00270 
00271 
00272 bool EmbeddedFile::isLocked() const
00273 {
00274 
00275   return false ;
00276 
00277 }
00278 
00279 
00280 
00281 time_t EmbeddedFile::getLastChangeTime() const
00282 {
00283 
00284 #if OSDL_USES_PHYSICSFS
00285 
00286   try
00287   {
00288 
00289     return getCorrespondingFileSystemManager().getEntryChangeTime( _name ) ;
00290 
00291   }
00292   catch( const Ceylan::Exception & e )
00293   {
00294     throw FileLastChangeTimeRequestFailed(
00295       "EmbeddedFile::getLastChangeTime failed: "
00296       + e.toString() ) ;
00297   }
00298 
00299 #else // OSDL_USES_PHYSICSFS
00300 
00301   throw FileLastChangeTimeRequestFailed(
00302     "EmbeddedFile::getLastChangeTime failed: "
00303     "no PhysicsFS support available." ) ;
00304 
00305 #endif // OSDL_USES_PHYSICSFS
00306 
00307 }
00308 
00309 
00310 
00311 Size EmbeddedFile::read( Ceylan::Byte * buffer, Size maxLength )
00312 {
00313 
00314 #if OSDL_USES_PHYSICSFS
00315 
00316   PHYSFS_sint64 objectCount = PHYSFS_read( _physfsHandle,
00317     static_cast<void *>( buffer ),  1, maxLength ) ;
00318 
00319   if ( objectCount == -1 )
00320   {
00321     throw InputStream::ReadFailedException(
00322       "EmbeddedFile::read failed: "
00323       + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00324   }
00325 
00326   
00327 
00328   Size unsignedObjectCount = static_cast<Size>( objectCount ) ;
00329 
00330 #if OSDL_DEBUG
00331 
00332   
00333 
00334 
00335 
00336 
00337 
00338 
00339 
00340 
00341 
00342 #endif // OSDL_DEBUG
00343 
00344   if ( unsignedObjectCount < maxLength )
00345   {
00346 
00347     
00348     if ( ! ::PHYSFS_eof( _physfsHandle ) )
00349       throw InputStream::ReadFailedException(
00350         "EmbeddedFile::read failed: "
00351         + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00352     
00353 
00354 
00355 
00356 
00357 
00358 
00359 
00360 
00361 
00362 
00363 
00364   }
00365 
00366 
00367   
00368   if ( _cypher )
00369     DecypherBuffer( buffer, objectCount ) ;
00370 
00371   return unsignedObjectCount ;
00372 
00373 #else // OSDL_USES_PHYSICSFS
00374 
00375   throw InputStream::ReadFailedException(
00376     "EmbeddedFile::read failed: "
00377     "no PhysicsFS support available." ) ;
00378 
00379 #endif // OSDL_USES_PHYSICSFS
00380 
00381 }
00382 
00383 
00384 
00385 Size EmbeddedFile::write( const string & message )
00386 {
00387 
00388   return write( message.c_str(), message.size() );
00389 
00390 }
00391 
00392 
00393 
00394 Size EmbeddedFile::write( const Ceylan::Byte * buffer, Size maxLength )
00395 {
00396 
00397 #if OSDL_USES_PHYSICSFS
00398 
00399   const Ceylan::Byte * actualBuffer ;
00400 
00401   if ( _cypher )
00402   {
00403 
00404     
00405 
00406     Ceylan::Byte * newBuffer = new Ceylan::Byte[maxLength] ;
00407 
00408     ::memcpy( newBuffer, buffer, maxLength ) ;
00409 
00410     CypherBuffer( newBuffer, maxLength ) ;
00411 
00412     actualBuffer = newBuffer ;
00413 
00414   }
00415   else
00416   {
00417 
00418     actualBuffer = buffer ;
00419 
00420   }
00421 
00422 
00423   PHYSFS_sint64 objectCount = PHYSFS_write( _physfsHandle,
00424     static_cast<const void *>( actualBuffer ),  1,
00425     maxLength ) ;
00426 
00427 
00428   if ( _cypher )
00429     delete [] actualBuffer ;
00430 
00431 
00432   if ( objectCount == -1 )
00433     throw OutputStream::WriteFailedException(
00434       "EmbeddedFile::write failed: "
00435       + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00436   else
00437     return static_cast<Size>( objectCount ) ;
00438 
00439 #else // OSDL_USES_PHYSICSFS
00440 
00441   throw OutputStream::WriteFailedException(
00442     "EmbeddedFile::write failed: "
00443     "no PhysicsFS support available." ) ;
00444 
00445 #endif // OSDL_USES_PHYSICSFS
00446 
00447 }
00448 
00449 
00450 
00451 Position EmbeddedFile::tell()
00452 {
00453 
00454 #if OSDL_USES_PHYSICSFS
00455 
00456 
00457   
00458 
00459   PHYSFS_sint64 returnedPos = ::PHYSFS_tell( _physfsHandle ) ;
00460 
00461   if ( returnedPos < 0 )
00462     throw FileException( "EmbeddedFile::tell failed for '" + _name
00463       + "': " + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00464 
00465   Position pos = static_cast<Position>( returnedPos ) ;
00466 
00467   if ( pos != returnedPos )
00468     throw FileException( "EmbeddedFile::tell failed for '" + _name
00469       + "': offset too high for position variable." ) ;
00470 
00471   
00472 
00473 
00474 
00475 
00476   return pos ;
00477 
00478 #else // OSDL_USES_PHYSICSFS
00479 
00480   throw FileException( "EmbeddedFile::tell failed: "
00481     "no PhysicsFS support available." ) ;
00482 
00483 #endif // OSDL_USES_PHYSICSFS
00484 
00485 }
00486 
00487 
00488 
00489 void EmbeddedFile::seek( Position targetPosition )
00490 {
00491 
00492 #if OSDL_USES_PHYSICSFS
00493 
00494   
00495 
00496 
00497 
00498 
00499   int res = ::PHYSFS_seek( _physfsHandle, targetPosition ) ;
00500 
00501   if ( res == 0 )
00502     throw FileException( "EmbeddedFile::seek failed for '" + _name
00503       + "': " + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00504 
00505 #else // OSDL_USES_PHYSICSFS
00506 
00507   throw Ceylan::System::FileException( "EmbeddedFile::seek failed: "
00508     "no PhysicsFS support available." ) ;
00509 
00510 #endif // OSDL_USES_PHYSICSFS
00511 
00512 }
00513 
00514 
00515 
00516 
00517 
00518 
00519 
00520 
00521 
00522 Size EmbeddedFile::size() const
00523 {
00524 
00525 #if OSDL_USES_PHYSICSFS
00526 
00527   PHYSFS_sint64 fileSize = PHYSFS_fileLength( _physfsHandle ) ;
00528 
00529   if ( fileSize == - 1 )
00530     throw Ceylan::System::FileException(
00531       "EmbeddedFile::size failed: "
00532       + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00533 
00534   Size res = static_cast<Size>( fileSize ) ;
00535 
00536   
00537 
00538 
00539 
00540 
00541 
00542 
00543 
00544 
00545 
00546   return res ;
00547 
00548 #else // OSDL_USES_PHYSICSFS
00549 
00550   throw Ceylan::System::FileException(
00551     "EmbeddedFile::size failed: no PhysicsFS support available." ) ;
00552 
00553 #endif // OSDL_USES_PHYSICSFS
00554 
00555 }
00556 
00557 
00558 
00559 void EmbeddedFile::serialize( PHYSFS_File & handle )
00560 {
00561 
00562   
00563   FromHandletoHandle( *_physfsHandle, handle, size() ) ;
00564 
00565 }
00566 
00567 
00568 
00569 PHYSFS_File & EmbeddedFile::getPhysicsFSHandle() const
00570 {
00571 
00572 #if OSDL_USES_PHYSICSFS
00573 
00574   if ( _physfsHandle != 0 )
00575     return *_physfsHandle ;
00576   else
00577     throw EmbeddedFileException( "EmbeddedFile::getPhysicsFSHandle failed: "
00578       "null handle found." ) ;
00579 
00580 #else // OSDL_USES_PHYSICSFS
00581 
00582   throw EmbeddedFileException( "EmbeddedFile::getPhysicsFSHandle: "
00583     "no PhysicsFS support available." ) ;
00584 
00585 #endif // OSDL_USES_PHYSICSFS
00586 
00587 }
00588 
00589 
00590 
00591 
00592 void EmbeddedFile::CypherBuffer( Ceylan::Byte * buffer,
00593   Ceylan::System::Size size )
00594 {
00595 
00596   Ceylan::Byte XORByte = EmbeddedFileSystemManager::GetXORByte() ;
00597 
00598   for ( Size i = 0; i < size; i++ )
00599     buffer[i] = (buffer[i]^XORByte) + 117 ;
00600 
00601 }
00602 
00603 
00604 
00605 void EmbeddedFile::DecypherBuffer( Ceylan::Byte * buffer, Size size )
00606 {
00607 
00608   Ceylan::Byte XORByte = EmbeddedFileSystemManager::GetXORByte() ;
00609 
00610   for ( Size i = 0; i < size; i++ )
00611   {
00612     buffer[i] = (buffer[i]-117)^XORByte ;
00613 
00614     
00615 
00616 
00617 
00618   }
00619 
00620 }
00621 
00622 
00623 
00624 
00625 StreamID EmbeddedFile::getStreamID() const
00626 {
00627 
00628 #if OSDL_USES_PHYSICSFS
00629 
00630   
00631   return static_cast<StreamID>( reinterpret_cast<uintptr_t>(
00632       & getPhysicsFSHandle() ) ) ;
00633 
00634 #else // OSDL_USES_PHYSICSFS
00635 
00636   
00637   return -1 ;
00638 
00639 #endif // OSDL_USES_PHYSICSFS
00640 
00641 }
00642 
00643 
00644 
00645 const std::string EmbeddedFile::toString( Ceylan::VerbosityLevels level ) const
00646 {
00647 
00648   return "Embedded file object for user-specified filename '"
00649     + Ceylan::encodeToROT13( _name )
00650     + "', corresponding to an actual name in archive '" + _name + "'" ;
00651 
00652 }
00653 
00654 
00655 
00656 EmbeddedFile & EmbeddedFile::Create( const std::string & filename,
00657   OpeningFlag createFlag,   PermissionFlag permissionFlag )
00658 {
00659 
00660   
00661   return * new EmbeddedFile( filename, createFlag | File::CreateFile,
00662     permissionFlag ) ;
00663 
00664 }
00665 
00666 
00667 
00668 EmbeddedFile & EmbeddedFile::Open( const std::string & filename,
00669   OpeningFlag openFlag )
00670 {
00671 
00672   
00673   return * new EmbeddedFile( filename, openFlag & ~File::CreateFile
00674      ) ;
00675 
00676 }
00677 
00678 
00679 
00680 
00681 
00682 
00683 
00684 
00685 
00686 EmbeddedFile::EmbeddedFile( const string & name, OpeningFlag openFlag,
00687   PermissionFlag permissions ) :
00688   File( Ceylan::encodeToROT13(name), openFlag, permissions ),
00689   _physfsHandle( 0 )
00690 {
00691 
00692   
00693 
00694 #if OSDL_USES_PHYSICSFS
00695 
00696   _cypher = EmbeddedFileSystemManager::SecureEmbeddedFileSystemManager() ;
00697 
00698   if ( openFlag & NonBlocking )
00699     throw Ceylan::System::FileException( "EmbeddedFile constructor failed: "
00700       "cannot open a file in non-blocking mode." ) ;
00701 
00702   if ( openFlag & Synchronous )
00703     throw Ceylan::System::FileException( "EmbeddedFile constructor failed: "
00704       "cannot open a file in synchronous mode." ) ;
00705 
00706   if ( ! ( openFlag & Binary ) )
00707     throw Ceylan::System::FileException( "EmbeddedFile constructor failed: "
00708       "cannot open a file in non-binary mode." ) ;
00709 
00710   if ( openFlag != DoNotOpen )
00711     reopen() ;
00712 
00713 
00714 #else // OSDL_USES_PHYSICSFS
00715 
00716   throw Ceylan::System::FileException( "EmbeddedFile constructor failed: "
00717     "no PhysicsFS support available." ) ;
00718 
00719 #endif // OSDL_USES_PHYSICSFS
00720 
00721 }
00722 
00723 
00724 
00725 
00726 
00727 
00728 
00729 
00730 
00731 FileSystemManager & EmbeddedFile::getCorrespondingFileSystemManager() const
00732 {
00733 
00734   try
00735   {
00736 
00737     return EmbeddedFileSystemManager::GetEmbeddedFileSystemManager() ;
00738 
00739   }
00740   catch( const EmbeddedFileSystemManagerException & e )
00741   {
00742 
00743     throw FileDelegatingException(
00744       "EmbeddedFile::getCorrespondingFileSystemManager failed: "
00745       + e.toString() ) ;
00746 
00747   }
00748 
00749 }
00750 
00751 
00752 
00753 void EmbeddedFile::reopen()
00754 {
00755 
00756 #if OSDL_USES_PHYSICSFS
00757 
00758   PHYSFS_File * file ;
00759 
00760   if ( _openFlag & Ceylan::System::File::Write )
00761   {
00762 
00763     file = PHYSFS_openWrite( _name.c_str() ) ;
00764 
00765     if ( file == 0 )
00766       throw FileOpeningFailed("EmbeddedFile::reopen for writing failed for file '"
00767         + _name + "': "
00768         + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00769 
00770   }
00771   else if ( _openFlag & Ceylan::System::File::AppendFile )
00772   {
00773 
00774     file = PHYSFS_openAppend( _name.c_str() ) ;
00775 
00776     if ( file == 0 )
00777       throw FileOpeningFailed(
00778         "EmbeddedFile::reopen for appending failed for file '"
00779         + _name + "': "
00780         + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00781 
00782   }
00783   else if ( _openFlag & Ceylan::System::File::Read )
00784   {
00785 
00786     file = PHYSFS_openRead( _name.c_str() ) ;
00787 
00788     if ( file == 0 )
00789     {
00790       throw FileOpeningFailed(
00791         "EmbeddedFile::reopen for reading failed for file '"
00792         + _name + "': "
00793         + EmbeddedFileSystemManager::GetBackendLastError() ) ;
00794     }
00795   }
00796   else
00797   {
00798 
00799     throw FileOpeningFailed(
00800       "EmbeddedFile::reopen for reading failed for file '" + _name + "': "
00801       "only possible opening flags are writing, appending or reading." ) ;
00802   }
00803 
00804 
00805   _physfsHandle = file ;
00806 
00807 #else // OSDL_USES_PHYSICSFS
00808 
00809   throw Ceylan::System::FileOpeningFailed( "EmbeddedFile::reopen failed: "
00810     "no PhysicsFS support available." ) ;
00811 
00812 #endif // OSDL_USES_PHYSICSFS
00813 
00814 }
00815 
00816 
00817 
00818 std::string EmbeddedFile::interpretState() const
00819 {
00820 
00821   return "PhysicsFS-based embedded file" ;
00822 
00823 }
00824 
00825 
00826 
00827 
00828 
00829 
00830 
00831 
00832 void EmbeddedFile::FromHandletoHandle( PHYSFS_File & from, PHYSFS_File & to,
00833   Size length )
00834 {
00835 
00836   
00837 
00838   throw EmbeddedFileException( "EmbeddedFile::FromHandletoHandle: "
00839     "operation not available on embedded filesystems." ) ;
00840 
00841 }