// AVPlist.h: OS X-Style Property List and Its XML Parser #ifndef __AVPlist_h #define __AVPlist_h #include #include #include #include #include using namespace std; class PlistNode { public: PlistNode(const char *n, PlistNode *p=NULL) { _name = string(n); _parent = p; } PlistNode(string n="", PlistNode *p=NULL) { _name=n; _parent = p; } ~PlistNode() {} PlistNode(const PlistNode& n) { _name=n._name; _text=n._text; children=n.children; _parent=n._parent; } const PlistNode& operator=(const PlistNode& n) { _name=n._name; _text=n._text; children=n.children; _parent=n._parent; return *this; } PlistNode* addChild(const PlistNode& n) { children.push_back(n); children[children.size()-1]._parent = this; return &(children[children.size()-1]); } string str(int tab=0, string xmlhead="") { stringstream s; // if it's the parent node, tab-1 so that the first node has no indent int t = _parent ? tab: tab-1; if (children.size()) { if (!_parent) { s << xmlhead; } else { spacer(s, t); startTag(s); } for (int i=0; i\n"; } } else { if (!_parent) { s << xmlhead; } else { spacer(s, t); if (_text.length()) { s << "<" << _name << ">" << _text << "\n"; } else { startTag(s); } } } return s.str(); } PlistNode *parent() { return _parent; } const string &text() { return _text; } void setText(const string &t) { _text = t; } const string &name() { return _name; } void setName(const string &n) { _name = n; } void setParent(PlistNode *p) { _parent = p; } void addText(char c) { _text += string(1, c); } void addAttr(const char *k, const char *v) { pair p; p.first = string(k); p.second = string(v); attributes.push_back(p); } PlistNode *findChildByKey(const char *key) { return findChildByKey(string(key)); } PlistNode *findChildByKey(const string& key) { size_t i = 0; for (i=0 ; i < children.size(); i++) { if (children[i].name() == "key" && children[i].text() == key) break; } if (i+1 < children.size()) return &(children[i+1]); return NULL; } void setChildByKey(const char *key, const PlistNode& n) { setChildByKey(string(key), n); } void setChildByKey(const string& key, const PlistNode& n) { PlistNode *v; if (v=findChildByKey(key)) { *v = n; } else { PlistNode k("key", this); k.setText(key); addChild(k); addChild(n); } } PlistNode *childAtIndex(size_t i) { if (i >= children.size()) return NULL; return &(children[i]); } protected: void startTag(stringstream &s) { s << "<" << _name; if (attributes.size()) { for (int i=0; i\n"; } void spacer(stringstream &s, int tab) { for (int i=0; i children; vector > attributes; PlistNode *_parent; }; class PlistParser { public: // silently ignores every error PlistNode& parse(const char *buf, int size=-1) { int s = (size < 0) ? strlen(buf) : size; parent = PlistNode(); current = &parent; XML_Parser parser = XML_ParserCreate("UTF-8"); XML_SetElementHandler(parser, PlistParser::start, PlistParser::end); XML_SetCharacterDataHandler(parser, PlistParser::chardata); XML_SetUserData(parser, this); XML_Parse(parser, buf, s, 1); XML_ParserFree(parser); return parent; } protected: PlistNode parent; PlistNode *current; static void start(void *data, const char *el, const char **attr) { PlistParser *pr=(PlistParser*)data; PlistNode n(string(el), pr->current); pr->current = pr->current->addChild(n); for (int i = 0; attr[i]; i += 2) pr->current->addAttr(attr[i], attr[i+1]); } static void end(void *data, const char *el) { PlistParser *pr=(PlistParser*)data; PlistNode *p = pr->current->parent(); if (!p) pr->current = &(pr->parent); else pr->current=p; } static void chardata(void *data, const XML_Char *s, int len) { PlistParser *pr=(PlistParser*)data; for (int i=0; icurrent->addText(s[i]); } }; #endif