#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
This file is part of cpe package.
This module allows to store the value of the components of a CPE name
of version 2.3 of CPE (Common Platform Enumeration) specification
with formatted string style.
Copyright (C) 2013 Alejandro Galindo García, Roberto Abdelkader Martínez Pérez
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
For any problems using the cpe package, or general questions and
feedback about it, please contact:
- Alejandro Galindo García: galindo.garcia.alejandro@gmail.com
- Roberto Abdelkader Martínez Pérez: robertomartinezp@gmail.com
"""
from cpecomp2_3 import CPEComponent2_3
from cpecomp2_3_wfn import CPEComponent2_3_WFN
from cpecomp_simple import CPEComponentSimple
import re
[docs]class CPEComponent2_3_FS(CPEComponent2_3):
"""
Represents a component of version 2.3 of CPE specification with URI style.
"""
###############
# CONSTANTS #
###############
# Patterns used to check the value of component
_UNRESERVED = "\w|\.|\-"
_PUNC = "\!|\"|\;|\#|\$|\%|\&|\'|\(|\)|\+|\,|\/|\:|\<|\=|\>|\@|\[|\]|\^|\`|\{|\||\}|\~|\-"
#: Separator of components of CPE name with URI style
SEPARATOR_COMP = ":"
#: Separator of language parts: language and region
SEPARATOR_LANG = "-"
# Logical values in string format
#: Logical value associated with a any value logical value
VALUE_ANY = "*"
#: Logical value associated with a not applicable logical value
VALUE_NA = "-"
#: Constant associated with wildcard to indicate a sequence of characters
WILDCARD_MULTI = CPEComponent2_3_WFN.WILDCARD_MULTI
#: Constant associated with wildcard to indicate a character
WILDCARD_ONE = CPEComponent2_3_WFN.WILDCARD_ONE
###############
# VARIABLES #
###############
# Compilation of regular expression associated with value of CPE part
_logical = "(\{0}|{1})".format(VALUE_ANY, VALUE_NA)
_quest = "\{0}".format(WILDCARD_ONE)
_asterisk = "\{0}".format(WILDCARD_MULTI)
_special = "{0}|{1}".format(_quest, _asterisk)
_spec_chrs = "{0}+|{1}".format(_quest, _asterisk)
_quoted = r"\\(\\" + "|{0}|{1})".format(_special, _PUNC)
_avstring = "{0}|{1}".format(_UNRESERVED, _quoted)
_value_string_pattern = "^(({0}+|{1}*({2})+|{3}({4})+)({5})?|{6})$".format(
_quest, _quest, _avstring, _asterisk, _avstring, _spec_chrs, _logical)
_part_value_rxc = re.compile(_value_string_pattern)
####################
# OBJECT METHODS #
####################
def _decode(self):
"""
Convert the characters of string s to standard value (WFN value).
Inspect each character in value of component. Copy quoted characters,
with their escaping, into the result. Look for unquoted non
alphanumerics and if not "*" or "?", add escaping.
:exception: ValueError - invalid character in value of component
"""
result = []
idx = 0
s = self._encoded_value
embedded = False
errmsg = []
errmsg.append("Invalid character '")
while (idx < len(s)):
c = s[idx] # get the idx'th character of s
errmsg.append(c)
errmsg.append("'")
errmsg_str = "".join(errmsg)
if (CPEComponentSimple._is_alphanum(c)):
# Alphanumeric characters pass untouched
result.append(c)
idx += 1
embedded = True
continue
if c == "\\":
# Anything quoted in the bound string stays quoted
# in the unbound string.
result.append(s[idx: idx + 2])
idx += 2
embedded = True
continue
if (c == CPEComponent2_3_FS.WILDCARD_MULTI):
# An unquoted asterisk must appear at the beginning or
# end of the string.
if (idx == 0) or (idx == (len(s) - 1)):
result.append(c)
idx += 1
embedded = True
continue
else:
raise ValueError(errmsg_str)
if (c == CPEComponent2_3_FS.WILDCARD_ONE):
# An unquoted question mark must appear at the beginning or
# end of the string, or in a leading or trailing sequence:
# - ? legal at beginning or end
# - embedded is false, so must be preceded by ?
# - embedded is true, so must be followed by ?
if (((idx == 0) or (idx == (len(s) - 1))) or
((not embedded) and (s[idx - 1] == CPEComponent2_3_FS.WILDCARD_ONE)) or
(embedded and (s[idx + 1] == CPEComponent2_3_FS.WILDCARD_ONE))):
result.append(c)
idx += 1
embedded = False
continue
else:
raise ValueError(errmsg_str)
# all other characters must be quoted
result.append("\\")
result.append(c)
idx += 1
embedded = True
self._standard_value = "".join(result)
def _is_valid_value(self):
"""
Return True if the value of component in generic attribute is valid,
and otherwise False.
:returns: True if value is valid, False otherwise
:rtype: boolean
"""
comp_str = self._standard_value[0]
return CPEComponent2_3_FS._part_value_rxc.match(comp_str) is not None
if __name__ == "__main__":
import doctest
doctest.testmod()
doctest.testfile("../tests/testfile_cpecomp2_3_fs.txt")