-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbyte_array.py
More file actions
92 lines (74 loc) · 2.83 KB
/
byte_array.py
File metadata and controls
92 lines (74 loc) · 2.83 KB
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
from binascii import unhexlify
from collections import Iterable
from string import printable
class ByteArray(object):
"""
Helper class for string manipulations.
"""
def __init__(self, source):
self._source = source
self._source_int_list = None
self._all_printable = None
def get_source_string(self):
"""
To indicate that there is no set at all.
"""
return self._source
@property
def source_int_list(self):
if not self._source_int_list:
self._source_int_list = [ord(c) for c in self._source]
return self._source_int_list
@property
def is_all_printable(self):
if self._all_printable is None:
self._all_printable = all(map(lambda c: c in printable, self._source))
return self._all_printable
@classmethod
def from_hex(cls, source):
return cls(unhexlify(source))
@classmethod
def from_int_list(cls, source):
# Probably will be doing the calculate of int_list again,
# but decided to leave it like that cuz no better solution found.
return cls(''.join(chr(i) for i in source))
def __str__(self):
if self._all_printable:
return self._source
return '%r' % self._source
def __repr__(self):
return '<%s: %s>' % (type(self).__name__, str(self))
def _iter_couple(self, other):
if not isinstance(other, Iterable):
return NotImplemented
if isinstance(other, basestring):
other = ByteArray(other)
return zip(self.source_int_list, iter(other))
def __xor__(self, other):
"""
the xor stops when the shortest element exhausts.
@param other: must be an iterable of ints.
@type other: [int]
@return: Text of the xored texts.
"""
return ByteArray.from_int_list([i ^ j for i, j in self._iter_couple(other)])
def __and__(self, other):
return ByteArray.from_int_list([i & j for i, j in self._iter_couple(other)])
def __or__(self, other):
return ByteArray.from_int_list([i | j for i, j in self._iter_couple(other)])
def __iter__(self):
return iter(self.source_int_list)
def __cmp__(self, other):
if isinstance(other, basestring):
return cmp(self._source, other)
if isinstance(other, ByteArray):
return cmp(other._source, self._source)
return NotImplemented
def hamming_distance(self, other):
if isinstance(other, basestring):
other = ByteArray(other)
if not isinstance(other, ByteArray):
raise NotImplementedError("Other must be a string or a ByteArray (Not %s)" % type(other))
def comparator(x, y):
return x + bin(y[0] ^ y[1]).count("1")
return reduce(comparator, self._iter_couple(other), 0)