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
35struct _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
54static _prop_object_free_rv_t
55 _prop_string_free(prop_stack_t, prop_object_t *);
56static bool _prop_string_externalize(
57 struct _prop_object_externalize_context *,
58 void *);
59static _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
64static 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 */
76static _prop_object_free_rv_t
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
88static bool
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 */
107static _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)
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
125static prop_string_t
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 */
146prop_string_t
147prop_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 */
157prop_string_t
158prop_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 */
184prop_string_t
185prop_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 */
203prop_string_t
204prop_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 */
234prop_string_t
235prop_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 */
261size_t
262prop_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 */
275bool
276prop_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 */
290char *
291prop_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 */
310const char *
311prop_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 */
325bool
326prop_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 */
358bool
359prop_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 */
390bool
391prop_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 */
404bool
405prop_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 */
420bool
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