Branch data 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 : 556 : int bus_gvariant_get_size(const char *signature) { 13 : : const char *p; 14 : 556 : int sum = 0, r; 15 : : 16 : : /* For fixed size structs. Fails for variable size structs. */ 17 : : 18 : 556 : p = signature; 19 [ + + ]: 1036 : while (*p != 0) { 20 : : size_t n; 21 : : 22 : 696 : r = signature_element_length(p, &n); 23 [ + + ]: 696 : if (r < 0) 24 : 216 : return r; 25 : 692 : else { 26 : 692 : char t[n+1]; 27 : : 28 : 692 : memcpy(t, p, n); 29 : 692 : t[n] = 0; 30 : : 31 : 692 : r = bus_gvariant_get_alignment(t); 32 [ - + ]: 692 : if (r < 0) 33 : 0 : return r; 34 : : 35 : 692 : sum = ALIGN_TO(sum, r); 36 : : } 37 : : 38 [ + + + + : 692 : switch (*p) { + + - ] 39 : : 40 : 76 : case SD_BUS_TYPE_BOOLEAN: 41 : : case SD_BUS_TYPE_BYTE: 42 : 76 : sum += 1; 43 : 76 : break; 44 : : 45 : 8 : case SD_BUS_TYPE_INT16: 46 : : case SD_BUS_TYPE_UINT16: 47 : 8 : sum += 2; 48 : 8 : break; 49 : : 50 : 240 : case SD_BUS_TYPE_INT32: 51 : : case SD_BUS_TYPE_UINT32: 52 : : case SD_BUS_TYPE_UNIX_FD: 53 : 240 : sum += 4; 54 : 240 : break; 55 : : 56 : 56 : case SD_BUS_TYPE_INT64: 57 : : case SD_BUS_TYPE_UINT64: 58 : : case SD_BUS_TYPE_DOUBLE: 59 : 56 : sum += 8; 60 : 56 : break; 61 : : 62 : 156 : case SD_BUS_TYPE_STRUCT_BEGIN: 63 : : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 64 [ - + ]: 156 : if (n == 2) { 65 : : /* unary type () has fixed size of 1 */ 66 : 0 : r = 1; 67 : 156 : } else { 68 : 156 : char t[n-1]; 69 : : 70 : 156 : memcpy(t, p + 1, n - 2); 71 : 156 : t[n - 2] = 0; 72 : : 73 : 156 : r = bus_gvariant_get_size(t); 74 [ + + ]: 156 : if (r < 0) 75 : 56 : return r; 76 : : } 77 : : 78 : 100 : sum += r; 79 : 100 : break; 80 : : } 81 : : 82 : 156 : 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 : 156 : return -EINVAL; 88 : : 89 : 0 : default: 90 : 0 : assert_not_reached("Unknown signature type"); 91 : : } 92 : : 93 : 480 : p += n; 94 : : } 95 : : 96 : 340 : r = bus_gvariant_get_alignment(signature); 97 [ - + ]: 340 : if (r < 0) 98 : 0 : return r; 99 : : 100 : 340 : return ALIGN_TO(sum, r); 101 : : } 102 : : 103 : 2248 : int bus_gvariant_get_alignment(const char *signature) { 104 : 2248 : size_t alignment = 1; 105 : : const char *p; 106 : : int r; 107 : : 108 : 2248 : p = signature; 109 [ + + + + ]: 5200 : while (*p != 0 && alignment < 8) { 110 : : size_t n; 111 : : int a; 112 : : 113 : 2956 : r = signature_element_length(p, &n); 114 [ + + ]: 2956 : if (r < 0) 115 : 4 : return r; 116 : : 117 [ + + + + : 2952 : switch (*p) { + + - ] 118 : : 119 : 764 : 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 : 764 : a = 1; 125 : 764 : break; 126 : : 127 : 36 : case SD_BUS_TYPE_INT16: 128 : : case SD_BUS_TYPE_UINT16: 129 : 36 : a = 2; 130 : 36 : break; 131 : : 132 : 1060 : case SD_BUS_TYPE_INT32: 133 : : case SD_BUS_TYPE_UINT32: 134 : : case SD_BUS_TYPE_UNIX_FD: 135 : 1060 : a = 4; 136 : 1060 : break; 137 : : 138 : 440 : case SD_BUS_TYPE_INT64: 139 : : case SD_BUS_TYPE_UINT64: 140 : : case SD_BUS_TYPE_DOUBLE: 141 : : case SD_BUS_TYPE_VARIANT: 142 : 440 : a = 8; 143 : 440 : break; 144 : : 145 : 84 : case SD_BUS_TYPE_ARRAY: { 146 : 84 : char t[n]; 147 : : 148 : 84 : memcpy(t, p + 1, n - 1); 149 : 84 : t[n - 1] = 0; 150 : : 151 : 84 : a = bus_gvariant_get_alignment(t); 152 : 84 : break; 153 : : } 154 : : 155 : 568 : case SD_BUS_TYPE_STRUCT_BEGIN: 156 : 568 : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 157 : 568 : char t[n-1]; 158 : : 159 : 568 : memcpy(t, p + 1, n - 2); 160 : 568 : t[n - 2] = 0; 161 : : 162 : 568 : a = bus_gvariant_get_alignment(t); 163 : 568 : break; 164 : : } 165 : : 166 : 0 : default: 167 : 0 : assert_not_reached("Unknown signature type"); 168 : : } 169 : : 170 [ - + ]: 2952 : if (a < 0) 171 : 0 : return a; 172 : : 173 [ + - - + ]: 2952 : assert(a > 0 && a <= 8); 174 [ + + ]: 2952 : if ((size_t) a > alignment) 175 : 1816 : alignment = (size_t) a; 176 : : 177 : 2952 : p += n; 178 : : } 179 : : 180 : 2244 : return alignment; 181 : : } 182 : : 183 : 504 : int bus_gvariant_is_fixed_size(const char *signature) { 184 : : const char *p; 185 : : int r; 186 : : 187 [ - + ]: 504 : assert(signature); 188 : : 189 : 504 : p = signature; 190 [ + + ]: 820 : while (*p != 0) { 191 : : size_t n; 192 : : 193 : 616 : r = signature_element_length(p, &n); 194 [ + + ]: 616 : if (r < 0) 195 : 300 : return r; 196 : : 197 [ + + + - ]: 612 : switch (*p) { 198 : : 199 : 256 : 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 : 256 : return 0; 205 : : 206 : 288 : 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 : 288 : break; 217 : : 218 : 68 : case SD_BUS_TYPE_STRUCT_BEGIN: 219 : 68 : case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { 220 : 68 : char t[n-1]; 221 : : 222 : 68 : memcpy(t, p + 1, n - 2); 223 : 68 : t[n - 2] = 0; 224 : : 225 : 68 : r = bus_gvariant_is_fixed_size(t); 226 [ + + ]: 68 : if (r <= 0) 227 : 40 : return r; 228 : 28 : break; 229 : : } 230 : : 231 : 0 : default: 232 : 0 : assert_not_reached("Unknown signature type"); 233 : : } 234 : : 235 : 316 : p += n; 236 : : } 237 : : 238 : 204 : return true; 239 : : } 240 : : 241 : 148 : size_t bus_gvariant_determine_word_size(size_t sz, size_t extra) { 242 [ + + ]: 148 : if (sz + extra <= 0xFF) 243 : 136 : return 1; 244 [ + - ]: 12 : else if (sz + extra*2 <= 0xFFFF) 245 : 12 : return 2; 246 [ # # ]: 0 : else if (sz + extra*4 <= 0xFFFFFFFF) 247 : 0 : return 4; 248 : : else 249 : 0 : return 8; 250 : : } 251 : : 252 : 140 : 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 [ - + ]: 140 : assert(p); 260 : : 261 [ + + ]: 140 : if (sz == 1) 262 : 136 : return *(uint8_t*) p; 263 : : 264 : 4 : memcpy(&x, p, sz); 265 : : 266 [ + - ]: 4 : if (sz == 2) 267 : 4 : 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 : 84 : 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 [ - + ]: 84 : assert(p); 284 [ + - - + ]: 84 : assert(sz == 8 || (value < (1ULL << (sz*8)))); 285 : : 286 [ + + ]: 84 : if (sz == 1) { 287 : 80 : *(uint8_t*) p = value; 288 : 80 : return; 289 [ + - ]: 4 : } else if (sz == 2) 290 : 4 : 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 : 4 : memcpy(p, &x, sz); 299 : : }