reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    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
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
  222
  223
  224
  225
  226
#! /usr/bin/env python

import string
import struct
import sys


class FileExtract:
    '''Decode binary data from a file'''

    def __init__(self, f, b='='):
        '''Initialize with an open binary file and optional byte order'''

        self.file = f
        self.byte_order = b
        self.offsets = list()

    def set_byte_order(self, b):
        '''Set the byte order, valid values are "big", "little", "swap", "native", "<", ">", "@", "="'''
        if b == 'big':
            self.byte_order = '>'
        elif b == 'little':
            self.byte_order = '<'
        elif b == 'swap':
            # swap what ever the current byte order is
            self.byte_order = swap_unpack_char()
        elif b == 'native':
            self.byte_order = '='
        elif b == '<' or b == '>' or b == '@' or b == '=':
            self.byte_order = b
        else:
            print("error: invalid byte order specified: '%s'" % b)

    def is_in_memory(self):
        return False

    def seek(self, offset, whence=0):
        if self.file:
            return self.file.seek(offset, whence)
        raise ValueError

    def tell(self):
        if self.file:
            return self.file.tell()
        raise ValueError

    def read_size(self, byte_size):
        s = self.file.read(byte_size)
        if len(s) != byte_size:
            return None
        return s

    def push_offset_and_seek(self, offset):
        '''Push the current file offset and seek to "offset"'''
        self.offsets.append(self.file.tell())
        self.file.seek(offset, 0)

    def pop_offset_and_seek(self):
        '''Pop a previously pushed file offset, or do nothing if there were no previously pushed offsets'''
        if len(self.offsets) > 0:
            self.file.seek(self.offsets.pop())

    def get_sint8(self, fail_value=0):
        '''Extract a single int8_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(1)
        if s:
            v, = struct.unpack(self.byte_order + 'b', s)
            return v
        else:
            return fail_value

    def get_uint8(self, fail_value=0):
        '''Extract a single uint8_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(1)
        if s:
            v, = struct.unpack(self.byte_order + 'B', s)
            return v
        else:
            return fail_value

    def get_sint16(self, fail_value=0):
        '''Extract a single int16_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(2)
        if s:
            v, = struct.unpack(self.byte_order + 'h', s)
            return v
        else:
            return fail_value

    def get_uint16(self, fail_value=0):
        '''Extract a single uint16_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(2)
        if s:
            v, = struct.unpack(self.byte_order + 'H', s)
            return v
        else:
            return fail_value

    def get_sint32(self, fail_value=0):
        '''Extract a single int32_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(4)
        if s:
            v, = struct.unpack(self.byte_order + 'i', s)
            return v
        else:
            return fail_value

    def get_uint32(self, fail_value=0):
        '''Extract a single uint32_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(4)
        if s:
            v, = struct.unpack(self.byte_order + 'I', s)
            return v
        else:
            return fail_value

    def get_sint64(self, fail_value=0):
        '''Extract a single int64_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(8)
        if s:
            v, = struct.unpack(self.byte_order + 'q', s)
            return v
        else:
            return fail_value

    def get_uint64(self, fail_value=0):
        '''Extract a single uint64_t from the binary file at the current file position, returns a single integer'''
        s = self.read_size(8)
        if s:
            v, = struct.unpack(self.byte_order + 'Q', s)
            return v
        else:
            return fail_value

    def get_fixed_length_c_string(
            self,
            n,
            fail_value='',
            isprint_only_with_space_padding=False):
        '''Extract a single fixed length C string from the binary file at the current file position, returns a single C string'''
        s = self.read_size(n)
        if s:
            cstr, = struct.unpack(self.byte_order + ("%i" % n) + 's', s)
            # Strip trialing NULLs
            cstr = string.strip(cstr, "\0")
            if isprint_only_with_space_padding:
                for c in cstr:
                    if c in string.printable or ord(c) == 0:
                        continue
                    return fail_value
            return cstr
        else:
            return fail_value

    def get_c_string(self):
        '''Extract a single NULL terminated C string from the binary file at the current file position, returns a single C string'''
        cstr = ''
        byte = self.get_uint8()
        while byte != 0:
            cstr += "%c" % byte
            byte = self.get_uint8()
        return cstr

    def get_n_sint8(self, n, fail_value=0):
        '''Extract "n" int8_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'b', s)
        else:
            return (fail_value,) * n

    def get_n_uint8(self, n, fail_value=0):
        '''Extract "n" uint8_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'B', s)
        else:
            return (fail_value,) * n

    def get_n_sint16(self, n, fail_value=0):
        '''Extract "n" int16_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(2 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'h', s)
        else:
            return (fail_value,) * n

    def get_n_uint16(self, n, fail_value=0):
        '''Extract "n" uint16_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(2 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'H', s)
        else:
            return (fail_value,) * n

    def get_n_sint32(self, n, fail_value=0):
        '''Extract "n" int32_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(4 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'i', s)
        else:
            return (fail_value,) * n

    def get_n_uint32(self, n, fail_value=0):
        '''Extract "n" uint32_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(4 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'I', s)
        else:
            return (fail_value,) * n

    def get_n_sint64(self, n, fail_value=0):
        '''Extract "n" int64_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(8 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'q', s)
        else:
            return (fail_value,) * n

    def get_n_uint64(self, n, fail_value=0):
        '''Extract "n" uint64_t integers from the binary file at the current file position, returns a list of integers'''
        s = self.read_size(8 * n)
        if s:
            return struct.unpack(self.byte_order + ("%u" % n) + 'Q', s)
        else:
            return (fail_value,) * n