[Alephmodular-devel] Good progress on CFiles!
Status: Pre-Alpha
Brought to you by:
brefin
From: Br'fin <br...@ma...> - 2003-02-11 04:31:29
|
After working up the basics of the streams and the files types. Then getting the existing API working using the classes, I expanded upon CFileDesc and actually managed to push this through the code. Things appear to be working still for saving and loading files and handling preferences and vidmaster replays. All that really remains is for me to cleanup the code a bit more so I can land this version. In the meantime, I updated my document based upon what I've actually implemented. So while I work on cleaning up the code, you can check out what it looks like. I find myself fairly happy with the way this is looking. Especially after having stumbled across clone methods to help smooth out some spots that had a lot of potential for trouble. -Jeremy Parsons Note: This document is still evolving. But is being used to guide the process and is being updated to reflect final code. Technical Specification: File Hardware Abstraction First there was portable_files.h and it was good in concept. But there was only a Macintosh implementation. And even so, there was an evident bios in the structure towards the Macintosh. Please note that this does not handle file browsing. That is in the realm of the GUI. Platform specific stuff can use the platform specific CFileDesc constructor. IE MacOS X would support CFileDesc_Carbon(FSSpec&) CFileDescFactory is a singleton class that provides access to a set of base CFileDesc locations. But in order to navigate, you can't use just create a CFileDesc(...). Instead you either use a platform specific filebrowser, or you find files programatically by asking for a CFileDesc pointed at a standard directory and then navigating through its subdirectories. Since CFileDescFactory is a singleton, you get access to it's current instance via CFileDescFactory::get_instance(). And a CFileDescFactory instance implements the following methods that all return a CFileDesc*. You are responsible for deleting the pointer when you are done with it. CFileDesc* get_application_directory() const The directory the application has been run from (Typically Current dir if command line, directory of application executable otherwise) CFileDesc* get_preferences_directory() const The location to store a user's specific settings CFileDesc* get_save_game_directory() const Default location to save games CFileDesc* get_replay_directory() const Default location to save replays. Most notably the replay that is automatically recorded whenever you play a game. CFileDesc* get_resources_directory() const Where to find other required support files. For instance theme files for an SDL build. CFileDesc represents a file or directory's location. Under Unix, this would be the full path to a file. Under Macintosh this is akin to a FSSpec. Most typically it refers to a parent directory and knows the name of its object within that directory. Most notably this has functions for creating the specified file, opening the file for reading, or opening the file for writing. The basic strategy for CFileDesc is to get an initial CFileDesc, either from a platform specific file browser or by asking CFileDescFactory for a CFileDesc to a specific directory. The CFileDesc is then malleable. You can navigate it down within subdirectories to specify the file you want. And when you are done you free your CFileDesc. A CFileDesc implements the IFailable interface for reporting errors during operations. See CError.h for more information on IFailable. A given platform specific derivative should accept platform native file specifications. (For interfacing with native file browsers) Basic properties (Not necessarily public!) Internal represenation is definitly platform dependant. For instance CFileDesc_Carbon implements the basic information using MacOS FSSpec records. The parent directory of the pointed to file or directory The name of the current file or directory The type of the current file or directory See CFileType for more about the type of the element Basic public operations include: bool clone(CFileDesc*&) Returns whether or not the cloning was successful If successful, clone creates an entire duplicate of the current CFileDesc. You are responsible for maintaining and deleting this copy. If unsuccessful check the IFailable interface for errors. (Hence why clone isn't a const method) bool exists() const Returns true if the referred to file or directory exists in the file system bool is_file() const Returns true if the referred to item exists and is a file bool is_directory() const Returns true if the referred to item exists and is a directory void get_name(std::string&) const Returns in the passed string the name of the current file or directory public file operations (These are errors if called on a directory) void set_type(const CFileType& type) Specifies the type of the file. You must call this before calling create_file() const CFileType& get_type() const Returns the current type of the file. In the future this will be expected to confer with the CFileType mechanisms to determine the type of an arbitrary file. bool create_file() Creates the file specified by the CFileDesc at that location. It will delete a file that already exists in that location. Returns true on success or false and an IFailable error state on failure. bool delete_file() Deletes the specified file from the file system. Returns true on success or false and an IFailable error state on failure. bool open_for_reading(IFileRef&) Opens the specified file for binary reading and returns an istream compatible class. You are responsible for deleting the returned class. Returns true on success or false and an IFailable error state on failure. bool open_for_writing(OFileRef&) Opens the specified file for binary writing and returns an ostream compatible class. You are responsible for deleting the returned class. Returns true on success or false and an IFailable error state on failure. open_resources_for_reading (Returns CResourceFileRef) Not currently implemented public directory operations (IDirectoryDesc) (These are errors if called on a file) Not currently implemented beyond navigate() bool navigate(const std::string& _name) On success, return true and the CFileDesc points to the new element. On failure, for instance drilling down into multiple undefined directories, navigate returns false, sets an IFailable error state and doesn't change the location of the CFileDesc. Note that it should be ok to specify one level of non-existing element so you can then create it. Protected operations bool iofname(std::string&) Returns an if/ofstream compatible path for the file. Used internally for initially opening the files for reading/writing. This means a platform specific class has less to do, only needing to convert the platform specific representation into a path type string. swap(CFileDesc) Safe Save support Swaps contents of two file descs These should be two files on the same device and use OS file swapping calls where available Not currently implemented. Navigation of CFileDescs would include methods to work based on the CFileDesc ala CFileDesc GetParent() to get the parent of this directory and CFileDesc GetNamedChild(itemname) GetTemporaryCopy Returns a CFileDesc to a temporary file in the same directory as the current CFileDesc, the name should be unique and the file shouldn't already exist. IFileRef represents an open file for reading. Specifically it is a typedef std::istream* IFileRef COFileRef represents an open file for writing. Specifically it is a typedef std::ostream* OFileRef To close files of this sort, you should explicitly delete the class. Save saving is not yet implemented. A note on saving files. When you open a file for writing the following transpires. You are given an ofstream derived object that is internally associated with the current CFileDesc and a temporary one. The temporary CFileDesc is guaranteed to be in the same directory as CFileDesc and to have a unique name. Upon proper closure of the stream the temporary file the following happens. If CFileDesc exists, than the temporary file is swapped with it and the original content of CFileDesc discard (swap occurs, then temporary file deleted) Otherwise the temporary file is renamed to the name in CFileDesc. ofstream.close() isn't virtual, so we can't override it, but it does have a virtual destructor. Within there we can do: this->close() if(this->is_good()) // The closing of the file didn't raise any errors { curFileDesc.swap(tempFileDesc); tempFileDesc.delete(); } CResourceFileRef represents an open resource file. We will support reading of resources. We will support a way of reading in resources from a data file. We won't generally support saving of resource files. (Any new file formats heading forward should be flat files or bundles (multiple files in a strict directory hierarchy) Resource files are not yet implemented. CFileType represents the type of a file CFileDesc is our friend and can use the protected virtual methods for getting type_code, type_extension and the type checking. There are three special cases of CFileType CDirectoryType a plain old directories (a directory that was a bundle would be handled seperately) CUnknownType If we examine a CFileDesc and it matches no known types, then CUnknownType is the tye used for the file CFamilyType A hierarchy of types for checking a file's type against. For instance, checking if a given specific type is a map or a M2 file. CCreatorFamilyType is a subset of the family type which also knows its creator code. All others descend from CTypedFileType which has basic operations A file type generally encapsulates the following: The file's creator: ala M2, Minf, or AlephModular) The four character code associated with a file on MAcintosh: aka TEXT The extension associated with the file on other systems: aka txt (as in README.txt) a test() method for checking whether or not a CFileDesc matches the current type a test_contents() method for checking within a file for a type match Testing CDirectoryType against file decriptions only matches type with directories Testing CUnknownType against file descriptions is always false. It is only assigned when either nothing is known, or everything else fails to match. Testing CFamilyType against file descriptions always fails. Testing CTypedFileTypes against a file succeeds if type and creator match or if the extension matches. Subclasses may perform more complicated tests, such as inspecting the file's contents (by implementing test_contents(FileDesc*)) test_contents() is seperate from test() so that if a first pass by inspecting via test fails to locate a file's type, then that file can be checked over the available types by performing the content tests of the types. FileTypes support a matches(FileType) method to tell if the type who's matching method is being called considers itself to be the type of the argument, or a logical element of that type's set. CMarathon2MapType.matches(CAlephModularMapType) == false CMarathon2MapType.matches(CMarathon2MapType) == true CMarathon2MapType.matches(CMapFamily) == true CMarathon2MapType.matches(CMarathon2Family) == true I admit, on typing I'm trying to figure out if the class is C<whatever>Type and is essentially a singleton. What is a decent way of referring to one specific type or another? A CFileTypeFactory that offers GetTypeFor("<whatever>") with a hash or dictionary within? Here are the existing families Creators: CAlephModularFamilyType CMarathon2FamilyType Files: CImagesFamilyType CMapFamilyType CMusicFamilyType CPhysicsFamilyType CPreferencesFamilyType CReplayFamilyType CSaveGameFamilyType CShapesFamilyType CSoundsFamilyType Actual File Types: CAlephModularPreferencesFileType CAlephModularReplayFileType CAlephModularSaveGameFileType CMarathon2ImagesFileType CMarathon2MapFileType CMarathon2PhysicsFileType Cmarathon2ReplayFileType CMarathon2ShapesFileType CMarathon2SoundsFileType File organization details: Initial work will proceed in portable_files.h, files_macintosh.cpp, Support/CFiles.cpp, Support/CFileTypes.h, Support/CFileTypes.cpp, and CFileDesc_Carbon.h. At a later point in time when files are reorganized, this will become Support/CFiles.h (was portable_files.h) Support/CFiles.cpp Support/Carbon/CFileDesc_Carbon.h Support/Carbon/CFileDesc_Carbon.cpp (was files_macintosh.cpp) Support/CFileTypes.h Support/CFileTypes.cpp |