#ifndef FILEDAT_HPP #define FILEDAT_HPP #include #include #include #include #include #include #include /*! @file filedat.hpp * @brief Storing and reading data * * Easily organize data in a JSON-like file format */ namespace ztd { class filedat; class chunkdat; class format_error; //! @brief Abstract data storing object /*! Used for inheritance and type classing. Not for external use */ class chunk_abstract { public: //! @brief Type of data /*! Values: none , string , map , list */ enum typeEnum { none, string, map, list}; //! @brief Get type of chunk typeEnum type(); chunk_abstract(); virtual ~chunk_abstract(); protected: typeEnum m_type; }; //! @brief String data storing class /*! Back-end of string data chunk. Not for external use */ class chunk_string : public chunk_abstract { public: //! @brief String data std::string val; chunk_string(); virtual ~chunk_string(); }; //! @brief Map data storing class /*! Back-end of map data chunk. Not for external use */ class chunk_map : public chunk_abstract { public: //! @brief Mapped data std::map values; chunk_map(); virtual ~chunk_map(); }; //! @brief String data storing class /*! Back-end of list data chunk. Not for external use */ class chunk_list : public chunk_abstract { public: //! @brief List data std::vector list; chunk_list(); virtual ~chunk_list(); }; //! @brief Chunk data object /*! Object containing a chunk of data\n Either string, map, or list */ class chunkdat { public: //! @brief Constructor chunkdat(); //! @brief Constructor with initial value chunkdat(const char* in); //! @brief Constructor with initial value chunkdat(std::string const& in); chunkdat(const char* in, const int in_size, int offset=0, filedat* data=nullptr); //! @brief Constructor with copy chunkdat(chunkdat const& in); //dtor ~chunkdat(); //! @brief Clear contents void clear(); //! @brief Type of the stored data chunk_abstract::typeEnum type() const; //! @brief get pointer to chunk_abstract inline chunk_abstract* getp() const { return m_achunk; } //! @brief Size of list. -1 if not a list int listSize() const; //! @brief Get pointer to parent (debug) inline filedat* parent() const { return m_parent; } //! @brief Get data offset (debug) inline int offset() const { return m_offset; } //! @brief Set data /*! @param in C string data @param in_size Size of the string data @param offset Used for debugging @param data Used for debugging */ void set(const char* in, const int in_size, int offset=0, filedat* parent=nullptr); //! @brief Set data /*! @param in String data @param offset Used for debugging @param data Used for debuggingy */ inline void set(std::string const& in, int offset=0, filedat* data=nullptr) { this->set(in.c_str(), in.size(), offset, data); } //! @brief Copy chunk's data inline void set(chunkdat const& in) { this->set(in.strval(), in.offset(), in.parent()); } // TODO //! @brief Get string value of data /*! @param alignment Number of initial aligners @param aligner String to use for aligning sub-chunks @return String value of the whole chunk data */ std::string strval(unsigned int alignment=0, std::string const& aligner="\t") const; void addToMap(std::string const& name, chunkdat const& val); void addToMap(std::vector> const& vec); void addToList(chunkdat const& val); void addToList(std::vector const& vec); //! @brief Add keyed data to map chunk /*! @param name Key of the data @param val Data */ inline void add(std::string const& name, chunkdat const& val) { addToMap(name, val); } //! @brief Add multiple keyed data to map chunk /*! @param vec Vector of pairs of keys and data */ inline void add(std::vector> const& vec) { addToMap(vec); } //! @brief Append data to end of list /*! @param val Data to add */ inline void add(chunkdat const& val) { addToList(val); } //! @brief Append list of data to end of list /*! @param vec Vector of data to add */ inline void add(std::vector const& vec) { addToList(vec); } //! @brief Concatenate chunks of data /*! Effective only if the two chunks are of the same type\n Map: combines two maps into a single map\n List: combines into a single list\n String: Concatenate strings */ void concatenate(chunkdat const& chk); void erase(const std::string& key); void erase(const unsigned int index); //! @brief Create a copy of the chunk inline chunkdat copy() const { return chunkdat(*this); } //! @brief Create a pointed copy of the chunk inline chunkdat* pcopy() const { return new chunkdat(*this); } //! @brief Reference to subchunk of map /*! Throws format_error exception when operation fails @param a Key of the subchunk data @return Reference to the subchunk in question */ chunkdat& subChunkRef(std::string const& a) const; //! @brief Reference to subchunk of list /*! Throws format_error exception when operation fails @param a Position of subchunk data in list @return Reference to the subchunk in question */ chunkdat& subChunkRef(const unsigned int a) const; //! @brief Pointer to subchunk of map /*! @param a Key of the subchunk data @return Reference to the subchunk in question\n nullptr if operation failed */ chunkdat* subChunkPtr(std::string const& a) const; //! @brief Pointer to subchunk of list /*! @param a Position of subchunk data in list @return Reference to the subchunk in question\n nullptr if operation failed */ chunkdat* subChunkPtr(const unsigned int a) const; //! @brief Reference to subchunk of map. @see subChunkRef(std::string const& a) const inline chunkdat& operator[](std::string const& a) const { return subChunkRef(a); } //! @brief Reference to subchunk of list. @see subChunkRef(const unsigned int a) const inline chunkdat& operator[](const unsigned int a) const { return subChunkRef(a); } //! @brief Set chunk data and return *this. @see set(chunkdat const& in) inline chunkdat& operator=(chunkdat const& a) { set(a); return *this; } //! @brief add and return *this. @see add(std::string const& name, chunkdat const& val) inline chunkdat& operator+=(std::pair const& a) { add(a.first, a.second); return *this; } //! @brief add and return *this. @see add(std::vector> const& vec) inline chunkdat& operator+=(std::vector> const& a) { add(a); return *this; } //! @brief add and return *this. @see add(chunkdat const& val) inline chunkdat& operator+=(chunkdat const& a) { add(a); return *this; } //! @brief add and return *this. @see add(std::vector const& vec) inline chunkdat& operator+=(std::vector const& a) { add(a); return *this; } //! @brief concatenate and return *this. @see concatenate(chunkdat const& chk) inline chunkdat& operator*=(chunkdat const& a) { concatenate(a); return *this; } //! @brief remove and return *this. @see remove(const std::string& key) inline chunkdat& operator-=(const std::string& key) { erase(key); return *this; } //! @brief remove and return *this. @see remove(const unsigned int index) inline chunkdat& operator-=(const unsigned int index) { erase(index); return *this; } //add operator+ and operator* protected: filedat* m_parent; int m_offset; chunk_abstract* m_achunk; }; //! @brief add inline chunkdat operator+(const chunkdat& a, const std::pair& b) { chunkdat ret(a); ret += b; return ret; } //! @brief add inline chunkdat operator+(const chunkdat& a, const std::vector>& b) { chunkdat ret(a); ret += b; return ret; } //! @brief add inline chunkdat operator+(const chunkdat& a, const chunkdat& b) { chunkdat ret(a); ret += b; return ret; } //! @brief add inline chunkdat operator+(const chunkdat& a, const std::vector& b) { chunkdat ret(a); ret += b; return ret; } //! @brief concatenated chunk inline chunkdat operator*(const chunkdat& a, const chunkdat& b) { chunkdat ret(a); ret *= b; return ret; } //! @brief substract inline chunkdat operator-(const chunkdat& a, const std::string& b) { chunkdat ret(a); ret -= b; return ret; } //! @brief substract inline chunkdat operator-(const chunkdat& a, const unsigned int b) { chunkdat ret(a); ret -= b; return ret; } //! @brief File data object /*! Object for importing, reading, altering and writing of file data\n */ class filedat { public: //! @brief Constructor filedat(); //! @brief Constructor with initial file path filedat(std::string const& in); virtual ~filedat(); //! @brief Get current file path inline std::string filePath() const { return m_filePath; } //! @brief Set file path inline void setFilePath(std::string const& in) { m_filePath=in; } //! @brief Test wether file can be read bool readTest() const; //! @brief Import file data /*! Throws format_error exceptions if errors are encountered while reading @param path Will set this as file path if not empty */ void import_file(const std::string& path=""); //! @brief Import data from stdin /*! Throws format_error exceptions if errors are encountered while reading */ void import_stdin(); //! @brief Import data from string /*! Throws format_error exceptions if errors are encountered while reading */ void import_string(const std::string& data); //! @brief Export data to file /*! @param path Will set this as file path if not empty @param aligner String used to align subchunks */ bool export_file(std::string const& path="", std::string const& aligner="\t") const; //! @brief Clear contents of data void clear(); //! @brief Get string value of data /*! @param aligner String used to align subchunks */ std::string strval(std::string const& aligner="\t") const; //! @brief Get reference to chunk data inline chunkdat& data() const { return *m_dataChunk; } //! @brief Get pointer to chunk data inline chunkdat* pdata() const { return m_dataChunk; } //! @brief Set data /*! Throws format_error exceptions if errors are encountered @see chunkdat::set(chunkdat const& a) */ inline void set_data(chunkdat const& in) { m_dataChunk->set(in); } //! @brief Imported data as is. Used for debugging inline const std::string& im_data() const { return m_data; } //! @brief Imported data as is. Used for debugging inline const char* im_c_data() const { return m_data.c_str(); } //! @brief Reference to subchunk //! @see chunkdat::operator[](std::string const &a) const inline chunkdat& operator[](const std::string& index) { return m_dataChunk->subChunkRef(index); } //! @brief Reference to subchunk //! @see chunkdat::operator[](const unsigned int a) const inline chunkdat& operator[](const unsigned int index) { return m_dataChunk->subChunkRef(index); } //! @brief add data and return *this //! @see chunkdat::operator+=(std::pair const& a) inline filedat& operator+=(std::pair const& a) { *m_dataChunk += a; return *this; } //! @brief add data and return *this //! @see chunkdat::operator+=(std::vector> const& a) inline filedat& operator+=(std::vector> const& a) { *m_dataChunk += a; return *this; } //! @brief add data and return *this //! @see chunkdat::operator+=(chunkdat const& a) inline filedat& operator+=(chunkdat const& a) { *m_dataChunk += a; return *this; } //! @brief add() and return *this //! @see chunkdat::operator+=(std::vector const& a) inline filedat& operator+=(std::vector const& a) { *m_dataChunk += a; return *this; } //! @brief set_data() and return *this //! @see chunkdat::operator+=(std::vector const& a) inline filedat& operator=(chunkdat const& a) { set_data(a); return *this; } //! @brief Is a read char static bool isRead(char in); private: //functions void generateChunk(); //attributes std::string m_filePath; std::string m_data; chunkdat* m_dataChunk; }; //! @brief Data format exception /*! Thrown when errors are encountered when manipulating data chunks */ class format_error : public std::exception { public: //! @brief Conctructor inline format_error(const std::string& what, const std::string& origin, const std::string& data, int where) { desc=what; index=where; filename=origin; sdat=data; } //! @brief Error message inline const char * what () const throw () {return desc.c_str();} //! @brief Origin of the data, name of imported file, otherwise empty if generated inline const char * origin() const throw () {return filename.c_str();} //! @brief Data causing the exception inline const char * data() const throw () {return sdat.c_str();} //! @brief Where the error is located in the data inline const int where () const throw () {return index;} private: std::string desc; int index; std::string filename; std::string sdat; }; inline std::ostream& operator<<(std::ostream& stream, chunkdat const& a) { return stream << a.strval(); } inline std::ostream& operator<<(std::ostream& stream, filedat const& a) { return stream << a.strval(); } void printErrorIndex(const char* in, const int index, const std::string& message, const std::string& origin); //! @brief Print exception to console /*! If origin is known, displays location and discriminating line\n If origin is unknown, displays whole data up to discriminating line */ void printFormatException(format_error& exc); } #endif //FILEDAT_HPP