summaryrefslogtreecommitdiff
path: root/plugins/python/cglimpse/entropy.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/python/cglimpse/entropy.py')
-rw-r--r--plugins/python/cglimpse/entropy.py158
1 files changed, 158 insertions, 0 deletions
diff --git a/plugins/python/cglimpse/entropy.py b/plugins/python/cglimpse/entropy.py
new file mode 100644
index 0000000..f090624
--- /dev/null
+++ b/plugins/python/cglimpse/entropy.py
@@ -0,0 +1,158 @@
+
+import math
+
+from .method import GlimpseMethod
+
+
+class ShannonEntropy(GlimpseMethod):
+
+ def __init__(self, builder):
+ """Prepare a Shannon entropy display."""
+
+ super(ShannonEntropy, self).__init__(builder)
+
+ button = builder.get_object('shannon_color')
+ button.connect('color-set', self._on_color_set)
+
+ self._on_color_set(button)
+
+ self._step = 0x80
+
+ self._v_legend = 'Entropy'
+ self._h_legend = 'Byte offsets'
+
+ self._x_range = [ 0, 1024, 10240 ]
+ self._y_range = [ 0.0, 0.25, 1.0 ]
+
+ self._size = None
+ self._values = []
+
+
+ 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 ]
+
+
+ def format_legend(self, value, vert):
+ """Build the label used for a rule."""
+
+ if vert:
+ text = str(value)
+
+ else:
+
+ scale = [ ' kb', ' Mb', ' Gb', ' Tb' ]
+ suffix = ''
+
+ for i in range(len(scale)):
+
+ if value < 1024:
+ break
+
+ value /= 1024
+ suffix = scale[i]
+
+ text = '%u%s' % (value, suffix)
+
+ return text
+
+
+ def update(self, data):
+ """Provide a description for the method."""
+
+ self._size = len(data)
+
+ step = 2 ** math.ceil(math.log(self._size / 10, 2))
+
+ self._x_range = [ 0, step, 10 * step ]
+
+ self._values = []
+
+ for i in range(0, self._size, self._step):
+
+ counter = [ 0 for i in range(256) ]
+
+ start = i
+ end = i + self._step
+
+ if end > self._size:
+ end = self._size
+
+ for b in data[start : end]:
+ counter[b] += 1
+
+ ent = 0.0
+
+ for c in counter:
+ if c > 0:
+ freq = c / (end - start)
+ ent += freq * math.log(freq, 256)
+
+ self._values.append(-ent)
+
+
+ def render(self, cr, area):
+ """Draw the bytes distribution for the current binary, if any."""
+
+ step = 2 ** math.ceil(math.log(self._size / 10, 2))
+
+ if self._size % step == 0:
+ full_size = self._size
+ else:
+ full_size = (self._size + step - 1) & ~(step - 1)
+
+ start = 0
+ last_x = area[0]
+
+ last_y = area[1] + area[3] - (area[3] * self._values[0])
+ cr.move_to(last_x, last_y + 2)
+
+ for i in range(0, self._size, self._step):
+
+ end = i + self._step
+
+ if end > self._size:
+ end = self._size
+
+ x = area[0] + ((end - start) * area[2]) / full_size
+ y = area[1] + area[3] - (area[3] * self._values[int(i / self._step)])
+
+ if last_y != y:
+ cr.line_to(last_x, y + 2)
+
+ cr.line_to(x, y + 2)
+
+ last_x = x
+
+ cr.set_source_rgba(*self._shadow_color)
+ cr.set_line_width(4)
+ cr.stroke()
+
+ last_x = area[0]
+
+ last_y = area[1] + area[3] - (area[3] * self._values[0])
+ cr.move_to(last_x, last_y)
+
+ for i in range(0, self._size, self._step):
+
+ end = i + self._step
+
+ if end > self._size:
+ end = self._size
+
+ x = area[0] + ((end - start) * area[2]) / full_size
+ y = area[1] + area[3] - (area[3] * self._values[int(i / self._step)])
+
+ if last_y != y:
+ cr.line_to(last_x, y)
+
+ cr.line_to(x, y)
+
+ last_x = x
+
+ cr.set_source_rgba(*self._color)
+ cr.set_line_width(2)
+ cr.stroke()