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 ==
'_' ); }
84 typedef std::array<Value,Attribute::numAttributes>
Wfn;
89 Impl(
const std::string & cpe_r )
94 explicit operator bool()
const
95 {
for (
const auto & val :
_wfn )
if ( ! val.isANY() )
return true;
return false; }
103 ret <<
':' <<
_wfn[ai].asFs();
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() ) )
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 )
160 if ( ai ) ret <<
',';
163 ret <<
'"' << val <<
'"';
174 SetCompare ret = SetCompare::equal;
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 )
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() );
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;
271 static Wfn unbind(
const std::string & cpe_r );
295 if ( cpe_r[4] ==
'/' )
299 else if ( cpe_r[4] ==
'2'
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:/'" );
318 static constexpr
unsigned numUriAttr = 7u;
319 std::vector<std::string> field;
320 field.reserve( Attribute::numAttributes );
321 if (
str::splitFields( cpe_r.c_str()+5, 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 );
327 if ( ai == Attribute::edition && field[ai][0] ==
'~' )
330 static constexpr
unsigned numPacks = 6u;
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 );
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] );
352 std::vector<std::string> field;
353 field.reserve( Attribute::numAttributes );
354 if (
str::splitFields( cpe_r.c_str()+8, std::back_inserter(field),
":" ) > Attribute::numAttributes )
355 throw std::invalid_argument(
str::Str() <<
"CpeId:Fs: too many fields (" << field.size() <<
"); expected 11" );
356 if ( !field.empty() && field.back().empty() )
358 field.resize( Attribute::numAttributes,
"*" );
379 : _pimpl( new
Impl( cpe_r ) )
399 CpeId::operator bool()
const
400 {
return bool(*_pimpl); }
420 static std::map<Enum,std::string>
_table = {
421 #define OUTS(N) { N, #N }
447 if ( value_r.empty() )
450 _value.reset(
new std::string );
454 else if ( value_r !=
"*" )
456 bool starting =
true;
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" );
477 while ( *(chp+1) ==
'?' )
479 if ( ! ( starting || chp+1 == value_r.end() ) )
480 throw std::invalid_argument(
"CpeId:Wfn: embedded ?" );
484 if ( ! ( starting || chp+1 == value_r.end() ) )
485 throw std::invalid_argument(
"CpeId:Wfn: embedded *" );
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 ) );
507 if ( encoded_r !=
"*" )
509 if ( encoded_r ==
"-" )
516 bool starting =
true;
517 for_( chp, encoded_r.begin(), encoded_r.end() )
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" );
535 while ( *(chp+1) ==
'?' )
540 if ( ! ( starting || chp+1 == encoded_r.end() ) )
541 throw std::invalid_argument(
"CpeId:Fs: embedded ?" );
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 ) );
572 if ( ! encoded_r.empty() )
574 if ( encoded_r ==
"-" )
581 bool starting =
true;
582 for_( chp, encoded_r.begin(), encoded_r.end() )
588 int d1 = heDecodeCh( *(chp+1) );
591 int d2 = heDecodeCh( *(chp+2) );
600 while ( *(chp+1) ==
'%' && *(chp+2) ==
'0' && *(chp+3) ==
'1' )
605 if ( starting || chp+1 == encoded_r.end() )
611 throw std::invalid_argument(
"CpeId:Uri: embedded %01" );
615 if ( starting || chp+1 == encoded_r.end() )
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 ) );
652 static const std::string any(
"*" );
665 static const std::string asterisk(
"*" );
670 static const std::string dash(
"-" );
692 throw std::invalid_argument(
"CpeId:Wfn: Backslash escapes nothing" );
696 result <<
'\\' << *chp;
713 static const std::string dash(
"-" );
721 if ( chIsWfnUnescaped( *chp ) )
727 static const char *
const hdig =
"0123456789abcdef";
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" );
773 inline bool isWildchar(
char ch_r )
774 {
return( ch_r ==
'*' || ch_r ==
'?' ); }
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);
796 for_( it, begin_r, end_r )
799 if ( str_r[it] ==
'\\' )
809 inline bool matchWildcardfreeString(
const std::string & lhs,
const std::string & rhs )
838 inline bool matchWildcardedString( std::string src, std::string trg )
843 switch ( *src.begin() )
846 if ( src.size() == 1 )
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 );
859 src.erase( 0, prefx );
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() ) )
883 src.erase( src.size()-suffx );
893 match != std::string::npos;
894 match = trg.find( src, match+1 ) )
896 if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx )
899 if ( suffx != std::string::npos && trueCharsIn( trg, frontSize, trg.size() ) > suffx )
910 const std::string & value( *
_value );
911 return ( isWildchar( *value.begin() )
912 || ( isWildchar( *value.rbegin() ) && evenNumberOfBackslashes( ++value.rbegin(), value.rend() ) ) );
929 #define WFN_STRICT_SPEC 0
933 static const SetCompare kNeedsCloserLook( SetCompare::Enum(-1) );
934 static const SetCompare matchTabel[4][4] = {{
936 SetCompare::properSuperset,
937 SetCompare::properSuperset,
938 SetCompare::uncomparable,
940 SetCompare::properSubset,
942 SetCompare::disjoint,
943 SetCompare::uncomparable,
945 SetCompare::properSubset,
946 SetCompare::disjoint,
948 SetCompare::uncomparable,
950 SetCompare::properSubset,
951 SetCompare::disjoint,
953 SetCompare::uncomparable,
956 Type srcType = type();
957 Type trgType = trg.type();
958 SetCompare ret = matchTabel[srcType.asIntegral()][trgType.asIntegral()];
959 if ( ret == kNeedsCloserLook )
961 if ( srcType == Type::wildcardfree )
964 ret = matchWildcardfreeString( *
_value, *trg._value ) ? SetCompare::equal : SetCompare::disjoint;
966 else if ( srcType == Type::wildcarded )
969 ret = matchWildcardedString( *
_value, *trg._value ) ? SetCompare::properSuperset : SetCompare::disjoint;
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;
1013 else if ( ! trg.
isNA() )
1016 if ( isWildcarded() )
1021 ret = matchWildcardfreeString( *
_value, *trg.
_value ) ? SetCompare::equal : SetCompare::uncomparable;
1026 if ( matchWildcardedString( *
_value, *trg.
_value ) ) ret = SetCompare::properSuperset;
1034 if ( matchWildcardedString( *trg.
_value, *
_value ) ) ret = SetCompare::properSubset;
1039 if ( matchWildcardfreeString( *
_value, *trg.
_value ) ) ret = SetCompare::equal;
#define WFN_ATTRIBUTES
Initializer list with all wfn attributes.
#define for_(IT, BEG, END)
Convenient for-loops using iterator.
std::string asUri() const
Impl(const std::string &cpe_r)
SetCompare setRelationMixinCompare(const Impl &trg) const
static void assignAttr(Wfn &wfn_r, Attribute attr_r, const Value &val_r)
Assign val_r if it meets attr_r specific contraints.
static Wfn unbindUri(const std::string &cpe_r)
Parse Uri and unbind.
static Wfn unbind(const std::string &cpe_r)
Parse magic and unbind accordingly.
static Wfn unbindFs(const std::string &cpe_r)
Parse Fs and unbind.
std::array< Value, Attribute::numAttributes > Wfn
std::string asWfn() const
static constexpr UriFormatType uriFormat
Indicator argument for ctor arg in URI format.
static const Value ANY
Logical value matching ANY value.
bool isNA() const
Whether value is NA.
static const Value NA
Logical value indicating “not applicable/not used".
bool isWildcarded() const
An attribute value string with wildcards ([*?] at begin and/or end)
RWCOW_pointer< std::string > _value
bool isANY() const
Whether value is ANY.
bool isString() const
Whether it's an attribute value string (not logical value).
std::string asString() const
Default string representation [asWfn].
static constexpr FsFormatType fsFormat
Indicator argument for ctor arg in FS format.
std::string asFs() const
String representation as in Formated-String (ANY:"*", NA:"-")
SetCompare setRelationMixinCompare(const Value &trg) const
CPE name matching hook for SetRelationMixin.
Value()
Default ctor: ANY.
bool containsWildcard() const
HAs unquoted [*?] at begin and/or end of value.
std::string asUri() const
String representation as in URI (ANY:"", NA:"-")
std::string asWfn() const
String representation as in Well-Formed-Name (ANY:"*", NA:"").
Common Platform Enumearation (2.3) See http://cpe.mitre.org/ for more information on the Common Platf...
std::string asUri() const
String representation as URI (in/out).
base::EnumClass< EAttributeDef > Attribute
'enum class Attribute'
std::ostream & operator<<(std::ostream &str, const CpeId &obj)
Stream output.
std::string asWfn() const
String representation as Well-Formed-Name (internal format, out only).
std::string asFs() const
String representation as Formated-String (in/out).
SetCompare setRelationMixinCompare(const CpeId &trg) const
CPE name matching hook for SetRelationMixin.
CpeId()
Default ctor: ANY-Cpeid, all attribute values are ANY.
RWCOW_pointer< Impl > _pimpl
Implementation class.
SetCompare compare(const CpeId &trg) const
Compare sets.
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
static std::map< std::string, ServiceType::Type > _table
unsigned splitFields(const C_Str &line_r, TOutputIterator result_r, const C_Str &sepchars_r=":")
Split line_r into fields.
std::string toLower(const std::string &s)
Return lowercase version of s.
int compareCI(const C_Str &lhs, const C_Str &rhs)
Easy-to use interface to the ZYPP dependency resolver.
std::string asString(const DefaultIntegral< Tp, TInitial > &obj)
static const std::string & asString(Enum val_r)
string representantion
Indicator type for non-trowing ctor.
static std::string lastMalformed
Convenient building of std::string via std::ostringstream Basically a std::ostringstream autoconverti...