Interconvert a ctypes.Structure to/from a binary string?

Nick Craig-Wood nick at craig-wood.com
Mon Aug 4 07:32:56 EDT 2008


Andrew P. Lentvorski, Jr. <bsdder at gmail.com> wrote:
>  On Aug 1, 11:35 pm, Andrew Lentvorski <bs... at allcaps.org> wrote:
> > Basically, I'd like to use the ctypes module as a much more descriptive
> > "struct" module.
> >
> > Is there a way to take a ctypes.Structure-based class and convert it
> > to/from a binary string?
> >
> > Thanks,
> > -a
> 
>  After chugging through the ctypes source code, I found that I can
>  abuse ctypes into doing what I want.
> 
>  Here is how I did it.  I can abuse
>  string_at(addressof(SomeCtypesClass), length) to get a binary string
>  out of ctypes while I use:
> 
>  def analyze_elf_header(binaryData):
>      headerSize = ctypes.sizeof(Elf32_Ehdr)
>      header = Elf32_Ehdr()
> 
>      # Abuse ctypes to initialize from a string
>      bb = ctypes.create_string_buffer(binaryData[0:headerSize])
>      ctypes.memmove(ctypes.addressof(header), ctypes.addressof(bb),
>  headerSize)
> 
>  To jam stuff into a ctypes class.  This seems like an oversight in the
>  module though.  It would really be better if the class itself had
>  methods to init from/produce to a binary string.
> 
>  However, I would prefer that somebody who actually knows ctypes to
>  weigh in here with comments about what I did.

I have found myself doing this quite a bit with ctypes. It is common
to get a block of data in which represents a stream of structures
which have to be unpicked and made into ctypes structs before use.
Making that stream is an equal challenge.

I've found a couple of ways of doing it.

Setup

    >>> from ctypes import *
    >>> class A(Structure):
    ...     _fields_ = [("x", c_int)]
    ...
    >>> packet="\x02\x01\x00\x00"

Eg to make a struct from a string

    >>> a = cast(packet, POINTER(A)).contents
    >>> a.x
    258
    >>>  

Or (this is identical to your method)

    >>> a = A()
    >>> a.x
    0
    >>> memmove(addressof(a), packet, sizeof(a))
    3083811008L
    >>> a.x
    258

I think the second of those methods is promoted by the ctypes
documentation.  I'm not sure about the lifetimes of the .contents in
the first method!

And the reverse

    >>> string_at(addressof(a), sizeof(a))
    '\x02\x01\x00\x00'
    >>> 

Which I think is probably acceptable...

Some to/from binary methods would be nice, or failing that an explicit
section in the docs!

-- 
Nick Craig-Wood <nick at craig-wood.com> -- http://www.craig-wood.com/nick



More information about the Python-list mailing list