ctkLDAPExpr.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  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 "ctkLDAPExpr_p.h"
  16. #include <QSet>
  17. #include <QVariant>
  18. #include <QStringList>
  19. const int ctkLDAPExpr::AND = 0;
  20. const int ctkLDAPExpr::OR = 1;
  21. const int ctkLDAPExpr::NOT = 2;
  22. const int ctkLDAPExpr::EQ = 4;
  23. const int ctkLDAPExpr::LE = 8;
  24. const int ctkLDAPExpr::GE = 16;
  25. const int ctkLDAPExpr::APPROX = 32;
  26. const int ctkLDAPExpr::COMPLEX = ctkLDAPExpr::AND | ctkLDAPExpr::OR | ctkLDAPExpr::NOT;
  27. const int ctkLDAPExpr::SIMPLE = ctkLDAPExpr::EQ | ctkLDAPExpr::LE | ctkLDAPExpr::GE | ctkLDAPExpr::APPROX;
  28. const QChar ctkLDAPExpr::WILDCARD = 65535;
  29. const QString ctkLDAPExpr::WILDCARD_QString = QString( WILDCARD );
  30. const QString ctkLDAPExpr::NULLQ = "Null query";
  31. const QString ctkLDAPExpr::GARBAGE = "Trailing garbage";
  32. const QString ctkLDAPExpr::EOS = "Unexpected end of query";
  33. const QString ctkLDAPExpr::MALFORMED = "Malformed query";
  34. const QString ctkLDAPExpr::OPERATOR = "Undefined operator";
  35. //! Contains the current parser position and parsing utility methods.
  36. class ctkLDAPExpr::ParseState
  37. {
  38. private:
  39. int m_pos;
  40. QString m_str;
  41. public:
  42. ParseState(const QString &str) throw (std::invalid_argument);
  43. //! Move m_pos to remove the prefix \a pre
  44. bool prefix(const QString &pre);
  45. /** Peek a char at m_pos
  46. \note If index out of bounds, throw exception
  47. */
  48. QChar peek();
  49. //! Increment m_pos by n
  50. void skip(int n);
  51. //! return string from m_pos until the end
  52. QString rest() const;
  53. //! Move m_pos until there's no spaces
  54. void skipWhite();
  55. //! Get string until special chars. Move m_pos
  56. QString getAttributeName();
  57. //! Get string and convert * to WILDCARD
  58. QString getAttributeValue();
  59. //! Throw InvalidSyntaxException exception
  60. void error(const QString &m) const throw (std::invalid_argument);
  61. };
  62. /**
  63. \brief LDAP Expression Data
  64. \date 19 May 2010
  65. \author Xavi Planes
  66. \ingroup ctkPluginFramework
  67. */
  68. class ctkLDAPExprData : public QSharedData
  69. {
  70. public:
  71. ctkLDAPExprData( int op, QList<ctkLDAPExpr> args )
  72. : m_operator(op), m_args(args)
  73. {
  74. }
  75. ctkLDAPExprData( int op, QString attrName, QString attrValue )
  76. : m_operator(op), m_attrName(attrName), m_attrValue(attrValue)
  77. {
  78. }
  79. ctkLDAPExprData( const ctkLDAPExprData& other )
  80. : QSharedData(other), m_operator(other.m_operator),
  81. m_args(other.m_args), m_attrName(other.m_attrName),
  82. m_attrValue(other.m_attrValue)
  83. {
  84. }
  85. //!
  86. int m_operator;
  87. //!
  88. QList<ctkLDAPExpr> m_args;
  89. //!
  90. QString m_attrName;
  91. //!
  92. QString m_attrValue;
  93. };
  94. //----------------------------------------------------------------------------
  95. ctkLDAPExpr::ctkLDAPExpr()
  96. {
  97. }
  98. //----------------------------------------------------------------------------
  99. ctkLDAPExpr::ctkLDAPExpr( const QString &filter )
  100. {
  101. ParseState ps(filter);
  102. try
  103. {
  104. ctkLDAPExpr expr = parseExpr(ps);
  105. if (!ps.rest().trimmed().isEmpty())
  106. {
  107. ps.error(GARBAGE + " '" + ps.rest() + "'");
  108. }
  109. d = expr.d;
  110. }
  111. catch (const std::out_of_range&)
  112. {
  113. ps.error(EOS);
  114. }
  115. }
  116. //----------------------------------------------------------------------------
  117. ctkLDAPExpr::ctkLDAPExpr( int op, const QList<ctkLDAPExpr> &args )
  118. : d(new ctkLDAPExprData(op, args))
  119. {
  120. }
  121. //----------------------------------------------------------------------------
  122. ctkLDAPExpr::ctkLDAPExpr( int op, const QString &attrName, const QString &attrValue )
  123. : d(new ctkLDAPExprData(op, attrName, attrValue))
  124. {
  125. }
  126. //----------------------------------------------------------------------------
  127. ctkLDAPExpr::ctkLDAPExpr( const ctkLDAPExpr& other )
  128. : d(other.d)
  129. {
  130. }
  131. //----------------------------------------------------------------------------
  132. ctkLDAPExpr& ctkLDAPExpr::operator=(const ctkLDAPExpr& other)
  133. {
  134. d = other.d;
  135. return *this;
  136. }
  137. //----------------------------------------------------------------------------
  138. ctkLDAPExpr::~ctkLDAPExpr()
  139. {
  140. }
  141. //----------------------------------------------------------------------------
  142. QSet<QString> ctkLDAPExpr::getMatchedObjectClasses() const
  143. {
  144. QSet<QString> objClasses;
  145. if (d->m_operator == EQ)
  146. {
  147. if (d->m_attrName.compare(ctkPluginConstants::OBJECTCLASS, Qt::CaseInsensitive) &&
  148. d->m_attrValue.indexOf(WILDCARD) < 0)
  149. {
  150. objClasses.insert( d->m_attrValue );
  151. }
  152. }
  153. else if (d->m_operator == AND)
  154. {
  155. for (int i = 0; i < d->m_args.size( ); i++) {
  156. QSet<QString> r = d->m_args[i].getMatchedObjectClasses();
  157. if ( !r.empty() ) {
  158. if (objClasses.empty()) {
  159. objClasses = r;
  160. } else {
  161. // if AND op and classes in several operands,
  162. // then only the intersection is possible.
  163. objClasses = r;
  164. }
  165. }
  166. }
  167. } else if (d->m_operator == OR) {
  168. for (int i = 0; i < d->m_args.length( ); i++) {
  169. QSet<QString> r = d->m_args[i].getMatchedObjectClasses();
  170. if ( !r.empty() ) {
  171. objClasses += r;
  172. } else {
  173. objClasses.clear();
  174. break;
  175. }
  176. }
  177. }
  178. return objClasses;
  179. }
  180. //----------------------------------------------------------------------------
  181. bool ctkLDAPExpr::isSimple(
  182. const QStringList& keywords,
  183. LocalCache& cache,
  184. bool matchCase ) const
  185. {
  186. if (cache.isEmpty())
  187. {
  188. cache.resize(keywords.size());
  189. }
  190. if (d->m_operator == EQ) {
  191. int index;
  192. if ((index = keywords.indexOf(matchCase ? d->m_attrName : d->m_attrName.toLower())) >= 0 &&
  193. d->m_attrValue.indexOf(WILDCARD) < 0) {
  194. cache[index] = QStringList(d->m_attrValue);
  195. return true;
  196. }
  197. } else if (d->m_operator == OR) {
  198. for (int i = 0; i < d->m_args.size( ); i++) {
  199. if (!d->m_args[i].isSimple(keywords, cache, matchCase))
  200. return false;
  201. }
  202. return true;
  203. }
  204. return false;
  205. }
  206. //----------------------------------------------------------------------------
  207. bool ctkLDAPExpr::isNull() const
  208. {
  209. return !d;
  210. }
  211. //----------------------------------------------------------------------------
  212. bool ctkLDAPExpr::query( const QString &filter, const ctkDictionary &pd )
  213. {
  214. return ctkLDAPExpr(filter).evaluate(pd, false);
  215. }
  216. //----------------------------------------------------------------------------
  217. bool ctkLDAPExpr::evaluate( const ctkDictionary &p, bool matchCase ) const
  218. {
  219. if ((d->m_operator & SIMPLE) != 0) {
  220. return compare(p[ matchCase ? d->m_attrName : d->m_attrName.toLower() ],
  221. d->m_operator, d->m_attrValue);
  222. } else { // (d->m_operator & COMPLEX) != 0
  223. switch (d->m_operator) {
  224. case AND:
  225. for (int i = 0; i < d->m_args.length( ); i++) {
  226. if (!d->m_args[i].evaluate(p, matchCase))
  227. return false;
  228. }
  229. return true;
  230. case OR:
  231. for (int i = 0; i < d->m_args.length( ); i++) {
  232. if (d->m_args[i].evaluate(p, matchCase))
  233. return true;
  234. }
  235. return false;
  236. case NOT:
  237. return !d->m_args[0].evaluate(p, matchCase);
  238. default:
  239. return false; // Cannot happen
  240. }
  241. }
  242. }
  243. //----------------------------------------------------------------------------
  244. bool ctkLDAPExpr::compare( const QVariant &obj, int op, const QString &s ) const
  245. {
  246. if (obj.isNull())
  247. return false;
  248. if (op == EQ && s == WILDCARD_QString )
  249. return true;
  250. try {
  251. if ( obj.canConvert<QString>( ) ) {
  252. return compareString(obj.toString(), op, s);
  253. } else if (obj.canConvert<char>( ) ) {
  254. return compareString(obj.toString(), op, s);
  255. } else if (obj.canConvert<bool>( ) ) {
  256. if (op==LE || op==GE)
  257. return false;
  258. if ( obj.toBool() ) {
  259. return s.compare("true", Qt::CaseInsensitive);
  260. } else {
  261. return s.compare("false", Qt::CaseInsensitive);
  262. }
  263. }
  264. else if ( obj.canConvert<Byte>( ) || obj.canConvert<int>( ) )
  265. {
  266. switch(op) {
  267. case LE:
  268. return obj.toInt() <= s.toInt();
  269. case GE:
  270. return obj.toInt() >= s.toInt();
  271. default: /*APPROX and EQ*/
  272. return s.toInt( ) == obj.toInt();
  273. }
  274. } else if ( obj.canConvert<float>( ) ) {
  275. switch(op) {
  276. case LE:
  277. return obj.toFloat() <= s.toFloat();
  278. case GE:
  279. return obj.toFloat() >= s.toFloat();
  280. default: /*APPROX and EQ*/
  281. return s.toFloat() == obj.toFloat();
  282. }
  283. } else if (obj.canConvert<double>()) {
  284. switch(op) {
  285. case LE:
  286. return obj.toDouble() <= s.toDouble();
  287. case GE:
  288. return obj.toDouble() >= s.toDouble();
  289. default: /*APPROX and EQ*/
  290. return s.toDouble( ) == obj.toDouble( );
  291. }
  292. } else if (obj.canConvert<qlonglong>( )) {
  293. switch(op) {
  294. case LE:
  295. return obj.toLongLong() <= s.toLongLong( );
  296. case GE:
  297. return obj.toLongLong() >= s.toLongLong( );
  298. default: /*APPROX and EQ*/
  299. return obj.toLongLong() == s.toLongLong( );
  300. }
  301. }
  302. else if (obj.canConvert< QList<QVariant> >()) {
  303. QList<QVariant> list = obj.toList();
  304. QList<QVariant>::Iterator it;
  305. for (it=list.begin(); it != list.end( ); it++)
  306. if (compare(*it, op, s))
  307. return true;
  308. }
  309. } catch (...) {
  310. // This might happen if a QString-to-datatype conversion fails
  311. // Just consider it a false match and ignore the exception
  312. }
  313. return false;
  314. }
  315. //----------------------------------------------------------------------------
  316. bool ctkLDAPExpr::compareString( const QString &s1, int op, const QString &s2 )
  317. {
  318. switch(op) {
  319. case LE:
  320. return s1.compare(s2) <= 0;
  321. case GE:
  322. return s1.compare(s2) >= 0;
  323. case EQ:
  324. return patSubstr(s1,s2);
  325. case APPROX:
  326. return fixupString(s2) == fixupString(s1);
  327. default:
  328. return false;
  329. }
  330. }
  331. //----------------------------------------------------------------------------
  332. QString ctkLDAPExpr::fixupString( const QString &s )
  333. {
  334. QString sb;
  335. int len = s.length();
  336. for(int i=0; i<len; i++) {
  337. QChar c = s.at(i);
  338. if (!c.isSpace()) {
  339. if (c.isUpper())
  340. c = c.toLower();
  341. sb.append(c);
  342. }
  343. }
  344. return sb;
  345. }
  346. //----------------------------------------------------------------------------
  347. bool ctkLDAPExpr::patSubstr( const QString &s, int si, const QString &pat, int pi )
  348. {
  349. if (pat.size( )-pi == 0)
  350. return s.size( )-si == 0;
  351. if (QChar( pat[pi] ) == WILDCARD ) {
  352. pi++;
  353. for (;;) {
  354. if (patSubstr( s, si, pat, pi))
  355. return true;
  356. if (s.size( )-si == 0)
  357. return false;
  358. si++;
  359. }
  360. } else {
  361. if (s.size( )-si==0){
  362. return false;
  363. }
  364. if(s[si]!=pat[pi]){
  365. return false;
  366. }
  367. return patSubstr( s, ++si, pat, ++pi);
  368. }
  369. }
  370. //----------------------------------------------------------------------------
  371. bool ctkLDAPExpr::patSubstr( const QString &s, const QString &pat )
  372. {
  373. return s.isNull() ? false : patSubstr(s,0,pat,0);
  374. }
  375. //----------------------------------------------------------------------------
  376. ctkLDAPExpr ctkLDAPExpr::parseExpr( ParseState &ps )
  377. {
  378. ps.skipWhite();
  379. if (!ps.prefix("("))
  380. ps.error(MALFORMED);
  381. int op;
  382. ps.skipWhite();
  383. QChar c = ps.peek();
  384. if ( c == '&') {
  385. op = AND;
  386. }else if ( c == '|' ){
  387. op = OR;
  388. } else if ( c == '!' ) {
  389. op = NOT;
  390. } else {
  391. return parseSimple(ps);
  392. }
  393. ps.skip(1); // Ignore the d->m_operator
  394. QList<ctkLDAPExpr> v;
  395. do {
  396. v.append(parseExpr(ps));
  397. ps.skipWhite();
  398. } while (ps.peek() == '(');
  399. int n = v.size();
  400. if (!ps.prefix(")") || n == 0 || (op == NOT && n > 1))
  401. ps.error(MALFORMED);
  402. return ctkLDAPExpr(op, v);
  403. }
  404. //----------------------------------------------------------------------------
  405. ctkLDAPExpr ctkLDAPExpr::parseSimple( ParseState &ps )
  406. {
  407. QString attrName = ps.getAttributeName();
  408. if (attrName.isNull())
  409. ps.error(MALFORMED);
  410. int op = 0;
  411. if (ps.prefix("="))
  412. op = EQ;
  413. else if (ps.prefix("<="))
  414. op = LE;
  415. else if(ps.prefix(">="))
  416. op = GE;
  417. else if(ps.prefix("~="))
  418. op = APPROX;
  419. else {
  420. // System.out.println("undef op='" + ps.peek() + "'");
  421. ps.error(OPERATOR); // Does not return
  422. }
  423. QString attrValue = ps.getAttributeValue();
  424. if (!ps.prefix(")"))
  425. ps.error(MALFORMED);
  426. return ctkLDAPExpr(op, attrName, attrValue);
  427. }
  428. //----------------------------------------------------------------------------
  429. const QString ctkLDAPExpr::toString() const
  430. {
  431. QString res;
  432. res.append("(");
  433. if ((d->m_operator & SIMPLE) != 0) {
  434. res.append(d->m_attrName);
  435. switch (d->m_operator) {
  436. case EQ:
  437. res.append("=");
  438. break;
  439. case LE:
  440. res.append("<=");
  441. break;
  442. case GE:
  443. res.append(">=");
  444. break;
  445. case APPROX:
  446. res.append("~=");
  447. break;
  448. }
  449. for (int i = 0; i < d->m_attrValue.length(); i++) {
  450. QChar c = d->m_attrValue.at(i);
  451. if (c == '(' || c == ')' || c == '*' || c == '\\') {
  452. res.append('\\');
  453. } else if (c == WILDCARD) {
  454. c = '*';
  455. }
  456. res.append(c);
  457. }
  458. } else {
  459. switch (d->m_operator) {
  460. case AND:
  461. res.append("&");
  462. break;
  463. case OR:
  464. res.append("|");
  465. break;
  466. case NOT:
  467. res.append("!");
  468. break;
  469. }
  470. for (int i = 0; i < d->m_args.length( ); i++) {
  471. res.append(d->m_args[i].toString());
  472. }
  473. }
  474. res.append(")");
  475. return res;
  476. }
  477. //----------------------------------------------------------------------------
  478. ctkLDAPExpr::ParseState::ParseState( const QString &str ) throw (std::invalid_argument)
  479. {
  480. if (str.isEmpty())
  481. {
  482. error(NULLQ);
  483. }
  484. m_str = str;
  485. m_pos = 0;
  486. }
  487. //----------------------------------------------------------------------------
  488. bool ctkLDAPExpr::ParseState::prefix( const QString &pre )
  489. {
  490. if (!m_str.startsWith(pre.mid(m_pos)))
  491. return false;
  492. m_pos += pre.length();
  493. return true;
  494. }
  495. //----------------------------------------------------------------------------
  496. QChar ctkLDAPExpr::ParseState::peek()
  497. {
  498. if ( m_pos >= m_str.size() )
  499. {
  500. throw std::out_of_range( "LDAPExpr" );
  501. }
  502. return m_str.at(m_pos);
  503. }
  504. //----------------------------------------------------------------------------
  505. void ctkLDAPExpr::ParseState::skip( int n )
  506. {
  507. m_pos += n;
  508. }
  509. QString ctkLDAPExpr::ParseState::rest() const
  510. {
  511. return m_str.mid(m_pos);
  512. }
  513. //----------------------------------------------------------------------------
  514. void ctkLDAPExpr::ParseState::skipWhite()
  515. {
  516. while ( peek( ).isSpace( ) ) {
  517. m_pos++;
  518. }
  519. }
  520. //----------------------------------------------------------------------------
  521. QString ctkLDAPExpr::ParseState::getAttributeName()
  522. {
  523. int start = m_pos;
  524. int n = -1;
  525. for(;; m_pos++) {
  526. QChar c = peek( );
  527. if (c == '(' || c == ')' ||
  528. c == '<' || c == '>' ||
  529. c == '=' || c == '~') {
  530. break;
  531. } else if ( !c.isSpace( ) ) {
  532. n = m_pos - start + 1;
  533. }
  534. }
  535. if (n == -1) {
  536. return QString::Null( );
  537. }
  538. return m_str.mid(start, n);
  539. }
  540. //----------------------------------------------------------------------------
  541. QString ctkLDAPExpr::ParseState::getAttributeValue()
  542. {
  543. QString sb;
  544. bool exit = false;
  545. while( !exit ) {
  546. QChar c = peek( );
  547. switch(c.toLatin1()) {
  548. case '(':
  549. case ')':
  550. exit = true;
  551. break;
  552. case '*':
  553. sb.append(WILDCARD);
  554. break;
  555. case '\\':
  556. sb.append(m_str.at(++m_pos));
  557. break;
  558. default:
  559. sb.append(c);
  560. break;
  561. }
  562. if ( !exit )
  563. {
  564. m_pos++;
  565. }
  566. }
  567. return sb;
  568. }
  569. //----------------------------------------------------------------------------
  570. void ctkLDAPExpr::ParseState::error( const QString &m ) const throw (std::invalid_argument)
  571. {
  572. QString error = m + ": " + (m_str.isNull() ? "" : m_str.mid(m_pos) );
  573. throw std::invalid_argument( error.toStdString() );
  574. }