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