Initial import package dbus-python: D-Bus Python Bindings
[external/dbus-python.git] / _dbus_bindings / validation.c
1 /* Implementation of various validation functions for use in dbus-python.
2  *
3  * Copyright (C) 2006 Collabora Ltd. <http://www.collabora.co.uk/>
4  *
5  * Permission is hereby granted, free of charge, to any person
6  * obtaining a copy of this software and associated documentation
7  * files (the "Software"), to deal in the Software without
8  * restriction, including without limitation the rights to use, copy,
9  * modify, merge, publish, distribute, sublicense, and/or sell copies
10  * of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25
26 #include "dbus_bindings-internal.h"
27
28 dbus_bool_t
29 dbus_py_validate_bus_name(const char *name,
30                           dbus_bool_t may_be_unique,
31                           dbus_bool_t may_be_not_unique)
32 {
33     dbus_bool_t dot = FALSE;
34     dbus_bool_t unique;
35     char last;
36     const char *ptr;
37
38     if (name[0] == '\0') {
39         PyErr_SetString(PyExc_ValueError, "Invalid bus name: "
40                         "may not be empty");
41         return FALSE;
42     }
43     unique = (name[0] == ':');
44     if (unique && !may_be_unique) {
45         PyErr_Format(PyExc_ValueError, "Invalid well-known bus name '%s':"
46                      "only unique names may start with ':'", name);
47         return FALSE;
48     }
49     if (!unique && !may_be_not_unique) {
50         PyErr_Format(PyExc_ValueError, "Invalid unique bus name '%s': "
51                      "unique names must start with ':'", name);
52         return FALSE;
53     }
54     if (strlen(name) > 255) {
55         PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
56                      "too long (> 255 characters)", name);
57         return FALSE;
58     }
59     last = '\0';
60     for (ptr = name + (unique ? 1 : 0); *ptr; ptr++) {
61         if (*ptr == '.') {
62             dot = TRUE;
63             if (last == '.') {
64                 PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
65                              "contains substring '..'", name);
66                 return FALSE;
67             }
68             else if (last == '\0') {
69                 PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
70                              "must not start with '.'", name);
71                 return FALSE;
72             }
73         }
74         else if (*ptr >= '0' && *ptr <= '9') {
75             if (!unique) {
76                 if (last == '.') {
77                     PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
78                                  "a digit may not follow '.' except in a "
79                                  "unique name starting with ':'", name);
80                     return FALSE;
81                 }
82                 else if (last == '\0') {
83                     PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
84                              "must not start with a digit", name);
85                     return FALSE;
86                 }
87             }
88         }
89         else if ((*ptr < 'a' || *ptr > 'z') &&
90                  (*ptr < 'A' || *ptr > 'Z') && *ptr != '_' && *ptr != '-') {
91             PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': "
92                          "contains invalid character '%c'", name, *ptr);
93             return FALSE;
94         }
95         last = *ptr;
96     }
97     if (last == '.') {
98         PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': must "
99                         "not end with '.'", name);
100         return FALSE;
101     }
102     if (!dot) {
103         PyErr_Format(PyExc_ValueError, "Invalid bus name '%s': must "
104                         "contain '.'", name);
105         return FALSE;
106     }
107     return TRUE;
108 }
109
110 dbus_bool_t
111 dbus_py_validate_member_name(const char *name)
112 {
113     const char *ptr;
114
115     if (name[0] == '\0') {
116         PyErr_SetString(PyExc_ValueError, "Invalid member name: may not "
117                         "be empty");
118         return FALSE;
119     }
120     if (strlen(name) > 255) {
121         PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
122                      "too long (> 255 characters)", name);
123         return FALSE;
124     }
125     for (ptr = name; *ptr; ptr++) {
126         if (*ptr >= '0' && *ptr <= '9') {
127             if (ptr == name) {
128                 PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
129                              "must not start with a digit", name);
130                 return FALSE;
131             }
132         }
133         else if ((*ptr < 'a' || *ptr > 'z') &&
134                  (*ptr < 'A' || *ptr > 'Z') && *ptr != '_') {
135             PyErr_Format(PyExc_ValueError, "Invalid member name '%s': "
136                          "contains invalid character '%c'", name, *ptr);
137             return FALSE;
138         }
139     }
140     return TRUE;
141 }
142
143 dbus_bool_t
144 dbus_py_validate_interface_name(const char *name)
145 {
146     dbus_bool_t dot = FALSE;
147     char last;
148     const char *ptr;
149
150     if (name[0] == '\0') {
151         PyErr_SetString(PyExc_ValueError, "Invalid interface or error name: "
152                         "may not be empty");
153         return FALSE;
154     }
155     if (strlen(name) > 255) {
156         PyErr_Format(PyExc_ValueError, "Invalid interface or error name '%s': "
157                      "too long (> 255 characters)", name);
158         return FALSE;
159     }
160     last = '\0';
161     for (ptr = name; *ptr; ptr++) {
162         if (*ptr == '.') {
163             dot = TRUE;
164             if (last == '.') {
165                 PyErr_Format(PyExc_ValueError, "Invalid interface or "
166                              "error name '%s': contains substring '..'", name);
167                 return FALSE;
168             }
169             else if (last == '\0') {
170                 PyErr_Format(PyExc_ValueError, "Invalid interface or error "
171                              "name '%s': must not start with '.'", name);
172                 return FALSE;
173             }
174         }
175         else if (*ptr >= '0' && *ptr <= '9') {
176             if (last == '.') {
177                 PyErr_Format(PyExc_ValueError, "Invalid interface or error "
178                              "name '%s': a digit may not follow '.'", name);
179                 return FALSE;
180             }
181             else if (last == '\0') {
182                 PyErr_Format(PyExc_ValueError, "Invalid interface or error "
183                              "name '%s': must not start with a digit", name);
184                 return FALSE;
185             }
186         }
187         else if ((*ptr < 'a' || *ptr > 'z') &&
188                  (*ptr < 'A' || *ptr > 'Z') && *ptr != '_') {
189             PyErr_Format(PyExc_ValueError, "Invalid interface or error "
190                          "name '%s': contains invalid character '%c'",
191                          name, *ptr);
192             return FALSE;
193         }
194         last = *ptr;
195     }
196     if (last == '.') {
197         PyErr_Format(PyExc_ValueError, "Invalid interface or error name "
198                      "'%s': must not end with '.'", name);
199         return FALSE;
200     }
201     if (!dot) {
202         PyErr_Format(PyExc_ValueError, "Invalid interface or error name "
203                      "'%s': must contain '.'", name);
204         return FALSE;
205     }
206     return TRUE;
207 }
208
209
210 dbus_bool_t
211 dbus_py_validate_object_path(const char *path)
212 {
213     const char *ptr;
214
215     if (path[0] != '/') {
216         PyErr_Format(PyExc_ValueError, "Invalid object path '%s': does not "
217                      "start with '/'", path);
218         return FALSE;
219     }
220     if (path[1] == '\0') return TRUE;
221     for (ptr = path + 1; *ptr; ptr++) {
222         if (*ptr == '/') {
223             if (ptr[-1] == '/') {
224                 PyErr_Format(PyExc_ValueError, "Invalid object path '%s': "
225                              "contains substring '//'", path);
226                 return FALSE;
227             }
228         }
229         else if ((*ptr < 'a' || *ptr > 'z') &&
230                  (*ptr < 'A' || *ptr > 'Z') &&
231                  (*ptr < '0' || *ptr > '9') && *ptr != '_') {
232             PyErr_Format(PyExc_ValueError, "Invalid object path '%s': "
233                          "contains invalid character '%c'", path, *ptr);
234             return FALSE;
235         }
236     }
237     if (ptr[-1] == '/') {
238         PyErr_Format(PyExc_ValueError, "Invalid object path '%s': ends "
239                      "with '/' and is not just '/'", path);
240         return FALSE;
241     }
242     return TRUE;
243 }
244
245 /* vim:set ft=c cino< sw=4 sts=4 et: */