Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
usLDAPExpr.cpp
Go to the documentation of this file.
1 /*=============================================================================
2 
3  Library: CppMicroServices
4 
5  Copyright (c) German Cancer Research Center,
6  Division of Medical and Biological Informatics
7 
8  Licensed under the Apache License, Version 2.0 (the "License");
9  you may not use this file except in compliance with the License.
10  You may obtain a copy of the License at
11 
12  http://www.apache.org/licenses/LICENSE-2.0
13 
14  Unless required by applicable law or agreed to in writing, software
15  distributed under the License is distributed on an "AS IS" BASIS,
16  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  See the License for the specific language governing permissions and
18  limitations under the License.
19 
20 =============================================================================*/
21 
22 #include "usLDAPExpr_p.h"
23 
24 #include "usAny.h"
25 #include "usServicePropertiesImpl_p.h"
26 
27 #include <limits>
28 #include <iterator>
29 #include <cctype>
30 #include <stdexcept>
31 
32 #include <cerrno>
33 #include <cstdlib>
34 #include <cmath>
35 
36 US_BEGIN_NAMESPACE
37 
38 namespace LDAPExprConstants {
39 
40 static LDAPExpr::Byte WILDCARD()
41 {
42  static LDAPExpr::Byte b = std::numeric_limits<LDAPExpr::Byte>::max();
43  return b;
44 }
45 
46 static const std::string& WILDCARD_STRING()
47 {
48  static std::string s(1, WILDCARD());
49  return s;
50 }
51 
52 static const std::string& NULLQ()
53 {
54  static std::string s = "Null query";
55  return s;
56 }
57 
58 static const std::string& GARBAGE()
59 {
60  static std::string s = "Trailing garbage";
61  return s;
62 }
63 
64 static const std::string& EOS()
65 {
66  static std::string s = "Unexpected end of query";
67  return s;
68 }
69 
70 static const std::string& MALFORMED()
71 {
72  static std::string s = "Malformed query";
73  return s;
74 }
75 
76 static const std::string& OPERATOR()
77 {
78  static std::string s = "Undefined operator";
79  return s;
80 }
81 
82 }
83 
84 bool stricomp(const std::string::value_type& v1, const std::string::value_type& v2)
85 {
86  return ::tolower(v1) == ::tolower(v2);
87 }
88 
90 class LDAPExpr::ParseState
91 {
92 
93 private:
94 
95  std::size_t m_pos;
96  std::string m_str;
97 
98 public:
99 
100  ParseState(const std::string &str);
101 
103  bool prefix(const std::string &pre);
104 
108  LDAPExpr::Byte peek();
109 
111  void skip(int n);
112 
114  std::string rest() const;
115 
117  void skipWhite();
118 
120  std::string getAttributeName();
121 
123  std::string getAttributeValue();
124 
126  void error(const std::string &m) const;
127 
128 };
129 
130 
131 class LDAPExprData : public SharedData
132 {
133 public:
134 
135  LDAPExprData( int op, const std::vector<LDAPExpr>& args )
136  : m_operator(op), m_args(args), m_attrName(), m_attrValue()
137  {
138  }
139 
140  LDAPExprData( int op, std::string attrName, const std::string& attrValue )
141  : m_operator(op), m_args(), m_attrName(attrName), m_attrValue(attrValue)
142  {
143  }
144 
145  LDAPExprData( const LDAPExprData& other )
146  : SharedData(other), m_operator(other.m_operator),
147  m_args(other.m_args), m_attrName(other.m_attrName),
148  m_attrValue(other.m_attrValue)
149  {
150  }
151 
152  int m_operator;
153  std::vector<LDAPExpr> m_args;
154  std::string m_attrName;
155  std::string m_attrValue;
156 };
157 
158 LDAPExpr::LDAPExpr() : d()
159 {
160 }
161 
162 LDAPExpr::LDAPExpr( const std::string &filter ) : d()
163 {
164  ParseState ps(filter);
165  try
166  {
167  LDAPExpr expr = ParseExpr(ps);
168 
169  if (!Trim(ps.rest()).empty())
170  {
171  ps.error(LDAPExprConstants::GARBAGE() + " '" + ps.rest() + "'");
172  }
173 
174  d = expr.d;
175  }
176  catch (const std::out_of_range&)
177  {
178  ps.error(LDAPExprConstants::EOS());
179  }
180 }
181 
182 LDAPExpr::LDAPExpr( int op, const std::vector<LDAPExpr>& args )
183  : d(new LDAPExprData(op, args))
184 {
185 }
186 
187 LDAPExpr::LDAPExpr( int op, const std::string &attrName, const std::string &attrValue )
188  : d(new LDAPExprData(op, attrName, attrValue))
189 {
190 }
191 
192 LDAPExpr::LDAPExpr( const LDAPExpr& other )
193  : d(other.d)
194 {
195 }
196 
197 LDAPExpr& LDAPExpr::operator=(const LDAPExpr& other)
198 {
199  d = other.d;
200  return *this;
201 }
202 
203 LDAPExpr::~LDAPExpr()
204 {
205 }
206 
207 std::string LDAPExpr::Trim(std::string str)
208 {
209  str.erase(0, str.find_first_not_of(' '));
210  str.erase(str.find_last_not_of(' ')+1);
211  return str;
212 }
213 
214 bool LDAPExpr::GetMatchedObjectClasses(ObjectClassSet& objClasses) const
215 {
216  if (d->m_operator == EQ)
217  {
218  if (d->m_attrName.length() == ServiceConstants::OBJECTCLASS().length() &&
219  std::equal(d->m_attrName.begin(), d->m_attrName.end(), ServiceConstants::OBJECTCLASS().begin(), stricomp) &&
220  d->m_attrValue.find(LDAPExprConstants::WILDCARD()) == std::string::npos)
221  {
222  objClasses.insert( d->m_attrValue );
223  return true;
224  }
225  return false;
226  }
227  else if (d->m_operator == AND)
228  {
229  bool result = false;
230  for (std::size_t i = 0; i < d->m_args.size( ); i++)
231  {
232  LDAPExpr::ObjectClassSet r;
233  if (d->m_args[i].GetMatchedObjectClasses(r))
234  {
235  result = true;
236  if (objClasses.empty())
237  {
238  objClasses = r;
239  }
240  else
241  {
242  // if AND op and classes in several operands,
243  // then only the intersection is possible.
244  LDAPExpr::ObjectClassSet::iterator it1 = objClasses.begin();
245  LDAPExpr::ObjectClassSet::iterator it2 = r.begin();
246  while ( (it1 != objClasses.end()) && (it2 != r.end()) )
247  {
248  if (*it1 < *it2)
249  {
250  objClasses.erase(it1++);
251  }
252  else if (*it2 < *it1)
253  {
254  ++it2;
255  }
256  else
257  { // *it1 == *it2
258  ++it1;
259  ++it2;
260  }
261  }
262  // Anything left in set_1 from here on did not appear in set_2,
263  // so we remove it.
264  objClasses.erase(it1, objClasses.end());
265  }
266  }
267  }
268  return result;
269  }
270  else if (d->m_operator == OR)
271  {
272  for (std::size_t i = 0; i < d->m_args.size( ); i++)
273  {
274  LDAPExpr::ObjectClassSet r;
275  if (d->m_args[i].GetMatchedObjectClasses(r))
276  {
277  std::copy(r.begin(), r.end(), std::inserter(objClasses, objClasses.begin()));
278  }
279  else
280  {
281  objClasses.clear();
282  return false;
283  }
284  }
285  return true;
286  }
287  return false;
288 }
289 
290 std::string LDAPExpr::ToLower(const std::string& str)
291 {
292  std::string lowerStr(str);
293  std::transform(str.begin(), str.end(), lowerStr.begin(), ::tolower);
294  return lowerStr;
295 }
296 
297 bool LDAPExpr::IsSimple(const StringList& keywords, LocalCache& cache,
298  bool matchCase ) const
299 {
300  if (cache.empty())
301  {
302  cache.resize(keywords.size());
303  }
304 
305  if (d->m_operator == EQ)
306  {
307  StringList::const_iterator index;
308  if ((index = std::find(keywords.begin(), keywords.end(), matchCase ? d->m_attrName : ToLower(d->m_attrName))) != keywords.end() &&
309  d->m_attrValue.find_first_of(LDAPExprConstants::WILDCARD()) == std::string::npos)
310  {
311  cache[index - keywords.begin()] = StringList(1, d->m_attrValue);
312  return true;
313  }
314  }
315  else if (d->m_operator == OR)
316  {
317  for (std::size_t i = 0; i < d->m_args.size( ); i++)
318  {
319  if (!d->m_args[i].IsSimple(keywords, cache, matchCase))
320  return false;
321  }
322  return true;
323  }
324  return false;
325 }
326 
327 bool LDAPExpr::IsNull() const
328 {
329  return !d;
330 }
331 
332 bool LDAPExpr::Query( const std::string& filter, const ServicePropertiesImpl& pd)
333 {
334  return LDAPExpr(filter).Evaluate(pd, false);
335 }
336 
337 bool LDAPExpr::Evaluate( const ServicePropertiesImpl& p, bool matchCase ) const
338 {
339  if ((d->m_operator & SIMPLE) != 0)
340  {
341  // try case sensitive match first
342  int index = p.FindCaseSensitive(d->m_attrName);
343  if (index < 0 && !matchCase) index = p.Find(d->m_attrName);
344  return index < 0 ? false : Compare(p.Value(index), d->m_operator, d->m_attrValue);
345  }
346  else
347  { // (d->m_operator & COMPLEX) != 0
348  switch (d->m_operator)
349  {
350  case AND:
351  for (std::size_t i = 0; i < d->m_args.size(); i++)
352  {
353  if (!d->m_args[i].Evaluate(p, matchCase))
354  return false;
355  }
356  return true;
357  case OR:
358  for (std::size_t i = 0; i < d->m_args.size(); i++)
359  {
360  if (d->m_args[i].Evaluate(p, matchCase))
361  return true;
362  }
363  return false;
364  case NOT:
365  return !d->m_args[0].Evaluate(p, matchCase);
366  default:
367  return false; // Cannot happen
368  }
369  }
370 }
371 
372 bool LDAPExpr::Compare( const Any& obj, int op, const std::string& s ) const
373 {
374  if (obj.Empty())
375  return false;
376  if (op == EQ && s == LDAPExprConstants::WILDCARD_STRING())
377  return true;
378 
379  try
380  {
381  const std::type_info& objType = obj.Type();
382  if (objType == typeid(std::string))
383  {
384  return CompareString(ref_any_cast<std::string>(obj), op, s);
385  }
386  else if (objType == typeid(std::vector<std::string>))
387  {
388  const std::vector<std::string>& list = ref_any_cast<std::vector<std::string> >(obj);
389  for (std::size_t it = 0; it != list.size(); it++)
390  {
391  if (CompareString(list[it], op, s))
392  return true;
393  }
394  }
395  else if (objType == typeid(std::list<std::string>))
396  {
397  const std::list<std::string>& list = ref_any_cast<std::list<std::string> >(obj);
398  for (std::list<std::string>::const_iterator it = list.begin();
399  it != list.end(); ++it)
400  {
401  if (CompareString(*it, op, s))
402  return true;
403  }
404  }
405  else if (objType == typeid(char))
406  {
407  return CompareString(std::string(1, ref_any_cast<char>(obj)), op, s);
408  }
409  else if (objType == typeid(bool))
410  {
411  if (op==LE || op==GE)
412  return false;
413 
414  std::string boolVal = any_cast<bool>(obj) ? "true" : "false";
415  return std::equal(s.begin(), s.end(), boolVal.begin(), stricomp);
416  }
417  else if (objType == typeid(short))
418  {
419  return CompareIntegralType<short>(obj, op, s);
420  }
421  else if (objType == typeid(int))
422  {
423  return CompareIntegralType<int>(obj, op, s);
424  }
425  else if (objType == typeid(long int))
426  {
427  return CompareIntegralType<long int>(obj, op, s);
428  }
429  else if (objType == typeid(long long int))
430  {
431  return CompareIntegralType<long long int>(obj, op, s);
432  }
433  else if (objType == typeid(unsigned char))
434  {
435  return CompareIntegralType<unsigned char>(obj, op, s);
436  }
437  else if (objType == typeid(unsigned short))
438  {
439  return CompareIntegralType<unsigned short>(obj, op, s);
440  }
441  else if (objType == typeid(unsigned int))
442  {
443  return CompareIntegralType<unsigned int>(obj, op, s);
444  }
445  else if (objType == typeid(unsigned long int))
446  {
447  return CompareIntegralType<unsigned long int>(obj, op, s);
448  }
449  else if (objType == typeid(unsigned long long int))
450  {
451  return CompareIntegralType<unsigned long long int>(obj, op, s);
452  }
453  else if (objType == typeid(float))
454  {
455  errno = 0;
456  char* endptr = 0;
457  double sFloat = strtod(s.c_str(), &endptr);
458  if ((errno == ERANGE && (sFloat == 0 || sFloat == HUGE_VAL || sFloat == -HUGE_VAL)) ||
459  (errno != 0 && sFloat == 0) || endptr == s.c_str())
460  {
461  return false;
462  }
463 
464  double floatVal = static_cast<double>(any_cast<float>(obj));
465 
466  switch(op)
467  {
468  case LE:
469  return floatVal <= sFloat;
470  case GE:
471  return floatVal >= sFloat;
472  default: /*APPROX and EQ*/
473  double diff = floatVal - sFloat;
474  return (diff < std::numeric_limits<float>::epsilon()) && (diff > -std::numeric_limits<float>::epsilon());
475  }
476  }
477  else if (objType == typeid(double))
478  {
479  errno = 0;
480  char* endptr = 0;
481  double sDouble = strtod(s.c_str(), &endptr);
482  if ((errno == ERANGE && (sDouble == 0 || sDouble == HUGE_VAL || sDouble == -HUGE_VAL)) ||
483  (errno != 0 && sDouble == 0) || endptr == s.c_str())
484  {
485  return false;
486  }
487 
488  double doubleVal = any_cast<double>(obj);
489 
490  switch(op)
491  {
492  case LE:
493  return doubleVal <= sDouble;
494  case GE:
495  return doubleVal >= sDouble;
496  default: /*APPROX and EQ*/
497  double diff = doubleVal - sDouble;
498  return (diff < std::numeric_limits<double>::epsilon()) && (diff > -std::numeric_limits<double>::epsilon());
499  }
500  }
501  else if (objType == typeid(std::vector<Any>))
502  {
503  const std::vector<Any>& list = ref_any_cast<std::vector<Any> >(obj);
504  for (std::size_t it = 0; it != list.size(); it++)
505  {
506  if (Compare(list[it], op, s))
507  return true;
508  }
509  }
510  }
511  catch (...)
512  {
513  // This might happen if a std::string-to-datatype conversion fails
514  // Just consider it a false match and ignore the exception
515  }
516  return false;
517 }
518 
519 template<typename T>
520 bool LDAPExpr::CompareIntegralType(const Any& obj, const int op, const std::string& s) const
521 {
522  errno = 0;
523  char* endptr = 0;
524  long longInt = strtol(s.c_str(), &endptr, 10);
525  if ((errno == ERANGE && (longInt == std::numeric_limits<long>::max() || longInt == std::numeric_limits<long>::min())) ||
526  (errno != 0 && longInt == 0) || endptr == s.c_str())
527  {
528  return false;
529  }
530 
531  T sInt = static_cast<T>(longInt);
532  T intVal = any_cast<T>(obj);
533 
534  switch(op)
535  {
536  case LE:
537  return intVal <= sInt;
538  case GE:
539  return intVal >= sInt;
540  default: /*APPROX and EQ*/
541  return intVal == sInt;
542  }
543 }
544 
545 bool LDAPExpr::CompareString( const std::string& s1, int op, const std::string& s2 )
546 {
547  switch(op)
548  {
549  case LE:
550  return s1.compare(s2) <= 0;
551  case GE:
552  return s1.compare(s2) >= 0;
553  case EQ:
554  return PatSubstr(s1,s2);
555  case APPROX:
556  return FixupString(s2) == FixupString(s1);
557  default:
558  return false;
559  }
560 }
561 
562 std::string LDAPExpr::FixupString( const std::string& s )
563 {
564  std::string sb;
565  sb.reserve(s.size());
566  std::size_t len = s.length();
567  for(std::size_t i=0; i<len; i++)
568  {
569  char c = s.at(i);
570  if (!std::isspace(c))
571  {
572  if (std::isupper(c))
573  c = std::tolower(c);
574  sb.append(1, c);
575  }
576  }
577  return sb;
578 }
579 
580 bool LDAPExpr::PatSubstr( const std::string& s, int si, const std::string& pat, int pi )
581 {
582  if (pat.size()-pi == 0)
583  return s.size()-si == 0;
584  if (pat[pi] == LDAPExprConstants::WILDCARD())
585  {
586  pi++;
587  for (;;)
588  {
589  if (PatSubstr(s, si, pat, pi))
590  return true;
591  if (s.size()-si == 0)
592  return false;
593  si++;
594  }
595  }
596  else
597  {
598  if (s.size()-si == 0)
599  {
600  return false;
601  }
602  if(s[si] != pat[pi])
603  {
604  return false;
605  }
606  return PatSubstr(s, ++si, pat, ++pi);
607  }
608 }
609 
610 bool LDAPExpr::PatSubstr( const std::string& s, const std::string& pat )
611 {
612  return PatSubstr(s, 0, pat, 0);
613 }
614 
615 LDAPExpr LDAPExpr::ParseExpr( ParseState& ps )
616 {
617  ps.skipWhite();
618  if (!ps.prefix("("))
619  ps.error(LDAPExprConstants::MALFORMED());
620 
621  int op;
622  ps.skipWhite();
623  Byte c = ps.peek();
624  if ( c == '&')
625  {
626  op = AND;
627  }
628  else if ( c == '|' )
629  {
630  op = OR;
631  }
632  else if ( c == '!' )
633  {
634  op = NOT;
635  }
636  else
637  {
638  return ParseSimple(ps);
639  }
640  ps.skip(1); // Ignore the d->m_operator
641 
642  std::vector<LDAPExpr> v;
643  do
644  {
645  v.push_back(ParseExpr(ps));
646  ps.skipWhite();
647  } while (ps.peek() == '(');
648 
649  std::size_t n = v.size();
650  if (!ps.prefix(")") || n == 0 || (op == NOT && n > 1))
651  ps.error(LDAPExprConstants::MALFORMED());
652 
653  return LDAPExpr(op, v);
654 }
655 
656 LDAPExpr LDAPExpr::ParseSimple( ParseState &ps )
657 {
658  std::string attrName = ps.getAttributeName();
659  if (attrName.empty())
660  ps.error(LDAPExprConstants::MALFORMED());
661  int op = 0;
662  if (ps.prefix("="))
663  op = EQ;
664  else if (ps.prefix("<="))
665  op = LE;
666  else if(ps.prefix(">="))
667  op = GE;
668  else if(ps.prefix("~="))
669  op = APPROX;
670  else
671  {
672  // System.out.println("undef op='" + ps.peek() + "'");
673  ps.error(LDAPExprConstants::OPERATOR()); // Does not return
674  }
675  std::string attrValue = ps.getAttributeValue();
676  if (!ps.prefix(")"))
677  ps.error(LDAPExprConstants::MALFORMED());
678  return LDAPExpr(op, attrName, attrValue);
679 }
680 
681 const std::string LDAPExpr::ToString() const
682 {
683  std::string res;
684  res.append("(");
685  if ((d->m_operator & SIMPLE) != 0)
686  {
687  res.append(d->m_attrName);
688  switch (d->m_operator)
689  {
690  case EQ:
691  res.append("=");
692  break;
693  case LE:
694  res.append("<=");
695  break;
696  case GE:
697  res.append(">=");
698  break;
699  case APPROX:
700  res.append("~=");
701  break;
702  }
703 
704  for (std::size_t i = 0; i < d->m_attrValue.length(); i++)
705  {
706  Byte c = d->m_attrValue.at(i);
707  if (c == '(' || c == ')' || c == '*' || c == '\\')
708  {
709  res.append(1, '\\');
710  }
711  else if (c == LDAPExprConstants::WILDCARD())
712  {
713  c = '*';
714  }
715  res.append(1, c);
716  }
717  }
718  else
719  {
720  switch (d->m_operator)
721  {
722  case AND:
723  res.append("&");
724  break;
725  case OR:
726  res.append("|");
727  break;
728  case NOT:
729  res.append("!");
730  break;
731  }
732  for (std::size_t i = 0; i < d->m_args.size(); i++)
733  {
734  res.append(d->m_args[i].ToString());
735  }
736  }
737  res.append(")");
738  return res;
739 }
740 
741 LDAPExpr::ParseState::ParseState( const std::string& str )
742  : m_pos(0), m_str()
743 {
744  if (str.empty())
745  {
746  error(LDAPExprConstants::NULLQ());
747  }
748 
749  m_str = str;
750 }
751 
752 bool LDAPExpr::ParseState::prefix( const std::string& pre )
753 {
754  std::string::iterator startIter = m_str.begin() + m_pos;
755  if (!std::equal(pre.begin(), pre.end(), startIter))
756  return false;
757  m_pos += pre.size();
758  return true;
759 }
760 
761 char LDAPExpr::ParseState::peek()
762 {
763  if ( m_pos >= m_str.size() )
764  {
765  throw std::out_of_range( "LDAPExpr" );
766  }
767  return m_str.at(m_pos);
768 }
769 
770 void LDAPExpr::ParseState::skip( int n )
771 {
772  m_pos += n;
773 }
774 
775 std::string LDAPExpr::ParseState::rest() const
776 {
777  return m_str.substr(m_pos);
778 }
779 
780 void LDAPExpr::ParseState::skipWhite()
781 {
782  while (std::isspace(peek()))
783  {
784  m_pos++;
785  }
786 }
787 
788 std::string LDAPExpr::ParseState::getAttributeName()
789 {
790  std::size_t start = m_pos;
791  std::size_t n = 0;
792  bool nIsSet = false;
793  for(;; m_pos++)
794  {
795  Byte c = peek();
796  if (c == '(' || c == ')' ||
797  c == '<' || c == '>' ||
798  c == '=' || c == '~') {
799  break;
800  }
801  else if (!std::isspace(c))
802  {
803  n = m_pos - start + 1;
804  nIsSet = true;
805  }
806  }
807  if (!nIsSet)
808  {
809  return std::string();
810  }
811  return m_str.substr(start, n);
812 }
813 
814 std::string LDAPExpr::ParseState::getAttributeValue()
815 {
816  std::string sb;
817  bool exit = false;
818  while( !exit ) {
819  Byte c = peek( );
820  switch(c)
821  {
822  case '(':
823  case ')':
824  exit = true;
825  break;
826  case '*':
827  sb.append(1, LDAPExprConstants::WILDCARD());
828  break;
829  case '\\':
830  sb.append(1, m_str.at(++m_pos));
831  break;
832  default:
833  sb.append(1, c);
834  break;
835  }
836 
837  if ( !exit )
838  {
839  m_pos++;
840  }
841  }
842  return sb;
843 }
844 
845 void LDAPExpr::ParseState::error( const std::string &m ) const
846 {
847  std::string errorStr = m + ": " + (m_str.empty() ? "" : m_str.substr(m_pos));
848  throw std::invalid_argument(errorStr);
849 }
850 
851 US_END_NAMESPACE
static const std::string & OPERATOR()
Definition: usLDAPExpr.cpp:76
static LDAPExpr::Byte WILDCARD()
Definition: usLDAPExpr.cpp:40
static const std::string & WILDCARD_STRING()
Definition: usLDAPExpr.cpp:46
ValueType * any_cast(Any *operand)
Definition: usAny.h:377
static const std::string & MALFORMED()
Definition: usLDAPExpr.cpp:70
static const std::string & EOS()
Definition: usLDAPExpr.cpp:64
static const std::string & NULLQ()
Definition: usLDAPExpr.cpp:52
static T max(T x, T y)
Definition: svm.cpp:70
US_Core_EXPORT const std::string & OBJECTCLASS()
std::vector< std::string > StringList
const ValueType & ref_any_cast(const Any &operand)
Definition: usAny.h:449
static T min(T x, T y)
Definition: svm.cpp:67
bool stricomp(const std::string::value_type &v1, const std::string::value_type &v2)
Definition: usLDAPExpr.cpp:84
static const std::string & GARBAGE()
Definition: usLDAPExpr.cpp:58