/**
 * See dbus_message_get_serial()
 *
 * @param header the header
 * @returns the client serial
 */
dbus_uint32_t
_dbus_header_get_serial (DBusHeader *header)
{
  return _dbus_marshal_read_uint32 (&header->data,
                                    SERIAL_OFFSET,
                                    header->byte_order,
                                    NULL);
}
static dbus_bool_t
generate_wrong_length (DBusMessageDataIter *iter,
                       DBusString          *data,
                       DBusValidity        *expected_validity)
{
  int lengths[] = { -42, -17, -16, -15, -9, -8, -7, -6, -5, -4, -3, -2, -1,
                    1, 2, 3, 4, 5, 6, 7, 8, 9, 15, 16, 30 };
  int adjust;
  int len_seq;

 restart:
  len_seq = iter_get_sequence (iter);
  if (len_seq == _DBUS_N_ELEMENTS (lengths))
    return FALSE;

  _dbus_assert (len_seq < _DBUS_N_ELEMENTS (lengths));
  
  iter_recurse (iter);
  if (!generate_many_bodies (iter, data, expected_validity))
    {
      iter_set_sequence (iter, 0); /* reset to first body */
      iter_unrecurse (iter);
      iter_next (iter);            /* next length adjustment */
      goto restart;
    }
  iter_unrecurse (iter);

  adjust = lengths[len_seq];

  if (adjust < 0)
    {
      if ((_dbus_string_get_length (data) + adjust) < DBUS_MINIMUM_HEADER_SIZE)
        _dbus_string_set_length (data, DBUS_MINIMUM_HEADER_SIZE);
      else
        _dbus_string_shorten (data, - adjust);
      *expected_validity = DBUS_INVALID_FOR_UNKNOWN_REASON;
    }
  else
    {      
      if (!_dbus_string_lengthen (data, adjust))
        _dbus_assert_not_reached ("oom");
      *expected_validity = DBUS_INVALID_TOO_MUCH_DATA;
    }

  /* Fixup lengths */
  {
    int old_body_len;
    int new_body_len;
    int byte_order;
    
    _dbus_assert (_dbus_string_get_length (data) >= DBUS_MINIMUM_HEADER_SIZE);
    
    byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
    old_body_len = _dbus_marshal_read_uint32 (data,
                                              BODY_LENGTH_OFFSET,
                                              byte_order,
                                              NULL);
    _dbus_assert (old_body_len < _dbus_string_get_length (data));
    new_body_len = old_body_len + adjust;
    if (new_body_len < 0)
      {
        new_body_len = 0;
        /* we just munged the header, and aren't sure how */
        *expected_validity = DBUS_VALIDITY_UNKNOWN;
      }

    _dbus_verbose ("changing body len from %u to %u by adjust %d\n",
                   old_body_len, new_body_len, adjust);
    
    _dbus_marshal_set_uint32 (data, BODY_LENGTH_OFFSET,
                              new_body_len,
                              byte_order);
  }

  return TRUE;
}
static dbus_bool_t
generate_uint32_changed (DBusMessageDataIter *iter,
                         DBusString          *data,
                         DBusValidity        *expected_validity)
{
  int body_seq;
  int byte_seq;
  int change_seq;
  dbus_uint32_t v_UINT32;
  int byte_order;
  const UIntChange *change;
  int base_depth;

  /* Outer loop is each body, next loop is each change,
   * inner loop is each change location
   */

  base_depth = iter->depth;
  
 next_body:
  _dbus_assert (iter->depth == (base_depth + 0));
  _dbus_string_set_length (data, 0);
  body_seq = iter_get_sequence (iter);
  
  if (!generate_many_bodies (iter, data, expected_validity))
    return FALSE;

  _dbus_assert (iter->depth == (base_depth + 0));

  iter_set_sequence (iter, body_seq); /* undo the "next" from generate_many_bodies */
  iter_recurse (iter);
 next_change:
  _dbus_assert (iter->depth == (base_depth + 1));
  change_seq = iter_get_sequence (iter);
  
  if (change_seq == _DBUS_N_ELEMENTS (uint32_changes))
    {
      /* Reset change count */
      iter_set_sequence (iter, 0);
      iter_unrecurse (iter);
      iter_next (iter);
      goto next_body;
    }

  _dbus_assert (iter->depth == (base_depth + 1));
  
  iter_recurse (iter);
  _dbus_assert (iter->depth == (base_depth + 2));
  byte_seq = iter_get_sequence (iter);
  /* skip 4 bytes at a time */
  iter_next (iter);
  iter_next (iter);
  iter_next (iter);
  iter_next (iter);
  iter_unrecurse (iter);

  _dbus_assert (_DBUS_ALIGN_VALUE (byte_seq, 4) == (unsigned) byte_seq);
  if (byte_seq >= (_dbus_string_get_length (data) - 4))
    {
      /* reset byte count */
      _dbus_assert (iter->depth == (base_depth + 1));
      iter_recurse (iter);
      _dbus_assert (iter->depth == (base_depth + 2));
      iter_set_sequence (iter, 0);
      iter_unrecurse (iter);
      _dbus_assert (iter->depth == (base_depth + 1));
      iter_next (iter);
      goto next_change;
    }
  
  _dbus_assert (byte_seq <= (_dbus_string_get_length (data) - 4));

  byte_order = _dbus_string_get_byte (data, BYTE_ORDER_OFFSET);
  
  v_UINT32 = _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL);

  change = &uint32_changes[change_seq];

  if (change->type == CHANGE_TYPE_ADJUST)
    {
      v_UINT32 += (int) change->value;
    }
  else
    {
      v_UINT32 = change->value;
    }

