chiark / gitweb /
bus: suppress creating empty parts in messages
[elogind.git] / src / libsystemd-bus / bus-signature.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
24 #include "bus-signature.h"
25 #include "bus-type.h"
26
27 static int signature_element_length_internal(
28                 const char *s,
29                 bool allow_dict_entry,
30                 unsigned array_depth,
31                 unsigned struct_depth,
32                 size_t *l) {
33
34         int r;
35
36         if (!s)
37                 return -EINVAL;
38
39         assert(l);
40
41         if (bus_type_is_basic(*s) || *s == SD_BUS_TYPE_VARIANT) {
42                 *l = 1;
43                 return 0;
44         }
45
46         if (*s == SD_BUS_TYPE_ARRAY) {
47                 size_t t;
48
49                 if (array_depth >= 32)
50                         return -EINVAL;
51
52                 r = signature_element_length_internal(s + 1, true, array_depth+1, struct_depth, &t);
53                 if (r < 0)
54                         return r;
55
56                 *l = t + 1;
57                 return 0;
58         }
59
60         if (*s == SD_BUS_TYPE_STRUCT_BEGIN) {
61                 const char *p = s + 1;
62
63                 if (struct_depth >= 32)
64                         return -EINVAL;
65
66                 while (*p != SD_BUS_TYPE_STRUCT_END) {
67                         size_t t;
68
69                         r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
70                         if (r < 0)
71                                 return r;
72
73                         p += t;
74                 }
75
76                 *l = p - s + 1;
77                 return 0;
78         }
79
80         if (*s == SD_BUS_TYPE_DICT_ENTRY_BEGIN && allow_dict_entry) {
81                 const char *p = s + 1;
82                 unsigned n = 0;
83
84                 if (struct_depth >= 32)
85                         return -EINVAL;
86
87                 while (*p != SD_BUS_TYPE_DICT_ENTRY_END) {
88                         size_t t;
89
90                         if (n == 0 && !bus_type_is_basic(*p))
91                                 return -EINVAL;
92
93                         r = signature_element_length_internal(p, false, array_depth, struct_depth+1, &t);
94                         if (r < 0)
95                                 return r;
96
97                         p += t;
98                         n++;
99                 }
100
101                 if (n != 2)
102                         return -EINVAL;
103
104                 *l = p - s + 1;
105                 return 0;
106         }
107
108         return -EINVAL;
109 }
110
111
112 int signature_element_length(const char *s, size_t *l) {
113         return signature_element_length_internal(s, true, 0, 0, l);
114 }
115
116 bool signature_is_single(const char *s, bool allow_dict_entry) {
117         int r;
118         size_t t;
119
120         if (!s)
121                 return false;
122
123         r = signature_element_length_internal(s, allow_dict_entry, 0, 0, &t);
124         if (r < 0)
125                 return false;
126
127         return s[t] == 0;
128 }
129
130 bool signature_is_pair(const char *s) {
131
132         if (!s)
133                 return false;
134
135         if (!bus_type_is_basic(*s))
136                 return false;
137
138         return signature_is_single(s + 1, false);
139 }
140
141 bool signature_is_valid(const char *s, bool allow_dict_entry) {
142         const char *p;
143         int r;
144
145         if (!s)
146                 return false;
147
148         p = s;
149         while (*p) {
150                 size_t t;
151
152                 r = signature_element_length_internal(p, allow_dict_entry, 0, 0, &t);
153                 if (r < 0)
154                         return false;
155
156                 p += t;
157         }
158
159         return p - s <= 255;
160 }