1 /* $NetBSD: prop_string.c,v 1.4 2006/08/22 21:21:23 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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <prop/prop_string.h> 40 #include "prop_object_impl.h" 41 42 struct _prop_string { 43 struct _prop_object ps_obj; 44 union { 45 char * psu_mutable; 46 const char * psu_immutable; 47 } ps_un; 48 #define ps_mutable ps_un.psu_mutable 49 #define ps_immutable ps_un.psu_immutable 50 size_t ps_size; /* not including \0 */ 51 int ps_flags; 52 }; 53 54 #define PS_F_NOCOPY 0x01 55 56 _PROP_POOL_INIT(_prop_string_pool, sizeof(struct _prop_string), "propstng") 57 58 _PROP_MALLOC_DEFINE(M_PROP_STRING, "prop string", 59 "property string container object") 60 61 static void _prop_string_free(void *); 62 static boolean_t _prop_string_externalize( 63 struct _prop_object_externalize_context *, 64 void *); 65 static boolean_t _prop_string_equals(void *, void *); 66 67 static const struct _prop_object_type _prop_object_type_string = { 68 .pot_type = PROP_TYPE_STRING, 69 .pot_free = _prop_string_free, 70 .pot_extern = _prop_string_externalize, 71 .pot_equals = _prop_string_equals, 72 }; 73 74 #define prop_object_is_string(x) \ 75 ((x) != NULL && (x)->ps_obj.po_type == &_prop_object_type_string) 76 #define prop_string_contents(x) ((x)->ps_immutable ? (x)->ps_immutable : "") 77 78 static void 79 _prop_string_free(void *v) 80 { 81 prop_string_t ps = v; 82 83 if ((ps->ps_flags & PS_F_NOCOPY) == 0 && ps->ps_mutable != NULL) 84 _PROP_FREE(ps->ps_mutable, M_PROP_STRING); 85 _PROP_POOL_PUT(_prop_string_pool, v); 86 } 87 88 static boolean_t 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 static boolean_t 107 _prop_string_equals(void *v1, void *v2) 108 { 109 prop_string_t str1 = v1; 110 prop_string_t str2 = v2; 111 112 if (! (prop_object_is_string(str1) && 113 prop_object_is_string(str2))) 114 return (FALSE); 115 116 if (str1 == str2) 117 return (TRUE); 118 if (str1->ps_size != str2->ps_size) 119 return (FALSE); 120 return (strcmp(prop_string_contents(str1), 121 prop_string_contents(str2)) == 0); 122 } 123 124 static prop_string_t 125 _prop_string_alloc(void) 126 { 127 prop_string_t ps; 128 129 ps = _PROP_POOL_GET(_prop_string_pool); 130 if (ps != NULL) { 131 _prop_object_init(&ps->ps_obj, &_prop_object_type_string); 132 133 ps->ps_mutable = NULL; 134 ps->ps_size = 0; 135 ps->ps_flags = 0; 136 } 137 138 return (ps); 139 } 140 141 /* 142 * prop_string_create -- 143 * Create an empty mutable string. 144 */ 145 prop_string_t 146 prop_string_create(void) 147 { 148 149 return (_prop_string_alloc()); 150 } 151 152 /* 153 * prop_string_create_cstring -- 154 * Create a string that contains a copy of the provided C string. 155 */ 156 prop_string_t 157 prop_string_create_cstring(const char *str) 158 { 159 prop_string_t ps; 160 char *cp; 161 size_t len; 162 163 ps = _prop_string_alloc(); 164 if (ps != NULL) { 165 len = strlen(str); 166 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 167 if (cp == NULL) { 168 _prop_string_free(ps); 169 return (NULL); 170 } 171 strcpy(cp, str); 172 ps->ps_mutable = cp; 173 ps->ps_size = len; 174 } 175 return (ps); 176 } 177 178 /* 179 * prop_string_create_cstring_nocopy -- 180 * Create an immutable string that contains a refrence to the 181 * provided C string. 182 */ 183 prop_string_t 184 prop_string_create_cstring_nocopy(const char *str) 185 { 186 prop_string_t ps; 187 188 ps = _prop_string_alloc(); 189 if (ps != NULL) { 190 ps->ps_immutable = str; 191 ps->ps_size = strlen(str); 192 ps->ps_flags |= PS_F_NOCOPY; 193 } 194 return (ps); 195 } 196 197 /* 198 * prop_string_copy -- 199 * Copy a string. If the original string is immutable, then the 200 * copy is also immutable and references the same external data. 201 */ 202 prop_string_t 203 prop_string_copy(prop_string_t ops) 204 { 205 prop_string_t ps; 206 207 if (! prop_object_is_string(ops)) 208 return (NULL); 209 210 ps = _prop_string_alloc(); 211 if (ps != NULL) { 212 ps->ps_size = ops->ps_size; 213 ps->ps_flags = ops->ps_flags; 214 if (ops->ps_flags & PS_F_NOCOPY) 215 ps->ps_immutable = ops->ps_immutable; 216 else { 217 char *cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 218 if (cp == NULL) { 219 _prop_string_free(ps); 220 return (NULL); 221 } 222 strcpy(cp, prop_string_contents(ops)); 223 ps->ps_mutable = cp; 224 } 225 } 226 return (ps); 227 } 228 229 /* 230 * prop_string_copy_mutable -- 231 * Copy a string, always returning a mutable copy. 232 */ 233 prop_string_t 234 prop_string_copy_mutable(prop_string_t ops) 235 { 236 prop_string_t ps; 237 char *cp; 238 239 if (! prop_object_is_string(ops)) 240 return (NULL); 241 242 ps = _prop_string_alloc(); 243 if (ps != NULL) { 244 ps->ps_size = ops->ps_size; 245 cp = _PROP_MALLOC(ps->ps_size + 1, M_PROP_STRING); 246 if (cp == NULL) { 247 _prop_string_free(ps); 248 return (NULL); 249 } 250 strcpy(cp, prop_string_contents(ops)); 251 ps->ps_mutable = cp; 252 } 253 return (ps); 254 } 255 256 /* 257 * prop_string_size -- 258 * Return the size of the string, not including the terminating NUL. 259 */ 260 size_t 261 prop_string_size(prop_string_t ps) 262 { 263 264 if (! prop_object_is_string(ps)) 265 return (0); 266 267 return (ps->ps_size); 268 } 269 270 /* 271 * prop_string_mutable -- 272 * Return TRUE if the string is a mutable string. 273 */ 274 boolean_t 275 prop_string_mutable(prop_string_t ps) 276 { 277 278 if (! prop_object_is_string(ps)) 279 return (FALSE); 280 281 return ((ps->ps_flags & PS_F_NOCOPY) == 0); 282 } 283 284 /* 285 * prop_string_cstring -- 286 * Return a copy of the contents of the string as a C string. 287 * The string is allocated with the M_TEMP malloc type. 288 */ 289 char * 290 prop_string_cstring(prop_string_t ps) 291 { 292 char *cp; 293 294 if (! prop_object_is_string(ps)) 295 return (NULL); 296 297 cp = _PROP_MALLOC(ps->ps_size + 1, M_TEMP); 298 if (cp != NULL) 299 strcpy(cp, prop_string_contents(ps)); 300 301 return (cp); 302 } 303 304 /* 305 * prop_string_cstring_nocopy -- 306 * Return an immutable reference to the contents of the string 307 * as a C string. 308 */ 309 const char * 310 prop_string_cstring_nocopy(prop_string_t ps) 311 { 312 313 if (! prop_object_is_string(ps)) 314 return (NULL); 315 316 return (prop_string_contents(ps)); 317 } 318 319 /* 320 * prop_string_append -- 321 * Append the contents of one string to another. Returns TRUE 322 * upon success. The destination string must be mutable. 323 */ 324 boolean_t 325 prop_string_append(prop_string_t dst, prop_string_t src) 326 { 327 char *ocp, *cp; 328 size_t len; 329 330 if (! (prop_object_is_string(dst) && 331 prop_object_is_string(src))) 332 return (FALSE); 333 334 if (dst->ps_flags & PS_F_NOCOPY) 335 return (FALSE); 336 337 len = dst->ps_size + src->ps_size; 338 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 339 if (cp == NULL) 340 return (FALSE); 341 sprintf(cp, "%s%s", prop_string_contents(dst), 342 prop_string_contents(src)); 343 ocp = dst->ps_mutable; 344 dst->ps_mutable = cp; 345 dst->ps_size = len; 346 if (ocp != NULL) 347 _PROP_FREE(ocp, M_PROP_STRING); 348 349 return (TRUE); 350 } 351 352 /* 353 * prop_string_append_cstring -- 354 * Append a C string to a string. Returns TRUE upon success. 355 * The destination string must be mutable. 356 */ 357 boolean_t 358 prop_string_append_cstring(prop_string_t dst, const char *src) 359 { 360 char *ocp, *cp; 361 size_t len; 362 363 if (! prop_object_is_string(dst)) 364 return (FALSE); 365 366 _PROP_ASSERT(src != NULL); 367 368 if (dst->ps_flags & PS_F_NOCOPY) 369 return (FALSE); 370 371 len = dst->ps_size + strlen(src); 372 cp = _PROP_MALLOC(len + 1, M_PROP_STRING); 373 if (cp == NULL) 374 return (FALSE); 375 sprintf(cp, "%s%s", prop_string_contents(dst), src); 376 ocp = dst->ps_mutable; 377 dst->ps_mutable = cp; 378 dst->ps_size = len; 379 if (ocp != NULL) 380 _PROP_FREE(ocp, M_PROP_STRING); 381 382 return (TRUE); 383 } 384 385 /* 386 * prop_string_equals -- 387 * Return TRUE if two strings are equivalent. 388 */ 389 boolean_t 390 prop_string_equals(prop_string_t str1, prop_string_t str2) 391 { 392 393 return (_prop_string_equals(str1, str2)); 394 } 395 396 /* 397 * prop_string_equals_cstring -- 398 * Return TRUE if the string is equivalent to the specified 399 * C string. 400 */ 401 boolean_t 402 prop_string_equals_cstring(prop_string_t ps, const char *cp) 403 { 404 405 if (! prop_object_is_string(ps)) 406 return (FALSE); 407 408 return (strcmp(prop_string_contents(ps), cp) == 0); 409 } 410 411 /* 412 * _prop_string_internalize -- 413 * Parse a <string>...</string> and return the object created from the 414 * external representation. 415 */ 416 prop_object_t 417 _prop_string_internalize(struct _prop_object_internalize_context *ctx) 418 { 419 prop_string_t string; 420 char *str; 421 size_t len, alen; 422 423 if (ctx->poic_is_empty_element) 424 return (prop_string_create()); 425 426 /* No attributes recognized here. */ 427 if (ctx->poic_tagattr != NULL) 428 return (NULL); 429 430 /* Compute the length of the result. */ 431 if (_prop_object_internalize_decode_string(ctx, NULL, 0, &len, 432 NULL) == FALSE) 433 return (NULL); 434 435 str = _PROP_MALLOC(len + 1, M_PROP_STRING); 436 if (str == NULL) 437 return (NULL); 438 439 if (_prop_object_internalize_decode_string(ctx, str, len, &alen, 440 &ctx->poic_cp) == FALSE || 441 alen != len) { 442 _PROP_FREE(str, M_PROP_STRING); 443 return (NULL); 444 } 445 str[len] = '\0'; 446 447 if (_prop_object_internalize_find_tag(ctx, "string", 448 _PROP_TAG_TYPE_END) == FALSE) { 449 _PROP_FREE(str, M_PROP_STRING); 450 return (NULL); 451 } 452 453 string = _prop_string_alloc(); 454 if (string == NULL) { 455 _PROP_FREE(str, M_PROP_STRING); 456 return (NULL); 457 } 458 459 string->ps_mutable = str; 460 string->ps_size = len; 461 462 return (string); 463 } 464