about summary refs log tree commit diff stats
path: root/src/miasm/loader/strpatchwork.py
diff options
context:
space:
mode:
authorTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
committerTheofilos Augoustis <theofilos.augoustis@gmail.com>2025-10-14 09:09:29 +0000
commit579cf1d03fb932083e6317967d1613d5c2587fb6 (patch)
tree629f039935382a2a7391bce9253f6c9968159049 /src/miasm/loader/strpatchwork.py
parent51c15d3ea2e16d4fc5f0f01a3b9befc66b1f982e (diff)
downloadfocaccia-miasm-579cf1d03fb932083e6317967d1613d5c2587fb6.tar.gz
focaccia-miasm-579cf1d03fb932083e6317967d1613d5c2587fb6.zip
Convert to src-layout ta/nix
Diffstat (limited to 'src/miasm/loader/strpatchwork.py')
-rw-r--r--src/miasm/loader/strpatchwork.py106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/miasm/loader/strpatchwork.py b/src/miasm/loader/strpatchwork.py
new file mode 100644
index 00000000..e1a5de91
--- /dev/null
+++ b/src/miasm/loader/strpatchwork.py
@@ -0,0 +1,106 @@
+from array import array
+import struct
+from sys import maxsize
+
+from future.utils import PY3
+
+if PY3:
+
+    def array_frombytes(arr, value):
+        return arr.frombytes(value)
+
+    def array_tobytes(arr):
+        return arr.tobytes()
+
+
+else:
+
+    def array_frombytes(arr, value):
+        return arr.fromstring(value)
+
+    def array_tobytes(arr):
+        return arr.tostring()
+
+
+class StrPatchwork(object):
+
+    def __init__(self, s=b"", paddingbyte=b"\x00"):
+        s_raw = bytes(s)
+        val = array("B")
+        array_frombytes(val, s_raw)
+        self.s = val
+        # cache s to avoid rebuilding str after each find
+        self.s_cache = s_raw
+        self.paddingbyte = paddingbyte
+
+    def __bytes__(self):
+        return array_tobytes(self.s)
+
+    def __str__(self):
+        if PY3:
+            return repr(self)
+        return self.__bytes__()
+
+    def __getitem__(self, item):
+        s = self.s
+        if isinstance(item, slice):
+            end = item.stop
+            l = len(s)
+            if (end is not None and l < end) and end != maxsize:
+                # XXX hack [x:] give 2GB limit
+                # This is inefficient but avoids complicated maths if step is
+                # not 1
+                s = s[:]
+
+                tmp = array("B")
+                array_frombytes(tmp, self.paddingbyte * (end - l))
+                s.extend(tmp)
+            r = s[item]
+            return array_tobytes(r)
+
+        else:
+            if item > len(s):
+                return self.paddingbyte
+            else:
+                return struct.pack("B", s[item])
+
+    def __setitem__(self, item, val):
+        if val is None:
+            return
+        val_array = array("B")
+        array_frombytes(val_array, bytes(val))
+        if type(item) is not slice:
+            item = slice(item, item + len(val_array))
+        end = item.stop
+        l = len(self.s)
+        if l < end:
+            tmp = array("B")
+            array_frombytes(tmp, self.paddingbyte * (end - l))
+            self.s.extend(tmp)
+        self.s[item] = val_array
+        self.s_cache = None
+
+    def __repr__(self):
+        return "<Patchwork %r>" % array_tobytes(self.s)
+
+    def __len__(self):
+        return len(self.s)
+
+    def __contains__(self, val):
+        return val in bytes(self)
+
+    def __iadd__(self, other):
+        tmp = array("B")
+        array_frombytes(tmp, bytes(other))
+        self.s.extend(tmp)
+        return self
+
+    def find(self, pattern, start=0, end=None):
+        if not self.s_cache:
+            self.s_cache = array_tobytes(self.s)
+        return self.s_cache.find(pattern, start, end)
+
+    def rfind(self, pattern, start=0, end=None):
+        if not self.s_cache:
+            self.s_cache = array_tobytes(self.s)
+        return self.s_cache.rfind(pattern, start, end)