Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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... 
like image 639
Mr Temp Avatar asked Dec 01 '09 11:12

Mr Temp


People also ask

How do you pack a string in Python?

struct.pack() struct. pack() is the function that converts a given list of values into their corresponding string representation. It requires the user to specify the format and order of the values that need to be converted.

What does struct unpack return?

Strings of binary representation are converted into their original form using this function. The return of struct. unpack() is always a tuple.

How do you use structures in Python?

The module struct is used to convert the native data types of Python into string of bytes and vice versa. We don't have to install it. It's a built-in module available in Python3. The struct module is related to the C languages.


2 Answers

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.

like image 76
Mark Rushakoff Avatar answered Oct 06 '22 12:10

Mark Rushakoff


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

like image 34
Ralph Paul Avatar answered Oct 06 '22 13:10

Ralph Paul