/** * Copyright 2013 (c) Anna Schumaker. */ #ifndef OCARINA_CORE_FILE_H #define OCARINA_CORE_FILE_H #include #include /** * Constants defining how files can be opened. */ enum OpenMode { OPEN_READ, /**< File is open for reading. */ OPEN_WRITE, /**< File is open for writing. */ NOT_OPEN, /**< File is not open. */ }; /** * File data is store in the user's home directory according to the * XDG / freedesktop.org specification, meaning all of our data will * be stored in a subdirectory of $XDG_DATA_HOME. The actual subdirectory * changes based on what configuration values the user has set when Ocarina * is compiled. * * Config Value | Ocarina Directory * -------------|-------------------- * default | $XDG_DATA_HOME/ocarina/ * CONFIG_DEBUG | $XDG_DATA_HOME/ocarina-debug/ * CONFIG_TEST | $XDG_DATA_HOME/ocarina-test/ * * Data should be written to files using either a space or newline as a * delimiter. The beginning of every file is the current file version * followed by a newline. For example: * * 42 * * * * Data should be written to files using either a space or newline as * a delimiter. */ class File : public std::fstream { private: OpenMode _mode; /**< The file's current open mode. */ std::string _filename; /**< The file's basename. */ unsigned int _version; /**< The file's current data version. */ unsigned int _prev_version; /**< The file's on-disk data version. */ bool _open_read(); bool _open_write(); public: /** * Set up a new file object. * * @param name The name of the file. * @param version The file version of the new file. */ File(const std::string &, unsigned int); /** * Closes the file stream if it is still open. */ ~File(); /** * @return The full filepath of the file or an empty string if * the filename is not set. */ const std::string get_filepath(); /** * @return The version number of the file. If File::_mode is * ::OPEN_READ then File::_prev_version is returned. * File::_version is returned in all other cases. */ const unsigned int get_version(); /** * @return True if the file exists on disk, False otherwise. */ bool exists(); /** * Call to open a file for either reading or writing. * * When opening a file for reading: * -# Check if the file exists. * -# Open the file stream. * -# Read in File::_prev_version from the start of the file. * * When opening a file for writing: * -# Create missing directories as needed. * -# Write File::_version to the start of the file. * * @param mode How the file should be opened. * @return True if the open was successful. * @return False under the following conditions: * - File::_filename is unset * - mode is ::NOT_OPEN * - The file is already open (File::_mode != NOT_OPEN) * - The file does not exist (mode == ::OPEN_READ) */ bool open(OpenMode); /** * Close an open file and set File::mode to ::NOT_OPEN. */ void close(); /** * Read an entire line from the file and return it to the caller. * In theory a return value optimization will occur so returning * a string by value won't be a performance problem. * * @return A string containing the rest of the line. */ std::string getline(); }; #endif /* OCARINA_CORE_FILE_H */