#if 0
  printf ("body %d change %d pos %d ",
          body_seq, change_seq, byte_seq);

  if (change->type == CHANGE_TYPE_ADJUST)
    printf ("adjust by %d", (int) change->value);
  else
    printf ("set to %u", change->value);
  
  printf (" \t%u -> %u\n",
          _dbus_marshal_read_uint32 (data, byte_seq, byte_order, NULL),
          v_UINT32);
#endif
  
  _dbus_marshal_set_uint32 (data, byte_seq, v_UINT32, byte_order);
  *expected_validity = DBUS_VALIDITY_UNKNOWN;

  _dbus_assert (iter->depth == (base_depth + 1));
  iter_unrecurse (iter);
  _dbus_assert (iter->depth == (base_depth + 0));
          
  return TRUE;
}
static DBusValidity
load_and_validate_field (DBusHeader     *header,
                         int             field,
                         DBusTypeReader *variant_reader)
{
  int type;
  int expected_type;
  const DBusString *value_str;
  int value_pos;
  int str_data_pos;
  dbus_uint32_t v_UINT32;
  int bad_string_code;
  dbus_bool_t (* string_validation_func) (const DBusString *str,
                                          int start, int len);

  /* Supposed to have been checked already */
  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
  _dbus_assert (field != DBUS_HEADER_FIELD_INVALID);

  /* Before we can cache a field, we need to know it has the right type */
  type = _dbus_type_reader_get_current_type (variant_reader);

  _dbus_assert (_dbus_header_field_types[field].code == field);

  expected_type = EXPECTED_TYPE_OF_FIELD (field);
  if (type != expected_type)
    {
      _dbus_verbose ("Field %d should have type %d but has %d\n",
                     field, expected_type, type);
      return DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE;
    }

  /* If the field was provided twice, we aren't happy */
  if (header->fields[field].value_pos >= 0)
    {
      _dbus_verbose ("Header field %d seen a second time\n", field);
      return DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE;
    }

  /* Now we can cache and look at the field content */
  _dbus_verbose ("initially caching field %d\n", field);
  _dbus_header_cache_one (header, field, variant_reader);

  string_validation_func = NULL;

  /* make compiler happy that all this is initialized */
  v_UINT32 = 0;
  value_str = NULL;
  value_pos = -1;
  str_data_pos = -1;
  bad_string_code = DBUS_VALID;

  if (expected_type == DBUS_TYPE_UINT32)
    {
      _dbus_header_get_field_basic (header, field, expected_type,
                                    &v_UINT32);
    }
  else if (expected_type == DBUS_TYPE_STRING ||
           expected_type == DBUS_TYPE_OBJECT_PATH ||
           expected_type == DBUS_TYPE_SIGNATURE)
    {
      _dbus_header_get_field_raw (header, field,
                                  &value_str, &value_pos);
      str_data_pos = _DBUS_ALIGN_VALUE (value_pos, 4) + 4;
    }
  else
    {
      _dbus_assert_not_reached ("none of the known fields should have this type");
    }

  switch (field)
    {
    case DBUS_HEADER_FIELD_DESTINATION:
      string_validation_func = _dbus_validate_bus_name;
      bad_string_code = DBUS_INVALID_BAD_DESTINATION;
      break;
    case DBUS_HEADER_FIELD_INTERFACE:
      string_validation_func = _dbus_validate_interface;
      bad_string_code = DBUS_INVALID_BAD_INTERFACE;

      if (_dbus_string_equal_substring (&_dbus_local_interface_str,
                                        0,
                                        _dbus_string_get_length (&_dbus_local_interface_str),
                                        value_str, str_data_pos))
        {
          _dbus_verbose ("Message is on the local interface\n");
          return DBUS_INVALID_USES_LOCAL_INTERFACE;
        }
      break;

    case DBUS_HEADER_FIELD_MEMBER:
      string_validation_func = _dbus_validate_member;
      bad_string_code = DBUS_INVALID_BAD_MEMBER;
      break;

    case DBUS_HEADER_FIELD_ERROR_NAME:
      string_validation_func = _dbus_validate_error_name;
      bad_string_code = DBUS_INVALID_BAD_ERROR_NAME;
      break;

    case DBUS_HEADER_FIELD_SENDER:
      string_validation_func = _dbus_validate_bus_name;
      bad_string_code = DBUS_INVALID_BAD_SENDER;
      break;

    case DBUS_HEADER_FIELD_PATH:
      /* OBJECT_PATH was validated generically due to its type */
      string_validation_func = NULL;

      if (_dbus_string_equal_substring (&_dbus_local_path_str,
                                        0,
                                        _dbus_string_get_length (&_dbus_local_path_str),
                                        value_str, str_data_pos))
        {
          _dbus_verbose ("Message is from the local path\n");
          return DBUS_INVALID_USES_LOCAL_PATH;
        }
      break;

    case DBUS_HEADER_FIELD_REPLY_SERIAL:
      /* Can't be 0 */
      if (v_UINT32 == 0)
        {
          return DBUS_INVALID_BAD_SERIAL;
        }
      break;

    case DBUS_HEADER_FIELD_SIGNATURE:
      /* SIGNATURE validated generically due to its type */
      string_validation_func = NULL;
      break;

    default:
      _dbus_assert_not_reached ("unknown field shouldn't be seen here");
      break;
    }

  if (string_validation_func)
    {
      dbus_uint32_t len;

      _dbus_assert (bad_string_code != DBUS_VALID);

      len = _dbus_marshal_read_uint32 (value_str, value_pos,
                                       header->byte_order, NULL);

#if 0
      _dbus_verbose ("Validating string header field; code %d if fails\n",
                     bad_string_code);
#endif
      if (!(*string_validation_func) (value_str, str_data_pos, len))
        return bad_string_code;
    }

  return DBUS_VALID;
}
/**
 * Given data long enough to contain the length of the message body
 * and the fields array, check whether the data is long enough to
 * contain the entire message (assuming the claimed lengths are
 * accurate). Also checks that the lengths are in sanity parameters.
 *
 * @param max_message_length maximum length of a valid message
 * @param validity return location for why the data is invalid if it is
 * @param byte_order return location for byte order
 * @param fields_array_len return location for claimed fields array length
 * @param header_len return location for claimed header length
 * @param body_len return location for claimed body length
 * @param str the data
 * @param start start of data, 8-aligned
 * @param len length of data
 * @returns #TRUE if the data is long enough for the claimed length, and the lengths were valid
 */
