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