Miasm2
 All Classes Namespaces Files Functions Variables Typedefs Properties Macros
utils.py
Go to the documentation of this file.
1 import struct
2 import inspect
3 import UserDict
4 from operator import itemgetter
5 
6 upck8 = lambda x: struct.unpack('B', x)[0]
7 upck16 = lambda x: struct.unpack('H', x)[0]
8 upck32 = lambda x: struct.unpack('I', x)[0]
9 upck64 = lambda x: struct.unpack('Q', x)[0]
10 pck8 = lambda x: struct.pack('B', x)
11 pck16 = lambda x: struct.pack('H', x)
12 pck32 = lambda x: struct.pack('I', x)
13 pck64 = lambda x: struct.pack('Q', x)
14 
15 
16 pck = {8:pck8,
17  16:pck16,
18  32:pck32,
19  64:pck64}
20 
21 
23  pass
24 
25 
26 def hexdump(src, length=16):
27  FILTER = ''.join(
28  [(len(repr(chr(x))) == 3) and chr(x) or '.' for x in range(256)])
29  lines = []
30  for c in xrange(0, len(src), length):
31  chars = src[c:c + length]
32  hexa = ' '.join(["%02x" % ord(x) for x in chars])
33  printable = ''.join(
34  ["%s" % ((ord(x) <= 127 and FILTER[ord(x)]) or '.') for x in chars])
35  lines.append("%04x %-*s %s\n" % (c, length * 3, hexa, printable))
36  print ''.join(lines)
37 
38 # stackoverflow.com/questions/2912231
39 
40 import collections
41 
42 
43 class keydefaultdict(collections.defaultdict):
44 
45  def __missing__(self, key):
46  if self.default_factory is None:
47  raise KeyError(key)
48  value = self[key] = self.default_factory(key)
49  return value
50 
51 def whoami():
52  return inspect.stack()[2][3]
53 
54 
55 class BoundedDict(UserDict.DictMixin):
56  """Limited in size dictionnary.
57 
58  To reduce combinatory cost, once an upper limit @max_size is reached,
59  @max_size - @min_size elements are suppressed.
60  The targeted elements are the less accessed.
61 
62  One can define a callback called when an element is removed
63  """
64 
65  def __init__(self, max_size, min_size=None, initialdata=None,
66  delete_cb=None):
67  """Create a BoundedDict
68  @max_size: maximum size of the dictionnary
69  @min_size: (optional) number of most used element to keep when resizing
70  @initialdata: (optional) dict instance with initial data
71  @delete_cb: (optional) callback called when an element is removed
72  """
73  self._data = initialdata.copy() if initialdata else {}
74  self._min_size = min_size if min_size else max_size / 3
75  self._max_size = max_size
76  self._size = len(self._data)
77  # Do not use collections.Counter as it is quite slow
78  self._counter = {k: 1 for k in self._data}
79  self._delete_cb = delete_cb
80 
81  def __setitem__(self, asked_key, value):
82  if asked_key not in self._data:
83  # Update internal size and use's counter
84  self._size += 1
85 
86  # Bound can only be reached on a new element
87  if (self._size >= self._max_size):
88  most_common = sorted(self._counter.iteritems(),
89  key=itemgetter(1), reverse=True)
90 
91  # Handle callback
92  if self._delete_cb is not None:
93  for key, _ in most_common[self._min_size - 1:]:
94  self._delete_cb(key)
95 
96  # Keep only the most @_min_size used
97  self._data = {key:self._data[key]
98  for key, _ in most_common[:self._min_size - 1]}
99  self._size = self._min_size
100 
101  # Reset use's counter
102  self._counter = {k: 1 for k in self._data}
103 
104  # Avoid rechecking in dict: set to 1 here, add 1 otherwise
105  self._counter[asked_key] = 1
106  else:
107  self._counter[asked_key] += 1
108 
109  self._data[asked_key] = value
110 
111  def __contains__(self, key):
112  # Do not call has_key to avoid adding function call overhead
113  return key in self._data
114 
115  def has_key(self, key):
116  return key in self._data
117 
118  def keys(self):
119  "Return the list of dict's keys"
120  return self._data.keys()
121 
122  @property
123  def data(self):
124  "Return the current instance as a dictionnary"
125  return self._data
126 
127  def __getitem__(self, key):
128  # Retrieve data first to raise the proper exception on error
129  data = self._data[key]
130  # Should never raise, since the key is in self._data
131  self._counter[key] += 1
132  return data
133 
134  def __delitem__(self, key):
135  if self._delete_cb is not None:
136  self._delete_cb(key)
137  del self._data[key]
138  self._size -= 1
139  del self._counter[key]
140 
141  def __del__(self):
142  """Ensure the callback is called when last reference is lost"""
143  if self._delete_cb:
144  for key in self._data:
145  self._delete_cb(key)