1 /* $NetBSD: prop_string.c,v 1.12 2014/03/26 18:12:46 christos Exp $ */
2
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
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.
18 *
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.
30 */
31
32 #include <prop/prop_string.h>
33 #include "prop_object_impl.h"
34
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;
45 };
46
47 #define PS_F_NOCOPY 0x01
48
49 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng")
50
51 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string",
52 "property string container object")
53
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 *);
63
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,
69 };
70
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 : "")
74
75 /* ARGSUSED */
76 static _prop_object_free_rv_t
_prop_string_free(prop_stack_t stack,prop_object_t * obj)77 _prop_string_free(prop_stack_t stack, prop_object_t *obj)
78 {
79 prop_string_t ps = *obj;
80
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);
84
85 return (_PROP_OBJECT_FREE_DONE);
86 }
87
88 static bool
_prop_string_externalize(struct _prop_object_externalize_context * ctx,void * v)89 _prop_string_externalize(struct _prop_object_externalize_context *ctx,
90 void *v)
91 {
92 prop_string_t ps = v;
93
94 if (ps->ps_size == 0)
95 return (_prop_object_externalize_empty_tag(ctx, "string"));
96
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);
102
103 return (true);
104 }
105
106 /* ARGSUSED */
107 static _prop_object_equals_rv_t
_prop_string_equals(prop_object_t v1,prop_object_t v2,void ** stored_pointer1,void ** stored_pointer2,prop_object_t * next_obj1,prop_object_t * next_obj2)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)
111 {
112 prop_string_t str1 = v1;
113 prop_string_t str2 = v2;
114
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);
123 }
124
125 static prop_string_t
_prop_string_alloc(void)126 _prop_string_alloc(void)
127 {
128 prop_string_t ps;
129
130 ps = _PROP_POOL_GET(_prop_string_pool);
131 if (ps != NULL) {
132 _prop_object_init(&ps->ps_obj, &_prop_object_type_string);
133
134 ps->ps_mutable = NULL;
135 ps->ps_size = 0;
136 ps->ps_flags = 0;
137 }
138
139 return (ps);
140 }
141
142 /*
143 * prop_string_create --
144 * Create an empty mutable string.
145 */
146 prop_string_t
prop_string_create(void)147 prop_string_create(void)
148 {
149
150 return (_prop_string_alloc());
151 }
152
153 /*
154 * prop_string_create_cstring --
155 * Create a string that contains a copy of the provided C string.
156 */
157 prop_string_t
prop_string_create_cstring(const char * str)158 prop_string_create_cstring(const char *str)
159 {
160 prop_string_t ps;
161 char *cp;
162 size_t len;
163
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);
171 }
172 strcpy(cp, str);
173 ps->ps_mutable = cp;
174 ps->ps_size = len;
175 }
176 return (ps);
177 }
178
179 /*
180 * prop_string_create_cstring_nocopy --
181 * Create an immutable string that contains a refrence to the
182 * provided C string.
183 */
184 prop_string_t
prop_string_create_cstring_nocopy(const char * str)185 prop_string_create_cstring_nocopy(const char *str)
186 {
187 prop_string_t ps;
188
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;
194 }
195 return (ps);
196 }
197
198 /*
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.
202 */
203 prop_string_t
prop_string_copy(prop_string_t ops)204 prop_string_copy(prop_string_t ops)
205 {
206 prop_string_t ps;
207
208 if (! prop_object_is_string(ops))
209 return (NULL);
210
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);
222 }
223 strcpy(cp, prop_string_contents(ops));
224 ps->ps_mutable = cp;
225 }
226 }
227 return (ps);
228 }
229
230 /*
231 * prop_string_copy_mutable --
232 * Copy a string, always returning a mutable copy.
233 */
234 prop_string_t
prop_string_copy_mutable(prop_string_t ops)235 prop_string_copy_mutable(prop_string_t ops)
236 {
237 prop_string_t ps;
238 char *cp;
239
240 if (! prop_object_is_string(ops))
241 return (NULL);
242
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);
250 }
251 strcpy(cp, prop_string_contents(ops));
252 ps->ps_mutable = cp;
253 }
254 return (ps);
255 }
256
257 /*
258 * prop_string_size --
259 * Return the size of the string, not including the terminating NUL.
260 */
261 size_t
prop_string_size(prop_string_t ps)262 prop_string_size(prop_string_t ps)
263 {
264
265 if (! prop_object_is_string(ps))
266 return (0);
267
268 return (ps->ps_size);
269 }
270
271 /*
272 * prop_string_mutable --
273 * Return true if the string is a mutable string.
274 */
275 bool
prop_string_mutable(prop_string_t ps)276 prop_string_mutable(prop_string_t ps)
277 {
278
279 if (! prop_object_is_string(ps))
280 return (false);
281
282 return ((ps->ps_flags & PS_F_NOCOPY) == 0);
283 }
284
285 /*
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.
289 */
290 char *
prop_string_cstring(prop_string_t ps)291 prop_string_cstring(prop_string_t ps)
292 {
293 char *cp;
294
295 if (! prop_object_is_string(ps))
296 return (NULL);
297
298 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP);
299 if (cp != NULL)
300 strcpy(cp, prop_string_contents(ps));
301
302 return (cp);
303 }
304
305 /*
306 * prop_string_cstring_nocopy --
307 * Return an immutable reference to the contents of the string
308 * as a C string.
309 */
310 const char *
prop_string_cstring_nocopy(prop_string_t ps)311 prop_string_cstring_nocopy(prop_string_t ps)
312 {
313
314 if (! prop_object_is_string(ps))
315 return (NULL);
316
317 return (prop_string_contents(ps));
318 }
319
320 /*
321 * prop_string_append --
322 * Append the contents of one string to another. Returns true
323 * upon success. The destination string must be mutable.
324 */
325 bool
prop_string_append(prop_string_t dst,prop_string_t src)326 prop_string_append(prop_string_t dst, prop_string_t src)
327 {
328 char *ocp, *cp;
329 size_t len;
330
331 if (! (prop_object_is_string(dst) &&
332 prop_object_is_string(src)))
333 return (false);
334
335 if (dst->ps_flags & PS_F_NOCOPY)
336 return (false);
337
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 snprintf(cp, len + 1, "%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);
349
350 return (true);
351 }
352
353 /*
354 * prop_string_append_cstring --
355 * Append a C string to a string. Returns true upon success.
356 * The destination string must be mutable.
357 */
358 bool
prop_string_append_cstring(prop_string_t dst,const char * src)359 prop_string_append_cstring(prop_string_t dst, const char *src)
360 {
361 char *ocp, *cp;
362 size_t len;
363
364 if (! prop_object_is_string(dst))
365 return (false);
366
367 _PROP_ASSERT(src != NULL);
368
369 if (dst->ps_flags & PS_F_NOCOPY)
370 return (false);
371
372 len = dst->ps_size + strlen(src);
373 cp = _PROP_MALLOC(len + 1, M_PROP_STRING);
374 if (cp == NULL)
375 return (false);
376 snprintf(cp, len + 1, "%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);
382
383 return (true);
384 }
385
386 /*
387 * prop_string_equals --
388 * Return true if two strings are equivalent.
389 */
390 bool
prop_string_equals(prop_string_t str1,prop_string_t str2)391 prop_string_equals(prop_string_t str1, prop_string_t str2)
392 {
393 if (!prop_object_is_string(str1) || !prop_object_is_string(str2))
394 return (false);
395
396 return prop_object_equals(str1, str2);
397 }
398
399 /*
400 * prop_string_equals_cstring --
401 * Return true if the string is equivalent to the specified
402 * C string.
403 */
404 bool
prop_string_equals_cstring(prop_string_t ps,const char * cp)405 prop_string_equals_cstring(prop_string_t ps, const char *cp)
406 {
407
408 if (! prop_object_is_string(ps))
409 return (false);
410
411 return (strcmp(prop_string_contents(ps), cp) == 0);
412 }
413
414 /*
415 * _prop_string_internalize --
416 * Parse a <string>...</string> and return the object created from the
417 * external representation.
418 */
419 /* ARGSUSED */
420 bool
_prop_string_internalize(prop_stack_t stack,prop_object_t * obj,struct _prop_object_internalize_context * ctx)421 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj,
422 struct _prop_object_internalize_context *ctx)
423 {
424 prop_string_t string;
425 char *str;
426 size_t len, alen;
427
428 if (ctx->poic_is_empty_element) {
429 *obj = prop_string_create();
430 return (true);
431 }
432
433 /* No attributes recognized here. */
434 if (ctx->poic_tagattr != NULL)
435 return (true);
436
437 /* Compute the length of the result. */
438 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len,
439 NULL) == false)
440 return (true);
441
442 str = _PROP_MALLOC(len + 1, M_PROP_STRING);
443 if (str == NULL)
444 return (true);
445
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);
451 }
452 str[len] = '\0';
453
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);
458 }
459
460 string = _prop_string_alloc();
461 if (string == NULL) {
462 _PROP_FREE(str, M_PROP_STRING);
463 return (true);
464 }
465
466 string->ps_mutable = str;
467 string->ps_size = len;
468 *obj = string;
469
470 return (true);
471 }
472