def tobinstr(self, start=None, end=None, pad=0xFF, size=None): ''' Convert to binary form and return as a string. @param start start address of output bytes. @param end end address of output bytes (inclusive). @param pad fill empty spaces with this value (if None used self.padding). @param size size of the block, used with start or end parameter. @return string of binary data. ''' return asstr(self.tobinarray(start, end, pad, size).tostring())
def gets(self, addr, length): """Get string of bytes from given address. If any entries are blank from addr through addr+length, a NotEnoughDataError exception will be raised. Padding is not used.""" a = array('B', asbytes('\0' * length)) try: for i in range_g(length): a[i] = self._buf[addr + i] except KeyError: raise NotEnoughDataError(address=addr, length=length) return asstr(a.tostring())
def gets(self, addr, length): """Get string of bytes from given address. If any entries are blank from addr through addr+length, a NotEnoughDataError exception will be raised. Padding is not used.""" a = array('B', asbytes('\0'*length)) try: for i in xrange(length): a[i] = self._buf[addr+i] except KeyError: raise NotEnoughDataError(address=addr, length=length) return asstr(a.tostring())
def _from_bytes(bytes): """Takes a list of bytes, computes the checksum, and outputs the entire record as a string. bytes should be the hex record without the colon or final checksum. @param bytes list of byte values so far to pack into record. @return String representation of one HEX record """ assert len(bytes) >= 4 # calculate checksum s = (-sum(bytes)) & 0x0FF bin = array('B', bytes + [s]) return ':' + asstr(hexlify(bin.tostring())).upper()
def write_hex_file(self, f, write_start_addr=True): """Write data to file f in HEX format. @param f filename or file-like object for writing @param write_start_addr enable or disable writing start address record to file (enabled by default). If there is no start address in obj, nothing will be written regardless of this setting. """ fwrite = getattr(f, "write", None) if fwrite: fobj = f fclose = None else: fobj = open(f, 'w') fwrite = fobj.write fclose = fobj.close # Translation table for uppercasing hex ascii string. # timeit shows that using hexstr.translate(table) # is faster than hexstr.upper(): # 0.452ms vs. 0.652ms (translate vs. upper) if sys.version_info[0] >= 3: # Python 3 table = bytes(range_l(256)).upper() else: # Python 2 table = ''.join(chr(i).upper() for i in range_g(256)) # start address record if any if self.start_addr and write_start_addr: keys = dict_keys(self.start_addr) keys.sort() bin = array('B', asbytes('\0' * 9)) if keys == ['CS', 'IP']: # Start Segment Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 3 # rectyp cs = self.start_addr['CS'] bin[4] = (cs >> 8) & 0x0FF bin[5] = cs & 0x0FF ip = self.start_addr['IP'] bin[6] = (ip >> 8) & 0x0FF bin[7] = ip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') elif keys == ['EIP']: # Start Linear Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 5 # rectyp eip = self.start_addr['EIP'] bin[4] = (eip >> 24) & 0x0FF bin[5] = (eip >> 16) & 0x0FF bin[6] = (eip >> 8) & 0x0FF bin[7] = eip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') else: if fclose: fclose() raise InvalidStartAddressValueError(start_addr=self.start_addr) # data addresses = dict_keys(self._buf) addresses.sort() addr_len = len(addresses) if addr_len: minaddr = addresses[0] maxaddr = addresses[-1] if maxaddr > 65535: need_offset_record = True else: need_offset_record = False high_ofs = 0 cur_addr = minaddr cur_ix = 0 while cur_addr <= maxaddr: if need_offset_record: bin = array('B', asbytes('\0' * 7)) bin[0] = 2 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 4 # rectyp high_ofs = int(cur_addr >> 16) b = divmod(high_ofs, 256) bin[4] = b[0] # msb of high_ofs bin[5] = b[1] # lsb of high_ofs bin[6] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') while True: # produce one record low_addr = cur_addr & 0x0FFFF # chain_len off by 1 chain_len = min(15, 65535 - low_addr, maxaddr - cur_addr) # search continuous chain stop_addr = cur_addr + chain_len if chain_len: ix = bisect_right( addresses, stop_addr, cur_ix, min(cur_ix + chain_len + 1, addr_len)) chain_len = ix - cur_ix # real chain_len # there could be small holes in the chain # but we will catch them by try-except later # so for big continuous files we will work # at maximum possible speed else: chain_len = 1 # real chain_len bin = array('B', asbytes('\0' * (5 + chain_len))) b = divmod(low_addr, 256) bin[1] = b[0] # msb of low_addr bin[2] = b[1] # lsb of low_addr bin[3] = 0 # rectype try: # if there is small holes we'll catch them for i in range_g(chain_len): bin[4 + i] = self._buf[cur_addr + i] except KeyError: # we catch a hole so we should shrink the chain chain_len = i bin = bin[:5 + i] bin[0] = chain_len bin[4 + chain_len] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') # adjust cur_addr/cur_ix cur_ix += chain_len if cur_ix < addr_len: cur_addr = addresses[cur_ix] else: cur_addr = maxaddr + 1 break high_addr = int(cur_addr >> 16) if high_addr > high_ofs: break # end-of-file record fwrite(":00000001FF\n") if fclose: fclose()
def write_hex_file(self, f, write_start_addr=True): """Write data to file f in HEX format. @param f filename or file-like object for writing @param write_start_addr enable or disable writing start address record to file (enabled by default). If there is no start address in obj, nothing will be written regardless of this setting. """ fwrite = getattr(f, "write", None) if fwrite: fobj = f fclose = None else: fobj = open(f, 'w') fwrite = fobj.write fclose = fobj.close # Translation table for uppercasing hex ascii string. # timeit shows that using hexstr.translate(table) # is faster than hexstr.upper(): # 0.452ms vs. 0.652ms (translate vs. upper) if sys.version_info[0] >= 3: table = bytes(range(256)).upper() else: table = ''.join(chr(i).upper() for i in range(256)) # start address record if any if self.start_addr and write_start_addr: keys = self.start_addr.keys() keys.sort() bin = array('B', asbytes('\0'*9)) if keys == ['CS','IP']: # Start Segment Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 3 # rectyp cs = self.start_addr['CS'] bin[4] = (cs >> 8) & 0x0FF bin[5] = cs & 0x0FF ip = self.start_addr['IP'] bin[6] = (ip >> 8) & 0x0FF bin[7] = ip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') elif keys == ['EIP']: # Start Linear Address Record bin[0] = 4 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 5 # rectyp eip = self.start_addr['EIP'] bin[4] = (eip >> 24) & 0x0FF bin[5] = (eip >> 16) & 0x0FF bin[6] = (eip >> 8) & 0x0FF bin[7] = eip & 0x0FF bin[8] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') else: if fclose: fclose() raise InvalidStartAddressValueError(start_addr=self.start_addr) # data addresses = self._buf.keys() addresses.sort() addr_len = len(addresses) if addr_len: minaddr = addresses[0] maxaddr = addresses[-1] if maxaddr > 65535: need_offset_record = True else: need_offset_record = False high_ofs = 0 cur_addr = minaddr cur_ix = 0 while cur_addr <= maxaddr: if need_offset_record: bin = array('B', asbytes('\0'*7)) bin[0] = 2 # reclen bin[1] = 0 # offset msb bin[2] = 0 # offset lsb bin[3] = 4 # rectyp high_ofs = int(cur_addr>>16) b = divmod(high_ofs, 256) bin[4] = b[0] # msb of high_ofs bin[5] = b[1] # lsb of high_ofs bin[6] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') while True: # produce one record low_addr = cur_addr & 0x0FFFF # chain_len off by 1 chain_len = min(15, 65535-low_addr, maxaddr-cur_addr) # search continuous chain stop_addr = cur_addr + chain_len if chain_len: ix = bisect_right(addresses, stop_addr, cur_ix, min(cur_ix+chain_len+1, addr_len)) chain_len = ix - cur_ix # real chain_len # there could be small holes in the chain # but we will catch them by try-except later # so for big continuous files we will work # at maximum possible speed else: chain_len = 1 # real chain_len bin = array('B', asbytes('\0'*(5+chain_len))) b = divmod(low_addr, 256) bin[1] = b[0] # msb of low_addr bin[2] = b[1] # lsb of low_addr bin[3] = 0 # rectype try: # if there is small holes we'll catch them for i in range(chain_len): bin[4+i] = self._buf[cur_addr+i] except KeyError: # we catch a hole so we should shrink the chain chain_len = i bin = bin[:5+i] bin[0] = chain_len bin[4+chain_len] = (-sum(bin)) & 0x0FF # chksum fwrite(':' + asstr(hexlify(bin.tostring()).translate(table)) + '\n') # adjust cur_addr/cur_ix cur_ix += chain_len if cur_ix < addr_len: cur_addr = addresses[cur_ix] else: cur_addr = maxaddr + 1 break high_addr = int(cur_addr>>16) if high_addr > high_ofs: break # end-of-file record fwrite(":00000001FF\n") if fclose: fclose()
def _tobinstr_really(self, start, end, pad, size): return asstr(self._tobinarray_really(start, end, pad, size).tostring())