ctkPluginFrameworkUtil.cpp 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  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 <QCoreApplication>
  19. #include <ctkException.h>
  20. #include <ctkLocationManager_p.h>
  21. #include <ctkBasicLocation_p.h>
  22. /**
  23. * Class for tokenize an attribute string.
  24. */
  25. class AttributeTokenizer {
  26. public:
  27. QString s;
  28. int length;
  29. int pos;
  30. AttributeTokenizer(const QString& input)
  31. : s(input), length(input.size()), pos(0)
  32. {
  33. }
  34. //----------------------------------------------------------------------------
  35. QString getWord()
  36. {
  37. skipWhite();
  38. bool backslash = false;
  39. bool quote = false;
  40. QString val;
  41. int end = 0;
  42. for (; pos < length; pos++)
  43. {
  44. bool breakLoop = false;
  45. if (backslash)
  46. {
  47. backslash = false;
  48. val.append(s.at(pos));
  49. }
  50. else
  51. {
  52. QChar c = s.at(pos);
  53. switch (c.toLatin1())
  54. {
  55. case '"':
  56. quote = !quote;
  57. end = val.length();
  58. break;
  59. case '\\':
  60. backslash = true;
  61. break;
  62. case ',': case ':': case ';': case '=':
  63. if (!quote)
  64. {
  65. breakLoop = true;
  66. break;
  67. }
  68. // Fall through
  69. default:
  70. val.append(c);
  71. if (!c.isSpace())
  72. {
  73. end = val.length();
  74. }
  75. break;
  76. }
  77. if (breakLoop) break;
  78. }
  79. }
  80. if (quote || backslash || end == 0)
  81. {
  82. return QString();
  83. }
  84. return val.left(end);
  85. }
  86. //----------------------------------------------------------------------------
  87. QString getKey()
  88. {
  89. if (pos >= length) {
  90. return QString();
  91. }
  92. int save = pos;
  93. if (s.at(pos) == ';') {
  94. pos++;
  95. }
  96. QString res = getWord();
  97. if (!res.isNull()) {
  98. if (pos == length) {
  99. return res;
  100. }
  101. QChar c = s.at(pos);
  102. if (c == ';' || c == ',') {
  103. return res;
  104. }
  105. }
  106. pos = save;
  107. return QString();
  108. }
  109. //----------------------------------------------------------------------------
  110. QString getParam()
  111. {
  112. if (pos == length || s.at(pos) != ';') {
  113. return QString();
  114. }
  115. int save = pos++;
  116. QString res = getWord();
  117. if (!res.isNull()) {
  118. if (pos < length && s.at(pos) == '=') {
  119. return res;
  120. } if (pos + 1 < length && s.at(pos) == ':' && s.at(pos+1) == '=') {
  121. return res;
  122. }
  123. }
  124. pos = save;
  125. return QString();
  126. }
  127. //----------------------------------------------------------------------------
  128. bool isDirective()
  129. {
  130. if (pos + 1 < length && s.at(pos) == ':')
  131. {
  132. pos++;
  133. return true;
  134. }
  135. else
  136. {
  137. return false;
  138. }
  139. }
  140. //----------------------------------------------------------------------------
  141. QString getValue()
  142. {
  143. if (s.at(pos) != '=')
  144. {
  145. return QString();
  146. }
  147. int save = pos++;
  148. skipWhite();
  149. QString val = getWord();
  150. if (val.isNull())
  151. {
  152. pos = save;
  153. return QString();
  154. }
  155. return val;
  156. }
  157. //----------------------------------------------------------------------------
  158. bool getEntryEnd()
  159. {
  160. int save = pos;
  161. skipWhite();
  162. if (pos == length) {
  163. return true;
  164. } else if (s.at(pos) == ',') {
  165. pos++;
  166. return true;
  167. } else {
  168. pos = save;
  169. return false;
  170. }
  171. }
  172. //----------------------------------------------------------------------------
  173. bool getEnd()
  174. {
  175. int save = pos;
  176. skipWhite();
  177. if (pos == length) {
  178. return true;
  179. } else {
  180. pos = save;
  181. return false;
  182. }
  183. }
  184. //----------------------------------------------------------------------------
  185. QString getRest()
  186. {
  187. QString res = s.mid(pos).trimmed();
  188. return res.length() == 0 ? "<END OF LINE>" : res;
  189. }
  190. private:
  191. //----------------------------------------------------------------------------
  192. void skipWhite()
  193. {
  194. for (; pos < length; pos++) {
  195. if (!s.at(pos).isSpace()) {
  196. break;
  197. }
  198. }
  199. }
  200. };
  201. //----------------------------------------------------------------------------
  202. QList<QMap<QString, QStringList> > ctkPluginFrameworkUtil::parseEntries(const QString& a, const QString& s,
  203. bool single, bool unique, bool single_entry)
  204. {
  205. QList<QMap<QString, QStringList> > result;
  206. if (!s.isNull())
  207. {
  208. AttributeTokenizer at(s);
  209. do {
  210. QList<QString> keys;
  211. QMap<QString, QStringList > params;
  212. QStringList directives;
  213. QString key = at.getKey();
  214. if (key.isNull())
  215. {
  216. QString what = QString("Definition, ") + a + ", expected key at: " + at.getRest()
  217. + ". Key values are terminated by a ';' or a ',' and may not "
  218. + "contain ':', '='.";
  219. throw ctkInvalidArgumentException(what);
  220. }
  221. if (!single)
  222. {
  223. keys.push_back(key);
  224. while (!(key = at.getKey()).isNull())
  225. {
  226. keys.push_back(key);
  227. }
  228. }
  229. QString param;
  230. while (!(param = at.getParam()).isNull())
  231. {
  232. QStringList& old = params[param];
  233. bool is_directive = at.isDirective();
  234. if (!old.isEmpty() && unique)
  235. {
  236. QString what = QString("Definition, ") + a + ", duplicate " +
  237. (is_directive ? "directive" : "attribute") +
  238. ": " + param;
  239. throw ctkInvalidArgumentException(what);
  240. }
  241. QString value = at.getValue();
  242. if (value.isNull())
  243. {
  244. QString what = QString("Definition, ") + a + ", expected value at: " + at.getRest();
  245. throw ctkInvalidArgumentException(what);
  246. }
  247. if (is_directive)
  248. {
  249. // NYI Handle directives and check them
  250. directives.push_back(param);
  251. }
  252. if (unique)
  253. {
  254. params.insert(param, QStringList(value));
  255. } else {
  256. old.push_back(value);
  257. }
  258. }
  259. if (at.getEntryEnd())
  260. {
  261. if (single)
  262. {
  263. params.insert("$key", QStringList(key));
  264. }
  265. else
  266. {
  267. params.insert("$keys", keys);
  268. }
  269. result.push_back(params);
  270. }
  271. else
  272. {
  273. QString what = QString("Definition, ") + a + ", expected end of entry at: " + at.getRest();
  274. throw ctkInvalidArgumentException(what);
  275. }
  276. if (single_entry && !at.getEnd())
  277. {
  278. QString what = QString("Definition, ") + a + ", expected end of single entry at: " + at.getRest();
  279. throw ctkInvalidArgumentException(what);
  280. }
  281. params.insert("$directives", directives); // $ is not allowed in
  282. // param names...
  283. } while (!at.getEnd());
  284. }
  285. return result;
  286. }
  287. //----------------------------------------------------------------------------
  288. QString ctkPluginFrameworkUtil::getFrameworkDir(ctkPluginFrameworkContext* /*ctx*/)
  289. {
  290. ctkLocation* location = ctkLocationManager::getConfigurationLocation();
  291. if (location)
  292. {
  293. return location->getUrl().toLocalFile();
  294. }
  295. return QString();
  296. }
  297. //----------------------------------------------------------------------------
  298. QDir ctkPluginFrameworkUtil::getFileStorage(ctkPluginFrameworkContext* ctx,
  299. const QString& name)
  300. {
  301. // See if we have a storage directory
  302. QString fwdir = getFrameworkDir(ctx);
  303. if (fwdir.isEmpty())
  304. {
  305. throw ctkRuntimeException("The framework storge directory is empty");
  306. }
  307. QDir dir(fwdir + "/" + name);
  308. if (dir.exists())
  309. {
  310. if (!QFileInfo(dir.absolutePath()).isDir())
  311. {
  312. QString msg("Not a directory: ");
  313. msg.append(dir.absolutePath());
  314. throw ctkRuntimeException(msg);
  315. }
  316. }
  317. else
  318. {
  319. if (!dir.mkpath(dir.absolutePath()))
  320. {
  321. QString msg("Cannot create directory: ");
  322. msg.append(dir.absolutePath());
  323. throw ctkRuntimeException(msg);
  324. }
  325. }
  326. return dir;
  327. }
  328. //----------------------------------------------------------------------------
  329. bool ctkPluginFrameworkUtil::filterMatch(const QString& filter, const QString& s)
  330. {
  331. return patSubstr(s, 0, filter, 0);
  332. }
  333. //----------------------------------------------------------------------------
  334. bool ctkPluginFrameworkUtil::patSubstr(const QString& s, int si, const QString& pat, int pi)
  335. {
  336. if (pat.length() - pi == 0)
  337. {
  338. return s.length() - si == 0;
  339. }
  340. if (pat[pi] == '*')
  341. {
  342. pi++;
  343. for (;;)
  344. {
  345. if (patSubstr(s, si, pat, pi))
  346. return true;
  347. if (s.length() - si == 0)
  348. return false;
  349. si++;
  350. }
  351. }
  352. else
  353. {
  354. if (s.length() - si==0)
  355. {
  356. return false;
  357. }
  358. if(s[si] != pat[pi])
  359. {
  360. return false;
  361. }
  362. return patSubstr(s, ++si, pat, ++pi);
  363. }
  364. }
  365. bool pluginIdLessThan(const QSharedPointer<ctkPlugin>& p1, const QSharedPointer<ctkPlugin>& p2)
  366. {
  367. return p1->getPluginId() < p2->getPluginId();
  368. }