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