1 /*---------------------------------------------------------------------\
3 | |__ / \ / / . \ . \ |
8 \---------------------------------------------------------------------*/
9 /** \file zypp/CpeId.cc
14 #include "zypp/base/String.h"
15 #include "zypp/base/LogTools.h"
16 #include "zypp/base/NonCopyable.h"
18 #include "zypp/CpeId.h"
22 /** Initializer list with all wfn attributes */
23 #define WFN_ATTRIBUTES {\
30 Attribute::language, \
31 Attribute::sw_edition,\
32 Attribute::target_sw, \
33 Attribute::target_hw, \
37 ///////////////////////////////////////////////////////////////////
40 ///////////////////////////////////////////////////////////////////
43 /** Hex-digit to number or -1. */
44 inline int heDecodeCh( char ch )
46 if ( '0' <= ch && ch <= '9' )
48 if ( 'A' <= ch && ch <= 'F' )
49 return( ch - 'A' + 10 );
50 if ( 'a' <= ch && ch <= 'f' )
51 return( ch - 'a' + 10 );
55 /** Printable non whitespace in [0x00,0x7f] valid in WFN */
56 inline bool chIsValidRange( char ch )
57 { return( '!' <= ch && ch <= '~' ); }
60 inline bool chIsAlpha( char ch )
61 { return( ( 'a' <= ch && ch <= 'z' ) || ( 'A' <= ch && ch <= 'Z' ) ); }
64 inline bool chIsNum( char ch )
65 { return( '0' <= ch && ch <= '9' ); }
68 inline bool chIsAlNum( char ch )
69 { return( chIsAlpha( ch ) || chIsNum( ch ) ); }
71 /** Alphanum or \c underscore are unescaped in WFN */
72 inline bool chIsWfnUnescaped( char ch )
73 { return( chIsAlNum( ch ) || ch == '_' ); }
76 ///////////////////////////////////////////////////////////////////
78 ///////////////////////////////////////////////////////////////////
79 /// \class CpeId::Impl
80 /// \brief CpeId implementation.
81 ///////////////////////////////////////////////////////////////////
82 class CpeId::Impl : private base::NonCopyable
84 typedef std::array<Value,Attribute::numAttributes> Wfn;
89 Impl( const std::string & cpe_r )
90 : _wfn( unbind( cpe_r ) )
94 explicit operator bool() const
95 { for ( const auto & val : _wfn ) if ( ! val.isANY() ) return true; return false; }
97 std::string asFs() const
101 for ( auto ai : WFN_ATTRIBUTES )
103 ret << ':' << _wfn[ai].asFs();
108 std::string asUri() const
113 unsigned colon = 0; // to remember trailing colons
114 for ( auto ai : WFN_ATTRIBUTES )
116 val = _wfn[ai].asUri();
118 if ( ai == Attribute::edition )
120 if ( ! ( _wfn[Attribute::sw_edition].isANY()
121 && _wfn[Attribute::target_sw].isANY()
122 && _wfn[Attribute::target_hw].isANY()
123 && _wfn[Attribute::other].isANY() ) )
127 << '~' << val//Attribute::edition
128 << '~' << _wfn[Attribute::sw_edition].asUri()
129 << '~' << _wfn[Attribute::target_sw].asUri()
130 << '~' << _wfn[Attribute::target_hw].asUri()
131 << '~' << _wfn[Attribute::other].asUri();
138 ret << std::string( colon, ':' );
145 if ( ai == Attribute::language )
146 break; // remaining attrs packaed in edition
151 std::string asWfn() const
155 for ( auto ai : WFN_ATTRIBUTES )
157 const Value & val( _wfn[ai] );
160 if ( ai ) ret << ',';
161 ret << Attribute::asString( ai ) << '=';
162 if ( val.isString() )
163 ret << '"' << val << '"';
165 ret << "NA"; // as ANY is omitted, it must be NA
172 SetCompare setRelationMixinCompare( const Impl & trg ) const
174 SetCompare ret = SetCompare::equal;
175 for ( auto ai : WFN_ATTRIBUTES )
177 switch ( _wfn[ai].compare( trg._wfn[ai] ).asEnum() )
179 case SetCompare::uncomparable:
180 ret = SetCompare::uncomparable;
183 case SetCompare::equal:
186 case SetCompare::properSubset:
187 if ( ret == SetCompare::equal )
188 ret = SetCompare::properSubset;
189 else if ( ret != SetCompare::properSubset )
190 ret = SetCompare::uncomparable;
193 case SetCompare::properSuperset:
194 if ( ret == SetCompare::equal )
195 ret = SetCompare::properSuperset;
196 else if ( ret != SetCompare::properSuperset )
197 ret = SetCompare::uncomparable;
200 case SetCompare::disjoint:
201 ret = SetCompare::disjoint;
204 if ( ret == SetCompare::uncomparable || ret == SetCompare::disjoint )
211 /** Assign \a val_r if it meets \a attr_r specific contraints.
212 * \throws std::invalid_argument if string is malformed
214 static void assignAttr( Wfn & wfn_r, Attribute attr_r, const Value & val_r )
216 if ( val_r.isString() )
218 switch ( attr_r.asEnum() )
220 case Attribute::part:
222 const std::string & wfn( val_r.asWfn() );
228 if ( wfn[1] == '\0' )
232 throw std::invalid_argument( str::Str() << "CpeId:Wfn:part: '" << wfn << "' illegal value; expected: 'h' | 'o' | 'a'" );
238 case Attribute::language:
240 const std::string & wfn( val_r.asWfn() );
241 std::string::size_type len = 0;
242 // (2*3ALPHA) ["-" (2ALPHA / 3DIGIT)]
243 if ( chIsAlpha( wfn[0] ) && chIsAlpha( wfn[1] ) )
245 len = chIsAlpha( wfn[2] ) ? 3 : 2;
246 if ( wfn[len] == '-' )
248 if ( chIsAlpha( wfn[len+1] ) && chIsAlpha( wfn[len+2] ) )
250 else if ( chIsNum( wfn[len+1] ) && chIsNum( wfn[len+2] ) && chIsNum( wfn[len+3] ) )
254 if ( wfn.size() != len )
255 throw std::invalid_argument( str::Str() << "CpeId:Wfn:language: '" << wfn << "' illegal value; expected RFC5646 conform: language ['-' region]" );
264 wfn_r[attr_r.asIntegral()] = val_r;
268 /** Parse magic and unbind accordingly
269 * \throws std::invalid_argument if string is malformed
271 static Wfn unbind( const std::string & cpe_r );
273 /** Parse Uri and unbind
274 * \throws std::invalid_argument if string is malformed
276 static Wfn unbindUri( const std::string & cpe_r );
278 /** Parse Fs and unbind
279 * \throws std::invalid_argument if string is malformed
281 static Wfn unbindFs( const std::string & cpe_r );
287 CpeId::Impl::Wfn CpeId::Impl::unbind( const std::string & cpe_r )
295 if ( cpe_r[4] == '/' )
297 ret = unbindUri( cpe_r );
299 else if ( cpe_r[4] == '2'
304 ret = unbindFs( cpe_r );
307 throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
309 else if ( cpe_r[0] != '\0' )
310 throw std::invalid_argument( "CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
314 CpeId::Impl::Wfn CpeId::Impl::unbindUri( const std::string & cpe_r )
318 static constexpr unsigned numUriAttr = 7u; // basic URI attibutes
319 std::vector<std::string> field;
320 field.reserve( Attribute::numAttributes ); // reserve 7 + 4 for packed extened attrs in edition
321 if ( str::splitFields( cpe_r.c_str()+5/* skip magic 'cpe:/' */, std::back_inserter(field), ":" ) > numUriAttr )
322 throw std::invalid_argument( str::Str() << "CpeId:Uri: too many fields (" << field.size() << "); expected " << numUriAttr );
323 field.resize( Attribute::numAttributes ); // fillup with ANY(""),
325 for ( auto ai : WFN_ATTRIBUTES )
327 if ( ai == Attribute::edition && field[ai][0] == '~' )
329 // unpacking is needed
330 static constexpr unsigned numPacks = 6u; // dummy_before_~ + edition + 4 extended attributes
331 std::vector<std::string> pack;
332 pack.reserve( numPacks );
333 if ( str::splitFields( field[ai], std::back_inserter(pack), "~" ) > numPacks )
334 throw std::invalid_argument( str::Str() << "CpeId:Uri:edition: too many packs (" << pack.size() << "); expected " << numPacks );
335 pack.resize( numPacks ); // fillup with ANY(""), should be noOP
337 pack[1].swap( field[Attribute::edition] );
338 pack[2].swap( field[Attribute::sw_edition] );
339 pack[3].swap( field[Attribute::target_sw] );
340 pack[4].swap( field[Attribute::target_hw] );
341 pack[5].swap( field[Attribute::other] );
343 assignAttr( ret, ai, Value( field[ai], Value::uriFormat ) );
348 CpeId::Impl::Wfn CpeId::Impl::unbindFs( const std::string & cpe_r )
352 std::vector<std::string> field;
353 field.reserve( Attribute::numAttributes );
354 if ( str::splitFields( cpe_r.c_str()+8/* skip magic 'cpe:2.3:' */, std::back_inserter(field), ":" ) > Attribute::numAttributes )
355 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*/ );
356 if ( !field.empty() && field.back().empty() ) // A trailing ':' leads to an empty (illegal) field, but we fillup missing fields with ANY|"*"
358 field.resize( Attribute::numAttributes, "*" ); // fillup with ANY|"*"
360 for ( auto ai : WFN_ATTRIBUTES )
362 assignAttr( ret, ai, Value( field[ai], Value::fsFormat ) );
368 ///////////////////////////////////////////////////////////////////
370 ///////////////////////////////////////////////////////////////////
372 std::string CpeId::NoThrowType::lastMalformed;
378 CpeId::CpeId( const std::string & cpe_r )
379 : _pimpl( new Impl( cpe_r ) )
382 CpeId::CpeId( const std::string & cpe_r, NoThrowType )
386 _pimpl.reset( new Impl( cpe_r ) );
387 NoThrowType::lastMalformed.clear();
391 _pimpl.reset( new Impl );
392 NoThrowType::lastMalformed = cpe_r;
399 CpeId::operator bool() const
400 { return bool(*_pimpl); }
402 std::string CpeId::asFs() const
403 { return _pimpl->asFs(); }
405 std::string CpeId::asUri() const
406 { return _pimpl->asUri(); }
408 std::string CpeId::asWfn() const
409 { return _pimpl->asWfn(); }
411 SetCompare CpeId::setRelationMixinCompare( const CpeId & trg ) const
412 { return _pimpl->setRelationMixinCompare( *trg._pimpl ); }
414 ///////////////////////////////////////////////////////////////////
415 // class CpeId::WfnAttribute
416 ///////////////////////////////////////////////////////////////////
418 const std::string & CpeId::_AttributeDef::asString( Enum val_r )
420 static std::map<Enum,std::string> _table = {
421 #define OUTS(N) { N, #N }
435 return _table[val_r];
438 ///////////////////////////////////////////////////////////////////
439 // class CpeId::Value
440 ///////////////////////////////////////////////////////////////////
442 const CpeId::Value CpeId::Value::ANY;
443 const CpeId::Value CpeId::Value::NA( "" );
445 CpeId::Value::Value( const std::string & value_r )
447 if ( value_r.empty() ) // NA
449 if ( ! CpeId::Value::NA._value ) // initialized by this ctor!
450 _value.reset( new std::string );
452 _value = CpeId::Value::NA._value;
454 else if ( value_r != "*" ) // ANY is default constructed
456 bool starting = true; // false after the 1st non-?
457 for_( chp, value_r.begin(), value_r.end() )
463 if ( ! chIsValidRange( *chp ) )
466 throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal quoted character '\\" << reinterpret_cast<void*>(*chp) << "'" );
468 throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
470 else if ( chIsWfnUnescaped( *chp ) )
471 throw std::invalid_argument( str::Str() << "CpeId:Wfn: unnecessarily quoted character '\\" << *chp << "'" );
472 else if ( starting && *chp == '-' && chp+1 == value_r.end() )
473 throw std::invalid_argument( str::Str() << "CpeId:Wfn: '\\-' is illegal value" );
476 case '?': // sequence at beginning or end of string
477 while ( *(chp+1) == '?' )
479 if ( ! ( starting || chp+1 == value_r.end() ) )
480 throw std::invalid_argument( "CpeId:Wfn: embedded ?" );
483 case '*': // single at beginning or end of string
484 if ( ! ( starting || chp+1 == value_r.end() ) )
485 throw std::invalid_argument( "CpeId:Wfn: embedded *" );
488 default: // everything else unquoted
489 if ( ! chIsWfnUnescaped( *chp ) )
491 if ( chIsValidRange( *chp ) )
492 throw std::invalid_argument( str::Str() << "CpeId:Wfn: missing quote before '" << *chp << "'" );
494 throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal character '" << reinterpret_cast<void*>(*chp) << "'" );
501 _value.reset( new std::string( value_r ) );
505 CpeId::Value::Value( const std::string & encoded_r, FsFormatType )
507 if ( encoded_r != "*" ) // ANY is default constructed
509 if ( encoded_r == "-" ) // NA
511 _value = CpeId::Value::NA._value;
516 bool starting = true; // false after the 1st non-?
517 for_( chp, encoded_r.begin(), encoded_r.end() )
521 case '\\': // may stay quoted
523 if ( chIsWfnUnescaped( *chp ) )
525 else if ( chIsValidRange( *chp ) )
526 result << '\\' << *chp;
528 throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal quoted character '\\" << *chp << "'" );
530 throw std::invalid_argument( "CpeId:Fs: Backslash escapes nothing" );
533 case '?': // sequence at beginning or end of string
535 while ( *(chp+1) == '?' )
540 if ( ! ( starting || chp+1 == encoded_r.end() ) )
541 throw std::invalid_argument( "CpeId:Fs: embedded ?" );
544 case '*': // single at beginning or end of string
545 if ( starting || chp+1 == encoded_r.end() )
548 throw std::invalid_argument( "CpeId:Fs: embedded *" );
552 if ( chIsWfnUnescaped( *chp ) )
554 else if ( chIsValidRange( *chp ) )
555 result << '\\' << *chp;
557 throw std::invalid_argument( str::Str() << "CpeId:Fs: illegal character '" << reinterpret_cast<void*>(*chp) << "'" );
564 throw std::invalid_argument( "CpeId:Fs: '' value is illegal" );
565 _value.reset( new std::string( result ) );
570 CpeId::Value::Value( const std::string & encoded_r, UriFormatType )
572 if ( ! encoded_r.empty() ) // ANY is default constructed
574 if ( encoded_r == "-" ) // NA
576 _value = CpeId::Value::NA._value;
581 bool starting = true; // false after the 1st non-? (%01)
582 for_( chp, encoded_r.begin(), encoded_r.end() )
586 if ( ch == '%' ) // legal '%xx' sequence first
588 int d1 = heDecodeCh( *(chp+1) );
591 int d2 = heDecodeCh( *(chp+2) );
594 chp += 2; // skip sequence
597 if ( d2 == 1 ) // %01 - ? valid sequence at begin or end
600 while ( *(chp+1) == '%' && *(chp+2) == '0' && *(chp+3) == '1' )
605 if ( starting || chp+1 == encoded_r.end() )
608 continue; // -> continue;
611 throw std::invalid_argument( "CpeId:Uri: embedded %01" );
613 else if ( d2 == 2 ) // %02 - * valid at begin or end
615 if ( starting || chp+1 == encoded_r.end() )
619 continue; // -> continue;
622 throw std::invalid_argument( "CpeId:Uri: embedded %02" );
626 if ( ! chIsValidRange( ch ) )
627 throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal % encoded character '" << reinterpret_cast<void*>(ch) << "'" );
631 else if ( ! chIsValidRange( ch ) )
632 throw std::invalid_argument( str::Str() << "CpeId:Uri: illegal character '" << reinterpret_cast<void*>(ch) << "'" );
634 if ( chIsWfnUnescaped( ch ) )
637 result << '\\' << ch;
642 _value.reset( new std::string( result ) );
647 std::string CpeId::Value::asWfn() const
652 static const std::string any( "*" );
656 ret = *_value; // includes "" for NA
660 std::string CpeId::Value::asFs() const
665 static const std::string asterisk( "*" );
670 static const std::string dash( "-" );
676 for_( chp, _value->begin(), _value->end() )
688 result << *chp; // without escaping
692 throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
696 result << '\\' << *chp;
706 std::string CpeId::Value::asUri() const
708 std::string ret; // ANY
713 static const std::string dash( "-" );
719 for_( chp, _value->begin(), _value->end() )
721 if ( chIsWfnUnescaped( *chp ) )
727 static const char *const hdig = "0123456789abcdef";
736 result << *chp; // without encodeing
740 throw std::invalid_argument( "CpeId:Wfn: Backslash escapes nothing" );
744 result << '%' << hdig[(unsigned char)(*chp)/16] << hdig[(unsigned char)(*chp)%16];
758 throw std::invalid_argument( str::Str() << "CpeId:Wfn: illegal char '" << *chp << "' in WFN" );
769 ///////////////////////////////////////////////////////////////////
772 /** Whether it's a wildcard character (<tt>[*?]</tt>). */
773 inline bool isWildchar( char ch_r )
774 { return( ch_r == '*' || ch_r == '?' ); }
776 /** Whether there is an even number of consecutive backslashes before and including \a rbegin_r
777 * An even number of backslashes means the character following is unescaped.
779 inline bool evenNumberOfBackslashes( std::string::const_reverse_iterator rbegin_r, std::string::const_reverse_iterator rend_r )
781 unsigned backslashes = 0;
782 for_( it, rbegin_r, rend_r )
789 return !(backslashes & 1U);
792 /** Number of chars (not counting escaping backslashes) in <tt>[begin_r,end_r[</tt> */
793 inline unsigned trueCharsIn( const std::string & str_r, std::string::size_type begin_r, std::string::size_type end_r )
796 for_( it, begin_r, end_r )
799 if ( str_r[it] == '\\' )
808 /** Match helper comparing 2 Wildcardfree string values (case insensitive). */
809 inline bool matchWildcardfreeString( const std::string & lhs, const std::string & rhs )
810 { return( str::compareCI( lhs, rhs ) == 0 ); }
812 /** Match helper matching Wildcarded source against Wildcardfree target.
814 * Constraints on usage of the unquoted question mark (zero or one char in \a trg):
815 * 1. An unquoted question mark MAY be used at the beginning and/or the end of an
816 * attribute-value string.
817 * 2. A contiguous sequence of unquoted question marks MAY appear at the beginning
818 * and/or the end of an attribute-value string.
819 * 3. An unquoted question mark SHALL NOT be used in any other place in an
820 * attribute-value string.
822 * Constraints on usage of the unquoted asterisk (zero or more chars in \a trg):
823 * 1. A single unquoted asterisk MAY be used as the entire attribute-value string.
824 * 2. A single unquoted asterisk MAY be used at the beginning and/or end of an
825 * attribute-value string.
826 * 3. An unquoted asterisk SHALL NOT be used in any other place in an attribute-value
829 * Unquoted question marks and asterisks MAY appear in the same attribute-value string
830 * as long as they meet the constraints above.
832 * Example of illegal usage: "foo?bar", "bar??baz", "q??x",
833 * "foo*bar", "**foo", "bar***",
834 * "*?foobar", "foobar*?"
836 * \note Relies on \a src and \a trg being wellformed.
838 inline bool matchWildcardedString( std::string src, std::string trg )
840 // std::string::npos remembers an asterisk
841 // unescaped wildcard prefix
842 std::string::size_type prefx = 0;
843 switch ( *src.begin() ) // wellformed implies not empty
846 if ( src.size() == 1 )
847 return true; // "*" matches always: superset
849 prefx = std::string::npos;
854 for_( it, ++src.begin(), src.end() )
855 { if ( *it == '?' ) ++prefx; else break; }
856 if ( src.size() == prefx )
857 return( trg.size() <= prefx ); // "??..?": superset if at most #prefx chars
859 src.erase( 0, prefx );
864 // unescaped wildcard suffix
865 std::string::size_type suffx = 0;
868 switch ( *src.rbegin() )
871 if ( evenNumberOfBackslashes( ++src.rbegin(), src.rend() ) )
873 suffx = std::string::npos;
874 src.erase( src.size()-1 );
879 for_( it, ++src.rbegin(), src.rend() )
880 { if ( *it == '?' ) ++suffx; else break; }
881 if ( ! evenNumberOfBackslashes( src.rbegin()+suffx, src.rend() ) )
882 --suffx; // last '?' was escaped.
883 src.erase( src.size()-suffx );
889 // now match; find src in trg an check surrounding wildcards
890 src = str::toLower( src );
891 trg = str::toLower( trg );
892 for ( std::string::size_type match = trg.find( src, 0 );
893 match != std::string::npos;
894 match = trg.find( src, match+1 ) )
896 if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx )
897 break; // not "*", and already more chars than "?"s before match: disjoint
898 std::string::size_type frontSize = match + src.size();
899 if ( suffx != std::string::npos && trueCharsIn( trg, frontSize, trg.size() ) > suffx )
900 continue; // not "*", and still more chars than "?"s after match: check next match
901 return true; // match: superset
903 return false; // disjoint
906 ///////////////////////////////////////////////////////////////////
908 bool CpeId::Value::containsWildcard() const
910 const std::string & value( *_value );
911 return ( isWildchar( *value.begin() )
912 || ( isWildchar( *value.rbegin() ) && evenNumberOfBackslashes( ++value.rbegin(), value.rend() ) ) );
915 ///////////////////////////////////////////////////////////////////
916 /// Symmetric attribute compare if wildcards are involved!
917 /// The specs define any comarison with a wildcarded attribute as
918 /// target to return \c uncomparable:
920 /// wildcardfree <=> wildcarded ==> uncomparable,
921 /// wildcarded <=> wildcardfree ==> superset or disjoint
923 /// But a symmetric result is much more intuitive:
925 /// wildcardfree <=> wildcarded ==> subset or disjoint
926 /// wildcarded <=> wildcardfree ==> superset or disjoint
928 ///////////////////////////////////////////////////////////////////
929 #define WFN_STRICT_SPEC 0
931 //SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const
933 static const SetCompare _NeedsCloserLook( SetCompare::Enum(-1) ); // artificial Compare value
934 static const SetCompare matchTabel[4][4] = {{
935 /* ANY, ANY */ SetCompare::equal,
936 /* ANY, NA */ SetCompare::properSuperset,
937 /* ANY, wildcardfree */ SetCompare::properSuperset,
938 /* ANY, wildcarded */ SetCompare::uncomparable,
940 /* NA, ANY */ SetCompare::properSubset,
941 /* NA, NA */ SetCompare::equal,
942 /* NA, wildcardfree */ SetCompare::disjoint,
943 /* NA, wildcarded */ SetCompare::uncomparable,
945 /* wildcardfree, ANY */ SetCompare::properSubset,
946 /* wildcardfree, NA */ SetCompare::disjoint,
947 /* wildcardfree, wildcardfree */ _NeedsCloserLook, // equal or disjoint
948 /* wildcardfree, wildcarded */ SetCompare::uncomparable,
950 /* wildcarded, ANY */ SetCompare::properSubset,
951 /* wildcarded, NA */ SetCompare::disjoint,
952 /* wildcarded, wildcardfree */ _NeedsCloserLook, // superset or disjoint
953 /* wildcarded, wildcarded */ SetCompare::uncomparable,
956 Type srcType = type();
957 Type trgType = trg.type();
958 SetCompare ret = matchTabel[srcType.asIntegral()][trgType.asIntegral()];
959 if ( ret == _NeedsCloserLook )
961 if ( srcType == Type::wildcardfree ) // trgType == Type::wildcardfree
963 // simple string compare
964 ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::disjoint;
966 else if ( srcType == Type::wildcarded ) // trgType == Type::wildcardfree
968 // Needs wildcard compare
969 ret = matchWildcardedString( *_value, *trg._value ) ? SetCompare::properSuperset : SetCompare::disjoint;
975 SetCompare CpeId::Value::setRelationMixinCompare( const CpeId::Value & trg ) const
977 ///////////////////////////////////////////////////////////////////
979 // ANY, NA => properSuperset
980 // ANY, wildcardfree => properSuperset
981 // ANY, wildcarded => properSuperset
983 // NA, ANY => properSubset
985 // NA, wildcardfree => disjoint
986 // NA, wildcarded => disjoint
988 // wildcardfree, ANY => properSubset
989 // wildcardfree, NA => disjoint
990 // wildcardfree, wildcardfree => NeedsCloserLook: equal or disjoint
991 // wildcardfree, wildcarded => NeedsCloserLook: subset or disjoint
993 // wildcarded, ANY => properSubset
994 // wildcarded, NA => disjoint
995 // wildcarded, wildcardfree => NeedsCloserLook: superset or disjoint
996 // wildcarded, wildcarded => NeedsCloserLook" equal or uncomparable
997 ///////////////////////////////////////////////////////////////////
999 SetCompare ret = SetCompare::disjoint;
1003 ret = trg.isANY() ? SetCompare::equal : SetCompare::properSuperset;
1005 else if ( trg.isANY() )
1007 ret = SetCompare::properSubset;
1011 if ( trg.isNA() ) ret = SetCompare::equal; // else: SetCompare::disjoint;
1013 else if ( ! trg.isNA() ) // else: SetCompare::disjoint;
1016 if ( isWildcarded() )
1018 if ( trg.isWildcarded() )
1020 // simple string compare just to detect 'equal'
1021 ret = matchWildcardfreeString( *_value, *trg._value ) ? SetCompare::equal : SetCompare::uncomparable;
1025 // Needs wildcard compare (src,trg)
1026 if ( matchWildcardedString( *_value, *trg._value ) ) ret = SetCompare::properSuperset; // else: SetCompare::disjoint;
1031 if ( trg.isWildcarded() )
1033 // Needs wildcard compare (trg,src)
1034 if ( matchWildcardedString( *trg._value, *_value ) ) ret = SetCompare::properSubset; // else: SetCompare::disjoint;
1038 // simple string compare
1039 if ( matchWildcardfreeString( *_value, *trg._value ) ) ret = SetCompare::equal; // else: SetCompare::disjoint;
1045 #endif // WFN_STRICT_SPEC
1047 std::ostream & operator<<( std::ostream & str, const CpeId::Value & obj )
1048 { return str << obj.asString(); }
1051 ///////////////////////////////////////////////////////////////////