2012-04-27 9 views
6

Sto cercando di fare un parser di dati binari, e mentre potrei ricorrere a C, volevo vedere se potevo usare Python per il compito.Come dichiarare correttamente un ctype Structure + Union in Python?

ho qualche sentore di come ottenere questo corso, e il mio attuale implementazione simile a questa:

from ctypes import * 

class sHeader(Structure): 
    _fields_ = [("CC", c_uint8, 4), 
      ("AFC", c_uint8, 2), 
      ("TSC", c_uint8, 2), 
      ("PID", c_uint16, 13), 
      ("TP", c_uint16, 1), 
      ("PSI", c_uint16, 1), 
      ("TEI", c_uint16, 1), 
      ("SyncByte", c_uint8)] 

class Header(Union): 
    _fields_ = [("sData", sTsHeader), 
      ("ulData", c_uint32)] 

head = Header() 
head.ulData = 0xffffffff 
print(head.ulData) 
print(head.sData.SyncByte) 

print(sHeader.SyncByte) 
print(sHeader.TEI) 
print(sHeader.PSI) 
print(sHeader.TP) 
print(sHeader.PID) 
print(sHeader.TSC) 
print(sHeader.AFC) 
print(sHeader.CC) 


print(sizeof(sHeader)) 
print(sizeof(c_uint8)) 
print(sizeof(c_uint16)) 
print(sizeof(c_uint32)) 

che produce questo output:

V:\>C:\Python27\python.exe WidiUnpacker.py 
0xffffffffL 
0x0 
<Field type=c_ubyte, ofs=4, size=1> 
<Field type=c_ushort, ofs=2:15, bits=1> 
<Field type=c_ushort, ofs=2:14, bits=1> 
<Field type=c_ushort, ofs=2:13, bits=1> 
<Field type=c_ushort, ofs=2:0, bits=13> 
<Field type=c_ubyte, ofs=0:6, bits=2> 
<Field type=c_ubyte, ofs=0:4, bits=2> 
<Field type=c_ubyte, ofs=0:0, bits=4> 
6 
1 
2 
4 

Quindi ... Sembra a me come i miei byte non sono tanto i byte quanto le parole. Non ne so abbastanza su Python o sui ctype per capire perché è così, ma al momento è una specie di sconfiggere il mio scopo. Qualche idea?

risposta

6

Il tuo sHeader ha un campo a 4 bit, quindi un campo a 2 bit, quindi un campo a 2 bit (totale 8 bit = 1 byte) ... ma l'elemento successivo è uno c_uint16 che deve essere allineato su un 2 -byte boundary e quindi salta su un byte e passa al byte 2 prima di prendere 13 bit.

Se non si desidera che (e apparentemente non), basta fare tutto ciò che un c_uint32 o simili:

from ctypes import * 

class sHeader(Structure): 
    _fields_ = [("CC", c_uint32, 4), 
     ("AFC", c_uint32, 2), 
     ("TSC", c_uint32, 2), 
     ("PID", c_uint32, 13), 
     ("TP", c_uint32, 1), 
     ("PSI", c_uint32, 1), 
     ("TEI", c_uint32, 1), 
     ("SyncByte", c_uint32, 8)] # note: added 8 here 

print sHeader.PID 
print sHeader.SyncByte 

risultati in:

<Field type=c_uint, ofs=0:8, bits=13> 
<Field type=c_uint, ofs=0:24, bits=8> 

(ho scelto perché Uint32 i tuoi campi bit sommano fino a 32 bit. Sto usando Python 2.7 qui, quindi nessuna parentesi sui print s.)

5

È possibile controllare l'allineamento con unattributo 210 classe:

class sHeader(Structure): 
    _pack_ = 1 

risultati in

4294967295 
255 
<Field type=c_ubyte, ofs=3, size=1> 
<Field type=c_ushort, ofs=1:15, bits=1> 
<Field type=c_ushort, ofs=1:14, bits=1> 
<Field type=c_ushort, ofs=1:13, bits=1> 
<Field type=c_ushort, ofs=1:0, bits=13> 
<Field type=c_ubyte, ofs=0:6, bits=2> 
<Field type=c_ubyte, ofs=0:4, bits=2> 
<Field type=c_ubyte, ofs=0:0, bits=4> 
4 
1 
2 
4 
+0

appena provato questo su una struttura che è di 48 bit, e funziona bene. –

Problemi correlati