vm: fix potential null deref
[minix.git] / common / lib / libprop / prop_string.c
blob4f9ed88603c075fccb6e74077d0a65402b084811
1 /* $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 thorpej Exp $ */
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <prop/prop_string.h>
33 #include "prop_object_impl.h"
35 struct _prop_string {
36 struct _prop_object ps_obj;
37 union {
38 char * psu_mutable;
39 const char * psu_immutable;
40 } ps_un;
41 #define ps_mutable ps_un.psu_mutable
42 #define ps_immutable ps_un.psu_immutable
43 size_t ps_size; /* not including \0 */
44 int ps_flags;
47 #define PS_F_NOCOPY 0x01
49 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
51 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
52 "property string container object")
54 static _prop_object_free_rv_t
55 _prop_string_free(prop_stack_t, prop_object_t *);
56 static bool _prop_string_externalize(
57 struct _prop_object_externalize_context *,
58 void *);
59 static _prop_object_equals_rv_t
60 _prop_string_equals(prop_object_t, prop_object_t,
61 void **, void **,
62 prop_object_t *, prop_object_t *);
64 static const struct _prop_object_type _prop_object_type_string = {
65 .pot_type = PROP_TYPE_STRING,
66 .pot_free = _prop_string_free,
67 .pot_extern = _prop_string_externalize,
68 .pot_equals = _prop_string_equals,
71 #define prop_object_is_string(x) \
72 ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string)
73 #define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "")
75 /* ARGSUSED */
76 static _prop_object_free_rv_t
77 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
79 prop_string_t ps = *obj;
81 if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL)
82 _PROP_FREE(ps->ps_mutable, M_PROP_STRING);
83 _PROP_POOL_PUT(_prop_string_pool, ps);
85 return (_PROP_OBJECT_FREE_DONE);
88 static bool
89 _prop_string_externalize(struct _prop_object_externalize_context *ctx,
90 void *v)
92 prop_string_t ps = v;
94 if (ps->ps_size == 0)
95 return (_prop_object_externalize_empty_tag(ctx, "string"));
97 if (_prop_object_externalize_start_tag(ctx, "string") == false ||
98 _prop_object_externalize_append_encoded_cstring(ctx,
99 ps->ps_immutable) == false ||
100 _prop_object_externalize_end_tag(ctx, "string") == false)
101 return (false);
103 return (true);
106 /* ARGSUSED */
107 static _prop_object_equals_rv_t
108 _prop_string_equals(prop_object_t v1, prop_object_t v2,
109 void **stored_pointer1, void **stored_pointer2,
110 prop_object_t *next_obj1, prop_object_t *next_obj2)
112 prop_string_t str1 = v1;
113 prop_string_t str2 = v2;
115 if (str1 == str2)
116 return (_PROP_OBJECT_EQUALS_TRUE);
117 if (str1->ps_size != str2->ps_size)
118 return (_PROP_OBJECT_EQUALS_FALSE);
119 if (strcmp(prop_string_contents(str1), prop_string_contents(str2)))
120 return (_PROP_OBJECT_EQUALS_FALSE);
121 else
122 return (_PROP_OBJECT_EQUALS_TRUE);
125 static prop_string_t
126 _prop_string_alloc(void)
128 prop_string_t ps;
130 ps = _PROP_POOL_GET(_prop_string_pool);
131 if (ps != NULL) {
132 _prop_object_init(&ps->ps_obj, &_prop_object_type_string);
134 ps->ps_mutable = NULL;
135 ps->ps_size = 0;
136 ps->ps_flags = 0;
139 return (ps);
143 * prop_string_create --
144 * Create an empty mutable string.
146 prop_string_t
147 prop_string_create(void)
150 return (_prop_string_alloc());
154 * prop_string_create_cstring --
155 * Create a string that contains a copy of the provided C string.
157 prop_string_t
158 prop_string_create_cstring(const char *str)
160 prop_string_t ps;
161 char *cp;
162 size_t len;
164 ps = _prop_string_alloc();
165 if (ps != NULL) {
166 len = strlen(str);
167 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
168 if (cp == NULL) {
169 prop_object_release(ps);
170 return (NULL);
172 strcpy(cp, str);
173 ps->ps_mutable = cp;
174 ps->ps_size = len;
176 return (ps);
180 * prop_string_create_cstring_nocopy --
181 * Create an immutable string that contains a refrence to the
182 * provided C string.
184 prop_string_t
185 prop_string_create_cstring_nocopy(const char *str)
187 prop_string_t ps;
189 ps = _prop_string_alloc();
190 if (ps != NULL) {
191 ps->ps_immutable = str;
192 ps->ps_size = strlen(str);
193 ps->ps_flags |= PS_F_NOCOPY;
195 return (ps);
199 * prop_string_copy --
200 * Copy a string. If the original string is immutable, then the
201 * copy is also immutable and references the same external data.
203 prop_string_t
204 prop_string_copy(prop_string_t ops)
206 prop_string_t ps;
208 if (! prop_object_is_string(ops))
209 return (NULL);
211 ps = _prop_string_alloc();
212 if (ps != NULL) {
213 ps->ps_size = ops->ps_size;
214 ps->ps_flags = ops->ps_flags;
215 if (ops->ps_flags & PS_F_NOCOPY)
216 ps->ps_immutable = ops->ps_immutable;
217 else {
218 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
219 if (cp == NULL) {
220 prop_object_release(ps);
221 return (NULL);
223 strcpy(cp, prop_string_contents(ops));
224 ps->ps_mutable = cp;
227 return (ps);
231 * prop_string_copy_mutable --
232 * Copy a string, always returning a mutable copy.
234 prop_string_t
235 prop_string_copy_mutable(prop_string_t ops)
237 prop_string_t ps;
238 char *cp;
240 if (! prop_object_is_string(ops))
241 return (NULL);
243 ps = _prop_string_alloc();
244 if (ps != NULL) {
245 ps->ps_size = ops->ps_size;
246 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING);
247 if (cp == NULL) {
248 prop_object_release(ps);
249 return (NULL);
251 strcpy(cp, prop_string_contents(ops));
252 ps->ps_mutable = cp;
254 return (ps);
258 * prop_string_size --
259 * Return the size of the string, not including the terminating NUL.
261 size_t
262 prop_string_size(prop_string_t ps)
265 if (! prop_object_is_string(ps))
266 return (0);
268 return (ps->ps_size);
272 * prop_string_mutable --
273 * Return true if the string is a mutable string.
275 bool
276 prop_string_mutable(prop_string_t ps)
279 if (! prop_object_is_string(ps))
280 return (false);
282 return ((ps->ps_flags & PS_F_NOCOPY) == 0);
286 * prop_string_cstring --
287 * Return a copy of the contents of the string as a C string.
288 * The string is allocated with the M_TEMP malloc type.
290 char *
291 prop_string_cstring(prop_string_t ps)
293 char *cp;
295 if (! prop_object_is_string(ps))
296 return (NULL);
298 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
299 if (cp != NULL)
300 strcpy(cp, prop_string_contents(ps));
302 return (cp);
306 * prop_string_cstring_nocopy --
307 * Return an immutable reference to the contents of the string
308 * as a C string.
310 const char *
311 prop_string_cstring_nocopy(prop_string_t ps)
314 if (! prop_object_is_string(ps))
315 return (NULL);
317 return (prop_string_contents(ps));
321 * prop_string_append --
322 * Append the contents of one string to another. Returns true
323 * upon success. The destination string must be mutable.
325 bool
326 prop_string_append(prop_string_t dst, prop_string_t src)
328 char *ocp, *cp;
329 size_t len;
331 if (! (prop_object_is_string(dst) &&
332 prop_object_is_string(src)))
333 return (false);
335 if (dst->ps_flags & PS_F_NOCOPY)
336 return (false);
338 len = dst->ps_size + src->ps_size;
339 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
340 if (cp == NULL)
341 return (false);
342 sprintf(cp, "%s%s", prop_string_contents(dst),
343 prop_string_contents(src));
344 ocp = dst->ps_mutable;
345 dst->ps_mutable = cp;
346 dst->ps_size = len;
347 if (ocp != NULL)
348 _PROP_FREE(ocp, M_PROP_STRING);
350 return (true);
354 * prop_string_append_cstring --
355 * Append a C string to a string. Returns true upon success.
356 * The destination string must be mutable.
358 bool
359 prop_string_append_cstring(prop_string_t dst, const char *src)
361 char *ocp, *cp;
362 size_t len;
364 if (! prop_object_is_string(dst))
365 return (false);
367 _PROP_ASSERT(src != NULL);
369 if (dst->ps_flags & PS_F_NOCOPY)
370 return (false);
372 len = dst->ps_size + strlen(src);
373 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
374 if (cp == NULL)
375 return (false);
376 sprintf(cp, "%s%s", prop_string_contents(dst), src);
377 ocp = dst->ps_mutable;
378 dst->ps_mutable = cp;
379 dst->ps_size = len;
380 if (ocp != NULL)
381 _PROP_FREE(ocp, M_PROP_STRING);
383 return (true);
387 * prop_string_equals --
388 * Return true if two strings are equivalent.
390 bool
391 prop_string_equals(prop_string_t str1, prop_string_t str2)
393 if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
394 return (false);
396 return prop_object_equals(str1, str2);
400 * prop_string_equals_cstring --
401 * Return true if the string is equivalent to the specified
402 * C string.
404 bool
405 prop_string_equals_cstring(prop_string_t ps, const char *cp)
408 if (! prop_object_is_string(ps))
409 return (false);
411 return (strcmp(prop_string_contents(ps), cp) == 0);
415 * _prop_string_internalize --
416 * Parse a <string>...</string> and return the object created from the
417 * external representation.
419 /* ARGSUSED */
420 bool
421 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
422 struct _prop_object_internalize_context *ctx)
424 prop_string_t string;
425 char *str;
426 size_t len, alen;
428 if (ctx->poic_is_empty_element) {
429 *obj = prop_string_create();
430 return (true);
433 /* No attributes recognized here. */
434 if (ctx->poic_tagattr != NULL)
435 return (true);
437 /* Compute the length of the result. */
438 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
439 NULL) == false)
440 return (true);
442 str = _PROP_MALLOC(len + 1, M_PROP_STRING);
443 if (str == NULL)
444 return (true);
446 if (_prop_object_internalize_decode_string(ctx, str, len, &alen,
447 &ctx->poic_cp) == false ||
448 alen != len) {
449 _PROP_FREE(str, M_PROP_STRING);
450 return (true);
452 str[len] = '\0';
454 if (_prop_object_internalize_find_tag(ctx, "string",
455 _PROP_TAG_TYPE_END) == false) {
456 _PROP_FREE(str, M_PROP_STRING);
457 return (true);
460 string = _prop_string_alloc();
461 if (string == NULL) {
462 _PROP_FREE(str, M_PROP_STRING);
463 return (true);
466 string->ps_mutable = str;
467 string->ps_size = len;
468 *obj = string;
470 return (true);