1 /* -*- mode: C; c-file-style: "gnu" -*- */ 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include "dbus-marshal-byteswap.h" 25 #include "dbus-marshal-basic.h" 26 #include "dbus-signature.h" 27 28 /** 29 * @addtogroup DBusMarshal 30 * @{ 31 */ 32 33 static void 34 byteswap_body_helper (DBusTypeReader *reader, 35 dbus_bool_t walk_reader_to_end, 36 int old_byte_order, 37 int new_byte_order, 38 unsigned char *p, 39 unsigned char **new_p) 40 { 41 int current_type; 42 43 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) 44 { 45 switch (current_type) 46 { 47 case DBUS_TYPE_BYTE: 48 ++p; 49 break; 50 51 case DBUS_TYPE_INT16: 52 case DBUS_TYPE_UINT16: 53 { 54 p = _DBUS_ALIGN_ADDRESS (p, 2); 55 *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p)); 56 p += 2; 57 } 58 break; 59 60 case DBUS_TYPE_BOOLEAN: 61 case DBUS_TYPE_INT32: 62 case DBUS_TYPE_UINT32: 63 { 64 p = _DBUS_ALIGN_ADDRESS (p, 4); 65 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 66 p += 4; 67 } 68 break; 69 70 case DBUS_TYPE_INT64: 71 case DBUS_TYPE_UINT64: 72 case DBUS_TYPE_DOUBLE: 73 { 74 p = _DBUS_ALIGN_ADDRESS (p, 8); 75 #ifdef DBUS_HAVE_INT64 76 *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p)); 77 #else 78 _dbus_swap_array (p, 1, 8); 79 #endif 80 p += 8; 81 } 82 break; 83 84 case DBUS_TYPE_ARRAY: 85 case DBUS_TYPE_STRING: 86 case DBUS_TYPE_OBJECT_PATH: 87 { 88 dbus_uint32_t array_len; 89 90 p = _DBUS_ALIGN_ADDRESS (p, 4); 91 92 array_len = _dbus_unpack_uint32 (old_byte_order, p); 93 94 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 95 p += 4; 96 97 if (current_type == DBUS_TYPE_ARRAY) 98 { 99 int elem_type; 100 int alignment; 101 102 elem_type = _dbus_type_reader_get_element_type (reader); 103 alignment = _dbus_type_get_alignment (elem_type); 104 105 _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH); 106 107 p = _DBUS_ALIGN_ADDRESS (p, alignment); 108 109 if (dbus_type_is_fixed (elem_type)) 110 { 111 if (alignment > 1) 112 _dbus_swap_array (p, array_len / alignment, alignment); 113 p += array_len; 114 } 115 else 116 { 117 DBusTypeReader sub; 118 const unsigned char *array_end; 119 120 array_end = p + array_len; 121 122 _dbus_type_reader_recurse (reader, &sub); 123 124 while (p < array_end) 125 { 126 byteswap_body_helper (&sub, 127 FALSE, 128 old_byte_order, 129 new_byte_order, 130 p, &p); 131 } 132 } 133 } 134 else 135 { 136 _dbus_assert (current_type == DBUS_TYPE_STRING || 137 current_type == DBUS_TYPE_OBJECT_PATH); 138 139 p += (array_len + 1); /* + 1 for nul */ 140 } 141 } 142 break; 143 144 case DBUS_TYPE_SIGNATURE: 145 { 146 dbus_uint32_t sig_len; 147 148 sig_len = *p; 149 150 p += (sig_len + 2); /* +2 for len and nul */ 151 } 152 break; 153 154 case DBUS_TYPE_VARIANT: 155 { 156 /* 1 byte sig len, sig typecodes, align to 157 * contained-type-boundary, values. 158 */ 159 dbus_uint32_t sig_len; 160 DBusString sig; 161 DBusTypeReader sub; 162 int contained_alignment; 163 164 sig_len = *p; 165 ++p; 166 167 _dbus_string_init_const_len (&sig, p, sig_len); 168 169 p += (sig_len + 1); /* 1 for nul */ 170 171 contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0)); 172 173 p = _DBUS_ALIGN_ADDRESS (p, contained_alignment); 174 175 _dbus_type_reader_init_types_only (&sub, &sig, 0); 176 177 byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); 178 } 179 break; 180 181 case DBUS_TYPE_STRUCT: 182 case DBUS_TYPE_DICT_ENTRY: 183 { 184 DBusTypeReader sub; 185 186 p = _DBUS_ALIGN_ADDRESS (p, 8); 187 188 _dbus_type_reader_recurse (reader, &sub); 189 190 byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p); 191 } 192 break; 193 194 default: 195 _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); 196 break; 197 } 198 199 if (walk_reader_to_end) 200 _dbus_type_reader_next (reader); 201 else 202 break; 203 } 204 205 if (new_p) 206 *new_p = p; 207 } 208 209 /** 210 * Byteswaps the marshaled data in the given value_str. 211 * 212 * @param signature the types in the value_str 213 * @param signature_start where in signature is the signature 214 * @param old_byte_order the old byte order 215 * @param new_byte_order the new byte order 216 * @param value_str the string containing the body 217 * @param value_pos where the values start 218 */ 219 void 220 _dbus_marshal_byteswap (const DBusString *signature, 221 int signature_start, 222 int old_byte_order, 223 int new_byte_order, 224 DBusString *value_str, 225 int value_pos) 226 { 227 DBusTypeReader reader; 228 229 _dbus_assert (value_pos >= 0); 230 _dbus_assert (value_pos <= _dbus_string_get_length (value_str)); 231 232 if (old_byte_order == new_byte_order) 233 return; 234 235 _dbus_type_reader_init_types_only (&reader, 236 signature, signature_start); 237 238 byteswap_body_helper (&reader, TRUE, 239 old_byte_order, new_byte_order, 240 _dbus_string_get_data_len (value_str, value_pos, 0), 241 NULL); 242 } 243 244 /** @} */ 245 246 /* Tests in dbus-marshal-byteswap-util.c */ 247