modify data in struct in python - python

I would like to know if it's possible to modify an already made struct.
What I want is to calculate the CRC of header and then write the CRC value to the 3rd position in header.
import struct
import crcmod
crcfunc = crcmod.mkCrcFun(0x112, 0x00, 0x00)
header = struct.pack('!hii', 1, 2, 0)
crcvalue = crcfunc(header)

You can not do it directly: struct.pack returns a bytes object, which like str, is immutable. However, you can very easily create the updated object:
header = header[:-4] + c.to_bytes(4, byteorder=sys.byteorder)
If you really meant to compute the CRC value on everything excluding the last element, you can do something like this instead:
header = struct.pack('!hi', 1, 2)
header += crcfunc(header).to_bytes(4, byteorder=sys.byteorder)

Since the result of calling struct.pack is to create a byte string, it is immutable.
You could either splice the crc into the byte string by slicing it, or create a new byte string:
header2 = struct.pack('!hii', 1, 2, crcvalue)
Alternatively, if you want to create a mutable byte string, you could create a buffer, and use struct.pack_into instead of struct.pack.

Related

Replace multiple bytes in bytearray

How can I replace multiple bytes in a bytearray? For example:
b"\x00\x01\x02\x03\x04\x05"
I want to replace \x02\x03 with \xFF\xFF and \x04\x05 with \xEE\xEE. How can I do this all at once?
The replace method can also be used on byte object in python
a = b"\x00\x01\x02\x03\x04\x05"
b = a.replace(b"\x02\x03", b"\xFF\xFF").replace(b"\x04\x05", b"\xEE\xEE")

Storing and retrieving a single byte i2c address with strings

I am trying to store an i2c address, 0x3c, to a string to be stored in a text file that is later read. When reading the text file however, I cannot read the data from the string in the correct way, such that
value = string_read(text_file)
print(value == 0x3c)
would return true. How can I read a single byte stored in a string:
'0x3c'
into value so that the above code would return true?
See: https://stackoverflow.com/a/209550/9606335. Specifically, in your example, if you know your string is only "0x3c", then you can convert it to a numerical value by value = int("0x3c", 0). Now your expression should behave as you expect:
>>> print(int("0x3c", 0) == 0x3c)
True

Separating parts of a <class 'byte'> and printing it out to screen

so I am capturing packets with Pydivert. I can print out the full packet payload by using
print(packet.tcp.payload)
OR
print(packet.payload)
output was
b'\x03\x00\x34\xe2\xd1' //continued like this
same output in both cases. I printed out the type by using
print(type(packet.payload))
This showed the type to be
<class 'byte'>
I would like to take say the first 10 byte positions from the output and type it out and also save it into a variable so when I'm modifying the payload, I exclude the initial bytes and then modify the remaining parts. So I can somehow attach the separated out bytes to my newly created bytes to create a final byte stream like for example:
TotalByteStream = (initial bytes which I separated out) + b'\x03\x00\x34\xe2\xd1\x78\x23\x45\x79' //continued like this as needed
//And then do
packet.payload = TotalByteStream
Is this possible?
I'm not sure I understand your question, but you can manipulate bytes in a manner similar to strings.
If you have your original payload:
>>> payload_1 = b'\x03\x00\xf4\xe2\xd1'
>>> type(payload_1)
<class 'bytes'>
>>> payload_1
b'\x03\x00\xf4\xe2\xd1'
You can slice of the first few bytes
>>> part = payload_1[:2]
>>> part
b'\x03\x00'
And later create a new payload where you prepend the part variable
>>> payload_2 = part + b'\xf5\xe5\xd5'
>>> payload_2
b'\x03\x00\xf5\xe5\xd5'
>>> payload_1
b'\x03\x00\xf4\xe2\xd1'
So you get a new payload with the same starting bytes. Does this answer your question? Or did I misunderstand your issue?

How to address indicies in an array using HEX

