cannam@3: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ cannam@3: cannam@3: #include "SimpleXMLRuleLoader.h" cannam@4: #include "Rule.h" cannam@7: #include "ImageAction.h" cannam@8: #include "ExternalProcessAction.h" cannam@12: #include "FDWriteAction.h" cannam@3: cannam@3: #include cannam@3: #include cannam@3: #include cannam@3: cannam@3: SimpleXMLRuleLoader::SimpleXMLRuleLoader() : cannam@3: m_processor(0), cannam@3: m_inPlugins(false), cannam@7: m_inRules(false), cannam@7: m_inRule(false), cannam@7: m_rule(0) cannam@3: { cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::loadFile(Processor &processor, QString fileName) cannam@3: { cannam@3: QFile file(fileName); cannam@3: cannam@3: if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { cannam@3: std::cerr << "ERROR: SimpleXMLRuleLoader::load(" cannam@3: << fileName.toStdString() cannam@3: << "): Failed to open file for reading" << std::endl; cannam@3: return false; cannam@3: } cannam@3: cannam@3: QXmlInputSource source(&file); cannam@3: return loadXml(processor, source); cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::loadXml(Processor &processor, const QString &xmlData) cannam@3: { cannam@3: QXmlInputSource source; cannam@3: source.setData(xmlData); cannam@3: return loadXml(processor, source); cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::loadXml(Processor &processor, QXmlInputSource &source) cannam@3: { cannam@3: QXmlSimpleReader reader; cannam@3: reader.setContentHandler(this); cannam@3: reader.setErrorHandler(this); cannam@3: m_processor = &processor; cannam@3: return reader.parse(source); cannam@3: m_processor = 0; cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::startElement(const QString &namespaceURI, cannam@3: const QString &localName, cannam@3: const QString &qName, cannam@3: const QXmlAttributes &atts) cannam@3: { cannam@3: QString name = qName.toLower(); cannam@3: cannam@3: if (name == "plugins") { cannam@3: if (m_inPlugins) { cannam@3: std::cerr << "ERROR: SimpleXMLRuleLoader: Nested plugins elements" << std::endl; cannam@3: return false; cannam@3: } else { cannam@3: m_inPlugins = true; cannam@3: } cannam@3: } else if (name == "plugin") { cannam@4: if (!m_inPlugins) { cannam@4: std::cerr << "ERROR: SimpleXMLRuleLoader: Plugin outside plugins element" << std::endl; cannam@4: return false; cannam@4: } cannam@3: int extIndex = atts.value("index").toInt(); cannam@4: if (m_externalInternalIndexMap.find(extIndex) != cannam@4: m_externalInternalIndexMap.end()) { cannam@4: std::cerr << "ERROR: SimpleXMLRuleLoader: Duplicate plugin index " cannam@4: << extIndex << std::endl; cannam@4: return false; cannam@4: } cannam@3: QString id = atts.value("id"); cannam@3: int intIndex = m_processor->addPlugin(id); cannam@3: if (!intIndex) { cannam@3: std::cerr << "WARNING: SimpleXMLRuleLoader: Failed to load plugin \"" cannam@3: << id.toStdString() << "\"" << std::endl; cannam@3: } else { cannam@3: std::cerr << "INFO: SimpleXMLRuleLoader: Successfully loaded plugin \"" << id.toStdString() << "\" (internal index " << intIndex << ", external index " << extIndex << ")" << std::endl; cannam@3: m_externalInternalIndexMap[extIndex] = intIndex; cannam@3: } cannam@3: } else if (name == "rules") { cannam@3: if (m_inRules) { cannam@3: std::cerr << "ERROR: SimpleXMLRuleLoader: Nested rules elements" << std::endl; cannam@3: return false; cannam@3: } else { cannam@3: m_inRules = true; cannam@3: } cannam@4: } else if (name == "outputrule") { cannam@4: cannam@4: if (!m_inRules) { cannam@4: std::cerr << "ERROR: SimpleXMLRuleLoader: Rule outside rules element" << std::endl; cannam@4: return false; cannam@4: } cannam@7: if (m_inRule) { cannam@7: std::cerr << "ERROR: SimpleXMLRuleLoader: Nested output rules" << std::endl; cannam@7: return false; cannam@7: } cannam@4: cannam@7: m_inRule = true; cannam@7: m_rule = new Rule(); cannam@7: cannam@7: } else if (name == "condition") { cannam@7: cannam@7: if (!m_inRule) { cannam@7: std::cerr << "ERROR: SimpleXMLRuleLoader: Condition outside rule" << std::endl; cannam@7: return false; cannam@7: } cannam@7: cannam@4: int extIndex = atts.value("pluginIndex").toInt(); cannam@4: cannam@4: if (m_externalInternalIndexMap.find(extIndex) == cannam@4: m_externalInternalIndexMap.end()) { cannam@4: std::cerr << "ERROR: SimpleXMLRuleLoader: Unknown plugin index \"" cannam@4: << extIndex << "\" in rule" << std::endl; cannam@4: return false; cannam@4: } cannam@4: cannam@4: int intIndex = m_externalInternalIndexMap[extIndex]; cannam@4: cannam@4: bool ok = false; cannam@4: int outputNumber = atts.value("outputNumber").toInt(&ok); cannam@4: if (!ok) outputNumber = 0; cannam@4: cannam@4: QString condStr = atts.value("condition").toLower(); cannam@7: Condition::Type type(Condition::Present); cannam@4: cannam@7: if (condStr == "present") type = Condition::Present; cannam@7: else if (condStr == "equalto") type = Condition::EqualTo; cannam@7: else if (condStr == "greaterthan") type = Condition::GreaterThan; cannam@7: else if (condStr == "lessthan") type = Condition::LessThan; cannam@7: else if (condStr == "gapgreaterthan") type = Condition::GapGreaterThan; cannam@7: else if (condStr == "gaplessthan") type = Condition::GapLessThan; cannam@7: else if (condStr == "notequalto") type = Condition::NotEqualTo; cannam@7: else if (condStr == "changed") type = Condition::Changed; cannam@4: cannam@4: float arg = atts.value("argument").toFloat(&ok); cannam@4: if (!ok) arg = 0.f; cannam@4: cannam@7: Condition condition(intIndex, outputNumber, type, arg); cannam@4: cannam@7: m_rule->addCondition(condition); cannam@4: cannam@7: } else if (name == "action") { cannam@7: cannam@7: if (!m_inRule) { cannam@7: std::cerr << "ERROR: SimpleXMLRuleLoader: Action outside rule" << std::endl; cannam@7: return false; cannam@7: } cannam@7: cannam@7: QString type = atts.value("type").toLower(); cannam@7: cannam@7: if (type == "image") { cannam@13: QString image = atts.value("image"); cannam@7: Action *action = new ImageAction(image); cannam@9: m_rule->addAction(action); cannam@7: std::cerr << "INFO: SimpleXMLRuleLoader: Added image action" << std::endl; cannam@8: } else if (type == "process") { cannam@8: QString process = atts.value("process").toLower(); cannam@8: QStringList args = atts.value("arguments").split(','); cannam@8: Action *action = new ExternalProcessAction(process, args); cannam@9: m_rule->addAction(action); cannam@8: std::cerr << "INFO: SimpleXMLRuleLoader: Added external process action" << std::endl; cannam@12: } else if (type == "fdwrite") { cannam@12: QString file = atts.value("file"); cannam@12: QString data = atts.value("data"); cannam@12: bool togglePrevious = false; cannam@12: if (atts.value("togglePrevious") == "true") { cannam@12: togglePrevious = true; cannam@12: } cannam@12: Action *action = new FDWriteAction(file, data, togglePrevious); cannam@12: m_rule->addAction(action); cannam@12: std::cerr << "INFO: SimpleXMLRuleLoader: Added fd write action" << std::endl; cannam@4: } else { cannam@7: std::cerr << "WARNING: SimpleXMLRuleLoader: Unknown action type \"" cannam@7: << type.toStdString() << "\"" << std::endl; cannam@4: } cannam@4: } cannam@3: cannam@3: return true; cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::characters(const QString &s) cannam@3: { cannam@3: return true; cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::endElement(const QString &namespaceURI, cannam@3: const QString &localName, cannam@3: const QString &qName) cannam@3: { cannam@3: QString name = qName.toLower(); cannam@3: cannam@4: if (name == "plugins") { cannam@4: cannam@4: if (!m_inPlugins) { cannam@4: std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of plugins element (trying to continue)" << std::endl; cannam@4: } cannam@4: m_inPlugins = false; cannam@4: cannam@4: } else if (name == "rules") { cannam@4: cannam@4: if (!m_inRules) { cannam@4: std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of rules element (trying to continue)" << std::endl; cannam@4: } cannam@4: m_inRules = false; cannam@7: cannam@7: } else if (name == "outputrule") { cannam@7: cannam@7: if (!m_inRule) { cannam@7: std::cerr << "WARNING: SimpleXMLRuleLoader: Parse problem: unexpected end of outputRule element" << std::endl; cannam@7: return false; cannam@7: } else { cannam@7: m_processor->addRule(m_rule); cannam@7: } cannam@7: m_inRule = false; cannam@4: } cannam@7: cannam@3: return true; cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::error(const QXmlParseException &exception) cannam@3: { cannam@3: m_errorString = cannam@3: QString("ERROR: SimpleXMLRuleLoader: %1 at line %2, column %3") cannam@3: .arg(exception.message()) cannam@3: .arg(exception.lineNumber()) cannam@3: .arg(exception.columnNumber()); cannam@3: std::cerr << m_errorString.toLocal8Bit().data() << std::endl; cannam@3: return QXmlDefaultHandler::error(exception); cannam@3: } cannam@3: cannam@3: bool cannam@3: SimpleXMLRuleLoader::fatalError(const QXmlParseException &exception) cannam@3: { cannam@3: m_errorString = cannam@3: QString("FATAL ERROR: SimpleXMLRuleLoader: %1 at line %2, column %3") cannam@3: .arg(exception.message()) cannam@3: .arg(exception.lineNumber()) cannam@3: .arg(exception.columnNumber()); cannam@3: std::cerr << m_errorString.toLocal8Bit().data() << std::endl; cannam@3: return QXmlDefaultHandler::fatalError(exception); cannam@3: } cannam@3: