blob: 3afc0c3c1a0b27aa2b812db3fbf1fefffc67522b [file] [log] [blame]
Greg Clayton6a23d212013-09-04 17:31:40 +00001#! /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