Skip to content

Commit

Permalink
Refactor and simplify CPEVersion comparison code
Browse files Browse the repository at this point in the history
  • Loading branch information
ra1nb0rn committed Mar 1, 2024
1 parent a4613a7 commit 8f3cd8c
Showing 1 changed file with 30 additions and 87 deletions.
117 changes: 30 additions & 87 deletions cpe_version.py
Original file line number Diff line number Diff line change
@@ -1,47 +1,16 @@
import re
import string

from requests.models import iter_slices
VERSION_PART_SEP_RE = re.compile(r'[^\da-zA-Z]')

class CPEVersion:

def __init__(self, ver_str):
self.version_str = ver_str

def get_version_parts(self):
parts = []
cur_part = ''
cur_char_class = string.digits
is_leading_zeroes = False
for char in self.version_str:
if char not in cur_char_class:
if cur_part:
parts.append(cur_part)
elif cur_char_class == string.digits and is_leading_zeroes:
parts.append("0")

cur_part = ''
is_leading_zeroes = False
if char in string.digits:
cur_char_class = string.digits
if char == '0':
is_leading_zeroes = True
elif char in string.ascii_letters:
cur_char_class = string.ascii_letters
else:
cur_char_class = string.punctuation

if char not in string.punctuation:
if is_leading_zeroes and char == '0':
continue
is_leading_zeroes = False
cur_part += char

if cur_part:
parts.append(cur_part)
elif cur_char_class == string.digits and is_leading_zeroes:
parts.append("0")

return parts
re_version_parts = VERSION_PART_SEP_RE.split(self.version_str)
return [part.lstrip('0') for part in re_version_parts] # strip leading '0' from every part

def __eq__(self, other):
parts, other_parts = self.get_version_parts(), other.get_version_parts()
Expand Down Expand Up @@ -75,64 +44,38 @@ def __lt__(self, other):
min_part_count = min(len(parts), len(other_parts))
for part_idx in range(min_part_count):
part, other_part = parts[part_idx], other_parts[part_idx]
if part_idx < len(parts)-1 and part_idx < len(other_parts)-1:
if part.lower() == other_part.lower():
continue

val_part, val_part_other = 0, 0
# right-pad with '0' to make both parts the same length
if len(part) < len(other_part):
part = part.rjust(len(other_part), '0')
if len(other_part) < len(part):
other_part = other_part.rjust(len(part), '0')

# Variant 1: full "value" of version part matters
# for i, char in enumerate(part):
# if char in string.digits:
# val_part += int(char) * 10**(len(part)-i)
# else:
# val_part += (string.ascii_lowercase.find(char.lower())+1) * 36**(len(part)-i)
# if both parts are empty / were zeroes
if (not part) and (not other_part):
# continue if not in last step and return False otherwise
if part_idx < len(parts)-1 and part_idx < len(other_parts)-1:
continue
return False

# for i, char in enumerate(other_part):
# if char in string.digits:
# val_part_other += int(char) * 10**(len(other_part)-i)
# else:
# val_part_other += (string.ascii_lowercase.find(char.lower())+1) * 36**(len(other_part)-i)
# if the comparison is not in the last step and the current parts are equal
if part_idx < len(parts)-1 and part_idx < len(other_parts)-1:
if part.lower() == other_part.lower():
continue

# if val_part >= val_part_other:
# return False
# return True # if version part in front is smaller, the entire version is already smaller
# compare parts char by char
for i in range(len(part)):
if ord(part[i].lower()) < ord(other_part[i].lower()):
return True
if ord(part[i].lower()) > ord(other_part[i].lower()):
return False

# Variant 2: with version numbers made up of letters, the letters are compared step by step
if part[0].lower() in string.ascii_lowercase and other_part[0] in string.digits:
return False
elif part[0].lower() in string.digits and other_part[0] in string.ascii_lowercase:
return True
elif part[0] in string.ascii_letters:
iter_max = min(len(part), len(other_part))
for i in range(iter_max):
if ord(part[i].lower()) > ord(other_part[i].lower()):
return False
if (i == iter_max - 1 and len(parts) == len(other_parts) and
len(part) == len(other_part) and
ord(part[i].lower()) == ord(other_part[i].lower())):
return False
else:
for i, char in enumerate(part):
val_part += int(char) * 10**(len(part)-i-1)

for i, char in enumerate(other_part):
val_part_other += int(char) * 10**(len(other_part)-i-1)

if val_part > val_part_other:
# very last part of the comparison and both parts are equal
if (i == len(part) - 1 and part_idx == min_part_count - 1 and
len(parts) == len(other_parts) and
len(part) == len(other_part) and
ord(part[i].lower()) == ord(other_part[i].lower())):
return False
if val_part == val_part_other:
# check for equality and return False in that case
if len(parts) > len(other_parts) and all(x == "0" for x in parts[part_idx+1:]):
return False
if len(other_parts) > len(parts) and all(x == "0" for x in other_parts[part_idx+1:]):
return False

# check for greater number of version parts on last iteration and return False in that case
if part_idx > min_part_count-2 and len(parts) >= len(other_parts):
return False

return True # if version part in front is smaller, the entire version is already smaller

if len(parts) > len(other_parts):
return False
Expand Down

0 comments on commit 8f3cd8c

Please sign in to comment.