/* XDSP (XStruct Demonstration Protocol) message format */ typedef unsigned char octet; typedef struct { char magic[4]; /* must be "XSDP" */ octet version[2]; /* major version, minor version */ octet byte_order; /* 0 = big endian, 1 = little endian */ octet message_type; /* 0 = request, 1 = reply */ unsigned long correl_id; /* correlation id, links replies to requests */ octet data[16]; /* request or reply data */ } XsdpMessage;
Python 1.5.2 (#0, Apr 13 1999, 10:51:12) [MSC 32 bit (Intel)] on win32 Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam >>> import xstruct >>> XsdpMessage = xstruct.structdef(xstruct.big_endian, [ ("magic", (xstruct.string, 4), "XSDP", xstruct.readonly), ("version", (xstruct.octet, 2), (1, 0)), ("byte_order", (xstruct.octet, 1), 0, xstruct.readonly), ("message_type", (xstruct.octet, 1)), ("correl_id", (xstruct.unsigned_long, 1)), ("data", (xstruct.string, 16)) ])
The structdef function takes two parameters. The first parameter specifies the physical layout (i.e, byte order and alignment) of the structure in memory. The second parameter is a list of tuples that defines the fields of the structure. A single field tuple has the following format:
( field name, ( field type, repeat count ) , initial value , flags )
where initial value and flags are optional.
The structdef function returns a structdef object:
>>> XsdpMessage <structdef object at 79ad60>
The structdef object can be used to create actual structure objects.
>>> msg = XsdpMessage()
To see fields and their values, evaluate or print the structure object:
>>> print msg magic: XSDP version: (1, 0) byte_order: 0 message_type: 0 correl_id: 0L data:
Individual fields can be accessed as attributes of the structure object:
>>> msg.correl_id = 0x01020304 >>> msg.correl_id 16909060L
Alternatively, you can use the mapping interface of the structure object:
>>> msg['data'] = "Hello, World !" >>> msg['data'] 'Hello, World !\000\000'
If you try to change the value of a field that has been marked as readonly in the structure definition, an exception will be raised:
>>> msg.magic = "XXXX" Traceback (innermost last): File "<stdin>", line 1, in ? xstruct.error: field is not changeable
>>> buf = str(msg) >>> buf 'XSDP\001\000\000\000\000\001\002\003\004Hello, World !\000\000'
A more efficient way to manipulate the internal data buffer is to use the new buffer interface of Python 1.5.2. For this to work, however, the client code has to use this buffer interface as well. The standard Python file object already does this, as you can see from:
>>> open("tmp", "w").write(msg) >>> open("tmp", "r").read() 'XSDP\001\000\000\000\000\001\002\003\004Hello, World !\000\000'
Using this method, the packed binary data structure is written directly to the file, without the need of making a string copy first.
From a packed binary format, you can also create a structure object:
>>> msg2 = XsdpMessage(buf) >>> msg2 magic: XSDP version: (1, 0) byte_order: 0 message_type: 0 correl_id: 16909060L data: Hello, World !
Or using the buffer interface:
>>> msg3 = XsdpMessage() >>> open("tmp", "r").readinto(msg3) 28 >>> msg3 magic: XSDP version: (1, 0) byte_order: 0 message_type: 0 correl_id: 16909060L data: Hello, World !