# HG changeset patch # User Chris Cannam # Date 1456397590 0 # Node ID 88044af67bd1cfe3b526462c1c7d5dced163fc67 # Parent 4941e8b167c0fc1ea18910dcf1d639123ee94255 Better error reporting for transform load (from RDF and XML) diff -r 4941e8b167c0 -r 88044af67bd1 .hgsubstate --- a/.hgsubstate Wed Feb 24 13:39:14 2016 +0000 +++ b/.hgsubstate Thu Feb 25 10:53:10 2016 +0000 @@ -1,4 +1,4 @@ d16f0fd6db6104d87882bc43788a3bb1b0f8c528 dataquay 55ece8862b6d3a54aad271a53f9c1615e5d3bcf8 sv-dependency-builds -1dd98a5432cf1fa6bd403c82cac21c7f6cf5585f svcore +d094598f84bd0d1c0ea880580f01b0126a90165a svcore 632d90c185ecc8655f7a85ba58dc568351449dfd vamp-plugin-sdk diff -r 4941e8b167c0 -r 88044af67bd1 runner.pro --- a/runner.pro Wed Feb 24 13:39:14 2016 +0000 +++ b/runner.pro Thu Feb 25 10:53:10 2016 +0000 @@ -80,7 +80,7 @@ LIBS = $$MY_LIBS $$LIBS -#PRE_TARGETDEPS += svcore/libsvcore.a +PRE_TARGETDEPS += svcore/libsvcore.a HEADERS += \ vamp-plugin-sdk/vamp-hostsdk/PluginBase.h \ diff -r 4941e8b167c0 -r 88044af67bd1 runner/FeatureExtractionManager.cpp --- a/runner/FeatureExtractionManager.cpp Wed Feb 24 13:39:14 2016 +0000 +++ b/runner/FeatureExtractionManager.cpp Thu Feb 25 10:53:10 2016 +0000 @@ -427,11 +427,36 @@ } bool FeatureExtractionManager::addFeatureExtractorFromFile -(QString transformXmlFile, const vector &writers) +(QString transformFile, const vector &writers) { + // We support two formats for transform description files, XML (in + // a format specific to Sonic Annotator) and RDF/Turtle. The RDF + // format can describe multiple transforms in a single file, the + // XML only one. + + // Possible errors we should report: + // + // 1. File does not exist or cannot be opened + // 2. File is ostensibly XML, but is not parseable + // 3. File is ostensibly Turtle, but is not parseable + // 4. File is XML, but contains no valid transform (e.g. is unrelated XML) + // 5. File is Turtle, but contains no valid transform(s) + // 6. File is Turtle and contains both valid and invalid transform(s) + + { + // We don't actually need to open this here yet, we just hoist + // it to the top for error reporting purposes + QFile file(transformFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + // Error case 1. File does not exist or cannot be opened + cerr << "ERROR: Failed to open transform file \"" << transformFile + << "\" for reading" << endl; + return false; + } + } + bool tryRdf = true; - - if (transformXmlFile.endsWith(".xml") || transformXmlFile.endsWith(".XML")) { + if (transformFile.endsWith(".xml") || transformFile.endsWith(".XML")) { // We don't support RDF-XML (and nor does the underlying // parser library) so skip the RDF parse if the filename // suggests XML, to avoid puking out a load of errors from @@ -439,44 +464,90 @@ tryRdf = false; } + bool tryXml = true; + if (transformFile.endsWith(".ttl") || transformFile.endsWith(".TTL") || + transformFile.endsWith(".ntriples") || transformFile.endsWith(".NTRIPLES") || + transformFile.endsWith(".n3") || transformFile.endsWith(".N3")) { + tryXml = false; + } + + QString rdfError, xmlError; + if (tryRdf) { + RDFTransformFactory factory - (QUrl::fromLocalFile(QFileInfo(transformXmlFile).absoluteFilePath()) + (QUrl::fromLocalFile(QFileInfo(transformFile).absoluteFilePath()) .toString()); ProgressPrinter printer("Parsing transforms RDF file"); std::vector transforms = factory.getTransforms(&printer); - if (!factory.isOK()) { - cerr << "WARNING: FeatureExtractionManager::addFeatureExtractorFromFile: Failed to parse transforms file: " << factory.getErrorString().toStdString() << endl; + + if (factory.isOK()) { + if (transforms.empty()) { + cerr << "ERROR: Transform file \"" << transformFile + << "\" is valid RDF but defines no transforms" << endl; + return false; + } else { + bool success = true; + for (int i = 0; i < (int)transforms.size(); ++i) { + if (!addFeatureExtractor(transforms[i], writers)) { + success = false; + } + } + return success; + } + } else { // !factory.isOK() if (factory.isRDF()) { - return false; // no point trying it as XML + cerr << "ERROR: Invalid transform RDF file \"" << transformFile + << "\": " << factory.getErrorString() << endl; + return false; } - } - if (!transforms.empty()) { - bool success = true; - for (int i = 0; i < (int)transforms.size(); ++i) { - if (!addFeatureExtractor(transforms[i], writers)) { - success = false; - } - } - return success; + + // the not-RDF case: fall through without reporting an + // error, so we try the file as XML, and if that fails, we + // print a general unparseable-file error + rdfError = factory.getErrorString(); } } - QFile file(transformXmlFile); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - cerr << "ERROR: Failed to open transform XML file \"" - << transformXmlFile.toStdString() << "\" for reading" << endl; - return false; + if (tryXml) { + + QFile file(transformFile); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + cerr << "ERROR: Failed to open transform file \"" + << transformFile.toStdString() << "\" for reading" << endl; + return false; + } + + QTextStream *qts = new QTextStream(&file); + QString qs = qts->readAll(); + delete qts; + file.close(); + + Transform transform(qs); + xmlError = transform.getErrorString(); + + if (xmlError == "") { + + if (transform.getIdentifier() == "") { + cerr << "ERROR: Transform file \"" << transformFile + << "\" is valid XML but defines no transform" << endl; + return false; + } + + return addFeatureExtractor(transform, writers); + } } - QTextStream *qts = new QTextStream(&file); - QString qs = qts->readAll(); - delete qts; - file.close(); + cerr << "ERROR: Transform file \"" << transformFile + << "\" could not be parsed" << endl; + if (rdfError != "") { + cerr << "ERROR: RDF parser reported: " << rdfError << endl; + } + if (xmlError != "") { + cerr << "ERROR: XML parser reported: " << xmlError << endl; + } - Transform transform(qs); - - return addFeatureExtractor(transform, writers); + return false; } void FeatureExtractionManager::addSource(QString audioSource, bool willMultiplex) @@ -489,7 +560,7 @@ if (m_channels == 0 || m_defaultSampleRate == 0) { - ProgressPrinter retrievalProgress("Determining default rate and channel count from first input file..."); + ProgressPrinter retrievalProgress("Retrieving first input file to determine default rate and channel count..."); FileSource source(audioSource, &retrievalProgress); if (!source.isAvailable()) { @@ -524,14 +595,14 @@ if (m_channels == 0) { m_channels = reader->getChannelCount(); cerr << "Taking default channel count of " - << reader->getChannelCount() << " from file" << endl; + << reader->getChannelCount() << " from audio file" << endl; } } if (m_defaultSampleRate == 0) { m_defaultSampleRate = reader->getNativeRate(); cerr << "Taking default sample rate of " - << reader->getNativeRate() << "Hz from file" << endl; + << reader->getNativeRate() << "Hz from audio file" << endl; cerr << "(Note: Default may be overridden by transforms)" << endl; }