I have a file that I read lines from and manipulate the strings.
Here is an example of a few of the lines (the file is Intel's HEX format if you're interested):
:10DE50003EDE179280DB0338D2C32202023CD2D3CB
:10DE600022021792A0DB0338E2C32202023CE2D373
:10DE7000220292533EDEB0906400C4FF022082432F
:10DE80003EDE3741324190C3B8240013FDDBFF056D
:10DE900057494D453420D0D88CDEFDDB8FDEFF03A3
A buddy suggested I create an array with the first 4:7 bytes as the index, EG, DE50, then use the remaining 16 bytes as the data (00 after DE50 is not used, and last byte is not used). He said I could use HEX and add let's say, 10 to the DE50 to get DE5A and therefore locate the byte associated with that index. Problem is, I can't figure out a way to do that. Is it even possible? This would allow me to then address any byte I want by knowing the HEX index which would be really powerful.
Thank you!
There is an Intel Hex package in pypi perhaps you should look at that first
Here are some examples copied from the docs.
Once created, an IntelHex object can be loaded with data. This is only
necessary if “source” was unspecified in the constructor. You can also
load data several times (but if addresses in those files overlap you
get exception AddressOverlapError). This error is only raised when
reading from hex files. When reading from other formats, without
explicitly calling merge, the data will be overwritten. E.g.:
>>> from intelhex import IntelHex
>>> ih = IntelHex() # create empty object
>>> ih.loadhex('foo.hex') # load from hex
>>> ih.loadfile('bar.hex',format='hex') # also load from hex
>>> ih.fromfile('bar.hex',format='hex') # also load from hex
NOTE: using IntelHex.fromfile is recommended way.
All of the above examples will read from HEX files. IntelHex also
supports reading straight binary files. For example:
>>> from intelhex import IntelHex
>>> ih = IntelHex() # create empty object
>>> ih.loadbin('foo.bin') # load from bin
>>> ih.fromfile('bar.bin',format='bin') # also load from bin
>>> ih.loadbin('baz.bin',offset=0x1000) # load binary data and place them
>>> # starting with specified offset
Finally, data can be loaded from an appropriate Python dictionary.
This will permit you to store the data in an IntelHex object to a
builtin dictionary and restore the object at a later time. For
example:
>>> from intelhex import IntelHex
>>> ih = IntelHex('foo.hex') # create empty object
>>> pydict = ih.todict() # dump contents to pydict
...do something with the dictionary...
>>> newIH = IntelHex(pydict) # recreate object with dict
>>> another = IntelHex() # make a blank instance
>>> another.fromdict(pydict) # now another is the same as newIH
You're on the right track here, but you can't have an "array" indexed by hex characters. Arrays, and lists, are always indexed by integers, starting with 0.
If you know the initial offset (which you do, from the first line), you can make an index very easily. For example, everything from 'DE50' to 'DE5F' should be line #0, right? So, convert that DE50 to an integer, divide by 16 (truncating fractions), and subtract 0xDE50. Like this:
with open('hexfile.txt') as f:
lines = list(f)
offset = int(lines[0][4:7], 16) // 16
def get_line(hex_index):
index = int(hex_index, 16) // 16
return lines[index - offset]
Alternatively, you could use a dict keyed off the hex indices, instead of a list, and then do what your friend suggested:
with open('hexfile.txt') as f:
lines = {line[4:7]: line for line in f}
def get_line(hex_index):
base_hex_index = hex_index[:3] + '0'
return lines[base_hex_index]
However, this seems to be just adding extra complexity to your data structure for no benefit. If you've got sequential lines, just treat them sequentially. And if you've got numbers as hex strings, just convert them to numbers to treat them as indices.

Convert Integer to Hex with result always having 2 bytes

I'd like to convert an array of integer values I have received over USB using pyusb to a list of hex values. I'd like these hex values to always have two bytes, i.e. 0x##. However the normal hex() function will return 0x1 with an input of 1. I'd like it to return 0x01.
Then after having the list of hex values I'd like to append them together while throwing away the '0x' portion. This is what I currently have, pretty simple.
data_read = dev.read(0x82,64,0,1000)
hex_data = range(0,len(data_read))
for i in range(0,len(data_read)):
hex_data[i] = hex(data_read[i])
Any ideas? I can fudge it and do it the sloppy way, but I was hoping there is a proper way to do it. Thank you.
Update:
data_read = dev.read(0x82,64)
print data_read
>>> array('B', [169, 86, 128, 1, 0, 128])
for i in range(0,len(data_read)):
hex_data[i] = hex(data_read[i])
print hex_data
>>> ['0xa9', '0x56', '0x80', '0x1', '0x0', '0x80']
The method suggested by Lavon did not work since the resulting hex values were technically strings in my code? Instead I just skipped my whole for loop converting to hex and directly did as Lavon and moooeeeep suggested and it worked! Thanks!
hex_data = ('%02x' %i for i in data_read)
print ''.join(hex_data)
>>> a95680010080
Is there a good reference you use for syntax? i.e. the '%02x' you used? I haven't seen that before and would like to understand it better.
Does this fit the bill?
data = [0x1, 0x4, 0x5, 0xFF, 0x12]
new_data = ['%02X' %i for i in data]
print ''.join(new_data)
yields:
010405FF12
using list comprehension and the join operation.
Alternatively, as suggested by #moooeeeep here is the solution using a generator:
new_data = ('%02X' %i for i in data)
print ''.join(new_data)
For the string formatting options, see this
Then after having the list of hex values I'd like to append them together while throwing away the '0x' portion.
Do you mean something like this:
In [8]: data_read = [0x01, 0x2b, 0x22, 0x10]
In [9]: ''.join(map(lambda v: '%02x' % v, data_read))
Out[9]: '012b2210'
?
Just another way to do it
>>> data_read = [0x01, 0x2b, 0x22, 0x10]
>>> ("{:02x}"*len(data_read)).format(*data_read)
'012b2210'

Categories