23 #define WFN_ATTRIBUTES {\ 30 Attribute::language, \ 31 Attribute::sw_edition,\ 32 Attribute::target_sw, \ 33 Attribute::target_hw, \ 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 );
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 ) ); }
72 inline bool chIsWfnUnescaped(
char ch )
73 {
return( chIsAlNum( ch ) || ch ==
'_' ); }
86 using Wfn = std::array<Value, Attribute::numAttributes>;
91 Impl(
const std::string & cpe_r )
96 explicit operator bool()
const 97 {
for (
const auto & val :
_wfn )
if ( ! val.isANY() )
return true;
return false; }
105 ret <<
':' <<
_wfn[ai].asFs();
117 std::string val =
_wfn[ai].asUri();
119 if ( ai == Attribute::edition )
121 if ( ! (
_wfn[Attribute::sw_edition].isANY()
122 &&
_wfn[Attribute::target_sw].isANY()
123 &&
_wfn[Attribute::target_hw].isANY()
124 &&
_wfn[Attribute::other].isANY() ) )
129 <<
'~' <<
_wfn[Attribute::sw_edition].asUri()
130 <<
'~' <<
_wfn[Attribute::target_sw].asUri()
131 <<
'~' <<
_wfn[Attribute::target_hw].asUri()
132 <<
'~' <<
_wfn[Attribute::other].asUri();
139 ret << std::string( colon,
':' );
161 if ( ai ) ret <<
',';
164 ret <<
'"' << val <<
'"';
175 SetCompare ret = SetCompare::equal;
180 case SetCompare::uncomparable:
181 ret = SetCompare::uncomparable;
184 case SetCompare::equal:
187 case SetCompare::properSubset:
188 if ( ret == SetCompare::equal )
189 ret = SetCompare::properSubset;
190 else if ( ret != SetCompare::properSubset )
191 ret = SetCompare::uncomparable;
194 case SetCompare::properSuperset:
195 if ( ret == SetCompare::equal )
196 ret = SetCompare::properSuperset;
197 else if ( ret != SetCompare::properSuperset )
198 ret = SetCompare::uncomparable;
201 case SetCompare::disjoint:
202 ret = SetCompare::disjoint;
205 if ( ret == SetCompare::uncomparable || ret == SetCompare::disjoint )
219 switch ( attr_r.asEnum() )
221 case Attribute::part:
223 const std::string & wfn( val_r.
asWfn() );
229 if ( wfn[1] ==
'\0' )
233 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn:part: '" << wfn <<
"' illegal value; expected: 'h' | 'o' | 'a'" );
241 const std::string & wfn( val_r.
asWfn() );
244 if ( chIsAlpha( wfn[0] ) && chIsAlpha( wfn[1] ) )
246 len = chIsAlpha( wfn[2] ) ? 3 : 2;
247 if ( wfn[len] ==
'-' )
249 if ( chIsAlpha( wfn[len+1] ) && chIsAlpha( wfn[len+2] ) )
251 else if ( chIsNum( wfn[len+1] ) && chIsNum( wfn[len+2] ) && chIsNum( wfn[len+3] ) )
255 if ( wfn.size() != len )
256 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn:language: '" << wfn <<
"' illegal value; expected RFC5646 conform: language ['-' region]" );
265 wfn_r[attr_r.asIntegral()] = val_r;
272 static Wfn unbind(
const std::string & cpe_r );
296 if ( cpe_r[4] ==
'/' )
300 else if ( cpe_r[4] ==
'2' 308 throw std::invalid_argument(
"CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
310 else if ( cpe_r[0] !=
'\0' )
311 throw std::invalid_argument(
"CpeId: bad magic; expected: 'cpe:2.3:' | 'cpe:/'" );
319 static constexpr
unsigned numUriAttr = 7u;
320 std::vector<std::string> field;
321 field.reserve( Attribute::numAttributes );
322 if (
str::splitFields( cpe_r.c_str()+5, 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 );
328 if ( ai == Attribute::edition && field[ai][0] ==
'~' )
331 static constexpr
unsigned numPacks = 6u;
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 );
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] );
353 std::vector<std::string> field;
354 field.reserve( Attribute::numAttributes );
355 if (
str::splitFields( cpe_r.c_str()+8, std::back_inserter(field),
":" ) > Attribute::numAttributes )
356 throw std::invalid_argument(
str::Str() <<
"CpeId:Fs: too many fields (" << field.size() <<
"); expected 11" );
357 if ( !field.empty() && field.back().empty() )
359 field.resize( Attribute::numAttributes,
"*" );
380 : _pimpl( new
Impl( cpe_r ) )
401 {
return bool(*_pimpl); }
421 static std::map<Enum,std::string> _table = {
422 #define OUTS(N) { N, #N } 436 return _table[val_r];
451 if ( value_r.empty() )
454 _value.reset(
new std::string );
458 else if ( value_r !=
"*" )
460 bool starting =
true;
461 for_( chp, value_r.begin(), value_r.end() )
467 if ( ! chIsValidRange( *chp ) )
470 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn: illegal quoted character '\\" << reinterpret_cast<void*>(*chp) <<
"'" );
472 throw std::invalid_argument(
"CpeId:Wfn: Backslash escapes nothing" );
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" );
481 while ( *(chp+1) ==
'?' )
483 if ( ! ( starting || chp+1 == value_r.end() ) )
484 throw std::invalid_argument(
"CpeId:Wfn: embedded ?" );
488 if ( ! ( starting || chp+1 == value_r.end() ) )
489 throw std::invalid_argument(
"CpeId:Wfn: embedded *" );
493 if ( ! chIsWfnUnescaped( *chp ) )
495 if ( chIsValidRange( *chp ) )
496 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn: missing quote before '" << *chp <<
"'" );
498 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn: illegal character '" << reinterpret_cast<void*>(*chp) <<
"'" );
505 _value.reset(
new std::string( value_r ) );
511 if ( encoded_r !=
"*" )
513 if ( encoded_r ==
"-" )
520 bool starting =
true;
521 for_( chp, encoded_r.begin(), encoded_r.end() )
527 if ( chIsWfnUnescaped( *chp ) )
529 else if ( chIsValidRange( *chp ) )
530 result <<
'\\' << *chp;
532 throw std::invalid_argument(
str::Str() <<
"CpeId:Fs: illegal quoted character '\\" << *chp <<
"'" );
534 throw std::invalid_argument(
"CpeId:Fs: Backslash escapes nothing" );
539 while ( *(chp+1) ==
'?' )
544 if ( ! ( starting || chp+1 == encoded_r.end() ) )
545 throw std::invalid_argument(
"CpeId:Fs: embedded ?" );
549 if ( starting || chp+1 == encoded_r.end() )
552 throw std::invalid_argument(
"CpeId:Fs: embedded *" );
556 if ( chIsWfnUnescaped( *chp ) )
558 else if ( chIsValidRange( *chp ) )
559 result <<
'\\' << *chp;
561 throw std::invalid_argument(
str::Str() <<
"CpeId:Fs: illegal character '" << reinterpret_cast<void*>(*chp) <<
"'" );
568 throw std::invalid_argument(
"CpeId:Fs: '' value is illegal" );
569 _value.reset(
new std::string( result ) );
576 if ( ! encoded_r.empty() )
578 if ( encoded_r ==
"-" )
585 bool starting =
true;
586 for_( chp, encoded_r.begin(), encoded_r.end() )
592 int d1 = heDecodeCh( *(chp+1) );
595 int d2 = heDecodeCh( *(chp+2) );
604 while ( *(chp+1) ==
'%' && *(chp+2) ==
'0' && *(chp+3) ==
'1' )
609 if ( starting || chp+1 == encoded_r.end() )
615 throw std::invalid_argument(
"CpeId:Uri: embedded %01" );
619 if ( starting || chp+1 == encoded_r.end() )
626 throw std::invalid_argument(
"CpeId:Uri: embedded %02" );
630 if ( ! chIsValidRange( ch ) )
631 throw std::invalid_argument(
str::Str() <<
"CpeId:Uri: illegal % encoded character '" <<
reinterpret_cast<void*
>(ch) <<
"'" );
635 else if ( ! chIsValidRange( ch ) )
636 throw std::invalid_argument(
str::Str() <<
"CpeId:Uri: illegal character '" <<
reinterpret_cast<void*
>(ch) <<
"'" );
638 if ( chIsWfnUnescaped( ch ) )
641 result <<
'\\' << ch;
646 _value.reset(
new std::string( result ) );
656 static const std::string any(
"*" );
669 static const std::string asterisk(
"*" );
674 static const std::string dash(
"-" );
696 throw std::invalid_argument(
"CpeId:Wfn: Backslash escapes nothing" );
700 result <<
'\\' << *chp;
717 static const std::string dash(
"-" );
725 if ( chIsWfnUnescaped( *chp ) )
731 static const char *
const hdig =
"0123456789abcdef";
744 throw std::invalid_argument(
"CpeId:Wfn: Backslash escapes nothing" );
748 result <<
'%' << hdig[(
unsigned char)(*chp)/16] << hdig[(
unsigned char)(*chp)%16];
762 throw std::invalid_argument(
str::Str() <<
"CpeId:Wfn: illegal char '" << *chp <<
"' in WFN" );
777 inline bool isWildchar(
char ch_r )
778 {
return( ch_r ==
'*' || ch_r ==
'?' ); }
783 inline bool evenNumberOfBackslashes(
const std::string::const_reverse_iterator& rbegin_r,
const std::string::const_reverse_iterator& rend_r )
785 unsigned backslashes = 0;
786 for_( it, rbegin_r, rend_r )
793 return !(backslashes & 1U);
800 for_( it, begin_r, end_r )
803 if ( str_r[it] ==
'\\' )
813 inline bool matchWildcardfreeString(
const std::string & lhs,
const std::string & rhs )
842 inline bool matchWildcardedString( std::string src, std::string trg )
847 switch ( *src.begin() )
850 if ( src.size() == 1 )
853 prefx = std::string::npos;
858 for_( it, ++src.begin(), src.end() )
859 {
if ( *it ==
'?' ) ++prefx;
else break; }
860 if ( src.size() == prefx )
861 return( trg.size() <= prefx );
863 src.erase( 0, prefx );
872 switch ( *src.rbegin() )
875 if ( evenNumberOfBackslashes( ++src.rbegin(), src.rend() ) )
877 suffx = std::string::npos;
878 src.erase( src.size()-1 );
883 for_( it, ++src.rbegin(), src.rend() )
884 {
if ( *it ==
'?' ) ++suffx;
else break; }
885 if ( ! evenNumberOfBackslashes( src.rbegin()+suffx, src.rend() ) )
887 src.erase( src.size()-suffx );
897 match != std::string::npos;
898 match = trg.find( src, match+1 ) )
900 if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx )
903 if ( suffx != std::string::npos && trueCharsIn( trg, frontSize, trg.size() ) > suffx )
914 const std::string & value( *
_value );
915 return ( isWildchar( *value.begin() )
916 || ( isWildchar( *value.rbegin() ) && evenNumberOfBackslashes( ++value.rbegin(), value.rend() ) ) );
933 #define WFN_STRICT_SPEC 0 937 static const SetCompare kNeedsCloserLook( SetCompare::Enum(-1) );
938 static const SetCompare matchTabel[4][4] = {{
940 SetCompare::properSuperset,
941 SetCompare::properSuperset,
942 SetCompare::uncomparable,
944 SetCompare::properSubset,
946 SetCompare::disjoint,
947 SetCompare::uncomparable,
949 SetCompare::properSubset,
950 SetCompare::disjoint,
952 SetCompare::uncomparable,
954 SetCompare::properSubset,
955 SetCompare::disjoint,
957 SetCompare::uncomparable,
960 Type srcType = type();
961 Type trgType = trg.type();
962 SetCompare ret = matchTabel[srcType.asIntegral()][trgType.asIntegral()];
963 if ( ret == kNeedsCloserLook )
965 if ( srcType == Type::wildcardfree )
968 ret = matchWildcardfreeString( *
_value, *trg._value ) ? SetCompare::equal : SetCompare::disjoint;
970 else if ( srcType == Type::wildcarded )
973 ret = matchWildcardedString( *
_value, *trg._value ) ? SetCompare::properSuperset : SetCompare::disjoint;
1003 SetCompare ret = SetCompare::disjoint;
1007 ret = trg.
isANY() ? SetCompare::equal : SetCompare::properSuperset;
1009 else if ( trg.
isANY() )
1011 ret = SetCompare::properSubset;
1015 if ( trg.
isNA() ) ret = SetCompare::equal;
1017 else if ( ! trg.
isNA() )
1020 if ( isWildcarded() )
1025 ret = matchWildcardfreeString( *
_value, *trg.
_value ) ? SetCompare::equal : SetCompare::uncomparable;
1030 if ( matchWildcardedString( *
_value, *trg.
_value ) ) ret = SetCompare::properSuperset;
1038 if ( matchWildcardedString( *trg.
_value, *
_value ) ) ret = SetCompare::properSubset;
1043 if ( matchWildcardfreeString( *
_value, *trg.
_value ) ) ret = SetCompare::equal;
1049 #endif // WFN_STRICT_SPEC std::string toLower(const std::string &s)
Return lowercase version of s.
std::array< Value, Attribute::numAttributes > Wfn
Value()
Default ctor: ANY.
RWCOW_pointer< Impl > _pimpl
Implementation class.
SetCompare setRelationMixinCompare(const CpeId &trg) const
CPE name matching hook for SetRelationMixin.
std::ostream & operator<<(std::ostream &str, const CpeId &obj)
Indicator type for non-trowing ctor.
std::string asFs() const
String representation as in Formated-String (ANY:"*", NA:"-")
std::string asUri() const
String representation as in URI (ANY:"", NA:"-")
#define WFN_ATTRIBUTES
Initializer list with all wfn attributes.
static const Value NA
Logical value indicating “not applicable/not used".
RWCOW_pointer< std::string > _value
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
String related utilities and Regular expression matching.
Impl(const std::string &cpe_r)
Common Platform Enumearation (2.3) See http://cpe.mitre.org/ for more information on the Common Platf...
base::EnumClass< EAttributeDef > Attribute
'enum class Attribute'
static Wfn unbindFs(const std::string &cpe_r)
Parse Fs and unbind.
static Wfn unbindUri(const std::string &cpe_r)
Parse Uri and unbind.
bool isANY() const
Whether value is ANY.
static std::string lastMalformed
bool isNA() const
Whether value is NA.
CpeId()
Default ctor: ANY-Cpeid, all attribute values are ANY.
static const Value ANY
Logical value matching ANY value.
static Wfn unbind(const std::string &cpe_r)
Parse magic and unbind accordingly.
std::string asString(TInt val, char zero='0', char one='1')
For printing bits.
bool isString() const
Whether it's an attribute value string (not logical value).
static void assignAttr(Wfn &wfn_r, Attribute attr_r, const Value &val_r)
Assign val_r if it meets attr_r specific contraints.
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...
static constexpr NoThrowType noThrow
Indicator argument for non-trowing ctor.
std::string asString() const
Default string representation [asWfn].
std::string asWfn() const
int compareCI(const C_Str &lhs, const C_Str &rhs)
unsigned splitFields(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
static constexpr FsFormatType fsFormat
Indicator argument for ctor arg in FS format.
SetCompare compare(const CpeId &trg) const
Compare sets.
bool containsWildcard() const
HAs unquoted [*?] at begin and/or end of value.
std::string asWfn() const
String representation as in Well-Formed-Name (ANY:"*", NA:"").
SetCompare setRelationMixinCompare(const Value &trg) const
CPE name matching hook for SetRelationMixin.
std::string asUri() const
String representation as URI (in/out).
std::string asWfn() const
String representation as Well-Formed-Name (internal format, out only).
Easy-to use interface to the ZYPP dependency resolver.
SetCompare setRelationMixinCompare(const Impl &trg) const
bool isWildcarded() const
An attribute value string with wildcards ([*?] at begin and/or end)
std::string asUri() const
std::string asFs() const
String representation as Formated-String (in/out).
static constexpr UriFormatType uriFormat
Indicator argument for ctor arg in URI format.
static const std::string & asString(Enum val_r)
string representantion
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.