How to pack and unpack using ctypes (Structure str)

This might be a silly question but I couldn’t find a good answer in the docs or anywhere.

If I use struct to define a binary structure, the struct has 2 symmetrical methods for serialization and deserialization (pack and unpack) but it seems ctypes doesn’t have a straightforward way to do this. Here’s my solution, which feels wrong:

from ctypes import *

class Example(Structure):
    _fields_ = [
        ("index", c_int),
        ("counter", c_int),
        ]

def Pack(ctype_instance):
    buf = string_at(byref(ctype_instance), sizeof(ctype_instance))
    return buf

def Unpack(ctype, buf):
    cstring = create_string_buffer(buf)
    ctype_instance = cast(pointer(cstring), POINTER(ctype)).contents
    return ctype_instance

if __name__ == "__main__":
    e = Example(12, 13)
    buf = Pack(e)
    e2 = Unpack(Example, buf)
    assert(e.index == e2.index)
    assert(e.counter == e2.counter)
    # note: for some reason e == e2 is False...

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

The PythonInfo wiki has a solution for this.

FAQ: How do I copy bytes to Python from a ctypes.Structure?

def send(self):
    return buffer(self)[:]

FAQ: How do I copy bytes to a ctypes.Structure from Python?

def receiveSome(self, bytes):
    fit = min(len(bytes), ctypes.sizeof(self))
    ctypes.memmove(ctypes.addressof(self), bytes, fit)

Their send is the (more-or-less) equivalent of pack, and receiveSome is sort of a pack_into. If you have a “safe” situation where you’re unpacking into a struct of the same type as the original, you can one-line it like memmove(addressof(y), buffer(x)[:], sizeof(y)) to copy x into y. Of course, you’ll probably have a variable as the second argument, rather than a literal packing of x.

Method 2

Have a look at this link on binary i/o in python:

http://www.dabeaz.com/blog/2009/08/python-binary-io-handling.html

Based on this you can simply write the following to read from a buffer (not just files):

g = open("foo","rb")
q = Example()
g.readinto(q)

To write is simply:

g.write(q)

The same for using sockets:

s.send(q)

and

s.recv_into(q)

I did some testing with pack/unpack and ctypes and this approach is the fastest except for writing straight in C

Method 3

Tested on Python3

e = Example(12, 13)
serialized = bytes(e)
deserialized = Example.from_buffer_copy(serialized)


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x