/*- * Copyright (c) 2004 Jacques A. Vidrine * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace vuxml; BasicHandler::BasicHandler(EntryProcessor &proc) : parser_(0), proc_(proc), state_(&F_docroot) #define CLASS BasicHandler #include #include #include #include { #if defined(DEBUG_STATE) #include #include #include #include #endif } BasicHandler::~BasicHandler() { } XMLState * BasicHandler::signalError_(const char *msg) { parser_->signalError(msg); return &F_ignore; } XMLState * BasicHandler::docroot_child(const Element &element) { if (element.id() != T_vuxml) return signalError_("Not a VuXML document."); return &F_vuxml; } XMLState * BasicHandler::vuxml_child(const Element &element) { if (element.id() != T_vuln) return signalError_("Expected `vuln' element."); return &F_vuln0; } XMLState * BasicHandler::vuxml_end(const Element &element) { if (element.id() != T_vuxml) return &F_dead; return state_; } XMLState * BasicHandler::vuln0_child(const Element &element) { if (element.id() == T_topic) return &F_topic; else if (element.id() == T_cancelled) return &F_cxl; else return signalError_("Expected `topic' element."); } namespace { bool isValidVidCharacter(char c) { using std::islower; using std::isdigit; return (islower(c) || isdigit(c) || c == '-'); } } void BasicHandler::vuln0_start(const Element & __unused element, Attributes &attr) { entry_.reset(new Entry); std::string vid = killspace(attr["vid"]); if (vid.size() == 0) { signalError_("Empty or missing `vid' attribute."); return; } std::transform(vid.begin(), vid.end(), vid.begin(), ::tolower); std::string::const_iterator p = std::find_if(vid.begin(), vid.end(), std::not1(std::ptr_fun(isValidVidCharacter))); if (p != vid.end()) { signalError_("Malformed `vid' attribute."); return; } entry_->setVid(vid); } void BasicHandler::tmp_start(const Element & __unused element, Attributes & __unused attr) { tmp_ = std::string(); } void BasicHandler::tmp_characters(std::string &pcdata) { tmp_ += pcdata; } XMLState * BasicHandler::topic_end(const Element & __unused element) { entry_->setTopic(killspace(tmp_)); return &F_vuln1; } XMLState * BasicHandler::vuln1_child(const Element &element) { if (element.id() != T_affects) return signalError_("Expected `affects' element."); return &F_affects; } XMLState * BasicHandler::affects_child(const Element &element) { switch (element.id()) { case T_package: return &F_package; case T_system: return &F_system; default: return signalError_("Expected `package' or `system' element."); } } XMLState * BasicHandler::affects_end(const Element &element) { if (element.id() != T_affects) return &F_dead; return &F_vuln2; } XMLState * BasicHandler::package_child(const Element &element) { switch (element.id()) { case T_name: push_state(state_); return &F_name; case T_range: push_state(state_); return &F_range; default: return signalError_("Expected `name' or `range' element."); } } void BasicHandler::package_start(const Element & __unused element, Attributes & __unused attr) { entry_->addAffectedSet(); } XMLState * BasicHandler::package_end(const Element &element) { if (element.id() != T_package && element.id() != T_system) return &F_dead; return &F_affects; } XMLState * BasicHandler::name_end(const Element & __unused element) { entry_->addAffectedName(killspace(tmp_)); return pop_state(); } XMLState * BasicHandler::range_child(const Element &element) { switch (element.id()) { case T_gt: case T_ge: case T_lt: case T_le: case T_eq: return &F_rangeop; default: return signalError_("Expected range operator element."); } } void BasicHandler::range_start(const Element & __unused element, Attributes & __unused attr) { range_ = VersionRange(); } XMLState * BasicHandler::range_end(const Element & __unused element) { entry_->addAffectedRange(range_); return pop_state(); } XMLState * BasicHandler::rangeop_end(const Element &element) { tmp_ = killspace(tmp_); switch (element.id()) { case T_gt: range_.lo_closed = false; // fallthrough case T_ge: range_.lo = tmp_; break; case T_lt: range_.hi_closed = false; // fallthrough case T_le: range_.hi = tmp_; break; case T_eq: range_.hi = range_.lo = tmp_; break; default: throw except("Internal error: rangeop_end, bad element"); } return &F_range; } namespace { class appendAttribute : public std::unary_function &> { private: std::string &s_; public: appendAttribute(std::string &s) : s_(s) {} void operator()(std::pair &item) { s_ += ' '; s_ += item.first; s_ += "=\""; s_ += xmlescape(item.second); s_ += '"'; } }; } XMLState * BasicHandler::vuln2_child(const Element &element) { if (element.id() != T_description) return signalError_("Expected `description' element."); return &F_description; } void BasicHandler::description_start(const Element &element, Attributes &attr) { std::string s; switch (element.id()) { case T_description: break; case T_XHTML_BODY: break; case T_XHTML: s += '<'; s += element.name(); if (element.id() == T_XHTML_BODY) { s += " xmlns=\""; s += XHTML_NAMESPACE; s += '"'; } std::for_each(attr.begin(), attr.end(), appendAttribute(s)); s += '>'; entry_->appendDescription(s); break; default: signalError_("Expected element in XHTML namespace."); break; } } void BasicHandler::description_characters(std::string &pcdata) { entry_->appendDescription(xmlescape(pcdata)); } XMLState * BasicHandler::description_end(const Element &element) { if (element.id() == T_description) return &F_vuln3; else if (element.id() == T_XHTML_BODY) return state_; std::string s; s += "'; entry_->appendDescription(s); return state_; } XMLState * BasicHandler::vuln3_child(const Element &element) { if (element.id() != T_references) return signalError_("Expected `references' element."); return &F_references; } XMLState * BasicHandler::references_child(const Element &element) { switch (element.id()) { case T_url: case T_cvename: case T_freebsdsa: case T_bid: case T_certsa: case T_certvu: case T_mlist: case T_uscertsa: case T_uscertta: case T_freebsdpr: return &F_reference; default: return signalError_("Expected a reference element."); } } XMLState * BasicHandler::references_end(const Element &element) { if (element.id() != T_references) return &F_dead; return &F_vuln4; } XMLState * BasicHandler::reference_end(const Element &element) { entry_->addReference(element.name(), killspace(tmp_)); return &F_references; } XMLState * BasicHandler::vuln4_child(const Element &element) { if (element.id() != T_dates) return signalError_("Expected `dates' element."); return &F_dates0; } XMLState * BasicHandler::dates0_child(const Element &element) { if (element.id() != T_discovery) return signalError_("Expected `discovery' element."); return &F_discovery; } XMLState * BasicHandler::discovery_end(const Element & __unused element) { entry_->setDiscoveryDate(killspace(tmp_)); return &F_dates1; } XMLState * BasicHandler::dates1_child(const Element &element) { if (element.id() != T_entry) return signalError_("Expected `entry' element."); return &F_entry; } XMLState * BasicHandler::entry_end(const Element & __unused element) { entry_->setEntryDate(killspace(tmp_)); return &F_dates2; } XMLState * BasicHandler::dates2_child(const Element &element) { if (element.id() != T_modified) return signalError_("Expected `modified' element."); return &F_modified; } XMLState * BasicHandler::modified_end(const Element & __unused element) { entry_->setModifiedDate(killspace(tmp_)); return &F_dates3; } XMLState * BasicHandler::dates2_end(const Element &element) { if (element.id() != T_dates) return &F_dead; return &F_vuln5; } XMLState * BasicHandler::vuln5_end(const Element &element) { if (element.id() == T_vuln) { proc_(*entry_); return &F_vuxml; } return state_; } XMLState * BasicHandler::cxl_end(const Element &element) { return &F_vuln5; } void BasicHandler::setParser(Parser &parser) { parser_ = &parser; } XMLState * BasicHandler::top_state() { return state_stack_.top(); } XMLState * BasicHandler::pop_state() { XMLState *s = state_stack_.top(); state_stack_.pop(); return s; } void BasicHandler::push_state(XMLState *state) { state_stack_.push(state); } void BasicHandler::startElement(std::string &xmlns, std::string &name, Attributes &attr) { Element element(xmlns, name); #if defined(DEBUG_STATE) LOG << "child state=" << static_cast(state_) << '\n'; #endif state_ = state_->child(element); #if defined(DEBUG_STATE) LOG << "start state=" << static_cast(state_) << '\n'; #endif state_->start(element, attr); } void BasicHandler::characters(std::string &pcdata) { #if defined(DEBUG_STATE) LOG << "characters state=" << static_cast(state_) << '\n'; #endif state_->characters(pcdata); } void BasicHandler::endElement(std::string &xmlns, std::string &name) { Element element(xmlns, name); #if defined(DEBUG_STATE) LOG << "end state=" << static_cast(state_) << '\n'; #endif state_ = state_->end(element); } XMLState * BasicHandler::dead_child(const Element & __unused element) { return signalError_("Start of element unexpected."); } void BasicHandler::dead_start(const Element & __unused element, Attributes & __unused attr) { signalError_("Attributes unexpected."); } void BasicHandler::dead_characters(std::string & __unused pcdata) { signalError_("Character data unexpected."); } XMLState * BasicHandler::dead_end(const Element & __unused element) { return signalError_("End of element unexpected."); } XMLState * BasicHandler::ignore_child(const Element & __unused element) { return state_; } void BasicHandler::ignore_start(const Element & __unused element, Attributes & __unused attr) { } void BasicHandler::ignore_characters(std::string & __unused pcdata) { } XMLState * BasicHandler::ignore_end(const Element & __unused element) { return state_; }