summaryrefslogtreecommitdiff
path: root/plugins/python/cglimpse/distro.py
blob: 4b490e68a1be6deaa269e1b39d7b94939ff949b1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110

from gi.repository import Gdk
from pychrysalide.glibext import ConfigParam

from .method import GlimpseMethod


class ByteDistribution(GlimpseMethod):


    @staticmethod
    def setup_config(config):
        """Register the configuration parameters for the method."""

        color = Gdk.RGBA()
        color.parse('#3465A4')

        param = ConfigParam('cglimpse.distrib.color', ConfigParam.ConfigParamType.COLOR, color)
        config.add(param)


    def __init__(self, builder, config, update_cb):
        """Prepare a Distrib entropy display."""

        super(ByteDistribution, self).__init__(builder, config, update_cb)

        self._v_legend = 'Quantity'
        self._h_legend = 'Byte values'

        self._x_range = [ 0, 0x20, 0x100 ]
        self._y_range = [ 0, 25, 100 ]

        self._values = {}

        button = builder.get_object('distrib_color')
        button.connect('color-set', self._on_color_set)

        param = config.search('cglimpse.distrib.color')
        color = param.value

        self._color = [ color.red, color.green, color.blue, color.alpha ]
        self._shadow_color = [ color.red * 0.5, color.green * 0.5, color.blue * 0.5, color.alpha ]

        button.set_rgba(param.value)


    def _on_color_set(self, button):
        """React on color chosen for the rendering."""

        color = button.get_rgba()

        self._color = [ color.red, color.green, color.blue, color.alpha ]
        self._shadow_color = [ color.red * 0.5, color.green * 0.5, color.blue * 0.5, color.alpha ]

        param = self._config.search('cglimpse.distrib.color')
        param.value = color

        self._update_cb()


    def format_legend(self, value, vert):
        """Build the label used for a rule."""

        text = str(int(value))

        return text


    def update(self, data, coverage):
        """Compute internal values for the method."""

        max_count = 0

        self._values = {}

        for i in range(256):
            self._values[i] = 0

        for b in data[coverage[0] : coverage[1]]:

            if b in self._values.keys():
                self._values[b] += 1

        for c in self._values.values():
            if c > max_count:
                max_count = c

        self._y_range = [ 0, max_count / 4, max_count ]


    def render(self, cr, area):
        """Draw the bytes distribution for the current binary, if any."""

        max_count = self._y_range[-1]

        last_x = area[0]

        cr.set_source_rgba(*self._shadow_color)
        cr.set_source_rgba(*self._color)
        cr.set_line_width(1)

        for i in range(256):

            x = area[0] + ((i + 1) * area[2]) / 256
            h = (area[3] * self._values[i]) / max_count

            cr.rectangle(last_x, area[1] + area[3] - h, x - last_x, h)
            cr.fill()

            last_x = x