views:

167

answers:

2

I have the following CPython code which I now try to run in IronPython:

import ctypes

class BarHeader(ctypes.Structure):
    _fields_ = [
        ("id", ctypes.c_char * 4),
        ("version", ctypes.c_uint32)]

bar_file = open("data.bar", "rb")
header_raw = bar_file.read(ctypes.sizeof(BarHeader))
header = BarHeader.from_buffer_copy(header_raw)

The last line raises this exception: TypeError: expected array, got str

I tried BarHeader.from_buffer_copy(bytes(header_raw)) instead of the above, but then the exception message changes to TypeError: expected array, got bytes.

Any idea what I'm doing wrong?

+1  A: 

I tried the following code in Python 2.7 and it worked perfectly.

import ctypes  

class BarHeader(ctypes.Structure):
   _fields_ = [("version", ctypes.c_uint)]


header = BarHeader.from_buffer_copy("\x01\x00\x00\x00")
print header.version #prints 1 on little endian

And a solution using the array class

import ctypes
import array

class BarHeader(ctypes.Structure):
   _fields_ = [
      ("id", ctypes.c_char * 4),
      ("version", ctypes.c_uint32)]

bar_file = open("data.bar", "rb")

bytearray = array.array('b')
bytearray.fromfile(bar_file, ctypes.sizeof(BarHeader))

header = BarHeader.from_buffer_copy(bytearray)

print header.id
print header.version
evilpie
But have you tried it in IronPython? Look at my question again :)
Adal
Have you tried it? Okay i am installing this now, only for you ;)
evilpie
I don't understand why you posted the first sample, which doesn't work in IronPython. It's just like my original code, and like I stated, my code works in standard Python.Your second sample works.
Adal
I didnt test it, so i posted it.Ok tested second solution with "IronPython 2.6.1 for .NET 2.0 SP1" and it worked!
evilpie
+1  A: 

You can use the struct module instead of ctypes for working with packed binary data.

It uses a format string, with characters defining the type of data to pack/unpack.

The documentation is found here. The format string to read an array of four chars, then a unsigned integer would be '4sI'.

's' is the character for char array, while 4 specifies length. 'I' is the character for unsigned int.

Example code:

import struct

header_fmt = struct.Struct("4sI")

bar_file = open("data.bar", "rb")
header_raw = bar_file.read(header_fmt.size)
id, version = header_fmt.unpack(header_raw)
lunixbochs
Let me guess, you didn't test your answer in IronPython either. I know, because it doesn't work :)But it can be fixed to work. However, my actual structures are a little bit more complex (I kept only 2 fields for this question), and I'd like to avoid working with "4sIIIIII16s16sQQQQ" strings
Adal
you can use number notation for any type. the example string could actually be expressed as "4s 6I 16s 16s 4Q"... and I forgot files couldn't be used as buffers. that code didn't work in stock python either ;)
lunixbochs