/********************************************************************** Filename : GFile.h Content : Header for all internal file management- functions and structures to be inherited by OS specific subclasses. Created : July 29, 1998 Authors : Michael Antonov, Brendan Iribe, Andrew Reisse Notes : errno may not be preserved across use of GBaseFile member functions : Directories cannot be deleted while files opened from them are in use (For the GetFullName function) History : 4/04/1999 : Changed GBaseFile to support directory 1/20/1999 : Updated to follow new style 8/25/2001 : MA - Restructured file, directory, added streams, item directories & paths Copyright : (c) 1998-2003 Scaleform Corp. All Rights Reserved. Licensees may use this file in accordance with the valid Scaleform Commercial License Agreement provided with the software. This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR ANY PURPOSE. **********************************************************************/ #ifndef INC_GFILE_H #define INC_GFILE_H #include "GRefCount.h" #include "GFunctions.h" #include "GTypes.h" //#include "GTime.h" //#include "GStream.h" #include // ***** Declared classes class GFileConstants; class GFile; class GDelegatedFile; class GBufferedFile; class GSysFile; //class GFileStats; // ***** Flags for File & Directory accesses class GFileConstants { public: // *** File open flags enum OpenFlags { Open_Read = 1, Open_Write = 2, Open_ReadWrite = 3, // Opens file and truncates it to zero length // - file must have write permission // - when used with Create, it opens an existing // file and empties it or creates a new file Open_Truncate = 4, // Creates and opens new file // - does not erase contents if file already // exists unless combined with Truncate Open_Create = 8, // Returns an error value if the file already exists Open_CreateOnly = 24, Open_NoFollow = 32, // Only follow links that stay under this directory Open_NoFollowOut= 64 }; // *** File Mode flags enum Modes { Mode_Read = 0444, Mode_Write = 0222, Mode_Execute = 0111, Mode_ReadWrite = 0666 }; // *** Seek operations enum SeekOps { Seek_Set = 0, Seek_Cur = 1, Seek_End = 2 }; // *** Errors enum Errors { Error_FileNotFound = 0x1001, Error_Access = 0x1002, Error_IOError = 0x1003, Error_DiskFull = 0x1004 }; }; // ***** File Class // The pure virtual base random-access file // This is a base class to all files class GFile : public GRefCountBase, public GFileConstants { public: GFile() { SetRefCountMode(GFC_REFCOUNT_THREADSAFE); } // ** Location Information // Returns a file name path relative to the 'reference' directory // This is often a path that was used to create a file // (this is not a global path, global path can be obtained with help of directory) virtual const char* GetFilePath() = 0; // ** File Information // Return 1 if file's usable (open) virtual bool IsValid() = 0; // Return 1 if file's writable, otherwise 0 virtual bool IsWritable() = 0; // Return 1 if file supports CloseCancel() //virtual bool IsRecoverable() = 0; // Return position virtual SInt Tell () = 0; virtual SInt64 LTell () = 0; // File size virtual SInt GetLength () = 0; virtual SInt64 LGetLength () = 0; // Returns file stats // 0 for failure //virtual bool Stat(GFileStats *pfs) = 0; // Return errno-based error code // Useful if any other function failed virtual SInt GetErrorCode() = 0; // ** GFxStream implementation & I/O // Blocking write, will write in the given number of bytes to the stream // Returns : -1 for error // Otherwise number of bytes read virtual SInt Write(const UByte *pbufer, SInt numBytes) = 0; // Blocking read, will read in the given number of bytes or less from the stream // Returns : -1 for error // Otherwise number of bytes read, // if 0 or < numBytes, no more bytes available; end of file or the other side of stream is closed virtual SInt Read(UByte *pbufer, SInt numBytes) = 0; // Skips (ignores) a given # of bytes // Same return values as Read virtual SInt SkipBytes(SInt numBytes) = 0; // Returns the number of bytes available to read from a stream without blocking // For a file, this should generally be number of bytes to the end virtual SInt BytesAvailable() = 0; // Causes any implementation's buffered data to be delivered to destination // Return 0 for error virtual bool Flush() = 0; // Need to provide a more optimized implementation that doe snot necessarily involve a lot of seeking GINLINE bool IsEOF() { return !BytesAvailable(); } // Seeking // Returns new position, -1 for error virtual SInt Seek(SInt offset, SInt origin=Seek_Set) = 0; virtual SInt64 LSeek(SInt64 offset, SInt origin=Seek_Set) = 0; // Seek simplification SInt SeekToBegin() {return Seek(0); } SInt SeekToEnd() {return Seek(0,Seek_End); } SInt Skip(SInt numBytes) {return Seek(numBytes,Seek_Cur); } // Resizing the file // Return 0 for failure virtual bool ChangeSize(SInt newSize) = 0; // Appends other file data from a stream // Return -1 for error, else # of bytes written virtual SInt CopyFromStream(GFile *pstream, SInt byteSize) = 0; // Closes the file // After close, file cannot be accessed virtual bool Close() = 0; // Closes the file & recovers it to initial state, if supported //virtual bool CloseCancel() = 0; // ***** Inlines for convenient primitive type serialization // Read/Write helpers private: UInt64 PRead64() { UInt64 v = 0; Read((UByte*)&v, 8); return v; } UInt32 PRead32() { UInt32 v = 0; Read((UByte*)&v, 4); return v; } UInt16 PRead16() { UInt16 v = 0; Read((UByte*)&v, 2); return v; } UInt8 PRead8() { UInt8 v = 0; Read((UByte*)&v, 1); return v; } void PWrite64(UInt64 v) { Write((UByte*)&v, 8); } void PWrite32(UInt32 v) { Write((UByte*)&v, 4); } void PWrite16(UInt16 v) { Write((UByte*)&v, 2); } void PWrite8(UInt8 v) { Write((UByte*)&v, 1); } public: // Writing primitive types - Little Endian GINLINE void WriteUByte(UByte v) { PWrite8((UInt8)GByteUtil::SystemToLE(v)); } GINLINE void WriteSByte(SByte v) { PWrite8((UInt8)GByteUtil::SystemToLE(v)); } GINLINE void WriteUInt8(UInt8 v) { PWrite8((UInt8)GByteUtil::SystemToLE(v)); } GINLINE void WriteSInt8(SInt8 v) { PWrite8((UInt8)GByteUtil::SystemToLE(v)); } GINLINE void WriteUInt16(UInt16 v) { PWrite16((UInt16)GByteUtil::SystemToLE(v)); } GINLINE void WriteSInt16(SInt16 v) { PWrite16((UInt16)GByteUtil::SystemToLE(v)); } GINLINE void WriteUInt32(UInt32 v) { PWrite32((UInt32)GByteUtil::SystemToLE(v)); } GINLINE void WriteSInt32(SInt32 v) { PWrite32((UInt32)GByteUtil::SystemToLE(v)); } GINLINE void WriteUInt64(UInt64 v) { PWrite64((UInt64)GByteUtil::SystemToLE(v)); } GINLINE void WriteSInt64(SInt64 v) { PWrite64((UInt64)GByteUtil::SystemToLE(v)); } GINLINE void WriteFloat(Float v) { v = GByteUtil::SystemToLE(v); Write((UByte*)&v, 4); } GINLINE void WriteDouble(Double v) { v = GByteUtil::SystemToLE(v); Write((UByte*)&v, 8); } // Writing primitive types - Big Endian GINLINE void WriteUByteBE(UByte v) { PWrite8((UInt8)GByteUtil::SystemToBE(v)); } GINLINE void WriteSByteBE(SByte v) { PWrite8((UInt8)GByteUtil::SystemToBE(v)); } GINLINE void WriteUInt8BE(UInt16 v) { PWrite8((UInt8)GByteUtil::SystemToBE(v)); } GINLINE void WriteSInt8BE(SInt16 v) { PWrite8((UInt8)GByteUtil::SystemToBE(v)); } GINLINE void WriteUInt16BE(UInt16 v) { PWrite16((UInt16)GByteUtil::SystemToBE(v)); } GINLINE void WriteSInt16BE(UInt16 v) { PWrite16((UInt16)GByteUtil::SystemToBE(v)); } GINLINE void WriteUInt32BE(UInt32 v) { PWrite32((UInt32)GByteUtil::SystemToBE(v)); } GINLINE void WriteSInt32BE(UInt32 v) { PWrite32((UInt32)GByteUtil::SystemToBE(v)); } GINLINE void WriteUInt64BE(UInt64 v) { PWrite64((UInt64)GByteUtil::SystemToBE(v)); } GINLINE void WriteSInt64BE(UInt64 v) { PWrite64((UInt64)GByteUtil::SystemToBE(v)); } GINLINE void WriteFloatBE(Float v) { v = GByteUtil::SystemToBE(v); Write((UByte*)&v, 4); } GINLINE void WriteDoubleBE(Double v) { v = GByteUtil::SystemToBE(v); Write((UByte*)&v, 8); } // Reading primitive types - Little Endian GINLINE UByte ReadUByte() { return (UByte)GByteUtil::LEToSystem(PRead8()); } GINLINE SByte ReadSByte() { return (SByte)GByteUtil::LEToSystem(PRead8()); } GINLINE UInt8 ReadUInt8() { return (UInt8)GByteUtil::LEToSystem(PRead8()); } GINLINE SInt8 ReadSInt8() { return (SInt8)GByteUtil::LEToSystem(PRead8()); } GINLINE UInt16 ReadUInt16() { return (UInt16)GByteUtil::LEToSystem(PRead16()); } GINLINE SInt16 ReadSInt16() { return (SInt16)GByteUtil::LEToSystem(PRead16()); } GINLINE UInt32 ReadUInt32() { return (UInt32)GByteUtil::LEToSystem(PRead32()); } GINLINE SInt32 ReadSInt32() { return (SInt32)GByteUtil::LEToSystem(PRead32()); } GINLINE UInt64 ReadUInt64() { return (UInt64)GByteUtil::LEToSystem(PRead64()); } GINLINE SInt64 ReadSInt64() { return (SInt64)GByteUtil::LEToSystem(PRead64()); } GINLINE Float ReadFloat() { Float v = 0.0f; Read((UByte*)&v, 4); return GByteUtil::LEToSystem(v); } GINLINE Double ReadDouble() { Double v = 0.0; Read((UByte*)&v, 8); return GByteUtil::LEToSystem(v); } // Reading primitive types - Big Endian GINLINE UByte ReadUByteBE() { return (UByte)GByteUtil::BEToSystem(PRead8()); } GINLINE SByte ReadSByteBE() { return (SByte)GByteUtil::BEToSystem(PRead8()); } GINLINE UInt8 ReadUInt8BE() { return (UInt8)GByteUtil::BEToSystem(PRead8()); } GINLINE SInt8 ReadSInt8BE() { return (SInt8)GByteUtil::BEToSystem(PRead8()); } GINLINE UInt16 ReadUInt16BE() { return (UInt16)GByteUtil::BEToSystem(PRead16()); } GINLINE SInt16 ReadSInt16BE() { return (SInt16)GByteUtil::BEToSystem(PRead16()); } GINLINE UInt32 ReadUInt32BE() { return (UInt32)GByteUtil::BEToSystem(PRead32()); } GINLINE SInt32 ReadSInt32BE() { return (SInt32)GByteUtil::BEToSystem(PRead32()); } GINLINE UInt64 ReadUInt64BE() { return (UInt64)GByteUtil::BEToSystem(PRead64()); } GINLINE SInt64 ReadSInt64BE() { return (SInt64)GByteUtil::BEToSystem(PRead64()); } GINLINE Float ReadFloatBE() { Float v = 0.0f; Read((UByte*)&v, 4); return GByteUtil::BEToSystem(v); } GINLINE Double ReadDoubleBE() { Double v = 0.0; Read((UByte*)&v, 8); return GByteUtil::BEToSystem(v); } }; // *** Delegated File class GDelegatedFile : public GFile { protected: // Delegating file pointer GPtr pFile; // Hidden default constructor GDelegatedFile() { pFile=0; } GDelegatedFile(const GDelegatedFile &source) : GFile() { GUNUSED(source); } public: // Constructors GDelegatedFile(GFile *pfile) : pFile(pfile) { } // ** Location Information virtual const char* GetFilePath() { return pFile->GetFilePath(); } // ** File Information virtual bool IsValid() { return pFile && pFile->IsValid(); } virtual bool IsWritable() { return pFile->IsWritable(); } // virtual bool IsRecoverable() { return pFile->IsRecoverable(); } virtual SInt Tell() { return pFile->Tell(); } virtual SInt64 LTell() { return pFile->LTell(); } virtual SInt GetLength() { return pFile->GetLength(); } virtual SInt64 LGetLength() { return pFile->LGetLength(); } //virtual bool Stat(GFileStats *pfs) { return pFile->Stat(pfs); } virtual SInt GetErrorCode() { return pFile->GetErrorCode(); } // ** GFxStream implementation & I/O virtual SInt Write(const UByte *pbuffer, SInt numBytes) { return pFile->Write(pbuffer,numBytes); } virtual SInt Read(UByte *pbuffer, SInt numBytes) { return pFile->Read(pbuffer,numBytes); } virtual SInt SkipBytes(SInt numBytes) { return pFile->SkipBytes(numBytes); } virtual SInt BytesAvailable() { return pFile->BytesAvailable(); } virtual bool Flush() { return pFile->Flush(); } // Seeking virtual SInt Seek(SInt offset, SInt origin=Seek_Set) { return pFile->Seek(offset,origin); } virtual SInt64 LSeek(SInt64 offset, SInt origin=Seek_Set) { return pFile->LSeek(offset,origin); } // Resizing the file virtual bool ChangeSize(SInt newSize) { return pFile->ChangeSize(newSize); } virtual SInt CopyFromStream(GFile *pstream, SInt byteSize) { return pFile->CopyFromStream(pstream,byteSize); } // Closing the file virtual bool Close() { return pFile->Close(); } //virtual bool CloseCancel() { return pFile->CloseCancel(); } }; // *** Buffered File // This file class adds buffering to an existing file // Buffered file never fails by itself; if there's not // enough memory for buffer, no buffer's used class GBufferedFile : public GDelegatedFile { protected: enum BufferModeType { NoBuffer, ReadBuffer, WriteBuffer }; // Buffer & the mode it's in UByte* pBuffer; BufferModeType BufferMode; // Position in buffer UInt Pos; // Data in buffer if reading UInt DataSize; // Underlying file position UInt64 FilePos; // Initializes buffering to a certain mode GEXPORT bool SetBufferMode(BufferModeType mode); // Flushes buffer // WriteBuffer - write data to disk, ReadBuffer - reset buffer & fix file position GEXPORT void FlushBuffer(); // Loads data into ReadBuffer // WARNING: Right now LoadBuffer() assumes the buffer's empty GEXPORT void LoadBuffer(); // Hidden constructor GEXPORT GBufferedFile(); GINLINE GBufferedFile(const GBufferedFile &source) : GDelegatedFile() { GUNUSED(source); } public: // Constructor // - takes another file as source GEXPORT GBufferedFile(GFile *pfile); GEXPORT ~GBufferedFile(); // ** Overridden functions // We override all the functions that can possibly // require buffer mode switch, flush, or extra calculations GEXPORT virtual SInt Tell(); GEXPORT virtual SInt64 LTell(); GEXPORT virtual SInt GetLength(); GEXPORT virtual SInt64 LGetLength(); // GEXPORT virtual bool Stat(GFileStats *pfs); GEXPORT virtual SInt Write(const UByte *pbufer, SInt numBytes); GEXPORT virtual SInt Read(UByte *pbufer, SInt numBytes); GEXPORT virtual SInt SkipBytes(SInt numBytes); GEXPORT virtual SInt BytesAvailable(); GEXPORT virtual bool Flush(); GEXPORT virtual SInt Seek(SInt offset, SInt origin=Seek_Set); GEXPORT virtual SInt64 LSeek(SInt64 offset, SInt origin=Seek_Set); GEXPORT virtual bool ChangeSize(SInt newSize); GEXPORT virtual SInt CopyFromStream(GFile *pstream, SInt byteSize); GEXPORT virtual bool Close(); //GEXPORT virtual bool CloseCancel(); }; // *** File Statistics // This class contents are similar to _stat, providing // creation, modify and other information about the file. struct GFileStat { // No change or create time because they are not available on most systems SInt64 ModifyTime; SInt64 AccessTime; SInt64 FileSize; bool operator== (const GFileStat& stat) const { return ( (ModifyTime == stat.ModifyTime) && (AccessTime == stat.AccessTime) && (FileSize == stat.FileSize) ); } }; // *** System File #ifdef GFC_USE_SYSFILE // System file is created to access objects on file system directly // This file can refer directly to path. // System file can be open & closed several times; however, such use is not recommended class GSysFile : public GDelegatedFile { protected: GSysFile(const GSysFile &source) : GDelegatedFile () { GUNUSED(source); } public: // ** Constructor GEXPORT GSysFile(); // Opens a file GEXPORT GSysFile(const char *ppath, SInt flags =Open_Read, SInt mode = Mode_ReadWrite); // ** Open & management // Will fail if file's already open GEXPORT bool Open(const char *ppath, SInt flags =Open_Read, SInt mode = Mode_ReadWrite); GINLINE bool Create(const char *ppath, SInt mode = Mode_ReadWrite) { return Open(ppath, Open_ReadWrite|Open_Create, mode); } // Helper function: obtain file statistics information. In GFx, this is used to detect file changes. // Return 0 if function failed, most likely because the file doesn't exist. GEXPORT static bool GetFileStat(GFileStat* pfileStats, const char* ppath); // ** Overrides // Overridden to provide re-open support GEXPORT virtual SInt GetErrorCode(); GEXPORT virtual bool IsValid(); GEXPORT virtual bool Close(); //GEXPORT virtual bool CloseCancel(); }; #endif // GFC_USE_SYSFILE #ifdef GFC_OS_WII GFile *GFileWiiDvdOpen(const char *ppath, SInt flags=GFile::Open_Read); #elif defined(GFC_OS_PS2) GFile *GFilePS2Open(const char *ppath, SInt flags=GFile::Open_Read); #elif defined(GFC_OS_PSP) GFile *GFilePSPOpen(const char *ppath, SInt flags=GFile::Open_Read); #endif // *** Memory File class GMemoryFile : public GFile { public: const char *GetFilePath() { return FilePath; } bool IsValid() { return Valid; } bool IsWritable() { return false; } bool Flush() { return true; } SInt GetErrorCode() { return 0; } SInt Tell() { return FileIndex; } SInt64 LTell() { return (SInt64) FileIndex; } SInt GetLength() { return FileSize; } SInt64 LGetLength() { return (SInt64) FileSize; } bool Close() { Valid = false; return false; } SInt CopyFromStream(GFile *pstream, SInt byteSize) { GUNUSED2(pstream, byteSize); return 0; } SInt Write(const UByte *pbuffer, SInt numBytes) { GUNUSED2(pbuffer, numBytes); return 0; } SInt Read(UByte *pbufer, SInt numBytes) { if (FileIndex + numBytes > FileSize) { numBytes = FileSize - FileIndex; } if (numBytes > 0) { ::memcpy (pbufer, &FileData [FileIndex], numBytes); FileIndex += numBytes; } return numBytes; } SInt SkipBytes(SInt numBytes) { if (FileIndex + numBytes > FileSize) { numBytes = FileSize - FileIndex; } FileIndex += numBytes; return numBytes; } SInt BytesAvailable() { return (FileSize - FileIndex); } SInt Seek(SInt offset, SInt origin = Seek_Set) { switch (origin) { case Seek_Set : FileIndex = offset; break; case Seek_Cur : FileIndex += offset; break; case Seek_End : FileIndex = FileSize - offset; break; } return FileIndex; } SInt64 LSeek(SInt64 offset, SInt origin = Seek_Set) { return (SInt64) Seek((SInt) offset, origin); } bool ChangeSize(SInt newSize) { FileSize = newSize; return true; } public: GMemoryFile (const char *pFileName, const UByte *pBuffer, SInt buffSize) { FilePath = pFileName; FileData = pBuffer; FileSize = buffSize; FileIndex = 0; Valid = (pFileName && pBuffer && buffSize > 0) ? true : false; } private: const char *FilePath; const UByte *FileData; SInt FileSize; SInt FileIndex; bool Valid; }; #endif