123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413 |
- /*=============================================================================
- 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 <QString>
- #include <stdexcept>
- /**
- * 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 ? "<END OF LINE>" : res;
- }
- private:
- //----------------------------------------------------------------------------
- void skipWhite()
- {
- for (; pos < length; pos++) {
- if (!s.at(pos).isSpace()) {
- break;
- }
- }
- }
- };
- //----------------------------------------------------------------------------
- QList<QMap<QString, QStringList> > ctkPluginFrameworkUtil::parseEntries(const QString& a, const QString& s,
- bool single, bool unique, bool single_entry)
- {
- QList<QMap<QString, QStringList> > result;
- if (!s.isNull())
- {
- AttributeTokenizer at(s);
- do {
- QList<QString> keys;
- QMap<QString, QStringList > 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::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);
- }
- }
|