1/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 2/* dbus-marshal-byteswap.c Swap a block of marshaled data 3 * 4 * Copyright (C) 2005 Red Hat, Inc. 5 * 6 * Licensed under the Academic Free License version 2.1 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 * 22 */ 23 24#include <config.h> 25#include "dbus-marshal-byteswap.h" 26#include "dbus-marshal-basic.h" 27#include "dbus-signature.h" 28 29/** 30 * @addtogroup DBusMarshal 31 * @{ 32 */ 33 34static void 35byteswap_body_helper (DBusTypeReader *reader, 36 dbus_bool_t walk_reader_to_end, 37 int old_byte_order, 38 int new_byte_order, 39 unsigned char *p, 40 unsigned char **new_p) 41{ 42 int current_type; 43 44 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) 45 { 46 switch (current_type) 47 { 48 case DBUS_TYPE_BYTE: 49 ++p; 50 break; 51 52 case DBUS_TYPE_INT16: 53 case DBUS_TYPE_UINT16: 54 { 55 p = _DBUS_ALIGN_ADDRESS (p, 2); 56 *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p)); 57 p += 2; 58 } 59 break; 60 61 case DBUS_TYPE_BOOLEAN: 62 case DBUS_TYPE_INT32: 63 case DBUS_TYPE_UINT32: 64 { 65 p = _DBUS_ALIGN_ADDRESS (p, 4); 66 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 67 p += 4; 68 } 69 break; 70 71 case DBUS_TYPE_INT64: 72 case DBUS_TYPE_UINT64: 73 case DBUS_TYPE_DOUBLE: 74 { 75 p = _DBUS_ALIGN_ADDRESS (p, 8); 76#ifdef DBUS_HAVE_INT64 77 *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p)); 78#else 79 _dbus_swap_array (p, 1, 8); 80#endif 81 p += 8; 82 } 83 break; 84 85 case DBUS_TYPE_ARRAY: 86 case DBUS_TYPE_STRING: 87 case DBUS_TYPE_OBJECT_PATH: 88 { 89 dbus_uint32_t array_len; 90 91 p = _DBUS_ALIGN_ADDRESS (p, 4); 92 93 array_len = _dbus_unpack_uint32 (old_byte_order, p); 94 95 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 96 p += 4; 97 98 if (current_type == DBUS_TYPE_ARRAY) 99 { 100 int elem_type; 101 int alignment; 102 103 elem_type = _dbus_type_reader_get_element_type (reader); 104 alignment = _dbus_type_get_alignment (elem_type); 105 106 _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH); 107 108 p = _DBUS_ALIGN_ADDRESS (p, alignment); 109 110 if (dbus_type_is_fixed (elem_type)) 111 { 112 if (alignment > 1) 113 _dbus_swap_array (p, array_len / alignment, alignment); 114 p += array_len; 115 } 116 else 117 { 118 DBusTypeReader sub; 119 const unsigned char *array_end; 120 121 array_end = p + array_len; 122 123 _dbus_type_reader_recurse (reader, &sub); 124 125 while (p < array_end) 126 { 127 byteswap_body_helper (&sub, 128 FALSE, 129 old_byte_order, 130 new_byte_order, 131 p, &p); 132 } 133 } 134 } 135 else 136 { 137 _dbus_assert (current_type == DBUS_TYPE_STRING || 138 current_type == DBUS_TYPE_OBJECT_PATH); 139 140 p += (array_len + 1); /* + 1 for nul */ 141 } 142 } 143 break; 144 145 case DBUS_TYPE_SIGNATURE: 146 { 147 dbus_uint32_t sig_len; 148 149 sig_len = *p; 150 151 p += (sig_len + 2); /* +2 for len and nul */ 152 } 153 break; 154 155 case DBUS_TYPE_VARIANT: 156 { 157 /* 1 byte sig len, sig typecodes, align to 158 * contained-type-boundary, values. 159 */ 160 dbus_uint32_t sig_len; 161 DBusString sig; 162 DBusTypeReader sub; 163 int contained_alignment; 164 165 sig_len = *p; 166 ++p; 167 168 _dbus_string_init_const_len (&sig, p, sig_len); 169 170 p += (sig_len + 1); /* 1 for nul */ 171 172 contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0)); 173 174 p = _DBUS_ALIGN_ADDRESS (p, contained_alignment); 175 176 _dbus_type_reader_init_types_only (&sub, &sig, 0); 177 178 byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); 179 } 180 break; 181 182 case DBUS_TYPE_STRUCT: 183 case DBUS_TYPE_DICT_ENTRY: 184 { 185 DBusTypeReader sub; 186 187 p = _DBUS_ALIGN_ADDRESS (p, 8); 188 189 _dbus_type_reader_recurse (reader, &sub); 190 191 byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p); 192 } 193 break; 194 195 case DBUS_TYPE_UNIX_FD: 196 /* fds can only be passed on a local machine, so byte order must always match */ 197 _dbus_assert_not_reached("attempted to byteswap unix fds which makes no sense"); 198 break; 199 200 default: 201 _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); 202 break; 203 } 204 205 if (walk_reader_to_end) 206 _dbus_type_reader_next (reader); 207 else 208 break; 209 } 210 211 if (new_p) 212 *new_p = p; 213} 214 215/** 216 * Byteswaps the marshaled data in the given value_str. 217 * 218 * @param signature the types in the value_str 219 * @param signature_start where in signature is the signature 220 * @param old_byte_order the old byte order 221 * @param new_byte_order the new byte order 222 * @param value_str the string containing the body 223 * @param value_pos where the values start 224 */ 225void 226_dbus_marshal_byteswap (const DBusString *signature, 227 int signature_start, 228 int old_byte_order, 229 int new_byte_order, 230 DBusString *value_str, 231 int value_pos) 232{ 233 DBusTypeReader reader; 234 235 _dbus_assert (value_pos >= 0); 236 _dbus_assert (value_pos <= _dbus_string_get_length (value_str)); 237 238 if (old_byte_order == new_byte_order) 239 return; 240 241 _dbus_type_reader_init_types_only (&reader, 242 signature, signature_start); 243 244 byteswap_body_helper (&reader, TRUE, 245 old_byte_order, new_byte_order, 246 _dbus_string_get_data_len (value_str, value_pos, 0), 247 NULL); 248} 249 250/** @} */ 251 252/* Tests in dbus-marshal-byteswap-util.c */ 253