/*============================================================================= Library: CTK Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics 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. =============================================================================*/ #include "ctkPluginFrameworkUtil_p.h" #include "ctkPluginFrameworkContext_p.h" #include #include /** * Class for tokenize an attribute string. */ class AttributeTokenizer { public: QString s; int length; int pos; AttributeTokenizer(const QString& input) : s(input), length(input.size()), pos(0) { } //---------------------------------------------------------------------------- QString getWord() { skipWhite(); bool backslash = false; bool quote = false; QString val; int end = 0; for (; pos < length; pos++) { bool breakLoop = false; if (backslash) { backslash = false; val.append(s.at(pos)); } else { QChar c = s.at(pos); switch (c.toAscii()) { case '"': quote = !quote; end = val.length(); break; case '\\': backslash = true; break; case ',': case ':': case ';': case '=': if (!quote) { breakLoop = true; break; } // Fall through default: val.append(c); if (!c.isSpace()) { end = val.length(); } break; } if (breakLoop) break; } } if (quote || backslash || end == 0) { return QString(); } return val.left(end); } //---------------------------------------------------------------------------- QString getKey() { if (pos >= length) { return QString(); } int save = pos; if (s.at(pos) == ';') { pos++; } QString res = getWord(); if (!res.isNull()) { if (pos == length) { return res; } QChar c = s.at(pos); if (c == ';' || c == ',') { return res; } } pos = save; return QString(); } //---------------------------------------------------------------------------- QString getParam() { if (pos == length || s.at(pos) != ';') { return QString(); } int save = pos++; QString res = getWord(); if (!res.isNull()) { if (pos < length && s.at(pos) == '=') { return res; } if (pos + 1 < length && s.at(pos) == ':' && s.at(pos+1) == '=') { return res; } } pos = save; return QString(); } //---------------------------------------------------------------------------- bool isDirective() { if (pos + 1 < length && s.at(pos) == ':') { pos++; return true; } else { return false; } } //---------------------------------------------------------------------------- QString getValue() { if (s.at(pos) != '=') { return QString(); } int save = pos++; skipWhite(); QString val = getWord(); if (val.isNull()) { pos = save; return QString(); } return val; } //---------------------------------------------------------------------------- bool getEntryEnd() { int save = pos; skipWhite(); if (pos == length) { return true; } else if (s.at(pos) == ',') { pos++; return true; } else { pos = save; return false; } } //---------------------------------------------------------------------------- bool getEnd() { int save = pos; skipWhite(); if (pos == length) { return true; } else { pos = save; return false; } } //---------------------------------------------------------------------------- QString getRest() { QString res = s.mid(pos).trimmed(); return res.length() == 0 ? "" : res; } private: //---------------------------------------------------------------------------- void skipWhite() { for (; pos < length; pos++) { if (!s.at(pos).isSpace()) { break; } } } }; //---------------------------------------------------------------------------- QList > ctkPluginFrameworkUtil::parseEntries(const QString& a, const QString& s, bool single, bool unique, bool single_entry) { QList > result; if (!s.isNull()) { AttributeTokenizer at(s); do { QList keys; QMap params; QStringList directives; QString key = at.getKey(); if (key.isNull()) { QString what = QString("Definition, ") + a + ", expected key at: " + at.getRest() + ". Key values are terminated by a ';' or a ',' and may not " + "contain ':', '='."; throw std::invalid_argument(what.toStdString()); } if (!single) { keys.push_back(key); while (!(key = at.getKey()).isNull()) { keys.push_back(key); } } QString param; while (!(param = at.getParam()).isNull()) { QStringList& old = params[param]; bool is_directive = at.isDirective(); if (!old.isEmpty() && unique) { QString what = QString("Definition, ") + a + ", duplicate " + (is_directive ? "directive" : "attribute") + ": " + param; throw std::invalid_argument(what.toStdString()); } QString value = at.getValue(); if (value.isNull()) { QString what = QString("Definition, ") + a + ", expected value at: " + at.getRest(); throw std::invalid_argument(what.toStdString()); } if (is_directive) { // NYI Handle directives and check them directives.push_back(param); } if (unique) { params.insert(param, QStringList(value)); } else { old.push_back(value); } } if (at.getEntryEnd()) { if (single) { params.insert("$key", QStringList(key)); } else { params.insert("$keys", keys); } result.push_back(params); } else { QString what = QString("Definition, ") + a + ", expected end of entry at: " + at.getRest(); throw std::invalid_argument(what.toStdString()); } if (single_entry && !at.getEnd()) { QString what = QString("Definition, ") + a + ", expected end of single entry at: " + at.getRest(); throw std::invalid_argument(what.toStdString()); } params.insert("$directives", directives); // $ is not allowed in // param names... } while (!at.getEnd()); } return result; } //---------------------------------------------------------------------------- QString ctkPluginFrameworkUtil::getFrameworkDir(ctkPluginFrameworkContext* ctx) { QString s = ctx->props[ctkPluginConstants::FRAMEWORK_STORAGE].toString(); if (s.isEmpty()) { s = QCoreApplication::applicationDirPath(); if (s.lastIndexOf("/") != s.length() -1) { s.append("/"); } QString appName = QCoreApplication::applicationName(); appName.replace(" ", ""); if (!appName.isEmpty()) { s.append(appName + "_ctkpluginfw"); } else { s.append("ctkpluginfw"); qWarning() << "Warning: Using generic plugin framework storage directory:" << s; qWarning() << "You should set an application name via QCoreApplication::setApplicationName()"; } } return s; } //---------------------------------------------------------------------------- QDir ctkPluginFrameworkUtil::getFileStorage(ctkPluginFrameworkContext* ctx, const QString& name) { // See if we have a storage directory QString fwdir = getFrameworkDir(ctx); if (fwdir.isEmpty()) { throw std::runtime_error("The framework storge directory is empty"); } QDir dir(fwdir + "/" + name); if (dir.exists()) { if (!QFileInfo(dir.absolutePath()).isDir()) { QString msg("Not a directory: "); msg.append(dir.absolutePath()); throw std::runtime_error(msg.toStdString()); } } else { if (!dir.mkpath(dir.absolutePath())) { QString msg("Cannot create directory: "); msg.append(dir.absolutePath()); throw std::runtime_error(msg.toStdString()); } } return dir; } //---------------------------------------------------------------------------- bool ctkPluginFrameworkUtil::removeDir(const QString& dirName) { bool result = true; QDir dir(dirName); if (dir.exists(dirName)) { foreach (QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) { if (info.isDir()) { result = removeDir(info.absoluteFilePath()); } else { result = QFile::remove(info.absoluteFilePath()); } if (!result) { return result; } } result = dir.rmdir(dirName); } return result; } //---------------------------------------------------------------------------- bool ctkPluginFrameworkUtil::filterMatch(const QString& filter, const QString& s) { return patSubstr(s, 0, filter, 0); } bool ctkPluginFrameworkUtil::patSubstr(const QString& s, int si, const QString& pat, int pi) { if (pat.length() - pi == 0) { return s.length() - si == 0; } if (pat[pi] == '*') { pi++; for (;;) { if (patSubstr(s, si, pat, pi)) return true; if (s.length() - si == 0) return false; si++; } } else { if (s.length() - si==0) { return false; } if(s[si] != pat[pi]) { return false; } return patSubstr(s, ++si, pat, ++pi); } }