libzypp  17.36.3
CpeId.cc
Go to the documentation of this file.
1 /*---------------------------------------------------------------------\
2 | ____ _ __ __ ___ |
3 | |__ / \ / / . \ . \ |
4 | / / \ V /| _/ _/ |
5 | / /__ | | | | | | |
6 | /_____||_| |_| |_| |
7 | |
8 \---------------------------------------------------------------------*/
11 #include <iostream>
12 #include <array>
13 
14 #include <zypp/base/String.h>
15 #include <zypp/base/LogTools.h>
16 #include <zypp/base/NonCopyable.h>
17 
18 #include <zypp/CpeId.h>
19 
20 using std::endl;
21 
23 #define WFN_ATTRIBUTES {\
24  Attribute::part, \
25  Attribute::vendor, \
26  Attribute::product, \
27  Attribute::version, \
28  Attribute::update, \
29  Attribute::edition, \
30  Attribute::language, \
31  Attribute::sw_edition,\
32  Attribute::target_sw, \
33  Attribute::target_hw, \
34  Attribute::other, \
35 }
36 
38 namespace zypp
39 {
41  namespace
42  {
44  inline int heDecodeCh( char ch )
45  {
46  if ( '0' <= ch && ch <= '9' )
47  return( ch - '0' );
48  if ( 'A' <= ch && ch <= 'F' )
49  return( ch - 'A' + 10 );
50  if ( 'a' <= ch && ch <= 'f' )
51  return( ch - 'a' + 10 );
52  return -1;
53  }
54 
56  inline bool chIsValidRange( char ch )
57  { return( '!' <= ch && ch <= '~' ); }
58 
60  inline bool chIsAlpha( char ch )
61  { return( ( 'a' <= ch && ch <= 'z' ) || ( 'A' <= ch && ch <= 'Z' ) ); }
62 
64  inline bool chIsNum( char ch )
65  { return( '0' <= ch && ch <= '9' ); }
66 
68  inline bool chIsAlNum( char ch )
69  { return( chIsAlpha( ch ) || chIsNum( ch ) ); }
70 
72  inline bool chIsWfnUnescaped( char ch )
73  { return( chIsAlNum( ch ) || ch == '_' ); }
74 
75  } // namespace
77 
78  constexpr CpeId::NoThrowType CpeId::noThrow;
79 
85  {
86  using Wfn = std::array<Value, Attribute::numAttributes>;
87 
88  public:
89  Impl() {}
90 
91  Impl( const std::string & cpe_r )
92  : _wfn( unbind( cpe_r ) )
93  {}
94 
95  public:
96  explicit operator bool() const
97  { for ( const auto & val : _wfn ) if ( ! val.isANY() ) return true; return false; }
98 
99  std::string asFs() const
100  {
101  str::Str ret;
102  ret << "cpe:2.3";
103  for ( auto ai : WFN_ATTRIBUTES )
104  {
105  ret << ':' << _wfn[ai].asFs();
106  }
107  return ret;
108  }
109 
110  std::string asUri() const
111  {
112  str::Str ret;
113  ret << "cpe:/";
114  unsigned colon = 0; // to remember trailing colons
115  for ( auto ai : WFN_ATTRIBUTES )
116  {
117  std::string val = _wfn[ai].asUri();
118 
119  if ( ai == Attribute::edition )
120  {
121  if ( ! ( _wfn[Attribute::sw_edition].isANY()
122  && _wfn[Attribute::target_sw].isANY()
123  && _wfn[Attribute::target_hw].isANY()
124  && _wfn[Attribute::other].isANY() ) )
125  {
126  // packing is needed
127  val = str::Str()
128  << '~' << val//Attribute::edition
129  << '~' << _wfn[Attribute::sw_edition].asUri()
130  << '~' << _wfn[Attribute::target_sw].asUri()
131  << '~' << _wfn[Attribute::target_hw].asUri()
132  << '~' << _wfn[Attribute::other].asUri();
133  }
134  }
135 
136  if ( ! val.empty() )
137  {
138  if ( colon )
139  ret << std::string( colon, ':' );
140  ret << val;
141  colon = 1;
142  }
143  else
144  ++colon;
145 
146  if ( ai == Attribute::language )
147  break; // remaining attrs packaed in edition
148  }
149  return ret;
150  }
151 
152  std::string asWfn() const
153  {
154  str::Str ret;
155  ret << "wfn:[";
156  for ( auto ai : WFN_ATTRIBUTES )
157  {
158  const Value & val( _wfn[ai] );
159  if ( ! val.isANY() )
160  {
161  if ( ai ) ret << ',';
162  ret << Attribute::asString( ai ) << '=';
163  if ( val.isString() )
164  ret << '"' << val << '"';
165  else
166  ret << "NA"; // as ANY is omitted, it must be NA
167  }
168  }
169  return ret << "]";
170  }
171 
172  public:
173  SetCompare setRelationMixinCompare( const Impl & trg ) const
174  {
175  SetCompare ret = SetCompare::equal;
176  for ( auto ai : WFN_ATTRIBUTES )
177  {
178  switch ( _wfn[ai].compare( trg._wfn[ai] ).asEnum() )
179  {
180  case SetCompare::uncomparable:
181  ret = SetCompare::uncomparable;
182  break;
183 
184  case SetCompare::equal:
185  break;
186 
187  case SetCompare::properSubset:
188  if ( ret == SetCompare::equal )
189  ret = SetCompare::properSubset;
190  else if ( ret != SetCompare::properSubset )
191  ret = SetCompare::uncomparable;
192  break;
193 
194  case SetCompare::properSuperset:
195  if ( ret == SetCompare::equal )
196  ret = SetCompare::properSuperset;
197  else if ( ret != SetCompare::properSuperset )
198  ret = SetCompare::uncomparable;
199  break;
200 
201  case SetCompare::disjoint:
202  ret = SetCompare::disjoint;
203  break;
204  }
205  if ( ret == SetCompare::uncomparable || ret == SetCompare::disjoint )
206  break;
207  }
208  return ret;
209  }
210 
211  private:
215  static void assignAttr( Wfn & wfn_r, Attribute attr_r, const Value & val_r )
216  {
217  if ( val_r.isString() )
218  {
219  switch ( attr_r.asEnum() )
220  {
221  case Attribute::part:
222  {
223  const std::string & wfn( val_r.asWfn() );
224  switch ( wfn[0] )
225  {
226  case 'h':
227  case 'o':
228  case 'a':
229  if ( wfn[1] == '\0' )
230  break;
231  // else: fallthrough
232  default:
233  throw std::invalid_argument( str::Str() << "CpeId:Wfn:part: '" << wfn << "' illegal value; expected: 'h' | 'o' | 'a'" );
234  break;
235  }
236  }
237  break;
238 
239  case Attribute::language:
240  {
241  const std::string & wfn( val_r.asWfn() );
242  std::string::size_type len = 0;
243  // (2*3ALPHA) ["-" (2ALPHA / 3DIGIT)]
244  if ( chIsAlpha( wfn[0] ) && chIsAlpha( wfn[1] ) )
245  {
246  len = chIsAlpha( wfn[2] ) ? 3 : 2;
247  if ( wfn[len] == '-' )
248  {
249  if ( chIsAlpha( wfn[len+1] ) && chIsAlpha( wfn[len+2] ) )
250  len += 3;
251  else if ( chIsNum( wfn[len+1] ) && chIsNum( wfn[len+2] ) && chIsNum( wfn[len+3] ) )
252  len += 4;
253  }
254  }
255  if ( wfn.size() != len )
256  throw std::invalid_argument( str::Str() << "CpeId:Wfn:language: '" << wfn << "' illegal value; expected RFC5646 conform: language ['-' region]" );
257  }
258  break;
259 
260  default:
261  // no contraints
262  break;
263  }
264  }
265  wfn_r[attr_r.asIntegral()] = val_r;
266  }
267 
268  private:
272  static Wfn unbind( const std::string & cpe_r );
273 
277  static Wfn unbindUri( const std::string & cpe_r );
278 
282  static Wfn unbindFs( const std::string & cpe_r );
283 
284  private:
286  };
287 
288  CpeId::Impl::Wfn CpeId::Impl::unbind( const std::string & cpe_r )
289  {
290  Wfn ret;
291  if ( cpe_r[0] == 'c'
292  && cpe_r[1] == 'p'
293  && cpe_r[2] == 'e'
294  && cpe_r[3] == ':' )
295  {
296  if ( cpe_r[4] == '/' )
297  {
298  ret = unbindUri( cpe_r );
299  }
300  else if ( cpe_r[4] == '2'
301  && cpe_r[5] == '.'
302  && cpe_r[6] == '3'
303  && cpe_r[7] == ':' )
304  {
305  ret = unbindFs( cpe_r );
306  }
307  else
308  throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
309  }
310  else if ( cpe_r[0] != '\0' )
311  throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
312  return ret;
313  }
314 
315  CpeId::Impl::Wfn CpeId::Impl::unbindUri( const std::string & cpe_r )
316  {
317  Wfn ret;
318 
319  static constexpr unsigned numUriAttr = 7u; // basic URI attibutes
320  std::vector<std::string> field;
321  field.reserve( Attribute::numAttributes ); // reserve 7 + 4 for packed extened attrs in edition
322  if ( str::splitFields( cpe_r.c_str()+5/* skip magic 'cpe:/' */, std::back_inserter(field), ":" ) > numUriAttr )
323  throw std::invalid_argument( str::Str() << "CpeId:Uri: too many fields (" << field.size() << "); expected " << numUriAttr );
324  field.resize( Attribute::numAttributes ); // fillup with ANY(""),
325 
326  for ( auto ai : WFN_ATTRIBUTES )
327  {
328  if ( ai == Attribute::edition && field[ai][0] == '~' )
329  {
330  // unpacking is needed
331  static constexpr unsigned numPacks = 6u; // dummy_before_~ + edition + 4 extended attributes
332  std::vector<std::string> pack;
333  pack.reserve( numPacks );
334  if ( str::splitFields( field[ai], std::back_inserter(pack), "~" ) > numPacks )
335  throw std::invalid_argument( str::Str() << "CpeId:Uri:edition: too many packs (" << pack.size() << "); expected " << numPacks );
336  pack.resize( numPacks ); // fillup with ANY(""), should be noOP
337 
338  pack[1].swap( field[Attribute::edition] );
339  pack[2].swap( field[Attribute::sw_edition] );
340  pack[3].swap( field[Attribute::target_sw] );
341  pack[4].swap( field[Attribute::target_hw] );
342  pack[5].swap( field[Attribute::other] );
343  }
344  assignAttr( ret, ai, Value( field[ai], Value::uriFormat ) );
345  }
346  return ret;
347  }
348 
349  CpeId::Impl::Wfn CpeId::Impl::unbindFs( const std::string & cpe_r )
350  {
351  Wfn ret;
352 
353  std::vector<std::string> field;
354  field.reserve( Attribute::numAttributes );
355  if ( str::splitFields( cpe_r.c_str()+8/* skip magic 'cpe:2.3:' */, std::back_inserter(field), ":" ) > Attribute::numAttributes )
356  throw std::invalid_argument( str::Str() << "CpeId:Fs: too many fields (" << field.size() << "); expected 11" /*<< Attribute::numAttributes but g++ currently can't resoolve this as constexpr*/ );
357  if ( !field.empty() && field.back().empty() ) // A trailing ':' leads to an empty (illegal) field, but we fillup missing fields with ANY|"*"
358  field.back() = "*";
359  field.resize( Attribute::numAttributes, "*" ); // fillup with ANY|"*"
360 
361  for ( auto ai : WFN_ATTRIBUTES )
362  {
363  assignAttr( ret, ai, Value( field[ai], Value::fsFormat ) );
364  }
365  return ret;
366  }
367 
368 
370  // class CpeId
372 
374 
376  : _pimpl( new Impl )
377  {}
378 
379  CpeId::CpeId( const std::string & cpe_r )
380  : _pimpl( new Impl( cpe_r ) )
381  {}
382 
383  CpeId::CpeId( const std::string & cpe_r, NoThrowType )
384  {
385  try
386  {
387  _pimpl.reset( new Impl( cpe_r ) );
389  }
390  catch(...)
391  {
392  _pimpl.reset( new Impl );
394  }
395  }
396 
398  {}
399 
400  CpeId::operator bool() const
401  { return bool(*_pimpl); }
402 
403  std::string CpeId::asFs() const
404  { return _pimpl->asFs(); }
405 
406  std::string CpeId::asUri() const
407  { return _pimpl->asUri(); }
408 
409  std::string CpeId::asWfn() const
410  { return _pimpl->asWfn(); }
411 
412  SetCompare CpeId::setRelationMixinCompare( const CpeId & trg ) const
413  { return _pimpl->setRelationMixinCompare( *trg._pimpl ); }
414 
416  // class CpeId::WfnAttribute
418 
419  const std::string & CpeId::EAttributeDef::asString( Enum val_r )
420  {
421  static std::map<Enum,std::string> _table = {
422 #define OUTS(N) { N, #N }
423  OUTS( part ),
424  OUTS( vendor ),
425  OUTS( product ),
426  OUTS( version ),
427  OUTS( update ),
428  OUTS( edition ),
429  OUTS( language ),
430  OUTS( sw_edition ),
431  OUTS( target_sw ),
432  OUTS( target_hw ),
433  OUTS( other ),
434 #undef OUTS
435  };
436  return _table[val_r];
437  }
438 
440  // class CpeId::Value
442 
444  const CpeId::Value CpeId::Value::NA( "" );
445 
448 
449  CpeId::Value::Value( const std::string & value_r )
450  {
451  if ( value_r.empty() ) // NA
452  {
453  if ( ! CpeId::Value::NA._value ) // initialized by this ctor!
454  _value.reset( new std::string );
455  else
457  }
458  else if ( value_r != "*" ) // ANY is default constructed
459  {
460  bool starting = true; // false after the 1st non-?
461  for_( chp, value_r.begin(), value_r.end() )
462  {
463  switch ( *chp )
464  {
465  case '\\': // quoted
466  ++chp;
467  if ( ! chIsValidRange( *chp ) )
468  {
469  if ( *chp )
470  throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal quoted character '\\" << reinterpret_cast<void*>(*chp) << "'" );
471  else
472  throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
473  }
474  else if ( chIsWfnUnescaped( *chp ) )
475  throw std::invalid_argument( str::Str() << "CpeId:Wfn: unnecessarily quoted character '\\" << *chp << "'" );
476  else if ( starting && *chp == '-' && chp+1 == value_r.end() )
477  throw std::invalid_argument( str::Str() << "CpeId:Wfn: '\\-' is illegal value" );
478  break;
479 
480  case '?': // sequence at beginning or end of string
481  while ( *(chp+1) == '?' )
482  ++chp;
483  if ( ! ( starting || chp+1 == value_r.end() ) )
484  throw std::invalid_argument( "CpeId:Wfn: embedded ?" );
485  break;
486 
487  case '*': // single at beginning or end of string
488  if ( ! ( starting || chp+1 == value_r.end() ) )
489  throw std::invalid_argument( "CpeId:Wfn: embedded *" );
490  break;
491 
492  default: // everything else unquoted
493  if ( ! chIsWfnUnescaped( *chp ) )
494  {
495  if ( chIsValidRange( *chp ) )
496  throw std::invalid_argument( str::Str() << "CpeId:Wfn: missing quote before '" << *chp << "'" );
497  else
498  throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal character '" << reinterpret_cast<void*>(*chp) << "'" );
499  }
500  break;
501  }
502  if ( starting )
503  starting = false;
504  }
505  _value.reset( new std::string( value_r ) );
506  }
507  }
508 
509  CpeId::Value::Value( const std::string & encoded_r, FsFormatType )
510  {
511  if ( encoded_r != "*" ) // ANY is default constructed
512  {
513  if ( encoded_r == "-" ) // NA
514  {
516  }
517  else
518  {
519  str::Str result;
520  bool starting = true; // false after the 1st non-?
521  for_( chp, encoded_r.begin(), encoded_r.end() )
522  {
523  switch ( *chp )
524  {
525  case '\\': // may stay quoted
526  ++chp;
527  if ( chIsWfnUnescaped( *chp ) )
528  result << *chp;
529  else if ( chIsValidRange( *chp ) )
530  result << '\\' << *chp;
531  else if ( *chp )
532  throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal quoted character '\\" << *chp << "'" );
533  else
534  throw std::invalid_argument( "CpeId:Fs: Backslash escapes nothing" );
535  break;
536 
537  case '?': // sequence at beginning or end of string
538  result << '?';
539  while ( *(chp+1) == '?' )
540  {
541  ++chp;
542  result << '?';
543  }
544  if ( ! ( starting || chp+1 == encoded_r.end() ) )
545  throw std::invalid_argument( "CpeId:Fs: embedded ?" );
546  break;
547 
548  case '*': // single at beginning or end of string
549  if ( starting || chp+1 == encoded_r.end() )
550  result << '*';
551  else
552  throw std::invalid_argument( "CpeId:Fs: embedded *" );
553  break;
554 
555  default:
556  if ( chIsWfnUnescaped( *chp ) )
557  result << *chp;
558  else if ( chIsValidRange( *chp ) )
559  result << '\\' << *chp;
560  else
561  throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal character '" << reinterpret_cast<void*>(*chp) << "'" );
562  break;
563  }
564  if ( starting )
565  starting = false;
566  }
567  if ( starting )
568  throw std::invalid_argument( "CpeId:Fs: '' value is illegal" );
569  _value.reset( new std::string( result ) );
570  }
571  }
572  }
573 
574  CpeId::Value::Value( const std::string & encoded_r, UriFormatType )
575  {
576  if ( ! encoded_r.empty() ) // ANY is default constructed
577  {
578  if ( encoded_r == "-" ) // NA
579  {
581  }
582  else
583  {
584  str::Str result;
585  bool starting = true; // false after the 1st non-? (%01)
586  for_( chp, encoded_r.begin(), encoded_r.end() )
587  {
588  char ch = *chp;
589 
590  if ( ch == '%' ) // legal '%xx' sequence first
591  {
592  int d1 = heDecodeCh( *(chp+1) );
593  if ( d1 != -1 )
594  {
595  int d2 = heDecodeCh( *(chp+2) );
596  if ( d2 != -1 )
597  {
598  chp += 2; // skip sequence
599  if ( d1 == 0 )
600  {
601  if ( d2 == 1 ) // %01 - ? valid sequence at begin or end
602  {
603  result << '?';
604  while ( *(chp+1) == '%' && *(chp+2) == '0' && *(chp+3) == '1' )
605  {
606  chp += 3;
607  result << '?';
608  }
609  if ( starting || chp+1 == encoded_r.end() )
610  {
611  starting = false;
612  continue; // -> continue;
613  }
614  else
615  throw std::invalid_argument( "CpeId:Uri: embedded %01" );
616  }
617  else if ( d2 == 2 ) // %02 - * valid at begin or end
618  {
619  if ( starting || chp+1 == encoded_r.end() )
620  {
621  result << '*';
622  starting = false;
623  continue; // -> continue;
624  }
625  else
626  throw std::invalid_argument( "CpeId:Uri: embedded %02" );
627  }
628  }
629  ch = (d1<<4)|d2;
630  if ( ! chIsValidRange( ch ) )
631  throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal % encoded character '" << reinterpret_cast<void*>(ch) << "'" );
632  }
633  }
634  }
635  else if ( ! chIsValidRange( ch ) )
636  throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal character '" << reinterpret_cast<void*>(ch) << "'" );
637 
638  if ( chIsWfnUnescaped( ch ) )
639  result << ch;
640  else
641  result << '\\' << ch;
642 
643  if ( starting )
644  starting = false;
645  }
646  _value.reset( new std::string( result ) );
647  }
648  }
649  }
650 
651  std::string CpeId::Value::asWfn() const
652  {
653  std::string ret;
654  if ( ! _value )
655  {
656  static const std::string any( "*" );
657  ret = any;
658  }
659  else
660  ret = *_value; // includes "" for NA
661  return ret;
662  }
663 
664  std::string CpeId::Value::asFs() const
665  {
666  std::string ret;
667  if ( isANY() )
668  {
669  static const std::string asterisk( "*" );
670  ret = asterisk;
671  }
672  else if ( isNA() )
673  {
674  static const std::string dash( "-" );
675  ret = dash;
676  }
677  else
678  {
679  str::Str result;
680  for_( chp, _value->begin(), _value->end() )
681  {
682  if ( *chp != '\\' )
683  result << *chp;
684  else
685  {
686  ++chp;
687  switch ( *chp )
688  {
689  case '-':
690  case '.':
691  case '_':
692  result << *chp; // without escaping
693  break;
694 
695  case '\0':
696  throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
697  break;
698 
699  default:
700  result << '\\' << *chp;
701  break;
702  }
703  }
704  }
705  ret = result;
706  }
707  return ret;
708  }
709 
710  std::string CpeId::Value::asUri() const
711  {
712  std::string ret; // ANY
713  if ( ! isANY() )
714  {
715  if ( isNA() )
716  {
717  static const std::string dash( "-" );
718  ret = dash;
719  }
720  else
721  {
722  str::Str result;
723  for_( chp, _value->begin(), _value->end() )
724  {
725  if ( chIsWfnUnescaped( *chp ) )
726  {
727  result << *chp;
728  }
729  else
730  {
731  static const char *const hdig = "0123456789abcdef";
732  switch ( *chp )
733  {
734  case '\\':
735  ++chp;
736  switch ( *chp )
737  {
738  case '-':
739  case '.':
740  result << *chp; // without encodeing
741  break;
742 
743  case '\0':
744  throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
745  break;
746 
747  default:
748  result << '%' << hdig[(unsigned char)(*chp)/16] << hdig[(unsigned char)(*chp)%16];
749  break;
750  }
751  break;
752 
753  case '?':
754  result << "%01";
755  break;
756 
757  case '*':
758  result << "%02";
759  break;
760 
761  default:
762  throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal char '" << *chp << "' in WFN" );
763  break;
764  }
765  }
766  }
767  ret = result;
768  }
769  }
770  return ret;
771  }
772 
774  namespace
775  {
777  inline bool isWildchar( char ch_r )
778  { return( ch_r == '*' || ch_r == '?' ); }
779 
783  inline bool evenNumberOfBackslashes( const std::string::const_reverse_iterator& rbegin_r, const std::string::const_reverse_iterator& rend_r )
784  {
785  unsigned backslashes = 0;
786  for_( it, rbegin_r, rend_r )
787  {
788  if ( *it == '\\' )
789  ++backslashes;
790  else
791  break;
792  }
793  return !(backslashes & 1U);
794  }
795 
797  inline unsigned trueCharsIn( const std::string & str_r, std::string::size_type begin_r, std::string::size_type end_r )
798  {
799  unsigned chars = 0;
800  for_( it, begin_r, end_r )
801  {
802  ++chars;
803  if ( str_r[it] == '\\' )
804  {
805  if ( ++it == end_r )
806  break;
807  }
808  }
809  return chars;
810  }
811 
813  inline bool matchWildcardfreeString( const std::string & lhs, const std::string & rhs )
814  { return( str::compareCI( lhs, rhs ) == 0 ); }
815 
842  inline bool matchWildcardedString( std::string src, std::string trg )
843  {
844  // std::string::npos remembers an asterisk
845  // unescaped wildcard prefix
846  std::string::size_type prefx = 0;
847  switch ( *src.begin() ) // wellformed implies not empty
848  {
849  case '*':
850  if ( src.size() == 1 )
851  return true; // "*" matches always: superset
852  // else
853  prefx = std::string::npos;
854  src.erase( 0, 1 );
855  break;
856  case '?':
857  ++prefx;
858  for_( it, ++src.begin(), src.end() )
859  { if ( *it == '?' ) ++prefx; else break; }
860  if ( src.size() == prefx )
861  return( trg.size() <= prefx ); // "??..?": superset if at most #prefx chars
862  // else
863  src.erase( 0, prefx );
864  break;
865  default:
866  break;
867  }
868  // unescaped wildcard suffix
869  std::string::size_type suffx = 0;
870  if ( ! src.empty() )
871  {
872  switch ( *src.rbegin() )
873  {
874  case '*':
875  if ( evenNumberOfBackslashes( ++src.rbegin(), src.rend() ) )
876  {
877  suffx = std::string::npos;
878  src.erase( src.size()-1 );
879  }
880  break;
881  case '?':
882  ++suffx;
883  for_( it, ++src.rbegin(), src.rend() )
884  { if ( *it == '?' ) ++suffx; else break; }
885  if ( ! evenNumberOfBackslashes( src.rbegin()+suffx, src.rend() ) )
886  --suffx; // last '?' was escaped.
887  src.erase( src.size()-suffx );
888  break;
889  default:
890  break;
891  }
892  }
893  // now match; find src in trg an check surrounding wildcards
894  src = str::toLower( src );
895  trg = str::toLower( trg );
896  for ( std::string::size_type match = trg.find( src, 0 );
897  match != std::string::npos;
898  match = trg.find( src, match+1 ) )
899  {
900  if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx )
901  break; // not "*", and already more chars than "?"s before match: disjoint
902  std::string::size_type frontSize = match + src.size();
903  if ( suffx != std::string::npos && trueCharsIn( trg, frontSize, trg.size() ) > suffx )
904  continue; // not "*", and still more chars than "?"s after match: check next match
905  return true; // match: superset
906  }
907  return false; // disjoint
908  }
909  } // namespace
911 
913  {
914  const std::string & value( *_value );
915  return ( isWildchar( *value.begin() )
916  || ( isWildchar( *value.rbegin() ) && evenNumberOfBackslashes( ++value.rbegin(), value.rend() ) ) );
917  }
918 
933 #define WFN_STRICT_SPEC 0
934 #if WFN_STRICT_SPEC
935  //SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const
936  {
937  static const SetCompare kNeedsCloserLook( SetCompare::Enum(-1) ); // artificial Compare value
938  static const SetCompare matchTabel[4][4] = {{
939  /* ANY, ANY */ SetCompare::equal,
940  /* ANY, NA */ SetCompare::properSuperset,
941  /* ANY, wildcardfree */ SetCompare::properSuperset,
942  /* ANY, wildcarded */ SetCompare::uncomparable,
943  },{
944  /* NA, ANY */ SetCompare::properSubset,
945  /* NA, NA */ SetCompare::equal,
946  /* NA, wildcardfree */ SetCompare::disjoint,
947  /* NA, wildcarded */ SetCompare::uncomparable,
948  },{
949  /* wildcardfree, ANY */ SetCompare::properSubset,
950  /* wildcardfree, NA */ SetCompare::disjoint,
951  /* wildcardfree, wildcardfree */ kNeedsCloserLook, // equal or disjoint
952  /* wildcardfree, wildcarded */ SetCompare::uncomparable,
953  },{
954  /* wildcarded, ANY */ SetCompare::properSubset,
955  /* wildcarded, NA */ SetCompare::disjoint,
956  /* wildcarded, wildcardfree */ kNeedsCloserLook, // superset or disjoint
957  /* wildcarded, wildcarded */ SetCompare::uncomparable,
958  }};
959 
960  Type srcType = type();
961  Type trgType = trg.type();
962  SetCompare ret = matchTabel[srcType.asIntegral()][trgType.asIntegral()];
963  if ( ret == kNeedsCloserLook )
964  {
965  if ( srcType == Type::wildcardfree ) // trgType == Type::wildcardfree
966  {
967  // simple string compare
968  ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::disjoint;
969  }
970  else if ( srcType == Type::wildcarded ) // trgType == Type::wildcardfree
971  {
972  // Needs wildcard compare
973  ret = matchWildcardedString( *_value, *trg._value ) ? SetCompare::properSuperset : SetCompare::disjoint;
974  }
975  }
976  return ret;
977  }
978 #else
979  SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const
980  {
982  // ANY, ANY => equal
983  // ANY, NA => properSuperset
984  // ANY, wildcardfree => properSuperset
985  // ANY, wildcarded => properSuperset
986  //
987  // NA, ANY => properSubset
988  // NA, NA => equal
989  // NA, wildcardfree => disjoint
990  // NA, wildcarded => disjoint
991  //
992  // wildcardfree, ANY => properSubset
993  // wildcardfree, NA => disjoint
994  // wildcardfree, wildcardfree => NeedsCloserLook: equal or disjoint
995  // wildcardfree, wildcarded => NeedsCloserLook: subset or disjoint
996  //
997  // wildcarded, ANY => properSubset
998  // wildcarded, NA => disjoint
999  // wildcarded, wildcardfree => NeedsCloserLook: superset or disjoint
1000  // wildcarded, wildcarded => NeedsCloserLook" equal or uncomparable
1002 
1003  SetCompare ret = SetCompare::disjoint;
1004 
1005  if ( isANY() )
1006  {
1007  ret = trg.isANY() ? SetCompare::equal : SetCompare::properSuperset;
1008  }
1009  else if ( trg.isANY() )
1010  {
1011  ret = SetCompare::properSubset;
1012  }
1013  else if ( isNA() )
1014  {
1015  if ( trg.isNA() ) ret = SetCompare::equal; // else: SetCompare::disjoint;
1016  }
1017  else if ( ! trg.isNA() ) // else: SetCompare::disjoint;
1018  {
1019  // NeedsCloserLook:
1020  if ( isWildcarded() )
1021  {
1022  if ( trg.isWildcarded() )
1023  {
1024  // simple string compare just to detect 'equal'
1025  ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::uncomparable;
1026  }
1027  else
1028  {
1029  // Needs wildcard compare (src,trg)
1030  if ( matchWildcardedString( *_value, *trg._value ) ) ret = SetCompare::properSuperset; // else: SetCompare::disjoint;
1031  }
1032  }
1033  else
1034  {
1035  if ( trg.isWildcarded() )
1036  {
1037  // Needs wildcard compare (trg,src)
1038  if ( matchWildcardedString( *trg._value, *_value ) ) ret = SetCompare::properSubset; // else: SetCompare::disjoint;
1039  }
1040  else
1041  {
1042  // simple string compare
1043  if ( matchWildcardfreeString( *_value, *trg._value ) ) ret = SetCompare::equal; // else: SetCompare::disjoint;
1044  }
1045  }
1046  }
1047  return ret;
1048  }
1049 #endif // WFN_STRICT_SPEC
1050 
1051  std::ostream & operator<<( std::ostream & str, const CpeId::Value & obj )
1052  { return str << obj.asString(); }
1053 
1054 } // namespace zypp
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition: String.cc:178
std::array< Value, Attribute::numAttributes > Wfn
Definition: CpeId.cc:86
Value()
Default ctor: ANY.
Definition: CpeId.h:181
RWCOW_pointer< Impl > _pimpl
Implementation class.
Definition: CpeId.h:124
SetCompare setRelationMixinCompare(const CpeId &trg) const
CPE name matching hook for SetRelationMixin.
Definition: CpeId.cc:412
Indicator type for ctor arg in FS format.
Definition: CpeId.h:170
std::ostream & operator<<(std::ostream &str, const CpeId &obj)
Definition: CpeId.h:133
Indicator type for non-trowing ctor.
Definition: CpeId.h:61
std::string asFs() const
String representation as in Formated-String (ANY:"*", NA:"-")
Definition: CpeId.cc:664
std::string asUri() const
String representation as in URI (ANY:"", NA:"-")
Definition: CpeId.cc:710
#define WFN_ATTRIBUTES
Initializer list with all wfn attributes.
Definition: CpeId.cc:23
static const Value NA
Logical value indicating “not applicable/not used".
Definition: CpeId.h:166
RWCOW_pointer< std::string > _value
Definition: CpeId.h:293
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition: Easy.h:27
String related utilities and Regular expression matching.
Impl(const std::string &cpe_r)
Definition: CpeId.cc:91
~CpeId()
Dtor.
Definition: CpeId.cc:397
Common Platform Enumearation (2.3) See http://cpe.mitre.org/ for more information on the Common Platf...
Definition: CpeId.h:32
base::EnumClass< EAttributeDef > Attribute
&#39;enum class Attribute&#39;
Definition: CpeId.h:57
static Wfn unbindFs(const std::string &cpe_r)
Parse Fs and unbind.
Definition: CpeId.cc:349
static Wfn unbindUri(const std::string &cpe_r)
Parse Uri and unbind.
Definition: CpeId.cc:315
Edition * _value
Definition: SysContent.cc:311
bool isANY() const
Whether value is ANY.
Definition: CpeId.h:227
static std::string lastMalformed
Definition: CpeId.h:61
bool isNA() const
Whether value is NA.
Definition: CpeId.h:231
CpeId()
Default ctor: ANY-Cpeid, all attribute values are ANY.
Definition: CpeId.cc:375
static const Value ANY
Logical value matching ANY value.
Definition: CpeId.h:163
static Wfn unbind(const std::string &cpe_r)
Parse magic and unbind accordingly.
Definition: CpeId.cc:288
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
Definition: Bit.h:57
bool isString() const
Whether it&#39;s an attribute value string (not logical value).
Definition: CpeId.h:242
static void assignAttr(Wfn &wfn_r, Attribute attr_r, const Value &val_r)
Assign val_r if it meets attr_r specific contraints.
Definition: CpeId.cc:215
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition: String.h:211
static constexpr NoThrowType noThrow
Indicator argument for non-trowing ctor.
Definition: CpeId.h:63
Indicator type for ctor arg in URI format.
Definition: CpeId.h:175
std::string asString() const
Default string representation [asWfn].
Definition: CpeId.h:258
std::string asWfn() const
Definition: CpeId.cc:152
int compareCI(const C_Str &lhs, const C_Str &rhs)
Definition: String.h:984
WFN attribute value.
Definition: CpeId.h:159
unsigned splitFields(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
Definition: String.h:725
static constexpr FsFormatType fsFormat
Indicator argument for ctor arg in FS format.
Definition: CpeId.h:172
SetCompare compare(const CpeId &trg) const
Compare sets.
bool containsWildcard() const
HAs unquoted [*?] at begin and/or end of value.
Definition: CpeId.cc:912
std::string asWfn() const
String representation as in Well-Formed-Name (ANY:"*", NA:"").
Definition: CpeId.cc:651
SetCompare setRelationMixinCompare(const Value &trg) const
CPE name matching hook for SetRelationMixin.
Definition: CpeId.cc:979
std::string asUri() const
String representation as URI (in/out).
Definition: CpeId.cc:406
std::string asFs() const
Definition: CpeId.cc:99
CpeId implementation.
Definition: CpeId.cc:84
std::string asWfn() const
String representation as Well-Formed-Name (internal format, out only).
Definition: CpeId.cc:409
Easy-to use interface to the ZYPP dependency resolver.
Definition: Application.cc:19
SetCompare setRelationMixinCompare(const Impl &trg) const
Definition: CpeId.cc:173
bool isWildcarded() const
An attribute value string with wildcards ([*?] at begin and/or end)
Definition: CpeId.h:253
std::string asUri() const
Definition: CpeId.cc:110
std::string asFs() const
String representation as Formated-String (in/out).
Definition: CpeId.cc:403
SolvableIdType size_type
Definition: PoolMember.h:126
static constexpr UriFormatType uriFormat
Indicator argument for ctor arg in URI format.
Definition: CpeId.h:177
static const std::string & asString(Enum val_r)
string representantion
Definition: CpeId.cc:419
#define OUTS(N)
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition: NonCopyable.h:26