Exemplo n.º 1
0
def object_path_component_cmp(comp1, comp2):
    """
    Compare a string/int to another string/int; this induces an ordering over
    all strings and ints.  It is used to perform a lexicographical sort on
    object paths.

    Ints and strings compare as usual to each other; ints compare less than
    strings.

    :param comp1: An object path component (string or int)
    :param comp2: An object path component (string or int)
    :return: <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """

    # both ints or both strings: use builtin comparison operators
    if (isinstance(comp1, int) and isinstance(comp2, int)) \
            or (isinstance(comp1, str) and isinstance(comp2, str)):
        result = generic_cmp(comp1, comp2)

    # one is int, one is string.  Let's say ints come before strings.
    elif isinstance(comp1, int):
        result = -1

    else:
        result = 1

    return result
Exemplo n.º 2
0
def generic_constant_cmp(const1, const2):
    """
    Generic comparator for most _Constant instances.  They must have a "value"
    attribute whose value supports the builtin comparison operators.

    :param const1: The first _Constant instance
    :param const2: The second _Constant instance
    :return: <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """
    return generic_cmp(const1.value, const2.value)
Exemplo n.º 3
0
def hex_cmp(value1, value2):
    """
    Compare two STIX "hex" values.  This decodes to bytes and compares that.
    It does *not* do a string compare on the hex representations.

    :param value1: The first HexConstant
    :param value2: The second HexConstant
    :return: <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """
    bytes1 = bytes.fromhex(value1.value)
    bytes2 = bytes.fromhex(value2.value)

    return generic_cmp(bytes1, bytes2)
Exemplo n.º 4
0
def bin_cmp(value1, value2):
    """
    Compare two STIX "binary" values.  This decodes to bytes and compares that.
    It does *not* do a string compare on the base64 representations.

    :param value1: The first BinaryConstant
    :param value2: The second BinaryConstant
    :return: <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """
    bytes1 = base64.standard_b64decode(value1.value)
    bytes2 = base64.standard_b64decode(value2.value)

    return generic_cmp(bytes1, bytes2)
Exemplo n.º 5
0
def comparison_operator_cmp(op1, op2):
    """
    Compare two comparison operators.

    :param op1: The first comparison operator (a string)
    :param op2: The second comparison operator (a string)
    :return: <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """
    op1_idx = _COMPARISON_OP_ORDER.index(op1)
    op2_idx = _COMPARISON_OP_ORDER.index(op2)

    result = generic_cmp(op1_idx, op2_idx)

    return result
Exemplo n.º 6
0
def constant_cmp(value1, value2):
    """
    Compare two constants.

    Args:
        value1: The first _Constant instance
        value2: The second _Constant instance

    Returns:
        <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """

    # Special handling for ints/floats: treat them generically as numbers,
    # ordered before all other types.
    if isinstance(value1, (IntegerConstant, FloatConstant)) \
            and isinstance(value2, (IntegerConstant, FloatConstant)):
        result = generic_constant_cmp(value1, value2)

    elif isinstance(value1, (IntegerConstant, FloatConstant)):
        result = -1

    elif isinstance(value2, (IntegerConstant, FloatConstant)):
        result = 1

    else:

        type1 = type(value1)
        type2 = type(value2)

        type1_idx = _CONSTANT_TYPE_ORDER.index(type1)
        type2_idx = _CONSTANT_TYPE_ORDER.index(type2)

        result = generic_cmp(type1_idx, type2_idx)
        if result == 0:
            # Types are the same; must compare values
            cmp_func = _CONSTANT_COMPARATORS.get(type1)
            if not cmp_func:
                raise TypeError("Don't know how to compare " + type1.__name__)

            result = cmp_func(value1, value2)

    return result
Exemplo n.º 7
0
def observation_expression_cmp(expr1, expr2):
    """
    Compare two observation expression ASTs.  This is sensitive to the order of
    the expressions' sub-components.  To achieve an order-insensitive
    comparison, the ASTs must be canonically ordered first.

    Args:
        expr1: The first observation expression
        expr2: The second observation expression

    Returns:
        <0, 0, or >0 depending on whether the first arg is less, equal or
        greater than the second
    """
    type1 = type(expr1)
    type2 = type(expr2)

    type1_idx = _OBSERVATION_EXPRESSION_TYPE_ORDER.index(type1)
    type2_idx = _OBSERVATION_EXPRESSION_TYPE_ORDER.index(type2)

    if type1_idx != type2_idx:
        result = generic_cmp(type1_idx, type2_idx)

    # else, both exprs are of same type.

    # If they're simple, use contained comparison expression order
    elif type1 is ObservationExpression:
        result = comparison_expression_cmp(
            expr1.operand,
            expr2.operand,
        )

    elif isinstance(expr1, _CompoundObservationExpression):
        # Both compound, and of same type (and/or/followedby): sort according
        # to contents.
        result = iter_lex_cmp(
            expr1.operands,
            expr2.operands,
            observation_expression_cmp,
        )

    else:  # QualifiedObservationExpression
        # Both qualified.  Check qualifiers first; if they are the same,
        # use order of the qualified expressions.
        qual1_type = type(expr1.qualifier)
        qual2_type = type(expr2.qualifier)

        qual1_type_idx = _QUALIFIER_TYPE_ORDER.index(qual1_type)
        qual2_type_idx = _QUALIFIER_TYPE_ORDER.index(qual2_type)

        result = generic_cmp(qual1_type_idx, qual2_type_idx)

        if result == 0:
            # Same qualifier type; compare qualifier details
            qual_cmp = _QUALIFIER_COMPARATORS.get(qual1_type)
            if qual_cmp:
                result = qual_cmp(expr1.qualifier, expr2.qualifier)
            else:
                raise TypeError(
                    "Can't compare qualifier type: " + qual1_type.__name__, )

        if result == 0:
            # Same qualifier type and details; use qualified expression order
            result = observation_expression_cmp(
                expr1.observation_expression,
                expr2.observation_expression,
            )

    return result