27
27
import re
28
28
import struct
29
29
from .base import (
30
+ NATIVE_ORDER ,
30
31
DEFINES ,
31
32
TYPEDEFS ,
32
33
STRUCTS ,
39
40
'parse_struct'
40
41
]
41
42
43
+ def align (__byte_order__ ):
44
+ return __byte_order__ is None or __byte_order__ == NATIVE_ORDER
45
+
42
46
class FieldType (object ):
43
47
44
48
def __init__ (self , vtype , vlen , vsize , fmt , offset , flexible_array ):
@@ -121,17 +125,16 @@ def __str__(self):
121
125
return str (self .tokens )
122
126
123
127
124
- def parse_type (tokens , __cls__ ):
125
- from . import factory
128
+ def parse_type (tokens , __cls__ , __byte_order__ ):
126
129
if len (tokens ) < 2 :
127
130
raise Exception ("Parsing error" )
128
131
vtype = tokens .pop ()
129
132
# signed/unsigned/struct
130
- if vtype == 'unsigned' or vtype == 'signed' or vtype == 'struct' and len (tokens ) > 1 :
133
+ if vtype in [ 'signed' , 'unsigned' , 'struct' , 'union' ] and len (tokens ) > 1 :
131
134
vtype = vtype + " " + tokens .pop ()
132
135
next_token = tokens .pop ()
133
136
# short int, long int, or long long
134
- if next_token == 'int' or next_token == 'long' :
137
+ if next_token in [ 'int' , 'long' ] :
135
138
vtype = vtype + " " + next_token
136
139
next_token = tokens .pop ()
137
140
# void *
@@ -170,22 +173,28 @@ def parse_type(tokens, __cls__):
170
173
kind , vtype = vtype .split (' ' , 1 )
171
174
if tokens .get () == '{' : # Named nested struct
172
175
tokens .pop ()
173
- vtype = factory (tokens , __name__ = vtype , __cls__ = __cls__ , __is_union__ = __is_union__ )
176
+ vtype = __cls__ . parse (tokens , __name__ = vtype , __is_union__ = __is_union__ , __byte_order__ = __byte_order__ )
174
177
elif vtype == '{' : # Unnamed nested struct
175
- vtype = factory (tokens , __is_union__ = __is_union__ )
178
+ vtype = __cls__ . parse (tokens , __is_union__ = __is_union__ , __byte_order__ = __byte_order__ )
176
179
else :
177
180
try :
178
181
vtype = STRUCTS [vtype ]
179
182
except KeyError :
180
183
raise Exception ("Unknow %s \" %s\" " % (kind , vtype ))
181
184
ttype = "c"
182
185
fmt = str (vlen * vtype .size ) + ttype
186
+ # alignment/
187
+ alignment = vtype .__alignment__
183
188
else : # other types
184
189
ttype = C_TYPE_TO_FORMAT .get (vtype , None )
185
190
if ttype is None :
186
191
raise Exception ("Unknow type \" " + vtype + "\" " )
187
192
fmt = (str (vlen ) if vlen > 1 or flexible_array else '' ) + ttype
188
- return vtype , vlen , fmt , flexible_array
193
+ # alignment
194
+ alignment = struct .calcsize ((__byte_order__ + ttype ) if __byte_order__ is not None else ttype )
195
+ fmt = (__byte_order__ + fmt ) if __byte_order__ is not None else fmt
196
+ vsize = struct .calcsize (fmt )
197
+ return vtype , vlen , vsize , fmt , flexible_array , alignment
189
198
190
199
191
200
def parse_struct (__struct__ , __cls__ = None , __fields__ = None , __is_union__ = False , __byte_order__ = None , ** kargs ):
@@ -195,6 +204,7 @@ def parse_struct(__struct__, __cls__=None, __fields__=None, __is_union__=False,
195
204
fields_types = {}
196
205
flexible_array = False
197
206
offset = 0
207
+ max_alignment = 0
198
208
if isinstance (__struct__ , Tokens ):
199
209
tokens = __struct__
200
210
else :
@@ -206,11 +216,17 @@ def parse_struct(__struct__, __cls__=None, __fields__=None, __is_union__=False,
206
216
# flexible array member must be the last member of such a struct
207
217
if flexible_array :
208
218
raise Exception ("Flexible array member must be the last member of such a struct" )
209
- vtype , vlen , fmt , flexible_array = parse_type (tokens , __cls__ )
219
+ vtype , vlen , vsize , fmt , flexible_array , alignment = parse_type (tokens , __cls__ , __byte_order__ )
210
220
vname = tokens .pop ()
211
221
fields .append (vname )
212
- fmt = (__byte_order__ + fmt ) if __byte_order__ is not None else fmt
213
- vsize = struct .calcsize (fmt )
222
+ # calculate the max field size (for the alignment)
223
+ max_alignment = max (max_alignment , alignment )
224
+ # align stuct if byte order is native
225
+ if not __is_union__ and align (__byte_order__ ) and vtype != 'char' :
226
+ modulo = offset % alignment
227
+ if modulo : # not aligned to the field size
228
+ delta = alignment - modulo
229
+ offset = offset + delta
214
230
fields_types [vname ] = FieldType (vtype , vlen , vsize , fmt , offset , flexible_array )
215
231
if not __is_union__ : # C struct
216
232
offset = offset + vsize
@@ -224,6 +240,12 @@ def parse_struct(__struct__, __cls__=None, __fields__=None, __is_union__=False,
224
240
fmt = '%ds' % size
225
241
else : # C struct
226
242
fmt = "" .join (fmt )
243
+ # add padding to stuct if byte order is native
244
+ if not __is_union__ and align (__byte_order__ ):
245
+ modulo = offset % max_alignment
246
+ if modulo : # not aligned to the max field size
247
+ delta = max_alignment - modulo
248
+ offset = offset + delta
227
249
size = offset # (offset is calculated as size sum)
228
250
229
251
# Add the byte order as prefix
@@ -236,7 +258,8 @@ def parse_struct(__struct__, __cls__=None, __fields__=None, __is_union__=False,
236
258
'__fields_types__' : fields_types ,
237
259
'__size__' : size ,
238
260
'__is_union__' : __is_union__ ,
239
- '__byte_order__' : __byte_order__
261
+ '__byte_order__' : __byte_order__ ,
262
+ '__alignment__' : max_alignment
240
263
}
241
264
242
265
# Add the missing fields to the class
0 commit comments