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 }