Top

miasm.core.interval module

from __future__ import print_function

INT_EQ = 0      # Equivalent
INT_B_IN_A = 1  # B in A
INT_A_IN_B = -1 # A in B
INT_DISJOIN = 2 # Disjoint
INT_JOIN = 3    # Overlap
INT_JOIN_AB = 4 # B starts at the end of A
INT_JOIN_BA = 5 # A starts at the end of B


def cmp_interval(inter1, inter2):
    """Compare @inter1 and @inter2 and returns the associated INT_* case
    @inter1, @inter2: interval instance
    """
    if inter1 == inter2:
        return INT_EQ

    inter1_start, inter1_stop = inter1
    inter2_start, inter2_stop = inter2
    result = INT_JOIN
    if inter1_start <= inter2_start and inter1_stop >= inter2_stop:
        result = INT_B_IN_A
    if inter2_start <= inter1_start and inter2_stop >= inter1_stop:
        result = INT_A_IN_B
    if inter1_stop + 1 == inter2_start:
        result = INT_JOIN_AB
    if inter2_stop + 1 == inter1_start:
        result = INT_JOIN_BA
    if inter1_start > inter2_stop + 1 or inter2_start > inter1_stop + 1:
        result = INT_DISJOIN
    return result


class interval(object):
    """Stands for intervals with integer bounds

    Offers common methods to work with interval"""

    def __init__(self, bounds=None):
        """Instance an interval object
        @bounds: (optional) list of (int, int) and/or interval instance
        """
        if bounds is None:
            bounds = []
        elif isinstance(bounds, interval):
            bounds = bounds.intervals
        self.is_cannon = False
        self.intervals = bounds
        self.cannon()

    def __iter__(self):
        """Iterate on intervals"""
        for inter in self.intervals:
            yield inter

    @staticmethod
    def cannon_list(tmp):
        """
        Return a cannonizes list of intervals
        @tmp: list of (int, int)
        """
        tmp = sorted([x for x in tmp if x[0] <= x[1]])
        out = []
        if not tmp:
            return out
        out.append(tmp.pop())
        while tmp:
            x = tmp.pop()
            rez = cmp_interval(out[-1], x)

            if rez == INT_EQ:
                continue
            elif rez == INT_DISJOIN:
                out.append(x)
            elif rez == INT_B_IN_A:
                continue
            elif rez in [INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
                u, v = x
                while out and cmp_interval(out[-1], (u, v)) in [
                    INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
                    u = min(u, out[-1][0])
                    v = max(v, out[-1][1])
                    out.pop()
                out.append((u, v))
            else:
                raise ValueError('unknown state', rez)
        return out[::-1]

    def cannon(self):
        "Apply .cannon_list() on self contained intervals"
        if self.is_cannon is True:
            return
        self.intervals = interval.cannon_list(self.intervals)
        self.is_cannon = True

    def __repr__(self):
        if self.intervals:
            o = " U ".join(["[0x%X 0x%X]" % (x[0], x[1])
                           for x in self.intervals])
        else:
            o = "[]"
        return o

    def __contains__(self, other):
        if isinstance(other, interval):
            for intervalB in other.intervals:
                is_in = False
                for intervalA in self.intervals:
                    if cmp_interval(intervalA, intervalB) in [INT_EQ, INT_B_IN_A]:
                        is_in = True
                        break
                if not is_in:
                    return False
            return True
        else:
            for intervalA in self.intervals:
                if intervalA[0] <= other <= intervalA[1]:
                    return True
            return False

    def __eq__(self, i):
        return self.intervals == i.intervals

    def __ne__(self, other):
        return not self.__eq__(other)

    def union(self, other):
        """
        Return the union of intervals
        @other: interval instance
        """

        if isinstance(other, interval):
            other = other.intervals
        other = interval(self.intervals + other)
        return other

    def difference(self, other):
        """
        Return the difference of intervals
        @other: interval instance
        """

        to_test = self.intervals[:]
        i = -1
        to_del = other.intervals[:]
        while i < len(to_test) - 1:
            i += 1
            x = to_test[i]
            if x[0] > x[1]:
                del to_test[i]
                i -= 1
                continue

            while to_del and to_del[0][1] < x[0]:
                del to_del[0]

            for y in to_del:
                if y[0] > x[1]:
                    break
                rez = cmp_interval(x, y)
                if rez == INT_DISJOIN:
                    continue
                elif rez == INT_EQ:
                    del to_test[i]
                    i -= 1
                    break
                elif rez == INT_A_IN_B:
                    del to_test[i]
                    i -= 1
                    break
                elif rez == INT_B_IN_A:
                    del to_test[i]
                    i1 = (x[0], y[0] - 1)
                    i2 = (y[1] + 1, x[1])
                    to_test[i:i] = [i1, i2]
                    i -= 1
                    break
                elif rez in [INT_JOIN_AB, INT_JOIN_BA]:
                    continue
                elif rez == INT_JOIN:
                    del to_test[i]
                    if x[0] < y[0]:
                        to_test[i:i] = [(x[0], y[0] - 1)]
                    else:
                        to_test[i:i] = [(y[1] + 1, x[1])]
                    i -= 1
                    break
                else:
                    raise ValueError('unknown state', rez)
        return interval(to_test)

    def intersection(self, other):
        """
        Return the intersection of intervals
        @other: interval instance
        """

        out = []
        for x in self.intervals:
            if x[0] > x[1]:
                continue
            for y in other.intervals:
                rez = cmp_interval(x, y)

                if rez == INT_DISJOIN:
                    continue
                elif rez == INT_EQ:
                    out.append(x)
                    continue
                elif rez == INT_A_IN_B:
                    out.append(x)
                    continue
                elif rez == INT_B_IN_A:
                    out.append(y)
                    continue
                elif rez == INT_JOIN_AB:
                    continue
                elif rez == INT_JOIN_BA:
                    continue
                elif rez == INT_JOIN:
                    if x[0] < y[0]:
                        out.append((y[0], x[1]))
                    else:
                        out.append((x[0], y[1]))
                    continue
                else:
                    raise ValueError('unknown state', rez)
        return interval(out)


    def __add__(self, other):
        return self.union(other)

    def __and__(self, other):
        return self.intersection(other)

    def __sub__(self, other):
        return self.difference(other)

    def hull(self):
        "Return the first and the last bounds of intervals"
        if not self.intervals:
            return None, None
        return self.intervals[0][0], self.intervals[-1][1]


    @property
    def empty(self):
        """Return True iff the interval is empty"""
        return not self.intervals

    def show(self, img_x=1350, img_y=20, dry_run=False):
        """
        show image representing the interval
        """
        try:
            import Image
            import ImageDraw
        except ImportError:
            print('cannot import python PIL imaging')
            return

        img = Image.new('RGB', (img_x, img_y), (100, 100, 100))
        draw = ImageDraw.Draw(img)
        i_min, i_max = self.hull()

        print(hex(i_min), hex(i_max))

        addr2x = lambda addr: ((addr - i_min) * img_x) // (i_max - i_min)
        for a, b in self.intervals:
            draw.rectangle((addr2x(a), 0, addr2x(b), img_y), (200, 0, 0))

        if dry_run is False:
            img.show()

    @property
    def length(self):
        """
        Return the cumulated length of intervals
        """
        # Do not use __len__ because we may return a value > 32 bits
        return sum((stop - start + 1) for start, stop in self.intervals)

Module variables

var INT_A_IN_B

var INT_B_IN_A

var INT_DISJOIN

var INT_EQ

var INT_JOIN

var INT_JOIN_AB

var INT_JOIN_BA

Functions

def cmp_interval(

inter1, inter2)

Compare @inter1 and @inter2 and returns the associated INT_* case @inter1, @inter2: interval instance

def cmp_interval(inter1, inter2):
    """Compare @inter1 and @inter2 and returns the associated INT_* case
    @inter1, @inter2: interval instance
    """
    if inter1 == inter2:
        return INT_EQ

    inter1_start, inter1_stop = inter1
    inter2_start, inter2_stop = inter2
    result = INT_JOIN
    if inter1_start <= inter2_start and inter1_stop >= inter2_stop:
        result = INT_B_IN_A
    if inter2_start <= inter1_start and inter2_stop >= inter1_stop:
        result = INT_A_IN_B
    if inter1_stop + 1 == inter2_start:
        result = INT_JOIN_AB
    if inter2_stop + 1 == inter1_start:
        result = INT_JOIN_BA
    if inter1_start > inter2_stop + 1 or inter2_start > inter1_stop + 1:
        result = INT_DISJOIN
    return result

Classes

class interval

Stands for intervals with integer bounds

Offers common methods to work with interval

class interval(object):
    """Stands for intervals with integer bounds

    Offers common methods to work with interval"""

    def __init__(self, bounds=None):
        """Instance an interval object
        @bounds: (optional) list of (int, int) and/or interval instance
        """
        if bounds is None:
            bounds = []
        elif isinstance(bounds, interval):
            bounds = bounds.intervals
        self.is_cannon = False
        self.intervals = bounds
        self.cannon()

    def __iter__(self):
        """Iterate on intervals"""
        for inter in self.intervals:
            yield inter

    @staticmethod
    def cannon_list(tmp):
        """
        Return a cannonizes list of intervals
        @tmp: list of (int, int)
        """
        tmp = sorted([x for x in tmp if x[0] <= x[1]])
        out = []
        if not tmp:
            return out
        out.append(tmp.pop())
        while tmp:
            x = tmp.pop()
            rez = cmp_interval(out[-1], x)

            if rez == INT_EQ:
                continue
            elif rez == INT_DISJOIN:
                out.append(x)
            elif rez == INT_B_IN_A:
                continue
            elif rez in [INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
                u, v = x
                while out and cmp_interval(out[-1], (u, v)) in [
                    INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
                    u = min(u, out[-1][0])
                    v = max(v, out[-1][1])
                    out.pop()
                out.append((u, v))
            else:
                raise ValueError('unknown state', rez)
        return out[::-1]

    def cannon(self):
        "Apply .cannon_list() on self contained intervals"
        if self.is_cannon is True:
            return
        self.intervals = interval.cannon_list(self.intervals)
        self.is_cannon = True

    def __repr__(self):
        if self.intervals:
            o = " U ".join(["[0x%X 0x%X]" % (x[0], x[1])
                           for x in self.intervals])
        else:
            o = "[]"
        return o

    def __contains__(self, other):
        if isinstance(other, interval):
            for intervalB in other.intervals:
                is_in = False
                for intervalA in self.intervals:
                    if cmp_interval(intervalA, intervalB) in [INT_EQ, INT_B_IN_A]:
                        is_in = True
                        break
                if not is_in:
                    return False
            return True
        else:
            for intervalA in self.intervals:
                if intervalA[0] <= other <= intervalA[1]:
                    return True
            return False

    def __eq__(self, i):
        return self.intervals == i.intervals

    def __ne__(self, other):
        return not self.__eq__(other)

    def union(self, other):
        """
        Return the union of intervals
        @other: interval instance
        """

        if isinstance(other, interval):
            other = other.intervals
        other = interval(self.intervals + other)
        return other

    def difference(self, other):
        """
        Return the difference of intervals
        @other: interval instance
        """

        to_test = self.intervals[:]
        i = -1
        to_del = other.intervals[:]
        while i < len(to_test) - 1:
            i += 1
            x = to_test[i]
            if x[0] > x[1]:
                del to_test[i]
                i -= 1
                continue

            while to_del and to_del[0][1] < x[0]:
                del to_del[0]

            for y in to_del:
                if y[0] > x[1]:
                    break
                rez = cmp_interval(x, y)
                if rez == INT_DISJOIN:
                    continue
                elif rez == INT_EQ:
                    del to_test[i]
                    i -= 1
                    break
                elif rez == INT_A_IN_B:
                    del to_test[i]
                    i -= 1
                    break
                elif rez == INT_B_IN_A:
                    del to_test[i]
                    i1 = (x[0], y[0] - 1)
                    i2 = (y[1] + 1, x[1])
                    to_test[i:i] = [i1, i2]
                    i -= 1
                    break
                elif rez in [INT_JOIN_AB, INT_JOIN_BA]:
                    continue
                elif rez == INT_JOIN:
                    del to_test[i]
                    if x[0] < y[0]:
                        to_test[i:i] = [(x[0], y[0] - 1)]
                    else:
                        to_test[i:i] = [(y[1] + 1, x[1])]
                    i -= 1
                    break
                else:
                    raise ValueError('unknown state', rez)
        return interval(to_test)

    def intersection(self, other):
        """
        Return the intersection of intervals
        @other: interval instance
        """

        out = []
        for x in self.intervals:
            if x[0] > x[1]:
                continue
            for y in other.intervals:
                rez = cmp_interval(x, y)

                if rez == INT_DISJOIN:
                    continue
                elif rez == INT_EQ:
                    out.append(x)
                    continue
                elif rez == INT_A_IN_B:
                    out.append(x)
                    continue
                elif rez == INT_B_IN_A:
                    out.append(y)
                    continue
                elif rez == INT_JOIN_AB:
                    continue
                elif rez == INT_JOIN_BA:
                    continue
                elif rez == INT_JOIN:
                    if x[0] < y[0]:
                        out.append((y[0], x[1]))
                    else:
                        out.append((x[0], y[1]))
                    continue
                else:
                    raise ValueError('unknown state', rez)
        return interval(out)


    def __add__(self, other):
        return self.union(other)

    def __and__(self, other):
        return self.intersection(other)

    def __sub__(self, other):
        return self.difference(other)

    def hull(self):
        "Return the first and the last bounds of intervals"
        if not self.intervals:
            return None, None
        return self.intervals[0][0], self.intervals[-1][1]


    @property
    def empty(self):
        """Return True iff the interval is empty"""
        return not self.intervals

    def show(self, img_x=1350, img_y=20, dry_run=False):
        """
        show image representing the interval
        """
        try:
            import Image
            import ImageDraw
        except ImportError:
            print('cannot import python PIL imaging')
            return

        img = Image.new('RGB', (img_x, img_y), (100, 100, 100))
        draw = ImageDraw.Draw(img)
        i_min, i_max = self.hull()

        print(hex(i_min), hex(i_max))

        addr2x = lambda addr: ((addr - i_min) * img_x) // (i_max - i_min)
        for a, b in self.intervals:
            draw.rectangle((addr2x(a), 0, addr2x(b), img_y), (200, 0, 0))

        if dry_run is False:
            img.show()

    @property
    def length(self):
        """
        Return the cumulated length of intervals
        """
        # Do not use __len__ because we may return a value > 32 bits
        return sum((stop - start + 1) for start, stop in self.intervals)

Ancestors (in MRO)

Static methods

def __init__(

self, bounds=None)

Instance an interval object @bounds: (optional) list of (int, int) and/or interval instance

def __init__(self, bounds=None):
    """Instance an interval object
    @bounds: (optional) list of (int, int) and/or interval instance
    """
    if bounds is None:
        bounds = []
    elif isinstance(bounds, interval):
        bounds = bounds.intervals
    self.is_cannon = False
    self.intervals = bounds
    self.cannon()

def cannon(

self)

Apply .cannon_list() on self contained intervals

def cannon(self):
    "Apply .cannon_list() on self contained intervals"
    if self.is_cannon is True:
        return
    self.intervals = interval.cannon_list(self.intervals)
    self.is_cannon = True

def cannon_list(

tmp)

Return a cannonizes list of intervals @tmp: list of (int, int)

@staticmethod
def cannon_list(tmp):
    """
    Return a cannonizes list of intervals
    @tmp: list of (int, int)
    """
    tmp = sorted([x for x in tmp if x[0] <= x[1]])
    out = []
    if not tmp:
        return out
    out.append(tmp.pop())
    while tmp:
        x = tmp.pop()
        rez = cmp_interval(out[-1], x)
        if rez == INT_EQ:
            continue
        elif rez == INT_DISJOIN:
            out.append(x)
        elif rez == INT_B_IN_A:
            continue
        elif rez in [INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
            u, v = x
            while out and cmp_interval(out[-1], (u, v)) in [
                INT_JOIN, INT_JOIN_AB, INT_JOIN_BA, INT_A_IN_B]:
                u = min(u, out[-1][0])
                v = max(v, out[-1][1])
                out.pop()
            out.append((u, v))
        else:
            raise ValueError('unknown state', rez)
    return out[::-1]

def difference(

self, other)

Return the difference of intervals @other: interval instance

def difference(self, other):
    """
    Return the difference of intervals
    @other: interval instance
    """
    to_test = self.intervals[:]
    i = -1
    to_del = other.intervals[:]
    while i < len(to_test) - 1:
        i += 1
        x = to_test[i]
        if x[0] > x[1]:
            del to_test[i]
            i -= 1
            continue
        while to_del and to_del[0][1] < x[0]:
            del to_del[0]
        for y in to_del:
            if y[0] > x[1]:
                break
            rez = cmp_interval(x, y)
            if rez == INT_DISJOIN:
                continue
            elif rez == INT_EQ:
                del to_test[i]
                i -= 1
                break
            elif rez == INT_A_IN_B:
                del to_test[i]
                i -= 1
                break
            elif rez == INT_B_IN_A:
                del to_test[i]
                i1 = (x[0], y[0] - 1)
                i2 = (y[1] + 1, x[1])
                to_test[i:i] = [i1, i2]
                i -= 1
                break
            elif rez in [INT_JOIN_AB, INT_JOIN_BA]:
                continue
            elif rez == INT_JOIN:
                del to_test[i]
                if x[0] < y[0]:
                    to_test[i:i] = [(x[0], y[0] - 1)]
                else:
                    to_test[i:i] = [(y[1] + 1, x[1])]
                i -= 1
                break
            else:
                raise ValueError('unknown state', rez)
    return interval(to_test)

def hull(

self)

Return the first and the last bounds of intervals

def hull(self):
    "Return the first and the last bounds of intervals"
    if not self.intervals:
        return None, None
    return self.intervals[0][0], self.intervals[-1][1]

def intersection(

self, other)

Return the intersection of intervals @other: interval instance

def intersection(self, other):
    """
    Return the intersection of intervals
    @other: interval instance
    """
    out = []
    for x in self.intervals:
        if x[0] > x[1]:
            continue
        for y in other.intervals:
            rez = cmp_interval(x, y)
            if rez == INT_DISJOIN:
                continue
            elif rez == INT_EQ:
                out.append(x)
                continue
            elif rez == INT_A_IN_B:
                out.append(x)
                continue
            elif rez == INT_B_IN_A:
                out.append(y)
                continue
            elif rez == INT_JOIN_AB:
                continue
            elif rez == INT_JOIN_BA:
                continue
            elif rez == INT_JOIN:
                if x[0] < y[0]:
                    out.append((y[0], x[1]))
                else:
                    out.append((x[0], y[1]))
                continue
            else:
                raise ValueError('unknown state', rez)
    return interval(out)

def show(

self, img_x=1350, img_y=20, dry_run=False)

show image representing the interval

def show(self, img_x=1350, img_y=20, dry_run=False):
    """
    show image representing the interval
    """
    try:
        import Image
        import ImageDraw
    except ImportError:
        print('cannot import python PIL imaging')
        return
    img = Image.new('RGB', (img_x, img_y), (100, 100, 100))
    draw = ImageDraw.Draw(img)
    i_min, i_max = self.hull()
    print(hex(i_min), hex(i_max))
    addr2x = lambda addr: ((addr - i_min) * img_x) // (i_max - i_min)
    for a, b in self.intervals:
        draw.rectangle((addr2x(a), 0, addr2x(b), img_y), (200, 0, 0))
    if dry_run is False:
        img.show()

def union(

self, other)

Return the union of intervals @other: interval instance

def union(self, other):
    """
    Return the union of intervals
    @other: interval instance
    """
    if isinstance(other, interval):
        other = other.intervals
    other = interval(self.intervals + other)
    return other

Instance variables

var empty

Return True iff the interval is empty

var intervals

var is_cannon

var length

Return the cumulated length of intervals