libzypp 17.34.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>
17
18#include <zypp/CpeId.h>
19
20using 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
38namespace 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 {
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 {
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 {
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
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
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
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
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
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
457 _value = CpeId::Value::NA._value;
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
511 {
512 if ( encoded_r != "*" ) // ANY is default constructed
513 {
514 if ( encoded_r == "-" ) // NA
515 {
516 _value = CpeId::Value::NA._value;
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
576 {
577 if ( ! encoded_r.empty() ) // ANY is default constructed
578 {
579 if ( encoded_r == "-" ) // NA
580 {
581 _value = CpeId::Value::NA._value;
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( const std::string::const_reverse_iterator& rbegin_r, const std::string::const_reverse_iterator& rend_r )
785 {
786 unsigned backslashes = 0;
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
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
#define WFN_ATTRIBUTES
Initializer list with all wfn attributes.
Definition CpeId.cc:23
#define OUTS(V)
Edition * _value
Reference counted access to a Tp object calling a custom Dispose function when the last AutoDispose h...
Definition AutoDispose.h:95
void swap(AutoDispose &rhs) noexcept
Exchange the contents of two AutoDispose objects.
void reset()
Reset to default Ctor values.
shared_ptr< Impl > _pimpl
CpeId implementation.
Definition CpeId.cc:85
std::string asUri() const
Definition CpeId.cc:110
Impl(const std::string &cpe_r)
Definition CpeId.cc:91
SetCompare setRelationMixinCompare(const Impl &trg) const
Definition CpeId.cc:174
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
static Wfn unbindUri(const std::string &cpe_r)
Parse Uri and unbind.
Definition CpeId.cc:316
std::string asFs() const
Definition CpeId.cc:99
static Wfn unbind(const std::string &cpe_r)
Parse magic and unbind accordingly.
Definition CpeId.cc:289
std::array< Value, Attribute::numAttributes > Wfn
Definition CpeId.cc:86
static Wfn unbindFs(const std::string &cpe_r)
Parse Fs and unbind.
Definition CpeId.cc:350
std::string asWfn() const
Definition CpeId.cc:153
WFN attribute value.
Definition CpeId.h:160
static const Value ANY
Logical value matching ANY value.
Definition CpeId.h:163
static const Value NA
Logical value indicating “not applicable/not used".
Definition CpeId.h:166
bool isANY() const
Whether value is ANY.
Definition CpeId.h:227
static constexpr UriFormatType uriFormat
Indicator argument for ctor arg in URI format.
Definition CpeId.h:177
static constexpr FsFormatType fsFormat
Indicator argument for ctor arg in FS format.
Definition CpeId.h:172
bool isString() const
Whether it's an attribute value string (not logical value).
Definition CpeId.h:242
std::string asFs() const
String representation as in Formated-String (ANY:"*", NA:"-")
Definition CpeId.cc:665
SetCompare setRelationMixinCompare(const Value &trg) const
CPE name matching hook for SetRelationMixin.
Definition CpeId.cc:980
Value()
Default ctor: ANY.
Definition CpeId.h:181
bool containsWildcard() const
HAs unquoted [*?] at begin and/or end of value.
Definition CpeId.cc:913
std::string asUri() const
String representation as in URI (ANY:"", NA:"-")
Definition CpeId.cc:711
std::string asWfn() const
String representation as in Well-Formed-Name (ANY:"*", NA:"").
Definition CpeId.cc:652
Common Platform Enumearation (2.3) See http://cpe.mitre.org/ for more information on the Common Platf...
Definition CpeId.h:33
std::string asUri() const
String representation as URI (in/out).
Definition CpeId.cc:407
~CpeId()
Dtor.
Definition CpeId.cc:398
std::ostream & operator<<(std::ostream &str, const CpeId &obj)
Stream output.
Definition CpeId.h:133
static constexpr NoThrowType noThrow
Indicator argument for non-trowing ctor.
Definition CpeId.h:63
base::EnumClass< EAttributeDef > Attribute
'enum class Attribute'
Definition CpeId.h:57
std::string asWfn() const
String representation as Well-Formed-Name (internal format, out only).
Definition CpeId.cc:410
std::string asFs() const
String representation as Formated-String (in/out).
Definition CpeId.cc:404
SetCompare setRelationMixinCompare(const CpeId &trg) const
CPE name matching hook for SetRelationMixin.
Definition CpeId.cc:413
CpeId()
Default ctor: ANY-Cpeid, all attribute values are ANY.
Definition CpeId.cc:376
RWCOW_pointer< Impl > _pimpl
Implementation class.
Definition CpeId.h:126
SetCompare compare(const CpeId &trg) const
Compare sets.
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
Definition NonCopyable.h:26
unsigned splitFields(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
Definition String.h:724
std::string toLower(const std::string &s)
Return lowercase version of s.
Definition String.cc:178
int compareCI(const C_Str &lhs, const C_Str &rhs)
Definition String.h:983
Easy-to use interface to the ZYPP dependency resolver.
static const std::string & asString(Enum val_r)
string representantion
Definition CpeId.cc:420
Indicator type for non-trowing ctor.
Definition CpeId.h:61
static std::string lastMalformed
Definition CpeId.h:61
Indicator type for ctor arg in FS format.
Definition CpeId.h:170
Indicator type for ctor arg in URI format.
Definition CpeId.h:175
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
Definition String.h:212
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
Definition Easy.h:28