/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ /*** This file is part of systemd. Copyright 2013 Lennart Poettering systemd is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. systemd is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with systemd; If not, see . ***/ #include "util.h" #include "bus-type.h" #include "bus-gvariant.h" #include "bus-signature.h" int bus_gvariant_get_size(const char *signature) { const char *p; int sum = 0, r; /* For fixed size structs. Fails for variable size structs. */ p = signature; while (*p != 0) { size_t n; r = signature_element_length(p, &n); if (r < 0) return r; else { char t[n+1]; memcpy(t, p, n); t[n] = 0; r = bus_gvariant_get_alignment(t); if (r < 0) return r; sum = ALIGN_TO(sum, r); } switch (*p) { case SD_BUS_TYPE_BOOLEAN: case SD_BUS_TYPE_BYTE: sum += 1; break; case SD_BUS_TYPE_INT16: case SD_BUS_TYPE_UINT16: sum += 2; break; case SD_BUS_TYPE_INT32: case SD_BUS_TYPE_UINT32: case SD_BUS_TYPE_UNIX_FD: sum += 4; break; case SD_BUS_TYPE_INT64: case SD_BUS_TYPE_UINT64: case SD_BUS_TYPE_DOUBLE: sum += 8; break; case SD_BUS_TYPE_STRUCT_BEGIN: case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { char t[n-1]; memcpy(t, p + 1, n - 2); t[n - 2] = 0; r = bus_gvariant_get_size(t); if (r < 0) return r; sum += r; break; } case SD_BUS_TYPE_STRING: case SD_BUS_TYPE_OBJECT_PATH: case SD_BUS_TYPE_SIGNATURE: case SD_BUS_TYPE_ARRAY: case SD_BUS_TYPE_VARIANT: return -EINVAL; default: assert_not_reached("Unknown signature type"); } p += n; } r = bus_gvariant_get_alignment(signature); if (r < 0) return r; return ALIGN_TO(sum, r); } int bus_gvariant_get_alignment(const char *signature) { size_t alignment = 1; const char *p; int r; p = signature; while (*p != 0 && alignment < 8) { size_t n; int a; r = signature_element_length(p, &n); if (r < 0) return r; switch (*p) { case SD_BUS_TYPE_BYTE: case SD_BUS_TYPE_BOOLEAN: case SD_BUS_TYPE_STRING: case SD_BUS_TYPE_OBJECT_PATH: case SD_BUS_TYPE_SIGNATURE: a = 1; break; case SD_BUS_TYPE_INT16: case SD_BUS_TYPE_UINT16: a = 2; break; case SD_BUS_TYPE_INT32: case SD_BUS_TYPE_UINT32: case SD_BUS_TYPE_UNIX_FD: a = 4; break; case SD_BUS_TYPE_INT64: case SD_BUS_TYPE_UINT64: case SD_BUS_TYPE_DOUBLE: case SD_BUS_TYPE_VARIANT: a = 8; break; case SD_BUS_TYPE_ARRAY: { char t[n]; memcpy(t, p + 1, n - 1); t[n - 1] = 0; a = bus_gvariant_get_alignment(t); break; } case SD_BUS_TYPE_STRUCT_BEGIN: case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { char t[n-1]; memcpy(t, p + 1, n - 2); t[n - 2] = 0; a = bus_gvariant_get_alignment(t); break; } default: assert_not_reached("Unknown signature type"); } if (a < 0) return a; assert(a > 0 && a <= 8); if ((size_t) a > alignment) alignment = (size_t) a; p += n; } return alignment; } int bus_gvariant_is_fixed_size(const char *signature) { const char *p; int r; assert(signature); p = signature; while (*p != 0) { size_t n; r = signature_element_length(p, &n); if (r < 0) return r; switch (*p) { case SD_BUS_TYPE_STRING: case SD_BUS_TYPE_OBJECT_PATH: case SD_BUS_TYPE_SIGNATURE: case SD_BUS_TYPE_ARRAY: case SD_BUS_TYPE_VARIANT: return 0; case SD_BUS_TYPE_BYTE: case SD_BUS_TYPE_BOOLEAN: case SD_BUS_TYPE_INT16: case SD_BUS_TYPE_UINT16: case SD_BUS_TYPE_INT32: case SD_BUS_TYPE_UINT32: case SD_BUS_TYPE_UNIX_FD: case SD_BUS_TYPE_INT64: case SD_BUS_TYPE_UINT64: case SD_BUS_TYPE_DOUBLE: break; case SD_BUS_TYPE_STRUCT_BEGIN: case SD_BUS_TYPE_DICT_ENTRY_BEGIN: { char t[n-1]; memcpy(t, p + 1, n - 2); t[n - 2] = 0; r = bus_gvariant_is_fixed_size(t); if (r <= 0) return r; break; } default: assert_not_reached("Unknown signature type"); } p += n; } return true; }