// Copyright 2017 Patrick Brosi // info@patrickbrosi.de #ifndef XML_FILE_H_ #define XML_FILE_H_ #include #include #include #include #include #include namespace xml { const static size_t BUFFER_S = 16 * 1024; class XmlFileException : public std::exception { public: XmlFileException(std::string msg, std::string file, const char* p, char* buff, size_t offset) { std::stringstream ss; ss << file << " at position " << (offset + (p - buff)) << ": " << msg; _msg = ss.str(); } ~XmlFileException() throw() {} virtual const char* what() const throw() { return _msg.c_str(); }; private: std::string _msg; }; enum State { NONE, IN_TAG_NAME, IN_TAG_NAME_META, IN_TAG, IN_TAG_CLOSE, IN_TAG_NAME_CLOSE, IN_TAG_TENTATIVE, IN_ATTRKEY, AFTER_ATTRKEY, AW_IN_ATTRVAL, IN_ATTRVAL_SQ, IN_ATTRVAL_DQ, IN_TEXT, IN_COMMENT_TENTATIVE, IN_COMMENT_TENTATIVE2, IN_COMMENT, IN_COMMENT_CL_TENTATIVE, IN_COMMENT_CL_TENTATIVE2, AW_CLOSING, WS_SKIP }; struct AttrCmp { bool operator()(const char* const& a, const char* const& b) const { return std::strcmp(a, b) < 0; } }; struct ParserState { ParserState() : s(NONE), hanging(0), off(0){}; std::stack tagStack; State s; size_t hanging; int64_t off; }; typedef std::map AttrMap; struct Tag { const char* name; const char* text; AttrMap attrs; }; class File { public: File(const std::string& path); ~File(); const Tag& get() const; bool next(); size_t level() const; void reset(); ParserState state(); void setState(const ParserState& s); static std::string decode(const char* str); static std::string decode(const std::string& str); private: int _file; ParserState _s; ParserState _prevs; char** _buffer; char* _c; int64_t _lastBytes; const char* _tmp; const char* _tmp2; size_t _which; std::string _path; int64_t _totReadBef; int64_t _lastNewData; Tag _ret; static size_t utf8(size_t cp, char* out); const char* emptyStr = ""; }; } #endif // XML_FILE_H_