ctkPluginFrameworkUtil.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*=============================================================================
  2. Library: CTK
  3. Copyright (c) German Cancer Research Center,
  4. Division of Medical and Biological Informatics
  5. Licensed under the Apache License, Version 2.0 (the "License");
  6. you may not use this file except in compliance with the License.
  7. You may obtain a copy of the License at
  8. http://www.apache.org/licenses/LICENSE-2.0
  9. Unless required by applicable law or agreed to in writing, software
  10. distributed under the License is distributed on an "AS IS" BASIS,
  11. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. See the License for the specific language governing permissions and
  13. limitations under the License.
  14. =============================================================================*/
  15. #include "ctkPluginFrameworkUtil_p.h"
  16. #include "ctkPluginFrameworkContext_p.h"
  17. #include <QString>
  18. #include <stdexcept>
  19. /**
  20. * Class for tokenize an attribute string.
  21. */
  22. class AttributeTokenizer {
  23. public:
  24. QString s;
  25. int length;
  26. int pos;
  27. AttributeTokenizer(const QString& input)
  28. : s(input), length(input.size()), pos(0)
  29. {
  30. }
  31. //----------------------------------------------------------------------------
  32. QString getWord()
  33. {
  34. skipWhite();
  35. bool backslash = false;
  36. bool quote = false;
  37. QString val;
  38. int end = 0;
  39. for (; pos < length; pos++)
  40. {
  41. bool breakLoop = false;
  42. if (backslash)
  43. {
  44. backslash = false;
  45. val.append(s.at(pos));
  46. }
  47. else
  48. {
  49. QChar c = s.at(pos);
  50. switch (c.toAscii())
  51. {
  52. case '"':
  53. quote = !quote;
  54. end = val.length();
  55. break;
  56. case '\\':
  57. backslash = true;
  58. break;
  59. case ',': case ':': case ';': case '=':
  60. if (!quote)
  61. {
  62. breakLoop = true;
  63. break;
  64. }
  65. // Fall through
  66. default:
  67. val.append(c);
  68. if (!c.isSpace())
  69. {
  70. end = val.length();
  71. }
  72. break;
  73. }
  74. if (breakLoop) break;
  75. }
  76. }
  77. if (quote || backslash || end == 0)
  78. {
  79. return QString();
  80. }
  81. return val.left(end);
  82. }
  83. //----------------------------------------------------------------------------
  84. QString getKey()
  85. {
  86. if (pos >= length) {
  87. return QString();
  88. }
  89. int save = pos;
  90. if (s.at(pos) == ';') {
  91. pos++;
  92. }
  93. QString res = getWord();
  94. if (!res.isNull()) {
  95. if (pos == length) {
  96. return res;
  97. }
  98. QChar c = s.at(pos);
  99. if (c == ';' || c == ',') {
  100. return res;
  101. }
  102. }
  103. pos = save;
  104. return QString();
  105. }
  106. //----------------------------------------------------------------------------
  107. QString getParam()
  108. {
  109. if (pos == length || s.at(pos) != ';') {
  110. return QString();
  111. }
  112. int save = pos++;
  113. QString res = getWord();
  114. if (!res.isNull()) {
  115. if (pos < length && s.at(pos) == '=') {
  116. return res;
  117. } if (pos + 1 < length && s.at(pos) == ':' && s.at(pos+1) == '=') {
  118. return res;
  119. }
  120. }
  121. pos = save;
  122. return QString();
  123. }
  124. //----------------------------------------------------------------------------
  125. bool isDirective()
  126. {
  127. if (pos + 1 < length && s.at(pos) == ':')
  128. {
  129. pos++;
  130. return true;
  131. }
  132. else
  133. {
  134. return false;
  135. }
  136. }
  137. //----------------------------------------------------------------------------
  138. QString getValue()
  139. {
  140. if (s.at(pos) != '=')
  141. {
  142. return QString();
  143. }
  144. int save = pos++;
  145. skipWhite();
  146. QString val = getWord();
  147. if (val.isNull())
  148. {
  149. pos = save;
  150. return QString();
  151. }
  152. return val;
  153. }
  154. //----------------------------------------------------------------------------
  155. bool getEntryEnd()
  156. {
  157. int save = pos;
  158. skipWhite();
  159. if (pos == length) {
  160. return true;
  161. } else if (s.at(pos) == ',') {
  162. pos++;
  163. return true;
  164. } else {
  165. pos = save;
  166. return false;
  167. }
  168. }
  169. //----------------------------------------------------------------------------
  170. bool getEnd()
  171. {
  172. int save = pos;
  173. skipWhite();
  174. if (pos == length) {
  175. return true;
  176. } else {
  177. pos = save;
  178. return false;
  179. }
  180. }
  181. //----------------------------------------------------------------------------
  182. QString getRest()
  183. {
  184. QString res = s.mid(pos).trimmed();
  185. return res.length() == 0 ? "<END OF LINE>" : res;
  186. }
  187. private:
  188. //----------------------------------------------------------------------------
  189. void skipWhite()
  190. {
  191. for (; pos < length; pos++) {
  192. if (!s.at(pos).isSpace()) {
  193. break;
  194. }
  195. }
  196. }
  197. };
  198. //----------------------------------------------------------------------------
  199. QList<QMap<QString, QStringList> > ctkPluginFrameworkUtil::parseEntries(const QString& a, const QString& s,
  200. bool single, bool unique, bool single_entry)
  201. {
  202. QList<QMap<QString, QStringList> > result;
  203. if (!s.isNull())
  204. {
  205. AttributeTokenizer at(s);
  206. do {
  207. QList<QString> keys;
  208. QMap<QString, QStringList > params;
  209. QStringList directives;
  210. QString key = at.getKey();
  211. if (key.isNull())
  212. {
  213. QString what = QString("Definition, ") + a + ", expected key at: " + at.getRest()
  214. + ". Key values are terminated by a ';' or a ',' and may not "
  215. + "contain ':', '='.";
  216. throw std::invalid_argument(what.toStdString());
  217. }
  218. if (!single)
  219. {
  220. keys.push_back(key);
  221. while (!(key = at.getKey()).isNull())
  222. {
  223. keys.push_back(key);
  224. }
  225. }
  226. QString param;
  227. while (!(param = at.getParam()).isNull())
  228. {
  229. QStringList& old = params[param];
  230. bool is_directive = at.isDirective();
  231. if (!old.isEmpty() && unique)
  232. {
  233. QString what = QString("Definition, ") + a + ", duplicate " +
  234. (is_directive ? "directive" : "attribute") +
  235. ": " + param;
  236. throw std::invalid_argument(what.toStdString());
  237. }
  238. QString value = at.getValue();
  239. if (value.isNull())
  240. {
  241. QString what = QString("Definition, ") + a + ", expected value at: " + at.getRest();
  242. throw std::invalid_argument(what.toStdString());
  243. }
  244. if (is_directive)
  245. {
  246. // NYI Handle directives and check them
  247. directives.push_back(param);
  248. }
  249. if (unique)
  250. {
  251. params.insert(param, QStringList(value));
  252. } else {
  253. old.push_back(value);
  254. }
  255. }
  256. if (at.getEntryEnd())
  257. {
  258. if (single)
  259. {
  260. params.insert("$key", QStringList(key));
  261. }
  262. else
  263. {
  264. params.insert("$keys", keys);
  265. }
  266. result.push_back(params);
  267. }
  268. else
  269. {
  270. QString what = QString("Definition, ") + a + ", expected end of entry at: " + at.getRest();
  271. throw std::invalid_argument(what.toStdString());
  272. }
  273. if (single_entry && !at.getEnd())
  274. {
  275. QString what = QString("Definition, ") + a + ", expected end of single entry at: " + at.getRest();
  276. throw std::invalid_argument(what.toStdString());
  277. }
  278. params.insert("$directives", directives); // $ is not allowed in
  279. // param names...
  280. } while (!at.getEnd());
  281. }
  282. return result;
  283. }
  284. //----------------------------------------------------------------------------
  285. QString ctkPluginFrameworkUtil::getFrameworkDir(ctkPluginFrameworkContext* ctx)
  286. {
  287. QString s = ctx->props[ctkPluginConstants::FRAMEWORK_STORAGE].toString();
  288. if (s.isEmpty())
  289. {
  290. s = QCoreApplication::applicationDirPath();
  291. if (s.lastIndexOf("/") != s.length() -1)
  292. {
  293. s.append("/");
  294. }
  295. QString appName = QCoreApplication::applicationName();
  296. appName.replace(" ", "");
  297. if (!appName.isEmpty())
  298. {
  299. s.append(appName + "_ctkpluginfw");
  300. }
  301. else
  302. {
  303. s.append("ctkpluginfw");
  304. qWarning() << "Warning: Using generic plugin framework storage directory:" << s;
  305. qWarning() << "You should set an application name via QCoreApplication::setApplicationName()";
  306. }
  307. }
  308. return s;
  309. }
  310. //----------------------------------------------------------------------------
  311. QDir ctkPluginFrameworkUtil::getFileStorage(ctkPluginFrameworkContext* ctx,
  312. const QString& name)
  313. {
  314. // See if we have a storage directory
  315. QString fwdir = getFrameworkDir(ctx);
  316. if (fwdir.isEmpty())
  317. {
  318. throw std::runtime_error("The framework storge directory is empty");
  319. }
  320. QDir dir(fwdir + "/" + name);
  321. if (dir.exists())
  322. {
  323. if (!QFileInfo(dir.absolutePath()).isDir())
  324. {
  325. QString msg("Not a directory: ");
  326. msg.append(dir.absolutePath());
  327. throw std::runtime_error(msg.toStdString());
  328. }
  329. }
  330. else
  331. {
  332. if (!dir.mkpath(dir.absolutePath()))
  333. {
  334. QString msg("Cannot create directory: ");
  335. msg.append(dir.absolutePath());
  336. throw std::runtime_error(msg.toStdString());
  337. }
  338. }
  339. return dir;
  340. }
  341. //----------------------------------------------------------------------------
  342. bool ctkPluginFrameworkUtil::filterMatch(const QString& filter, const QString& s)
  343. {
  344. return patSubstr(s, 0, filter, 0);
  345. }
  346. //----------------------------------------------------------------------------
  347. bool ctkPluginFrameworkUtil::patSubstr(const QString& s, int si, const QString& pat, int pi)
  348. {
  349. if (pat.length() - pi == 0)
  350. {
  351. return s.length() - si == 0;
  352. }
  353. if (pat[pi] == '*')
  354. {
  355. pi++;
  356. for (;;)
  357. {
  358. if (patSubstr(s, si, pat, pi))
  359. return true;
  360. if (s.length() - si == 0)
  361. return false;
  362. si++;
  363. }
  364. }
  365. else
  366. {
  367. if (s.length() - si==0)
  368. {
  369. return false;
  370. }
  371. if(s[si] != pat[pi])
  372. {
  373. return false;
  374. }
  375. return patSubstr(s, ++si, pat, ++pi);
  376. }
  377. }