generator: fix align-pads for switches which start at unaligned pos
[free-sw/xcb/libxcb] / src / c_client.py
index 87f268b..0a1f877 100644 (file)
@@ -358,7 +358,8 @@ def _c_type_setup(self, name, postfix):
                 field.c_pointer = '*'
                 field.c_field_const_type = 'const ' + field.c_field_type
                 self.c_need_aux = True
-            elif not field.type.fixed_size() and not field.type.is_case_or_bitcase:
+
+            if not field.type.fixed_size() and not field.type.is_case_or_bitcase:
                 self.c_need_sizeof = True
 
             field.c_iterator_type = _t(field.field_type + ('iterator',))      # xcb_fieldtype_iterator_t
@@ -656,9 +657,15 @@ def get_serialize_params(context, self, buffer_var='_buffer', aux_var='_aux'):
     return (param_fields, wire_fields, params)
 # get_serialize_params()
 
-def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
+def _c_serialize_helper_insert_padding(context, code_lines, space, postpone, is_case_or_bitcase):
     code_lines.append('%s    /* insert padding */' % space)
-    code_lines.append('%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
+    if is_case_or_bitcase:
+        code_lines.append(
+            '%s    xcb_pad = -(xcb_block_len + xcb_padding_offset) & (xcb_align_to - 1);'
+            % space)
+    else:
+        code_lines.append(
+            '%s    xcb_pad = -xcb_block_len & (xcb_align_to - 1);' % space)
 #    code_lines.append('%s    printf("automatically inserting padding: %%%%d\\n", xcb_pad);' % space)
     code_lines.append('%s    xcb_buffer_len += xcb_block_len + xcb_pad;' % space)
 
@@ -676,6 +683,8 @@ def _c_serialize_helper_insert_padding(context, code_lines, space, postpone):
         code_lines.append('%s    }' % space)
 
     code_lines.append('%s    xcb_block_len = 0;' % space)
+    if is_case_or_bitcase:
+        code_lines.append('%s    xcb_padding_offset = 0;' % space)
 
     # keep tracking of xcb_parts entries for serialize
     return 1
@@ -770,6 +779,10 @@ def _c_serialize_helper_switch_field(context, self, field, c_switch_variable, pr
     elif context in ('unserialize', 'unpack'):
         length = "%s(xcb_tmp, %s&%s%s)" % (field.type.c_unpack_name,
                                            c_field_names, prefix_str, field.c_field_name)
+    elif 'sizeof' == context:
+        # remove trailing ", " from c_field_names because it will be used at end of arglist
+        my_c_field_names = c_field_names[:-2]
+        length = "%s(xcb_tmp, %s)" % (field.type.c_sizeof_name, my_c_field_names)
 
     return length
 # _c_serialize_helper_switch_field()
@@ -869,9 +882,13 @@ def _c_serialize_helper_fields_fixed_size(context, self, field,
             # total padding = sizeof(pad0) * nmemb
             length += " * %d" % field.type.nmemb
 
-        if field.type.is_list:
-            # no such case in the protocol, cannot be tested and therefore ignored for now
-            raise Exception('list with fixed number of elemens unhandled in _unserialize()')
+        elif field.type.is_list:
+            # list with fixed number of elements
+            # length of array = sizeof(arrayElementType) * nmemb
+            length += " * %d" % field.type.nmemb
+            # use memcpy because C cannot assign whole arrays with operator=
+            value = '    memcpy(%s, xcb_tmp, %s);' % (abs_field_name, length)
+
 
     elif 'serialize' == context:
         value = '    xcb_parts[xcb_parts_idx].iov_base = (char *) '
@@ -996,13 +1013,15 @@ def _c_serialize_helper_fields(context, self,
                 # Variable length pad is <pad align= />
                 code_lines.append('%s    xcb_align_to = %d;' % (space, field.type.align))
                 count += _c_serialize_helper_insert_padding(context, code_lines, space,
-                                                        self.c_var_followed_by_fixed_fields)
+                                                            self.c_var_followed_by_fixed_fields,
+                                                            is_case_or_bitcase)
                 continue
             else:
                 # switch/bitcase: always calculate padding before and after variable sized fields
                 if need_padding or is_case_or_bitcase:
                     count += _c_serialize_helper_insert_padding(context, code_lines, space,
-                                                            self.c_var_followed_by_fixed_fields)
+                                                                self.c_var_followed_by_fixed_fields,
+                                                                is_case_or_bitcase)
 
                 value, length = _c_serialize_helper_fields_variable_size(context, self, field,
                                                                          code_lines, temp_vars,
@@ -1042,7 +1061,12 @@ def _c_serialize_helper_fields(context, self,
             code_lines.append('%s    xcb_parts_idx++;' % space)
             count += 1
 
-        code_lines.append('%s    xcb_align_to = ALIGNOF(%s);' % (space, 'char' if field.c_field_type == 'void' else field.c_field_type))
+        code_lines.append(
+            '%s    xcb_align_to = ALIGNOF(%s);'
+             % (space,
+                 'char'
+                  if field.c_field_type == 'void' or field.type.is_switch
+                  else field.c_field_type))
 
         need_padding = True
         if self.c_var_followed_by_fixed_fields:
@@ -1086,7 +1110,7 @@ def _c_serialize_helper(context, complex_type,
                                             code_lines, temp_vars,
                                             space, prefix, False)
     # "final padding"
-    count += _c_serialize_helper_insert_padding(context, code_lines, space, False)
+    count += _c_serialize_helper_insert_padding(context, code_lines, space, False, self.is_switch)
 
     return count
 # _c_serialize_helper()
@@ -1156,6 +1180,8 @@ def _c_serialize(context, self):
             _c('    char *xcb_out = *_buffer;')
             _c('    unsigned int xcb_buffer_len = 0;')
             _c('    unsigned int xcb_align_to = 0;')
+        if self.is_switch:
+            _c('    unsigned int xcb_padding_offset = ((size_t)xcb_out) & 7;')
         prefix = [('_aux', '->', self)]
         aux_ptr = 'xcb_out'
 
@@ -1179,6 +1205,8 @@ def _c_serialize(context, self):
         _c('    unsigned int xcb_block_len = 0;')
         _c('    unsigned int xcb_pad = 0;')
         _c('    unsigned int xcb_align_to = 0;')
+        if self.is_switch:
+            _c('    unsigned int xcb_padding_offset = ((size_t)_buffer) & 7;')
 
     elif 'sizeof' == context:
         param_names = [p[2] for p in params]
@@ -1196,6 +1224,8 @@ def _c_serialize(context, self):
         else:
             _c('    char *xcb_tmp = (char *)_buffer;')
             prefix = [('_aux', '->', self)]
+            if self.is_switch:
+                _c('    unsigned int xcb_padding_offset = 0;')
 
     count = _c_serialize_helper(context, self, code_lines, temp_vars, prefix=prefix)
     # update variable size fields (only important for context=='serialize'