xref: /llvm-project/lldb/examples/python/file_extract.py (revision 6a23d212897d5402035cfaea82260f6dae1c8f2a)
1#! /usr/bin/env python
2
3import string
4import struct
5import sys
6
7class FileExtract:
8    '''Decode binary data from a file'''
9
10    def __init__(self, f, b = '='):
11        '''Initialize with an open binary file and optional byte order'''
12
13        self.file = f
14        self.byte_order = b
15        self.offsets = list()
16
17    def set_byte_order(self, b):
18        '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
19        if b == 'big':
20            self.byte_order = '>'
21        elif b == 'little':
22            self.byte_order = '<'
23        elif b == 'swap':
24            # swap what ever the current byte order is
25            self.byte_order = swap_unpack_char()
26        elif b == 'native':
27            self.byte_order = '='
28        elif b == '<' or b == '>' or b == '@' or b == '=':
29            self.byte_order = b
30        else:
31            print "error: invalid byte order specified: '%s'" % b
32
33    def is_in_memory(self):
34        return False
35
36    def seek(self, offset, whence = 0):
37        if self.file:
38            return self.file.seek(offset, whence)
39        raise ValueError
40
41    def tell(self):
42        if self.file:
43            return self.file.tell()
44        raise ValueError
45
46    def read_size (self, byte_size):
47        s = self.file.read(byte_size)
48        if len(s) != byte_size:
49            return None
50        return s
51
52    def push_offset_and_seek(self, offset):
53        '''Push the current file offset and seek to "offset"'''
54        self.offsets.append(self.file.tell())
55        self.file.seek(offset, 0)
56
57    def pop_offset_and_seek(self):
58        '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
59        if len(self.offsets) > 0:
60            self.file.seek(self.offsets.pop())
61
62    def get_sint8(self, fail_value=0):
63        '''Extract a single int8_t from the binary file at the current file position, returns a single integer'''
64        s = self.read_size(1)
65        if s:
66            v, = struct.unpack(self.byte_order + 'b', s)
67            return v
68        else:
69            return fail_value
70
71    def get_uint8(self, fail_value=0):
72        '''Extract a single uint8_t from the binary file at the current file position, returns a single integer'''
73        s = self.read_size(1)
74        if s:
75            v, = struct.unpack(self.byte_order + 'B', s)
76            return v
77        else:
78            return fail_value
79
80    def get_sint16(self, fail_value=0):
81        '''Extract a single int16_t from the binary file at the current file position, returns a single integer'''
82        s = self.read_size(2)
83        if s:
84            v, = struct.unpack(self.byte_order + 'h', s)
85            return v
86        else:
87            return fail_value
88
89    def get_uint16(self, fail_value=0):
90        '''Extract a single uint16_t from the binary file at the current file position, returns a single integer'''
91        s = self.read_size(2)
92        if s:
93            v, = struct.unpack(self.byte_order + 'H', s)
94            return v
95        else:
96            return fail_value
97
98    def get_sint32(self, fail_value=0):
99        '''Extract a single int32_t from the binary file at the current file position, returns a single integer'''
100        s = self.read_size(4)
101        if s:
102            v, = struct.unpack(self.byte_order + 'i', s)
103            return v
104        else:
105            return fail_value
106
107    def get_uint32(self, fail_value=0):
108        '''Extract a single uint32_t from the binary file at the current file position, returns a single integer'''
109        s = self.read_size(4)
110        if s:
111            v, = struct.unpack(self.byte_order + 'I', s)
112            return v
113        else:
114            return fail_value
115
116    def get_sint64(self, fail_value=0):
117        '''Extract a single int64_t from the binary file at the current file position, returns a single integer'''
118        s = self.read_size(8)
119        if s:
120            v, = struct.unpack(self.byte_order + 'q', s)
121            return v
122        else:
123            return fail_value
124
125    def get_uint64(self, fail_value=0):
126        '''Extract a single uint64_t from the binary file at the current file position, returns a single integer'''
127        s = self.read_size(8)
128        if s:
129            v, = struct.unpack(self.byte_order + 'Q', s)
130            return v
131        else:
132            return fail_value
133
134    def get_fixed_length_c_string(self, n, fail_value='', isprint_only_with_space_padding=False):
135        '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string'''
136        s = self.read_size(n)
137        if s:
138            cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s)
139            # Strip trialing NULLs
140            cstr = string.strip(cstr, "\0")
141            if isprint_only_with_space_padding:
142                for c in cstr:
143                    if c in string.printable or ord(c) == 0:
144                        continue
145                    return fail_value
146            return cstr
147        else:
148            return fail_value
149
150    def get_c_string(self):
151        '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string'''
152        cstr = ''
153        byte = self.get_uint8()
154        while byte != 0:
155            cstr += "%c" % byte
156            byte = self.get_uint8()
157        return cstr
158
159    def get_n_sint8(self, n, fail_value=0):
160        '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers'''
161        s = self.read_size(n)
162        if s:
163            return struct.unpack(self.byte_order + ("%u" % n) + 'b', s)
164        else:
165            return (fail_value,) * n
166
167    def get_n_uint8(self, n, fail_value=0):
168        '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers'''
169        s = self.read_size(n)
170        if s:
171            return struct.unpack(self.byte_order + ("%u" % n) + 'B', s)
172        else:
173            return (fail_value,) * n
174
175    def get_n_sint16(self, n, fail_value=0):
176        '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers'''
177        s = self.read_size(2*n)
178        if s:
179            return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
180        else:
181            return (fail_value,) * n
182
183    def get_n_uint16(self, n, fail_value=0):
184        '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers'''
185        s = self.read_size(2*n)
186        if s:
187            return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
188        else:
189            return (fail_value,) * n
190
191    def get_n_sint32(self, n, fail_value=0):
192        '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers'''
193        s = self.read_size(4*n)
194        if s:
195            return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
196        else:
197            return (fail_value,) * n
198
199    def get_n_uint32(self, n, fail_value=0):
200        '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers'''
201        s = self.read_size(4*n)
202        if s:
203            return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
204        else:
205            return (fail_value,) * n
206
207    def get_n_sint64(self, n, fail_value=0):
208        '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers'''
209        s = self.read_size(8*n)
210        if s:
211            return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
212        else:
213            return (fail_value,) * n
214
215    def get_n_uint64(self, n, fail_value=0):
216        '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers'''
217        s = self.read_size(8*n)
218        if s:
219            return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
220        else:
221            return (fail_value,) * n
222