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, 
':' );
 
  146        if ( ai == Attribute::language )
 
 
  161          if ( ai ) ret << 
',';
 
  162          ret << Attribute::asString( ai ) << 
'=';
 
  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'"   );
 
  239          case Attribute::language:
 
  241              const std::string & wfn( val_r.
asWfn() );
 
  242              std::string::size_type len = 0;
 
  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, 
"*" );      
 
 
  404  { 
return _pimpl->asFs(); }
 
 
  407  { 
return _pimpl->asUri(); }
 
 
  410  { 
return _pimpl->asWfn(); }
 
 
  413  { 
return _pimpl->setRelationMixinCompare( *trg.
_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);
 
  797    inline unsigned trueCharsIn( 
const std::string & str_r, std::string::size_type begin_r, std::string::size_type end_r )
 
  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 )
 
  846      std::string::size_type prefx = 0;
 
  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 );
 
  869      std::string::size_type suffx = 0;
 
  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 );
 
  896      for ( std::string::size_type match = trg.find( src, 0 );
 
  897            match != std::string::npos;
 
  898            match = trg.find( src, match+1 ) )
 
  900        if ( prefx != std::string::npos && trueCharsIn( trg, 0, match ) > prefx )
 
  902        std::string::size_type frontSize = match + src.size();
 
  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() ) 
 
 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; 
 
 
#define WFN_ATTRIBUTES
Initializer list with all wfn attributes.
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.
std::array< Value, Attribute::numAttributes > Wfn
static Wfn unbindFs(const std::string &cpe_r)
Parse Fs and unbind.
std::string asWfn() const
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 ([*?
RWCOW_pointer< std::string > _value
bool isANY() const
Whether value is ANY.
static constexpr UriFormatType uriFormat
Indicator argument for ctor arg in URI format.
static constexpr FsFormatType fsFormat
Indicator argument for ctor arg in FS format.
bool isString() const
Whether it's an attribute value string (not logical value).
std::string asString() const
Default string representation [asWfn].
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 [*?
std::string asUri() const
String representation as in URI (ANY:"", NA:"-")
std::string asWfn() const
String representation as in Well-Formed-Name (ANY:"*", NA:"").
std::string asUri() const
String representation as URI (in/out).
std::ostream & operator<<(std::ostream &str, const CpeId &obj)
Stream output.
static constexpr NoThrowType noThrow
Indicator argument for non-trowing ctor.
base::EnumClass< EAttributeDef > Attribute
'enum class Attribute'
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 SetRelationMixin< CpeId > &src, const SetRelationMixin< CpeId > &trg)
String related utilities and Regular expression matching.
boost::noncopyable NonCopyable
Ensure derived classes cannot be copied.
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.
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...
#define for_(IT, BEG, END)
Convenient for-loops using iterator.