123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /*=============================================================================
- Library: CTK
- Copyright (c) 2010 Brigham and Women's Hospital (BWH) All Rights Reserved.
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
- =============================================================================*/
- // Qt includes
- #include <QDebug>
- #include <QXmlSchema>
- #include <QXmlSchemaValidator>
- #include <QAbstractMessageHandler>
- #include <QXmlStreamReader>
- // CTK includes
- #include "ctkModuleDescription.h"
- #include "ctkModuleParameterParsers_p.h"
- // STD includes
- #include <stdexcept>
- class ctkModuleDescriptionParser
- {
- public:
- ctkModuleDescriptionParser(QIODevice* device, ctkModuleDescription* md);
- ~ctkModuleDescriptionParser();
- void validate();
- void doParse();
- void handleExecutableElement();
- void handleParametersElement();
- ctkModuleParameter* handleParameterElement();
- private:
- QIODevice* const _device;
- ctkModuleDescription* _md;
- QXmlStreamReader _xmlReader;
- QHash<QString, ctkModuleParameterParser*> _paramParsers;
- };
- namespace {
- static const QString DESCRIPTION = "description";
- }
- // ----------------------------------------------------------------------------
- ctkModuleDescriptionParser::ctkModuleDescriptionParser(QIODevice* device,
- ctkModuleDescription* md)
- : _device(device), _md(md)
- {
- _paramParsers["integer"] = new ctkModuleScalarParameterParser; // type="scalarType"/>
- _paramParsers["integer-vector"] = new ctkModuleScalarVectorParameterParser; // type="scalarVectorType"/>
- _paramParsers["boolean"] = new ctkModuleParameterParser; // type="paramType"/>
- _paramParsers["float"] = new ctkModuleScalarParameterParser; // type="scalarType"/>
- _paramParsers["float-vector"] = new ctkModuleScalarVectorParameterParser; // type="scalarVectorType"/>
- _paramParsers["double"] = new ctkModuleScalarParameterParser; // type="scalarType"/>
- _paramParsers["double-vector"] = new ctkModuleScalarVectorParameterParser; // type="scalarVectorType"/>
- _paramParsers["string"] = new ctkModuleMultipleParameterParser; // type="multipleType"/>
- _paramParsers["string-vector"] = new ctkModuleParameterParser; // type="paramType"/>
- _paramParsers["point"] = new ctkModulePointParameterParser; // type="pointType"/>
- _paramParsers["region"] = new ctkModulePointParameterParser; // type="pointType"/>
- _paramParsers["string-enumeration"] = new ctkModuleEnumerationParameterParser; // type="enumerationType"/>
- _paramParsers["integer-enumeration"] = new ctkModuleEnumerationParameterParser; // type="enumerationType"/>
- _paramParsers["float-enumeration"] = new ctkModuleEnumerationParameterParser; // type="enumerationType"/>
- _paramParsers["double-enumeration"] = new ctkModuleEnumerationParameterParser; // type="enumerationType"/>
- _paramParsers["file"] = new ctkModuleFileParameterParser; // type="fileType"/>
- _paramParsers["directory"] = new ctkModuleChannelParameterParser; // type="channelType"/>
- _paramParsers["image"] = new ctkModuleImageParameterParser; // type="imageType"/>
- _paramParsers["geometry"] = new ctkModuleGeometryParameterParser; // type="geometryType"/>
- }
- // ----------------------------------------------------------------------------
- ctkModuleDescriptionParser::~ctkModuleDescriptionParser()
- {
- qDeleteAll(_paramParsers.values());
- }
- // ----------------------------------------------------------------------------
- void ctkModuleDescriptionParser::validate()
- {
- class _MessageHandler : public QAbstractMessageHandler
- {
- public:
- QString statusMessage() const { return m_description; }
- int line() const { return m_sourceLocation.line(); }
- int column() const { return m_sourceLocation.column(); }
- protected:
- virtual void handleMessage(QtMsgType type, const QString& description,
- const QUrl& identifier, const QSourceLocation& sourceLocation)
- {
- Q_UNUSED(identifier)
- m_messageType = type;
- m_sourceLocation = sourceLocation;
- QXmlStreamReader reader(description);
- m_description.clear();
- m_description.reserve(description.size());
- while(!reader.atEnd())
- {
- reader.readNext();
- switch(reader.tokenType())
- {
- case QXmlStreamReader::Characters:
- {
- m_description.append(reader.text().toString());
- continue;
- }
- case QXmlStreamReader::StartElement:
- /* Fallthrough, */
- case QXmlStreamReader::EndElement:
- /* Fallthrough, */
- case QXmlStreamReader::StartDocument:
- /* Fallthrough, */
- case QXmlStreamReader::EndDocument:
- continue;
- default:
- Q_ASSERT_X(false, Q_FUNC_INFO,
- "Unexpected node.");
- }
- }
- }
- private:
- QtMsgType m_messageType;
- QString m_description;
- QSourceLocation m_sourceLocation;
- };
- _MessageHandler errorHandler;
- QXmlSchema schema;
- schema.setMessageHandler(&errorHandler);
- schema.load(QUrl::fromLocalFile(":/ctkModuleDescription.xsd"));
- bool res = schema.isValid();
- if (!res)
- {
- QString msg("Invalid Schema at line %1, column %2: %3");
- msg = msg.arg(errorHandler.line()).arg(errorHandler.column()).arg(errorHandler.statusMessage());
- throw std::runtime_error(msg.toStdString());
- }
- QXmlSchemaValidator validator(schema);
- _device->open(QIODevice::ReadOnly);
- res = validator.validate(_device);
- _device->close();
- if (!res)
- {
- QString msg("Error validating XML description, at line %1, column %2: %3");
- throw std::runtime_error(msg.arg(errorHandler.line())
- .arg(errorHandler.column())
- .arg(errorHandler.statusMessage()).toStdString());
- }
- }
- // ----------------------------------------------------------------------------
- void ctkModuleDescriptionParser::doParse()
- {
- _xmlReader.clear();
- _xmlReader.setDevice(_device);
- _device->open(QIODevice::ReadOnly);
- _xmlReader.readNextStartElement();
- this->handleExecutableElement();
- if (_xmlReader.hasError())
- {
- QString msg("Error parsing module description at line %1, column %2: %3");
- throw std::runtime_error(msg.arg(_xmlReader.lineNumber()).arg(_xmlReader.columnNumber())
- .arg(_xmlReader.errorString()).toStdString());
- }
- }
- // ----------------------------------------------------------------------------
- void ctkModuleDescriptionParser::handleExecutableElement()
- {
- while(_xmlReader.readNextStartElement())
- {
- QStringRef name = _xmlReader.name();
- if (name.compare("category", Qt::CaseInsensitive) == 0)
- {
- _md->setCategory(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("title", Qt::CaseInsensitive) == 0)
- {
- _md->setTitle(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("version", Qt::CaseInsensitive) == 0)
- {
- _md->setVersion(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("documentation-url", Qt::CaseInsensitive) == 0)
- {
- _md->setDocumentationURL(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("license", Qt::CaseInsensitive) == 0)
- {
- _md->setLicense(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("acknowledgements", Qt::CaseInsensitive) == 0)
- {
- _md->setAcknowledgements(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("contributor", Qt::CaseInsensitive) == 0)
- {
- _md->setContributor(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("description", Qt::CaseInsensitive) == 0)
- {
- _md->setDescription(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("parameters", Qt::CaseInsensitive) == 0)
- {
- this->handleParametersElement();
- }
- else
- {
- qCritical() << "Unknown element" << name << "encountered at line"
- << _xmlReader.lineNumber() << ", column" << _xmlReader.columnNumber() << ".";
- _xmlReader.skipCurrentElement();
- }
- }
- }
- // ----------------------------------------------------------------------------
- void ctkModuleDescriptionParser::handleParametersElement()
- {
- ctkModuleParameterGroup* group = new ctkModuleParameterGroup();
- group->setAdvanced(parseBooleanAttribute(_xmlReader.attributes().value("advanced")));
- while(_xmlReader.readNextStartElement())
- {
- QStringRef name = _xmlReader.name();
- if (name.compare("label", Qt::CaseInsensitive) == 0)
- {
- group->setLabel(_xmlReader.readElementText().trimmed());
- }
- else if (name.compare("description", Qt::CaseInsensitive) == 0)
- {
- group->setDescription(_xmlReader.readElementText().trimmed());
- }
- else
- {
- ctkModuleParameter* parameter = this->handleParameterElement();
- if (parameter)
- {
- group->addParameter(parameter);
- }
- }
- }
- _md->addParameterGroup(group);
- }
- // ----------------------------------------------------------------------------
- ctkModuleParameter* ctkModuleDescriptionParser::handleParameterElement()
- {
- QString paramTag = _xmlReader.name().toString().toLower();
- ctkModuleParameterParser* paramParser = _paramParsers[paramTag];
- if (paramParser == 0)
- {
- _xmlReader.skipCurrentElement();
- qCritical() << "No parser for element" << paramTag << "available, line"
- << _xmlReader.lineNumber() << ", column" << _xmlReader.columnNumber();
- return 0;
- }
- else
- {
- ctkModuleParameter* moduleParam = paramParser->parse(_xmlReader);
- moduleParam->setTag(paramTag);
- return moduleParam;
- }
- }
- // ----------------------------------------------------------------------------
- ctkModuleDescription* ctkModuleDescription::parse(QIODevice* device)
- {
- ctkModuleDescription* moduleDescription = new ctkModuleDescription();
- ctkModuleDescriptionParser parser(device, moduleDescription);
- try
- {
- // Verify the xml is correct
- parser.validate();
- parser.doParse();
- }
- catch(...)
- {
- delete moduleDescription;
- throw;
- }
- return moduleDescription;
- }
|