Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */ 2 : 3 : #include <errno.h> 4 : #include <string.h> 5 : 6 : #include "sd-bus.h" 7 : 8 : #include "bus-gvariant.h" 9 : #include "bus-signature.h" 10 : #include "bus-type.h" 11 : 12 139 : int bus_gvariant_get_size(const char *signature) { 13 : const char *p; 14 139 : int sum = 0, r; 15 : 16 : /* For fixed size structs. Fails for variable size structs. */ 17 : 18 139 : p = signature; 19 259 : while (*p != 0) { 20 : size_t n; 21 : 22 174 : r = signature_element_length(p, &n); 23 174 : if (r < 0) 24 54 : return r; 25 173 : else { 26 173 : char t[n+1]; 27 : 28 173 : memcpy(t, p, n); 29 173 : t[n] = 0; 30 : 31 173 : r = bus_gvariant_get_alignment(t); 32 173 : if (r < 0) 33 0 : return r; 34 : 35 173 : sum = ALIGN_TO(sum, r); 36 : } 37 : 38 173 : switch (*p) { 39 : 40 19 : case SD_BUS_TYPE_BOOLEAN: 41 : case SD_BUS_TYPE_BYTE: 42 19 : sum += 1; 43 19 : break; 44 : 45 2 : case SD_BUS_TYPE_INT16: 46 : case SD_BUS_TYPE_UINT16: 47 2 : sum += 2; 48 2 : break; 49 : 50 60 : case SD_BUS_TYPE_INT32: 51 : case SD_BUS_TYPE_UINT32: 52 : case SD_BUS_TYPE_UNIX_FD: 53 60 : sum += 4; 54 60 : break; 55 : 56 14 : case SD_BUS_TYPE_INT64: 57 : case SD_BUS_TYPE_UINT64: 58 : case SD_BUS_TYPE_DOUBLE: 59 14 : sum += 8; 60 14 : break; 61 : 62 39 : case SD_BUS_TYPE_STRUCT_BEGIN: 63 : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 64 39 : if (n == 2) { 65 : /* unary type () has fixed size of 1 */ 66 0 : r = 1; 67 39 : } else { 68 39 : char t[n-1]; 69 : 70 39 : memcpy(t, p + 1, n - 2); 71 39 : t[n - 2] = 0; 72 : 73 39 : r = bus_gvariant_get_size(t); 74 39 : if (r < 0) 75 14 : return r; 76 : } 77 : 78 25 : sum += r; 79 25 : break; 80 : } 81 : 82 39 : case SD_BUS_TYPE_STRING: 83 : case SD_BUS_TYPE_OBJECT_PATH: 84 : case SD_BUS_TYPE_SIGNATURE: 85 : case SD_BUS_TYPE_ARRAY: 86 : case SD_BUS_TYPE_VARIANT: 87 39 : return -EINVAL; 88 : 89 0 : default: 90 0 : assert_not_reached("Unknown signature type"); 91 : } 92 : 93 120 : p += n; 94 : } 95 : 96 85 : r = bus_gvariant_get_alignment(signature); 97 85 : if (r < 0) 98 0 : return r; 99 : 100 85 : return ALIGN_TO(sum, r); 101 : } 102 : 103 562 : int bus_gvariant_get_alignment(const char *signature) { 104 562 : size_t alignment = 1; 105 : const char *p; 106 : int r; 107 : 108 562 : p = signature; 109 1300 : while (*p != 0 && alignment < 8) { 110 : size_t n; 111 : int a; 112 : 113 739 : r = signature_element_length(p, &n); 114 739 : if (r < 0) 115 1 : return r; 116 : 117 738 : switch (*p) { 118 : 119 191 : case SD_BUS_TYPE_BYTE: 120 : case SD_BUS_TYPE_BOOLEAN: 121 : case SD_BUS_TYPE_STRING: 122 : case SD_BUS_TYPE_OBJECT_PATH: 123 : case SD_BUS_TYPE_SIGNATURE: 124 191 : a = 1; 125 191 : break; 126 : 127 9 : case SD_BUS_TYPE_INT16: 128 : case SD_BUS_TYPE_UINT16: 129 9 : a = 2; 130 9 : break; 131 : 132 265 : case SD_BUS_TYPE_INT32: 133 : case SD_BUS_TYPE_UINT32: 134 : case SD_BUS_TYPE_UNIX_FD: 135 265 : a = 4; 136 265 : break; 137 : 138 110 : case SD_BUS_TYPE_INT64: 139 : case SD_BUS_TYPE_UINT64: 140 : case SD_BUS_TYPE_DOUBLE: 141 : case SD_BUS_TYPE_VARIANT: 142 110 : a = 8; 143 110 : break; 144 : 145 21 : case SD_BUS_TYPE_ARRAY: { 146 21 : char t[n]; 147 : 148 21 : memcpy(t, p + 1, n - 1); 149 21 : t[n - 1] = 0; 150 : 151 21 : a = bus_gvariant_get_alignment(t); 152 21 : break; 153 : } 154 : 155 142 : case SD_BUS_TYPE_STRUCT_BEGIN: 156 142 : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 157 142 : char t[n-1]; 158 : 159 142 : memcpy(t, p + 1, n - 2); 160 142 : t[n - 2] = 0; 161 : 162 142 : a = bus_gvariant_get_alignment(t); 163 142 : break; 164 : } 165 : 166 0 : default: 167 0 : assert_not_reached("Unknown signature type"); 168 : } 169 : 170 738 : if (a < 0) 171 0 : return a; 172 : 173 738 : assert(a > 0 && a <= 8); 174 738 : if ((size_t) a > alignment) 175 454 : alignment = (size_t) a; 176 : 177 738 : p += n; 178 : } 179 : 180 561 : return alignment; 181 : } 182 : 183 126 : int bus_gvariant_is_fixed_size(const char *signature) { 184 : const char *p; 185 : int r; 186 : 187 126 : assert(signature); 188 : 189 126 : p = signature; 190 205 : while (*p != 0) { 191 : size_t n; 192 : 193 154 : r = signature_element_length(p, &n); 194 154 : if (r < 0) 195 75 : return r; 196 : 197 153 : switch (*p) { 198 : 199 64 : case SD_BUS_TYPE_STRING: 200 : case SD_BUS_TYPE_OBJECT_PATH: 201 : case SD_BUS_TYPE_SIGNATURE: 202 : case SD_BUS_TYPE_ARRAY: 203 : case SD_BUS_TYPE_VARIANT: 204 64 : return 0; 205 : 206 72 : case SD_BUS_TYPE_BYTE: 207 : case SD_BUS_TYPE_BOOLEAN: 208 : case SD_BUS_TYPE_INT16: 209 : case SD_BUS_TYPE_UINT16: 210 : case SD_BUS_TYPE_INT32: 211 : case SD_BUS_TYPE_UINT32: 212 : case SD_BUS_TYPE_UNIX_FD: 213 : case SD_BUS_TYPE_INT64: 214 : case SD_BUS_TYPE_UINT64: 215 : case SD_BUS_TYPE_DOUBLE: 216 72 : break; 217 : 218 17 : case SD_BUS_TYPE_STRUCT_BEGIN: 219 17 : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 220 17 : char t[n-1]; 221 : 222 17 : memcpy(t, p + 1, n - 2); 223 17 : t[n - 2] = 0; 224 : 225 17 : r = bus_gvariant_is_fixed_size(t); 226 17 : if (r <= 0) 227 10 : return r; 228 7 : break; 229 : } 230 : 231 0 : default: 232 0 : assert_not_reached("Unknown signature type"); 233 : } 234 : 235 79 : p += n; 236 : } 237 : 238 51 : return true; 239 : } 240 : 241 37 : size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) { 242 37 : if (sz + extra <= 0xFF) 243 34 : return 1; 244 3 : else if (sz + extra*2 <= 0xFFFF) 245 3 : return 2; 246 0 : else if (sz + extra*4 <= 0xFFFFFFFF) 247 0 : return 4; 248 : else 249 0 : return 8; 250 : } 251 : 252 35 : size_t bus_gvariant_read_word_le(void *p, size_t sz) { 253 : union { 254 : uint16_t u16; 255 : uint32_t u32; 256 : uint64_t u64; 257 : } x; 258 : 259 35 : assert(p); 260 : 261 35 : if (sz == 1) 262 34 : return *(uint8_t*) p; 263 : 264 1 : memcpy(&x, p, sz); 265 : 266 1 : if (sz == 2) 267 1 : return le16toh(x.u16); 268 0 : else if (sz == 4) 269 0 : return le32toh(x.u32); 270 0 : else if (sz == 8) 271 0 : return le64toh(x.u64); 272 : 273 0 : assert_not_reached("unknown word width"); 274 : } 275 : 276 21 : void bus_gvariant_write_word_le(void *p, size_t sz, size_t value) { 277 : union { 278 : uint16_t u16; 279 : uint32_t u32; 280 : uint64_t u64; 281 : } x; 282 : 283 21 : assert(p); 284 21 : assert(sz == 8 || (value < (1ULL << (sz*8)))); 285 : 286 21 : if (sz == 1) { 287 20 : *(uint8_t*) p = value; 288 20 : return; 289 1 : } else if (sz == 2) 290 1 : x.u16 = htole16((uint16_t) value); 291 0 : else if (sz == 4) 292 0 : x.u32 = htole32((uint32_t) value); 293 0 : else if (sz == 8) 294 0 : x.u64 = htole64((uint64_t) value); 295 : else 296 0 : assert_not_reached("unknown word width"); 297 : 298 1 : memcpy(p, &x, sz); 299 : }