dbus_bool_t
_dbus_header_have_message_untrusted (int                max_message_length,
                                     DBusValidity      *validity,
                                     int               *byte_order,
                                     int               *fields_array_len,
                                     int               *header_len,
                                     int               *body_len,
                                     const DBusString  *str,
                                     int                start,
                                     int                len)

{
  dbus_uint32_t header_len_unsigned;
  dbus_uint32_t fields_array_len_unsigned;
  dbus_uint32_t body_len_unsigned;

  _dbus_assert (start >= 0);
  _dbus_assert (start < _DBUS_INT32_MAX / 2);
  _dbus_assert (len >= 0);

  _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8));

  *byte_order = _dbus_string_get_byte (str, start + BYTE_ORDER_OFFSET);

  if (*byte_order != DBUS_LITTLE_ENDIAN && *byte_order != DBUS_BIG_ENDIAN)
    {
      *validity = DBUS_INVALID_BAD_BYTE_ORDER;
      return FALSE;
    }

  _dbus_assert (FIELDS_ARRAY_LENGTH_OFFSET + 4 <= len);
  fields_array_len_unsigned = _dbus_marshal_read_uint32 (str, start + FIELDS_ARRAY_LENGTH_OFFSET,
                                                         *byte_order, NULL);

  if (fields_array_len_unsigned > (unsigned) max_message_length)
    {
      *validity = DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH;
      return FALSE;
    }

  _dbus_assert (BODY_LENGTH_OFFSET + 4 < len);
  body_len_unsigned = _dbus_marshal_read_uint32 (str, start + BODY_LENGTH_OFFSET,
                                                 *byte_order, NULL);

  if (body_len_unsigned > (unsigned) max_message_length)
    {
      *validity = DBUS_INVALID_INSANE_BODY_LENGTH;
      return FALSE;
    }

  header_len_unsigned = FIRST_FIELD_OFFSET + fields_array_len_unsigned;
  header_len_unsigned = _DBUS_ALIGN_VALUE (header_len_unsigned, 8);

  /* overflow should be impossible since the lengths aren't allowed to
   * be huge.
   */
  _dbus_assert (max_message_length < _DBUS_INT32_MAX / 2);
  if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length)
    {
      *validity = DBUS_INVALID_MESSAGE_TOO_LONG;
      return FALSE;
    }

  _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT32_MAX);
  _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT32_MAX);
  _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT32_MAX);

  *body_len = body_len_unsigned;
  *fields_array_len = fields_array_len_unsigned;
  *header_len = header_len_unsigned;

  *validity = DBUS_VALID;

  _dbus_verbose ("have %d bytes, need body %u + header %u = %u\n",
                 len, body_len_unsigned, header_len_unsigned,
                 body_len_unsigned + header_len_unsigned);

  return (body_len_unsigned + header_len_unsigned) <= (unsigned) len;
}