D-Bus
1.10.12
|
00001 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ 00002 /* dbus-marshal-byteswap.c Swap a block of marshaled data 00003 * 00004 * Copyright (C) 2005 Red Hat, Inc. 00005 * 00006 * Licensed under the Academic Free License version 2.1 00007 * 00008 * This program is free software; you can redistribute it and/or modify 00009 * it under the terms of the GNU General Public License as published by 00010 * the Free Software Foundation; either version 2 of the License, or 00011 * (at your option) any later version. 00012 * 00013 * This program is distributed in the hope that it will be useful, 00014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 * GNU General Public License for more details. 00017 * 00018 * You should have received a copy of the GNU General Public License 00019 * along with this program; if not, write to the Free Software 00020 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00021 * 00022 */ 00023 00024 #include <config.h> 00025 #include "dbus-marshal-byteswap.h" 00026 #include "dbus-marshal-basic.h" 00027 #include "dbus-signature.h" 00028 00034 static void 00035 byteswap_body_helper (DBusTypeReader *reader, 00036 dbus_bool_t walk_reader_to_end, 00037 int old_byte_order, 00038 int new_byte_order, 00039 unsigned char *p, 00040 unsigned char **new_p) 00041 { 00042 int current_type; 00043 00044 while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID) 00045 { 00046 switch (current_type) 00047 { 00048 case DBUS_TYPE_BYTE: 00049 ++p; 00050 break; 00051 00052 case DBUS_TYPE_INT16: 00053 case DBUS_TYPE_UINT16: 00054 { 00055 p = _DBUS_ALIGN_ADDRESS (p, 2); 00056 *((dbus_uint16_t*)p) = DBUS_UINT16_SWAP_LE_BE (*((dbus_uint16_t*)p)); 00057 p += 2; 00058 } 00059 break; 00060 00061 case DBUS_TYPE_BOOLEAN: 00062 case DBUS_TYPE_INT32: 00063 case DBUS_TYPE_UINT32: 00064 { 00065 p = _DBUS_ALIGN_ADDRESS (p, 4); 00066 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 00067 p += 4; 00068 } 00069 break; 00070 00071 case DBUS_TYPE_INT64: 00072 case DBUS_TYPE_UINT64: 00073 case DBUS_TYPE_DOUBLE: 00074 { 00075 p = _DBUS_ALIGN_ADDRESS (p, 8); 00076 *((dbus_uint64_t*)p) = DBUS_UINT64_SWAP_LE_BE (*((dbus_uint64_t*)p)); 00077 p += 8; 00078 } 00079 break; 00080 00081 case DBUS_TYPE_ARRAY: 00082 case DBUS_TYPE_STRING: 00083 case DBUS_TYPE_OBJECT_PATH: 00084 { 00085 dbus_uint32_t array_len; 00086 00087 p = _DBUS_ALIGN_ADDRESS (p, 4); 00088 00089 array_len = _dbus_unpack_uint32 (old_byte_order, p); 00090 00091 *((dbus_uint32_t*)p) = DBUS_UINT32_SWAP_LE_BE (*((dbus_uint32_t*)p)); 00092 p += 4; 00093 00094 if (current_type == DBUS_TYPE_ARRAY) 00095 { 00096 int elem_type; 00097 int alignment; 00098 00099 elem_type = _dbus_type_reader_get_element_type (reader); 00100 alignment = _dbus_type_get_alignment (elem_type); 00101 00102 _dbus_assert ((array_len / alignment) < DBUS_MAXIMUM_ARRAY_LENGTH); 00103 00104 p = _DBUS_ALIGN_ADDRESS (p, alignment); 00105 00106 if (dbus_type_is_fixed (elem_type)) 00107 { 00108 if (alignment > 1) 00109 _dbus_swap_array (p, array_len / alignment, alignment); 00110 p += array_len; 00111 } 00112 else 00113 { 00114 DBusTypeReader sub; 00115 const unsigned char *array_end; 00116 00117 array_end = p + array_len; 00118 00119 _dbus_type_reader_recurse (reader, &sub); 00120 00121 while (p < array_end) 00122 { 00123 byteswap_body_helper (&sub, 00124 FALSE, 00125 old_byte_order, 00126 new_byte_order, 00127 p, &p); 00128 } 00129 } 00130 } 00131 else 00132 { 00133 _dbus_assert (current_type == DBUS_TYPE_STRING || 00134 current_type == DBUS_TYPE_OBJECT_PATH); 00135 00136 p += (array_len + 1); /* + 1 for nul */ 00137 } 00138 } 00139 break; 00140 00141 case DBUS_TYPE_SIGNATURE: 00142 { 00143 dbus_uint32_t sig_len; 00144 00145 sig_len = *p; 00146 00147 p += (sig_len + 2); /* +2 for len and nul */ 00148 } 00149 break; 00150 00151 case DBUS_TYPE_VARIANT: 00152 { 00153 /* 1 byte sig len, sig typecodes, align to 00154 * contained-type-boundary, values. 00155 */ 00156 dbus_uint32_t sig_len; 00157 DBusString sig; 00158 DBusTypeReader sub; 00159 int contained_alignment; 00160 00161 sig_len = *p; 00162 ++p; 00163 00164 _dbus_string_init_const_len (&sig, p, sig_len); 00165 00166 p += (sig_len + 1); /* 1 for nul */ 00167 00168 contained_alignment = _dbus_type_get_alignment (_dbus_first_type_in_signature (&sig, 0)); 00169 00170 p = _DBUS_ALIGN_ADDRESS (p, contained_alignment); 00171 00172 _dbus_type_reader_init_types_only (&sub, &sig, 0); 00173 00174 byteswap_body_helper (&sub, FALSE, old_byte_order, new_byte_order, p, &p); 00175 } 00176 break; 00177 00178 case DBUS_TYPE_STRUCT: 00179 case DBUS_TYPE_DICT_ENTRY: 00180 { 00181 DBusTypeReader sub; 00182 00183 p = _DBUS_ALIGN_ADDRESS (p, 8); 00184 00185 _dbus_type_reader_recurse (reader, &sub); 00186 00187 byteswap_body_helper (&sub, TRUE, old_byte_order, new_byte_order, p, &p); 00188 } 00189 break; 00190 00191 case DBUS_TYPE_UNIX_FD: 00192 /* fds can only be passed on a local machine, so byte order must always match */ 00193 _dbus_assert_not_reached("attempted to byteswap unix fds which makes no sense"); 00194 break; 00195 00196 default: 00197 _dbus_assert_not_reached ("invalid typecode in supposedly-validated signature"); 00198 break; 00199 } 00200 00201 if (walk_reader_to_end) 00202 _dbus_type_reader_next (reader); 00203 else 00204 break; 00205 } 00206 00207 if (new_p) 00208 *new_p = p; 00209 } 00210 00221 void 00222 _dbus_marshal_byteswap (const DBusString *signature, 00223 int signature_start, 00224 int old_byte_order, 00225 int new_byte_order, 00226 DBusString *value_str, 00227 int value_pos) 00228 { 00229 DBusTypeReader reader; 00230 00231 _dbus_assert (value_pos >= 0); 00232 _dbus_assert (value_pos <= _dbus_string_get_length (value_str)); 00233 00234 if (old_byte_order == new_byte_order) 00235 return; 00236 00237 _dbus_type_reader_init_types_only (&reader, 00238 signature, signature_start); 00239 00240 byteswap_body_helper (&reader, TRUE, 00241 old_byte_order, new_byte_order, 00242 _dbus_string_get_data_len (value_str, value_pos, 0), 00243 NULL); 00244 } 00245 00248 /* Tests in dbus-marshal-byteswap-util.c */