// Copyright 2017 Patrick Brosi // info@patrickbrosi.de #ifndef XML_FILE_H_ #define XML_FILE_H_ #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) : _msg(msg) {} ~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, 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; 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); }; } #endif // XML_FILE_H_