svcore  1.9
PluginXml.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "PluginXml.h"
00017 
00018 #include <QRegExp>
00019 #include <QXmlAttributes>
00020 
00021 #include <QDomDocument>
00022 #include <QDomElement>
00023 #include <QDomNamedNodeMap>
00024 #include <QDomAttr>
00025 
00026 #include <QTextStream>
00027 
00028 #include <vamp-hostsdk/PluginBase.h>
00029 #include "RealTimePluginInstance.h"
00030 
00031 #include <iostream>
00032 
00033 PluginXml::PluginXml(Vamp::PluginBase *plugin) :
00034     m_plugin(plugin)
00035 {
00036 }
00037 
00038 PluginXml::~PluginXml() { }
00039 
00040 QString
00041 PluginXml::encodeConfigurationChars(QString text)
00042 {
00043     QString rv(text);
00044     rv.replace(";", "[[SEMICOLON]]");
00045     rv.replace("=", "[[EQUALS]]");
00046     return rv;
00047 }
00048 
00049 QString
00050 PluginXml::decodeConfigurationChars(QString text)
00051 {
00052     QString rv(text);
00053     rv.replace("[[SEMICOLON]]", ";");
00054     rv.replace("[[EQUALS]]", "=");
00055     return rv;
00056 }
00057     
00058 void
00059 PluginXml::toXml(QTextStream &stream,
00060                  QString indent, QString extraAttributes) const
00061 {
00062     stream << indent;
00063 
00064     stream << QString("<plugin identifier=\"%1\" name=\"%2\" description=\"%3\" maker=\"%4\" version=\"%5\" copyright=\"%6\" %7 ")
00065         .arg(encodeEntities(QString(m_plugin->getIdentifier().c_str())))
00066         .arg(encodeEntities(QString(m_plugin->getName().c_str())))
00067         .arg(encodeEntities(QString(m_plugin->getDescription().c_str())))
00068         .arg(encodeEntities(QString(m_plugin->getMaker().c_str())))
00069         .arg(m_plugin->getPluginVersion())
00070         .arg(encodeEntities(QString(m_plugin->getCopyright().c_str())))
00071         .arg(extraAttributes);
00072 
00073     if (!m_plugin->getPrograms().empty()) {
00074         stream << QString("program=\"%1\" ")
00075             .arg(encodeEntities(m_plugin->getCurrentProgram().c_str()));
00076     }
00077 
00078     Vamp::PluginBase::ParameterList parameters =
00079         m_plugin->getParameterDescriptors();
00080 
00081     for (Vamp::PluginBase::ParameterList::const_iterator i = parameters.begin();
00082          i != parameters.end(); ++i) {
00083 
00084 //        SVDEBUG << "PluginXml::toXml: parameter name \""
00085 //                  << i->name.c_str() << "\" has value "
00086 //                  << m_plugin->getParameter(i->name) << endl;
00087 
00088         stream << QString("param-%1=\"%2\" ")
00089             .arg(stripInvalidParameterNameCharacters(QString(i->identifier.c_str())))
00090             .arg(m_plugin->getParameter(i->identifier));
00091     }
00092 
00093     RealTimePluginInstance *rtpi =
00094         dynamic_cast<RealTimePluginInstance *>(m_plugin);
00095     if (rtpi) {
00096         std::map<std::string, std::string> configurePairs =
00097             rtpi->getConfigurePairs();
00098         QString config;
00099         for (std::map<std::string, std::string>::iterator i = configurePairs.begin();
00100              i != configurePairs.end(); ++i) {
00101             QString key = i->first.c_str();
00102             QString value = i->second.c_str();
00103             key = encodeConfigurationChars(key);
00104             value = encodeConfigurationChars(value);
00105             if (config != "") config += ";";
00106             config += QString("%1=%2").arg(key).arg(value);
00107         }
00108         if (config != "") {
00109             stream << QString("configuration=\"%1\" ")
00110                 .arg(encodeEntities(config));
00111         }
00112     }
00113 
00114     stream << "/>\n";
00115 }
00116 
00117 #define CHECK_ATTRIBUTE(ATTRIBUTE, ACCESSOR) \
00118     QString ATTRIBUTE = attrs.value(#ATTRIBUTE); \
00119     if (ATTRIBUTE != "" && ATTRIBUTE != ACCESSOR().c_str()) { \
00120         cerr << "WARNING: PluginXml::setParameters: Plugin " \
00121                   << #ATTRIBUTE << " does not match (attributes have \"" \
00122                   << ATTRIBUTE << "\", my " \
00123                   << #ATTRIBUTE << " is \"" << ACCESSOR() << "\")" << endl; \
00124     }
00125 
00126 void
00127 PluginXml::setParameters(const QXmlAttributes &attrs)
00128 {
00129     CHECK_ATTRIBUTE(identifier, m_plugin->getIdentifier);
00130     CHECK_ATTRIBUTE(name, m_plugin->getName);
00131     CHECK_ATTRIBUTE(description, m_plugin->getDescription);
00132     CHECK_ATTRIBUTE(maker, m_plugin->getMaker);
00133     CHECK_ATTRIBUTE(copyright, m_plugin->getCopyright);
00134 
00135     bool ok;
00136     int version = attrs.value("version").trimmed().toInt(&ok);
00137     if (ok && version != m_plugin->getPluginVersion()) {
00138         cerr << "WARNING: PluginXml::setParameters: Plugin version does not match (attributes have " << version << ", my version is " << m_plugin->getPluginVersion() << ")" << endl;
00139     }
00140 
00141     RealTimePluginInstance *rtpi =
00142         dynamic_cast<RealTimePluginInstance *>(m_plugin);
00143     if (rtpi) {
00144         QString config = attrs.value("configuration");
00145         if (config != "") {
00146             QStringList configList = config.split(";");
00147             for (QStringList::iterator i = configList.begin();
00148                  i != configList.end(); ++i) {
00149                 QStringList kv = i->split("=");
00150                 if (kv.count() < 2) {
00151                     cerr << "WARNING: PluginXml::setParameters: Malformed configure pair string: \"" << *i << "\"" << endl;
00152                     continue;
00153                 }
00154                 QString key(kv[0]), value(kv[1]);
00155                 key = decodeConfigurationChars(key);
00156                 value = decodeConfigurationChars(value);
00157                 rtpi->configure(key.toStdString(), value.toStdString());
00158             }
00159         }
00160     }
00161 
00162     if (!m_plugin->getPrograms().empty()) {
00163         m_plugin->selectProgram(attrs.value("program").toStdString());
00164     }
00165 
00166     Vamp::PluginBase::ParameterList parameters =
00167         m_plugin->getParameterDescriptors();
00168 
00169     for (Vamp::PluginBase::ParameterList::const_iterator i =
00170              parameters.begin(); i != parameters.end(); ++i) {
00171 
00172         QString pname = QString("param-%1")
00173             .arg(stripInvalidParameterNameCharacters
00174                  (QString(i->identifier.c_str())));
00175 
00176         if (attrs.value(pname) == "") {
00177 //            SVDEBUG << "PluginXml::setParameters: no parameter \"" << i->name << "\" (attribute \"" << name << "\")" << endl;
00178             continue;
00179         }
00180 
00181         bool ok;
00182         float value = attrs.value(pname).trimmed().toFloat(&ok);
00183         if (ok) {
00184 //            SVDEBUG << "PluginXml::setParameters: setting parameter \""
00185 //                      << i->identifier << "\" to value " << value << endl;
00186             m_plugin->setParameter(i->identifier, value);
00187         } else {
00188             cerr << "WARNING: PluginXml::setParameters: Invalid value \"" << attrs.value(pname) << "\" for parameter \"" << i->identifier << "\" (attribute \"" << pname << "\")" << endl;
00189         }
00190     }
00191 }
00192 
00193 void
00194 PluginXml::setParametersFromXml(QString xml)
00195 {
00196     QDomDocument doc;
00197 
00198     QString error;
00199     int errorLine;
00200     int errorColumn;
00201 
00202 //    SVDEBUG << "PluginXml::setParametersFromXml: XML is \""
00203 //              << xml << "\"" << endl;
00204 
00205     if (!doc.setContent(xml, false, &error, &errorLine, &errorColumn)) {
00206         cerr << "PluginXml::setParametersFromXml: Error in parsing XML: " << error << " at line " << errorLine << ", column " << errorColumn << endl;
00207         cerr << "Input follows:" << endl;
00208         cerr << xml << endl;
00209         cerr << "Input ends." << endl;
00210         return;
00211     }
00212 
00213     QDomElement pluginElt = doc.firstChildElement("plugin");
00214     QDomNamedNodeMap attrNodes = pluginElt.attributes();
00215     QXmlAttributes attrs;
00216 
00217     for (int i = 0; i < attrNodes.length(); ++i) {
00218         QDomAttr attr = attrNodes.item(i).toAttr();
00219         if (attr.isNull()) continue;
00220 //        SVDEBUG << "PluginXml::setParametersFromXml: Adding attribute \"" << attr.name()//                  << "\" with value \"" << attr.value() << "\"" << endl;
00221         attrs.append(attr.name(), "", "", attr.value());
00222     }
00223 
00224     setParameters(attrs);
00225 }
00226 
00227 QString
00228 PluginXml::stripInvalidParameterNameCharacters(QString s) const
00229 {
00230     s.replace(QRegExp("[^a-zA-Z0-9_]*"), "");
00231     return s;
00232 }
00233