chiark / gitweb /
bus: add missing LE meta data enforcement for gvariant serializer
[elogind.git] / src / libsystemd-bus / bus-gvariant.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "util.h"
23 #include "bus-type.h"
24 #include "bus-gvariant.h"
25 #include "bus-signature.h"
26
27 int bus_gvariant_get_size(char c) {
28
29         switch (c) {
30
31         case SD_BUS_TYPE_BOOLEAN:
32         case SD_BUS_TYPE_BYTE:
33                 return 1;
34
35         case SD_BUS_TYPE_INT16:
36         case SD_BUS_TYPE_UINT16:
37                 return 2;
38
39         case SD_BUS_TYPE_INT32:
40         case SD_BUS_TYPE_UINT32:
41         case SD_BUS_TYPE_UNIX_FD:
42                 return 4;
43
44         case SD_BUS_TYPE_INT64:
45         case SD_BUS_TYPE_UINT64:
46         case SD_BUS_TYPE_DOUBLE:
47                 return 8;
48         }
49
50         return -EINVAL;
51 }
52
53 int bus_gvariant_get_alignment(const char *signature) {
54         size_t alignment = 1;
55         const char *p;
56         int r;
57
58         p = signature;
59         while (*p != 0 && alignment < 8) {
60                 size_t n;
61                 int a;
62
63                 r = signature_element_length(p, &n);
64                 if (r < 0)
65                         return r;
66
67                 switch (*p) {
68
69                 case SD_BUS_TYPE_BYTE:
70                 case SD_BUS_TYPE_BOOLEAN:
71                 case SD_BUS_TYPE_STRING:
72                 case SD_BUS_TYPE_OBJECT_PATH:
73                 case SD_BUS_TYPE_SIGNATURE:
74                         a = 1;
75                         break;
76
77                 case SD_BUS_TYPE_INT16:
78                 case SD_BUS_TYPE_UINT16:
79                         a = 2;
80                         break;
81
82                 case SD_BUS_TYPE_INT32:
83                 case SD_BUS_TYPE_UINT32:
84                 case SD_BUS_TYPE_UNIX_FD:
85                         a = 4;
86                         break;
87
88                 case SD_BUS_TYPE_INT64:
89                 case SD_BUS_TYPE_UINT64:
90                 case SD_BUS_TYPE_DOUBLE:
91                 case SD_BUS_TYPE_VARIANT:
92                         a = 8;
93                         break;
94
95                 case SD_BUS_TYPE_ARRAY: {
96                         char t[n];
97
98                         memcpy(t, p + 1, n - 1);
99                         t[n - 1] = 0;
100
101                         a = bus_gvariant_get_alignment(t);
102                         break;
103                 }
104
105                 case SD_BUS_TYPE_STRUCT_BEGIN:
106                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
107                         char t[n-1];
108
109                         memcpy(t, p + 1, n - 2);
110                         t[n - 2] = 0;
111
112                         a = bus_gvariant_get_alignment(t);
113                         break;
114                 }
115
116                 default:
117                         assert_not_reached("Unknown signature type");
118                 }
119
120                 if (a < 0)
121                         return a;
122
123                 assert(a > 0 && a <= 8);
124                 if ((size_t) a > alignment)
125                         alignment = (size_t) a;
126
127                 p += n;
128         }
129
130         return alignment;
131 }
132
133 int bus_gvariant_is_fixed_size(const char *signature) {
134         const char *p;
135         int r;
136
137         assert(signature);
138
139         p = signature;
140         while (*p != 0) {
141                 size_t n;
142
143                 r = signature_element_length(p, &n);
144                 if (r < 0)
145                         return r;
146
147                 switch (*p) {
148
149                 case SD_BUS_TYPE_STRING:
150                 case SD_BUS_TYPE_OBJECT_PATH:
151                 case SD_BUS_TYPE_SIGNATURE:
152                 case SD_BUS_TYPE_ARRAY:
153                 case SD_BUS_TYPE_VARIANT:
154                         return 0;
155
156                 case SD_BUS_TYPE_BYTE:
157                 case SD_BUS_TYPE_BOOLEAN:
158                 case SD_BUS_TYPE_INT16:
159                 case SD_BUS_TYPE_UINT16:
160                 case SD_BUS_TYPE_INT32:
161                 case SD_BUS_TYPE_UINT32:
162                 case SD_BUS_TYPE_UNIX_FD:
163                 case SD_BUS_TYPE_INT64:
164                 case SD_BUS_TYPE_UINT64:
165                 case SD_BUS_TYPE_DOUBLE:
166                         break;
167
168                 case SD_BUS_TYPE_STRUCT_BEGIN:
169                 case SD_BUS_TYPE_DICT_ENTRY_BEGIN: {
170                         char t[n-1];
171
172                         memcpy(t, p + 1, n - 2);
173                         t[n - 2] = 0;
174
175                         r = bus_gvariant_is_fixed_size(t);
176                         if (r <= 0)
177                                 return r;
178                         break;
179                 }
180
181                 default:
182                         assert_not_reached("Unknown signature type");
183                 }
184
185                 p += n;
186         }
187
188         return true;
189 }