#include #include #include #include "parser.h" #include "parser_pp.h" using namespace std; const char *htmlcxx::CSS::IE_CSS = DEFAULT_CSS; namespace htmlcxx { namespace CSS { Parser::Selector::Selector() : mPsClass(NONE_CLASS), mPsElement(NONE_ELEMENT) {} Parser::Selector::Selector(const string& e, const string& i, const string& c, const PseudoClass& pc, const PseudoElement& pe) { setElement(e); setId(i); setClass(c); setPseudoClass(pc); setPseudoElement(pe); } void Parser::Selector::setElement(const string& str) { mElement = str; transform(mElement.begin(), mElement.end(), mElement.begin(), ::tolower); } void Parser::Selector::setId(const string& str) { mId = str; transform(mId.begin(), mId.end(), mId.begin(), ::tolower); } void Parser::Selector::setClass(const string& str) { mEClass = str; transform(mEClass.begin(), mEClass.end(), mEClass.begin(), ::tolower); } void Parser::Selector::setPseudoClass(enum PseudoClass p) { mPsClass = p; } void Parser::Selector::setPseudoElement(enum PseudoElement p) { mPsElement = p; } bool Parser::Selector::match(const Selector& s) const { if (mElement.empty()) return false; if (s.mElement.empty()) { Selector s2(s); s2.mElement = mElement; return *this == s2; } else { return *this == s; } } bool Parser::Selector::operator==(const Selector& s) const { if (mElement == s.mElement && mId == s.mId && mEClass == s.mEClass && mPsClass == s.mPsClass && mPsElement == s.mPsElement) { return true; } else { return false; } } bool Parser::Selector::operator<(const Selector& s) const { int my_count = 0, count = 0; if (!mElement.empty()) ++my_count; if (!mId.empty()) ++my_count; if (!mEClass.empty()) ++my_count; if (mPsClass != NONE_CLASS) ++my_count; if (mPsElement != NONE_ELEMENT) ++my_count; if (!s.mElement.empty()) ++count; if (!s.mId.empty()) ++count; if (!s.mEClass.empty()) ++count; if (s.mPsClass != NONE_CLASS) ++count; if (s.mPsElement != NONE_ELEMENT) ++count; if (my_count == count) { if (mElement == s.mElement) { if (mId == s.mId) { if (mEClass == s.mEClass) { if (mPsClass == s.mPsClass) { if (mPsElement == s.mPsElement) { return false; } else { return mPsElement < s.mPsElement; } } else { return mPsClass < s.mPsClass; } } else { return mEClass < s.mEClass; } } else { return mId < s.mId; } } else { return mElement > s.mElement; } } else { return count > my_count; } } bool Parser::match(const vector& selector, const vector& path) { if (path.empty()) return false; if (selector.empty()) return false; const Selector& element = path[0]; // cout << "Trying: " << path[0] << " against " << selector[0] << endl; if (element.match(selector[0])) { // cout << "Matched" << endl; vector::const_iterator m, n; m = path.begin() + 1; n = selector.begin() + 1; while (n != selector.end()) { // cout << "Trying: " << *m << " against " << *n << endl; while (m != path.end() && !m->match(*n)) ++m; if (m == path.end()) break; else ++n, ++m; } if (n == selector.end()) return true; } return false; } map Parser::getAttributes(const vector& path) const { map ret; for (RuleSet::const_iterator i = mRuleSets.begin(); i != mRuleSets.end(); ++i) { if (match(i->first, path)) { map::const_iterator j; for (j = i->second.begin(); j != i->second.end(); ++j) { ret[j->first] = j->second.mVal; } } } return ret; } void Parser::merge(const Parser& p) { RuleSet::const_iterator i; for (i = p.mRuleSets.begin(); i != p.mRuleSets.end(); ++i) { map& mine = mRuleSets[i->first]; const map& their = i->second; map::const_iterator j; for (j = their.begin(); j != their.end(); ++j) { mine[j->first] = j->second; } } } bool Parser::parse(const string& css) { return parse(css.c_str(), css.length()); } bool Parser::parse(const char *buf, int buf_len) { struct selector_list_t *css, *pos; css = css_parse(buf, buf_len); pos = css; while (pos != NULL) { struct selector_t *sel = pos->selector; vector p; while (sel != NULL) { Selector s; if (sel->element_name) { s.setElement(sel->element_name); } if (sel->id) { s.setId(sel->id); } if (sel->e_class) { s.setClass(sel->e_class); } switch (sel->pseudo_class) { case PS_CLASS_NONE: s.setPseudoClass(NONE_CLASS); break; case PS_CLASS_LINK: s.setPseudoClass(LINK); break; case PS_CLASS_VISITED: s.setPseudoClass(VISITED); break; case PS_CLASS_ACTIVE: s.setPseudoClass(ACTIVE); break; } switch (sel->pseudo_element) { case PS_ELEMENT_NONE: s.setPseudoElement(NONE_ELEMENT); break; case PS_ELEMENT_FIRST_LETTER: s.setPseudoElement(FIRST_LETTER); break; case PS_ELEMENT_FIRST_LINE: s.setPseudoElement(FIRST_LINE); break; } p.push_back(s); sel = sel->next; } reverse(p.begin(), p.end()); map& m = mRuleSets[p]; struct property_t *prop = pos->selector->property; while (prop != NULL) { m[prop->name] = Attribute(prop->val, prop->important); prop = prop->next; } pos = pos->next; } free_rulesets(css); return true; } ostream& operator<<(ostream& out, const map& s) { map::const_iterator i; for (i = s.begin(); i != s.end(); ++i) { if (i != s.begin()) out << " "; out << i->first << ": " << i->second.mVal; if (i->second.mImportant) out << " !important"; out << ";"; } return out; } string psc2str(const enum Parser::PseudoClass& s) { switch (s) { case Parser::LINK: return ":link"; break; case Parser::VISITED: return ":visited"; break; case Parser::ACTIVE: return ":active"; break; default: return ""; } } string pse2str(const enum Parser::PseudoElement& s) { switch (s) { case Parser::FIRST_LETTER: return ":first_letter"; break; case Parser::FIRST_LINE: return ":first_line"; break; default: return ""; break; } } ostream& operator<<(ostream& out, const Parser::Selector& s) { out << s.mElement; if (!s.mId.empty()) out << "#" << s.mId; if (!s.mEClass.empty()) out << "." << s.mEClass; out << psc2str(s.mPsClass) << pse2str(s.mPsElement); return out; } ostream& operator<<(ostream &out, const CSS::Parser& p) { for (CSS::Parser::RuleSet::const_iterator i = p.mRuleSets.begin(); i != p.mRuleSets.end(); ++i) { if (i != p.mRuleSets.begin()) out << endl; copy(i->first.rbegin(), i->first.rend(), ostream_iterator(out," ")); out << "{ "; out << i->second << " }"; } return out; } }//namespace CSS }//namespace htmlcxx