1 /* $NetBSD: prop_string.c,v 1.11 2008/08/03 04:00:12 thorpej 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 <libprop/prop_string.h> 33 #include "prop_object_impl.h" 34 35 #if defined(_KERNEL) 36 #define sprintf ksprintf 37 #endif 38 39 struct _prop_string { 40 struct _prop_object ps_obj; 41 union { 42 char * psu_mutable; 43 const char * psu_immutable; 44 } ps_un; 45 #define ps_mutable ps_un.psu_mutable 46 #define ps_immutable ps_un.psu_immutable 47 size_t ps_size; /* not including \0 */ 48 int ps_flags; 49 }; 50 51 #define PS_F_NOCOPY 0x01 52 53 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng"); 54 55 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string", 56 "property string container object") 57 58 static _prop_object_free_rv_t 59 _prop_string_free(prop_stack_t, prop_object_t *); 60 static bool _prop_string_externalize( 61 struct _prop_object_externalize_context *, 62 void *); 63 static _prop_object_equals_rv_t 64 _prop_string_equals(prop_object_t, prop_object_t, 65 void **, void **, 66 prop_object_t *, prop_object_t *); 67 68 static const struct _prop_object_type _prop_object_type_string = { 69 .pot_type = PROP_TYPE_STRING, 70 .pot_free = _prop_string_free, 71 .pot_extern = _prop_string_externalize, 72 .pot_equals = _prop_string_equals, 73 }; 74 75 #define prop_object_is_string(x) \ 76 ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string) 77 #define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "") 78 79 /* ARGSUSED */ 80 static _prop_object_free_rv_t 81 _prop_string_free(prop_stack_t stack, prop_object_t *obj) 82 { 83 prop_string_t ps = *obj; 84 85 if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL) 86 _PROP_FREE(ps->ps_mutable, M_PROP_STRING); 87 _PROP_POOL_PUT(_prop_string_pool, ps); 88 89 return (_PROP_OBJECT_FREE_DONE); 90 } 91 92 static bool 93 _prop_string_externalize(struct _prop_object_externalize_context *ctx, 94 void *v) 95 { 96 prop_string_t ps = v; 97 98 if (ps->ps_size == 0) 99 return (_prop_object_externalize_empty_tag(ctx, "string")); 100 101 if (_prop_object_externalize_start_tag(ctx, "string") == false || 102 _prop_object_externalize_append_encoded_cstring(ctx, 103 ps->ps_immutable) == false || 104 _prop_object_externalize_end_tag(ctx, "string") == false) 105 return (false); 106 107 return (true); 108 } 109 110 /* ARGSUSED */ 111 static _prop_object_equals_rv_t 112 _prop_string_equals(prop_object_t v1, prop_object_t v2, 113 void **stored_pointer1, void **stored_pointer2, 114 prop_object_t *next_obj1, prop_object_t *next_obj2) 115 { 116 prop_string_t str1 = v1; 117 prop_string_t str2 = v2; 118 119 if (str1 == str2) 120 return (_PROP_OBJECT_EQUALS_TRUE); 121 if (str1->ps_size != str2->ps_size) 122 return (_PROP_OBJECT_EQUALS_FALSE); 123 if (strcmp(prop_string_contents(str1), prop_string_contents(str2))) 124 return (_PROP_OBJECT_EQUALS_FALSE); 125 else 126 return (_PROP_OBJECT_EQUALS_TRUE); 127 } 128 129 static prop_string_t 130 _prop_string_alloc(void) 131 { 132 prop_string_t ps; 133 134 ps = _PROP_POOL_GET(_prop_string_pool); 135 if (ps != NULL) { 136 _prop_object_init(&ps->ps_obj, &_prop_object_type_string); 137 138 ps->ps_mutable = NULL; 139 ps->ps_size = 0; 140 ps->ps_flags = 0; 141 } 142 143 return (ps); 144 } 145 146 /* 147 * prop_string_create -- 148 * Create an empty mutable string. 149 */ 150 prop_string_t 151 prop_string_create(void) 152 { 153 154 return (_prop_string_alloc()); 155 } 156 157 /* 158 * prop_string_create_cstring -- 159 * Create a string that contains a copy of the provided C string. 160 */ 161 prop_string_t 162 prop_string_create_cstring(const char *str) 163 { 164 prop_string_t ps; 165 char *cp; 166 size_t len; 167 168 ps = _prop_string_alloc(); 169 if (ps != NULL) { 170 len = strlen(str); 171 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 172 if (cp == NULL) { 173 prop_object_release(ps); 174 return (NULL); 175 } 176 strcpy(cp, str); 177 ps->ps_mutable = cp; 178 ps->ps_size = len; 179 } 180 return (ps); 181 } 182 183 /* 184 * prop_string_create_cstring_nocopy -- 185 * Create an immutable string that contains a refrence to the 186 * provided C string. 187 */ 188 prop_string_t 189 prop_string_create_cstring_nocopy(const char *str) 190 { 191 prop_string_t ps; 192 193 ps = _prop_string_alloc(); 194 if (ps != NULL) { 195 ps->ps_immutable = str; 196 ps->ps_size = strlen(str); 197 ps->ps_flags |= PS_F_NOCOPY; 198 } 199 return (ps); 200 } 201 202 /* 203 * prop_string_copy -- 204 * Copy a string. If the original string is immutable, then the 205 * copy is also immutable and references the same external data. 206 */ 207 prop_string_t 208 prop_string_copy(prop_string_t ops) 209 { 210 prop_string_t ps; 211 212 if (! prop_object_is_string(ops)) 213 return (NULL); 214 215 ps = _prop_string_alloc(); 216 if (ps != NULL) { 217 ps->ps_size = ops->ps_size; 218 ps->ps_flags = ops->ps_flags; 219 if (ops->ps_flags & PS_F_NOCOPY) 220 ps->ps_immutable = ops->ps_immutable; 221 else { 222 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 223 if (cp == NULL) { 224 prop_object_release(ps); 225 return (NULL); 226 } 227 strcpy(cp, prop_string_contents(ops)); 228 ps->ps_mutable = cp; 229 } 230 } 231 return (ps); 232 } 233 234 /* 235 * prop_string_copy_mutable -- 236 * Copy a string, always returning a mutable copy. 237 */ 238 prop_string_t 239 prop_string_copy_mutable(prop_string_t ops) 240 { 241 prop_string_t ps; 242 char *cp; 243 244 if (! prop_object_is_string(ops)) 245 return (NULL); 246 247 ps = _prop_string_alloc(); 248 if (ps != NULL) { 249 ps->ps_size = ops->ps_size; 250 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 251 if (cp == NULL) { 252 prop_object_release(ps); 253 return (NULL); 254 } 255 strcpy(cp, prop_string_contents(ops)); 256 ps->ps_mutable = cp; 257 } 258 return (ps); 259 } 260 261 /* 262 * prop_string_size -- 263 * Return the size of the string, not including the terminating NUL. 264 */ 265 size_t 266 prop_string_size(prop_string_t ps) 267 { 268 269 if (! prop_object_is_string(ps)) 270 return (0); 271 272 return (ps->ps_size); 273 } 274 275 /* 276 * prop_string_mutable -- 277 * Return true if the string is a mutable string. 278 */ 279 bool 280 prop_string_mutable(prop_string_t ps) 281 { 282 283 if (! prop_object_is_string(ps)) 284 return (false); 285 286 return ((ps->ps_flags & PS_F_NOCOPY) == 0); 287 } 288 289 /* 290 * prop_string_cstring -- 291 * Return a copy of the contents of the string as a C string. 292 * The string is allocated with the M_TEMP malloc type. 293 */ 294 char * 295 prop_string_cstring(prop_string_t ps) 296 { 297 char *cp; 298 299 if (! prop_object_is_string(ps)) 300 return (NULL); 301 302 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP); 303 if (cp != NULL) 304 strcpy(cp, prop_string_contents(ps)); 305 306 return (cp); 307 } 308 309 /* 310 * prop_string_cstring_nocopy -- 311 * Return an immutable reference to the contents of the string 312 * as a C string. 313 */ 314 const char * 315 prop_string_cstring_nocopy(prop_string_t ps) 316 { 317 318 if (! prop_object_is_string(ps)) 319 return (NULL); 320 321 return (prop_string_contents(ps)); 322 } 323 324 /* 325 * prop_string_append -- 326 * Append the contents of one string to another. Returns true 327 * upon success. The destination string must be mutable. 328 */ 329 bool 330 prop_string_append(prop_string_t dst, prop_string_t src) 331 { 332 char *ocp, *cp; 333 size_t len; 334 335 if (! (prop_object_is_string(dst) && 336 prop_object_is_string(src))) 337 return (false); 338 339 if (dst->ps_flags & PS_F_NOCOPY) 340 return (false); 341 342 len = dst->ps_size + src->ps_size; 343 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 344 if (cp == NULL) 345 return (false); 346 sprintf(cp, "%s%s", prop_string_contents(dst), 347 prop_string_contents(src)); 348 ocp = dst->ps_mutable; 349 dst->ps_mutable = cp; 350 dst->ps_size = len; 351 if (ocp != NULL) 352 _PROP_FREE(ocp, M_PROP_STRING); 353 354 return (true); 355 } 356 357 /* 358 * prop_string_append_cstring -- 359 * Append a C string to a string. Returns true upon success. 360 * The destination string must be mutable. 361 */ 362 bool 363 prop_string_append_cstring(prop_string_t dst, const char *src) 364 { 365 char *ocp, *cp; 366 size_t len; 367 368 if (! prop_object_is_string(dst)) 369 return (false); 370 371 _PROP_ASSERT(src != NULL); 372 373 if (dst->ps_flags & PS_F_NOCOPY) 374 return (false); 375 376 len = dst->ps_size + strlen(src); 377 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 378 if (cp == NULL) 379 return (false); 380 sprintf(cp, "%s%s", prop_string_contents(dst), src); 381 ocp = dst->ps_mutable; 382 dst->ps_mutable = cp; 383 dst->ps_size = len; 384 if (ocp != NULL) 385 _PROP_FREE(ocp, M_PROP_STRING); 386 387 return (true); 388 } 389 390 /* 391 * prop_string_equals -- 392 * Return true if two strings are equivalent. 393 */ 394 bool 395 prop_string_equals(prop_string_t str1, prop_string_t str2) 396 { 397 if (!prop_object_is_string(str1) || !prop_object_is_string(str2)) 398 return (false); 399 400 return prop_object_equals(str1, str2); 401 } 402 403 /* 404 * prop_string_equals_cstring -- 405 * Return true if the string is equivalent to the specified 406 * C string. 407 */ 408 bool 409 prop_string_equals_cstring(prop_string_t ps, const char *cp) 410 { 411 412 if (! prop_object_is_string(ps)) 413 return (false); 414 415 return (strcmp(prop_string_contents(ps), cp) == 0); 416 } 417 418 /* 419 * _prop_string_internalize -- 420 * Parse a <string>...</string> and return the object created from the 421 * external representation. 422 */ 423 /* ARGSUSED */ 424 bool 425 _prop_string_internalize(prop_stack_t stack, prop_object_t *obj, 426 struct _prop_object_internalize_context *ctx) 427 { 428 prop_string_t string; 429 char *str; 430 size_t len, alen; 431 432 if (ctx->poic_is_empty_element) { 433 *obj = prop_string_create(); 434 return (true); 435 } 436 437 /* No attributes recognized here. */ 438 if (ctx->poic_tagattr != NULL) 439 return (true); 440 441 /* Compute the length of the result. */ 442 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len, 443 NULL) == false) 444 return (true); 445 446 str = _PROP_MALLOC(len + 1, M_PROP_STRING); 447 if (str == NULL) 448 return (true); 449 450 if (_prop_object_internalize_decode_string(ctx, str, len, &alen, 451 &ctx->poic_cp) == false || 452 alen != len) { 453 _PROP_FREE(str, M_PROP_STRING); 454 return (true); 455 } 456 str[len] = '\0'; 457 458 if (_prop_object_internalize_find_tag(ctx, "string", 459 _PROP_TAG_TYPE_END) == false) { 460 _PROP_FREE(str, M_PROP_STRING); 461 return (true); 462 } 463 464 string = _prop_string_alloc(); 465 if (string == NULL) { 466 _PROP_FREE(str, M_PROP_STRING); 467 return (true); 468 } 469 470 string->ps_mutable = str; 471 string->ps_size = len; 472 *obj = string; 473 474 return (true); 475 } 476