1 /* $NetBSD: prop_array.c,v 1.7 2006/10/03 15:45:04 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_array.h> 40 #include "prop_object_impl.h" 41 42 #if !defined(_KERNEL) && !defined(_STANDALONE) 43 #include <errno.h> 44 #endif 45 46 struct _prop_array { 47 struct _prop_object pa_obj; 48 _PROP_RWLOCK_DECL(pa_rwlock) 49 prop_object_t * pa_array; 50 unsigned int pa_capacity; 51 unsigned int pa_count; 52 int pa_flags; 53 54 uint32_t pa_version; 55 }; 56 57 #define PA_F_IMMUTABLE 0x01 /* array is immutable */ 58 59 _PROP_POOL_INIT(_prop_array_pool, sizeof(struct _prop_array), "proparay") 60 _PROP_MALLOC_DEFINE(M_PROP_ARRAY, "prop array", 61 "property array container object") 62 63 static void _prop_array_free(void *); 64 static boolean_t _prop_array_externalize( 65 struct _prop_object_externalize_context *, 66 void *); 67 static boolean_t _prop_array_equals(void *, void *); 68 69 static const struct _prop_object_type _prop_object_type_array = { 70 .pot_type = PROP_TYPE_ARRAY, 71 .pot_free = _prop_array_free, 72 .pot_extern = _prop_array_externalize, 73 .pot_equals = _prop_array_equals, 74 }; 75 76 #define prop_object_is_array(x) \ 77 ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array) 78 79 #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0) 80 81 struct _prop_array_iterator { 82 struct _prop_object_iterator pai_base; 83 unsigned int pai_index; 84 }; 85 86 #define EXPAND_STEP 16 87 88 static void 89 _prop_array_free(void *v) 90 { 91 prop_array_t pa = v; 92 prop_object_t po; 93 unsigned int idx; 94 95 _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 96 _PROP_ASSERT((pa->pa_capacity == 0 && pa->pa_array == NULL) || 97 (pa->pa_capacity != 0 && pa->pa_array != NULL)); 98 99 for (idx = 0; idx < pa->pa_count; idx++) { 100 po = pa->pa_array[idx]; 101 _PROP_ASSERT(po != NULL); 102 prop_object_release(po); 103 } 104 105 if (pa->pa_array != NULL) 106 _PROP_FREE(pa->pa_array, M_PROP_ARRAY); 107 108 _PROP_RWLOCK_DESTROY(pa->pa_rwlock); 109 110 _PROP_POOL_PUT(_prop_array_pool, pa); 111 } 112 113 static boolean_t 114 _prop_array_externalize(struct _prop_object_externalize_context *ctx, 115 void *v) 116 { 117 prop_array_t pa = v; 118 struct _prop_object *po; 119 prop_object_iterator_t pi; 120 unsigned int i; 121 boolean_t rv = FALSE; 122 123 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 124 125 if (pa->pa_count == 0) { 126 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 127 return (_prop_object_externalize_empty_tag(ctx, "array")); 128 } 129 130 /* XXXJRT Hint "count" for the internalize step? */ 131 if (_prop_object_externalize_start_tag(ctx, "array") == FALSE || 132 _prop_object_externalize_append_char(ctx, '\n') == FALSE) 133 goto out; 134 135 pi = prop_array_iterator(pa); 136 if (pi == NULL) 137 goto out; 138 139 ctx->poec_depth++; 140 _PROP_ASSERT(ctx->poec_depth != 0); 141 142 while ((po = prop_object_iterator_next(pi)) != NULL) { 143 if ((*po->po_type->pot_extern)(ctx, po) == FALSE) { 144 prop_object_iterator_release(pi); 145 goto out; 146 } 147 } 148 149 prop_object_iterator_release(pi); 150 151 ctx->poec_depth--; 152 for (i = 0; i < ctx->poec_depth; i++) { 153 if (_prop_object_externalize_append_char(ctx, '\t') == FALSE) 154 goto out; 155 } 156 if (_prop_object_externalize_end_tag(ctx, "array") == FALSE) 157 goto out; 158 159 rv = TRUE; 160 161 out: 162 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 163 return (rv); 164 } 165 166 static boolean_t 167 _prop_array_equals(void *v1, void *v2) 168 { 169 prop_array_t array1 = v1; 170 prop_array_t array2 = v2; 171 unsigned int idx; 172 boolean_t rv = FALSE; 173 174 if (! (prop_object_is_array(array1) && 175 prop_object_is_array(array2))) 176 return (FALSE); 177 178 if (array1 == array2) 179 return (TRUE); 180 181 if ((uintptr_t)array1 < (uintptr_t)array2) { 182 _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 183 _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 184 } else { 185 _PROP_RWLOCK_RDLOCK(array2->pa_rwlock); 186 _PROP_RWLOCK_RDLOCK(array1->pa_rwlock); 187 } 188 189 if (array1->pa_count != array2->pa_count) 190 goto out; 191 192 for (idx = 0; idx < array1->pa_count; idx++) { 193 if (prop_object_equals(array1->pa_array[idx], 194 array2->pa_array[idx]) == FALSE) 195 goto out; 196 } 197 198 rv = TRUE; 199 200 out: 201 _PROP_RWLOCK_UNLOCK(array1->pa_rwlock); 202 _PROP_RWLOCK_UNLOCK(array2->pa_rwlock); 203 return (rv); 204 } 205 206 static prop_array_t 207 _prop_array_alloc(unsigned int capacity) 208 { 209 prop_array_t pa; 210 prop_object_t *array; 211 212 if (capacity != 0) { 213 array = _PROP_CALLOC(capacity * sizeof(prop_object_t), 214 M_PROP_ARRAY); 215 if (array == NULL) 216 return (NULL); 217 } else 218 array = NULL; 219 220 221 pa = _PROP_POOL_GET(_prop_array_pool); 222 if (pa != NULL) { 223 _prop_object_init(&pa->pa_obj, &_prop_object_type_array); 224 pa->pa_obj.po_type = &_prop_object_type_array; 225 226 _PROP_RWLOCK_INIT(pa->pa_rwlock); 227 pa->pa_array = array; 228 pa->pa_capacity = capacity; 229 pa->pa_count = 0; 230 pa->pa_flags = 0; 231 232 pa->pa_version = 0; 233 } else if (array != NULL) 234 _PROP_FREE(array, M_PROP_ARRAY); 235 236 return (pa); 237 } 238 239 static boolean_t 240 _prop_array_expand(prop_array_t pa, unsigned int capacity) 241 { 242 prop_object_t *array, *oarray; 243 244 /* 245 * Array must be WRITE-LOCKED. 246 */ 247 248 oarray = pa->pa_array; 249 250 array = _PROP_CALLOC(capacity * sizeof(*array), M_PROP_ARRAY); 251 if (array == NULL) 252 return (FALSE); 253 if (oarray != NULL) 254 memcpy(array, oarray, pa->pa_capacity * sizeof(*array)); 255 pa->pa_array = array; 256 pa->pa_capacity = capacity; 257 258 if (oarray != NULL) 259 _PROP_FREE(oarray, M_PROP_ARRAY); 260 261 return (TRUE); 262 } 263 264 static prop_object_t 265 _prop_array_iterator_next_object(void *v) 266 { 267 struct _prop_array_iterator *pai = v; 268 prop_array_t pa = pai->pai_base.pi_obj; 269 prop_object_t po = NULL; 270 271 _PROP_ASSERT(prop_object_is_array(pa)); 272 273 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 274 275 if (pa->pa_version != pai->pai_base.pi_version) 276 goto out; /* array changed during iteration */ 277 278 _PROP_ASSERT(pai->pai_index <= pa->pa_count); 279 280 if (pai->pai_index == pa->pa_count) 281 goto out; /* we've iterated all objects */ 282 283 po = pa->pa_array[pai->pai_index]; 284 pai->pai_index++; 285 286 out: 287 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 288 return (po); 289 } 290 291 static void 292 _prop_array_iterator_reset(void *v) 293 { 294 struct _prop_array_iterator *pai = v; 295 prop_array_t pa = pai->pai_base.pi_obj; 296 297 _PROP_ASSERT(prop_object_is_array(pa)); 298 299 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 300 301 pai->pai_index = 0; 302 pai->pai_base.pi_version = pa->pa_version; 303 304 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 305 } 306 307 /* 308 * prop_array_create -- 309 * Create an empty array. 310 */ 311 prop_array_t 312 prop_array_create(void) 313 { 314 315 return (_prop_array_alloc(0)); 316 } 317 318 /* 319 * prop_array_create_with_capacity -- 320 * Create an array with the capacity to store N objects. 321 */ 322 prop_array_t 323 prop_array_create_with_capacity(unsigned int capacity) 324 { 325 326 return (_prop_array_alloc(capacity)); 327 } 328 329 /* 330 * prop_array_copy -- 331 * Copy an array. The new array has an initial capacity equal to 332 * the number of objects stored in the original array. The new 333 * array contains references to the original array's objects, not 334 * copies of those objects (i.e. a shallow copy). 335 */ 336 prop_array_t 337 prop_array_copy(prop_array_t opa) 338 { 339 prop_array_t pa; 340 prop_object_t po; 341 unsigned int idx; 342 343 if (! prop_object_is_array(opa)) 344 return (NULL); 345 346 _PROP_RWLOCK_RDLOCK(opa->pa_rwlock); 347 348 pa = _prop_array_alloc(opa->pa_count); 349 if (pa != NULL) { 350 for (idx = 0; idx < opa->pa_count; idx++) { 351 po = opa->pa_array[idx]; 352 prop_object_retain(po); 353 pa->pa_array[idx] = po; 354 } 355 pa->pa_count = opa->pa_count; 356 pa->pa_flags = opa->pa_flags; 357 } 358 _PROP_RWLOCK_UNLOCK(opa->pa_rwlock); 359 return (pa); 360 } 361 362 /* 363 * prop_array_copy_mutable -- 364 * Like prop_array_copy(), but the resulting array is mutable. 365 */ 366 prop_array_t 367 prop_array_copy_mutable(prop_array_t opa) 368 { 369 prop_array_t pa; 370 371 pa = prop_array_copy(opa); 372 if (pa != NULL) 373 pa->pa_flags &= ~PA_F_IMMUTABLE; 374 375 return (pa); 376 } 377 378 /* 379 * prop_array_capacity -- 380 * Return the capacity of the array. 381 */ 382 unsigned int 383 prop_array_capacity(prop_array_t pa) 384 { 385 unsigned int rv; 386 387 if (! prop_object_is_array(pa)) 388 return (0); 389 390 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 391 rv = pa->pa_capacity; 392 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 393 394 return (rv); 395 } 396 397 /* 398 * prop_array_count -- 399 * Return the number of objects stored in the array. 400 */ 401 unsigned int 402 prop_array_count(prop_array_t pa) 403 { 404 unsigned int rv; 405 406 if (! prop_object_is_array(pa)) 407 return (0); 408 409 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 410 rv = pa->pa_count; 411 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 412 413 return (rv); 414 } 415 416 /* 417 * prop_array_ensure_capacity -- 418 * Ensure that the array has the capacity to store the specified 419 * total number of objects (inluding the objects already stored 420 * in the array). 421 */ 422 boolean_t 423 prop_array_ensure_capacity(prop_array_t pa, unsigned int capacity) 424 { 425 boolean_t rv; 426 427 if (! prop_object_is_array(pa)) 428 return (FALSE); 429 430 _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 431 if (capacity > pa->pa_capacity) 432 rv = _prop_array_expand(pa, capacity); 433 else 434 rv = TRUE; 435 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 436 437 return (rv); 438 } 439 440 /* 441 * prop_array_iterator -- 442 * Return an iterator for the array. The array is retained by 443 * the iterator. 444 */ 445 prop_object_iterator_t 446 prop_array_iterator(prop_array_t pa) 447 { 448 struct _prop_array_iterator *pai; 449 450 if (! prop_object_is_array(pa)) 451 return (NULL); 452 453 pai = _PROP_CALLOC(sizeof(*pai), M_TEMP); 454 if (pai == NULL) 455 return (NULL); 456 pai->pai_base.pi_next_object = _prop_array_iterator_next_object; 457 pai->pai_base.pi_reset = _prop_array_iterator_reset; 458 prop_object_retain(pa); 459 pai->pai_base.pi_obj = pa; 460 _prop_array_iterator_reset(pai); 461 462 return (&pai->pai_base); 463 } 464 465 /* 466 * prop_array_make_immutable -- 467 * Make the array immutable. 468 */ 469 void 470 prop_array_make_immutable(prop_array_t pa) 471 { 472 473 _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 474 if (prop_array_is_immutable(pa) == FALSE) 475 pa->pa_flags |= PA_F_IMMUTABLE; 476 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 477 } 478 479 /* 480 * prop_array_mutable -- 481 * Returns TRUE if the array is mutable. 482 */ 483 boolean_t 484 prop_array_mutable(prop_array_t pa) 485 { 486 boolean_t rv; 487 488 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 489 rv = prop_array_is_immutable(pa) == FALSE; 490 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 491 492 return (rv); 493 } 494 495 /* 496 * prop_array_get -- 497 * Return the object stored at the specified array index. 498 */ 499 prop_object_t 500 prop_array_get(prop_array_t pa, unsigned int idx) 501 { 502 prop_object_t po = NULL; 503 504 if (! prop_object_is_array(pa)) 505 return (NULL); 506 507 _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); 508 if (idx >= pa->pa_count) 509 goto out; 510 po = pa->pa_array[idx]; 511 _PROP_ASSERT(po != NULL); 512 out: 513 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 514 return (po); 515 } 516 517 static boolean_t 518 _prop_array_add(prop_array_t pa, prop_object_t po) 519 { 520 521 /* 522 * Array must be WRITE-LOCKED. 523 */ 524 525 _PROP_ASSERT(pa->pa_count <= pa->pa_capacity); 526 527 if (prop_array_is_immutable(pa) || 528 (pa->pa_count == pa->pa_capacity && 529 _prop_array_expand(pa, pa->pa_capacity + EXPAND_STEP) == FALSE)) 530 return (FALSE); 531 532 prop_object_retain(po); 533 pa->pa_array[pa->pa_count++] = po; 534 pa->pa_version++; 535 536 return (TRUE); 537 } 538 539 /* 540 * prop_array_set -- 541 * Store a reference to an object at the specified array index. 542 * This method is not allowed to create holes in the array; the 543 * caller must either be setting the object just beyond the existing 544 * count or replacing an already existing object reference. 545 */ 546 boolean_t 547 prop_array_set(prop_array_t pa, unsigned int idx, prop_object_t po) 548 { 549 prop_object_t opo; 550 boolean_t rv = FALSE; 551 552 if (! prop_object_is_array(pa)) 553 return (FALSE); 554 555 _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 556 557 if (prop_array_is_immutable(pa)) 558 goto out; 559 560 if (idx == pa->pa_count) { 561 rv = _prop_array_add(pa, po); 562 goto out; 563 } 564 565 _PROP_ASSERT(idx < pa->pa_count); 566 567 opo = pa->pa_array[idx]; 568 _PROP_ASSERT(opo != NULL); 569 570 prop_object_retain(po); 571 pa->pa_array[idx] = po; 572 pa->pa_version++; 573 574 prop_object_release(opo); 575 576 rv = TRUE; 577 578 out: 579 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 580 return (rv); 581 } 582 583 /* 584 * prop_array_add -- 585 * Add a refrerence to an object to the specified array, appending 586 * to the end and growing the array's capacity, if necessary. 587 */ 588 boolean_t 589 prop_array_add(prop_array_t pa, prop_object_t po) 590 { 591 boolean_t rv; 592 593 if (! prop_object_is_array(pa)) 594 return (FALSE); 595 596 _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 597 rv = _prop_array_add(pa, po); 598 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 599 600 return (rv); 601 } 602 603 /* 604 * prop_array_remove -- 605 * Remove the reference to an object from an array at the specified 606 * index. The array will be compacted following the removal. 607 */ 608 void 609 prop_array_remove(prop_array_t pa, unsigned int idx) 610 { 611 prop_object_t po; 612 613 if (! prop_object_is_array(pa)) 614 return; 615 616 _PROP_RWLOCK_WRLOCK(pa->pa_rwlock); 617 618 _PROP_ASSERT(idx < pa->pa_count); 619 620 /* XXX Should this be a _PROP_ASSERT()? */ 621 if (prop_array_is_immutable(pa)) { 622 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 623 return; 624 } 625 626 po = pa->pa_array[idx]; 627 _PROP_ASSERT(po != NULL); 628 629 for (++idx; idx < pa->pa_count; idx++) 630 pa->pa_array[idx - 1] = pa->pa_array[idx]; 631 pa->pa_count--; 632 pa->pa_version++; 633 634 _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); 635 636 prop_object_release(po); 637 } 638 639 /* 640 * prop_array_equals -- 641 * Return TRUE if the two arrays are equivalent. Note we do a 642 * by-value comparison of the objects in the array. 643 */ 644 boolean_t 645 prop_array_equals(prop_array_t array1, prop_array_t array2) 646 { 647 648 return (_prop_array_equals(array1, array2)); 649 } 650 651 /* 652 * prop_array_externalize -- 653 * Externalize an array, return a NUL-terminated buffer 654 * containing the XML-style representation. The buffer is allocated 655 * with the M_TEMP memory type. 656 */ 657 char * 658 prop_array_externalize(prop_array_t pa) 659 { 660 struct _prop_object_externalize_context *ctx; 661 char *cp; 662 663 ctx = _prop_object_externalize_context_alloc(); 664 if (ctx == NULL) 665 return (NULL); 666 667 if (_prop_object_externalize_header(ctx) == FALSE || 668 (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == FALSE || 669 _prop_object_externalize_footer(ctx) == FALSE) { 670 /* We are responsible for releasing the buffer. */ 671 _PROP_FREE(ctx->poec_buf, M_TEMP); 672 _prop_object_externalize_context_free(ctx); 673 return (NULL); 674 } 675 676 cp = ctx->poec_buf; 677 _prop_object_externalize_context_free(ctx); 678 679 return (cp); 680 } 681 682 /* 683 * _prop_array_internalize -- 684 * Parse an <array>...</array> and return the object created from the 685 * external representation. 686 */ 687 prop_object_t 688 _prop_array_internalize(struct _prop_object_internalize_context *ctx) 689 { 690 prop_array_t array; 691 prop_object_t obj; 692 693 /* We don't currently understand any attributes. */ 694 if (ctx->poic_tagattr != NULL) 695 return (NULL); 696 697 array = prop_array_create(); 698 if (array == NULL) 699 return (NULL); 700 701 if (ctx->poic_is_empty_element) 702 return (array); 703 704 for (;;) { 705 /* Fetch the next tag. */ 706 if (_prop_object_internalize_find_tag(ctx, NULL, 707 _PROP_TAG_TYPE_EITHER) == FALSE) 708 goto bad; 709 710 /* Check to see if this is the end of the array. */ 711 if (_PROP_TAG_MATCH(ctx, "array") && 712 ctx->poic_tag_type == _PROP_TAG_TYPE_END) 713 break; 714 715 /* Fetch the object. */ 716 obj = _prop_object_internalize_by_tag(ctx); 717 if (obj == NULL) 718 goto bad; 719 720 if (prop_array_add(array, obj) == FALSE) { 721 prop_object_release(obj); 722 goto bad; 723 } 724 prop_object_release(obj); 725 } 726 727 return (array); 728 729 bad: 730 prop_object_release(array); 731 return (NULL); 732 } 733 734 /* 735 * prop_array_internalize -- 736 * Create an array by parsing the XML-style representation. 737 */ 738 prop_array_t 739 prop_array_internalize(const char *xml) 740 { 741 prop_array_t array = NULL; 742 struct _prop_object_internalize_context *ctx; 743 744 ctx = _prop_object_internalize_context_alloc(xml); 745 if (ctx == NULL) 746 return (NULL); 747 748 /* We start with a <plist> tag. */ 749 if (_prop_object_internalize_find_tag(ctx, "plist", 750 _PROP_TAG_TYPE_START) == FALSE) 751 goto out; 752 753 /* Plist elements cannot be empty. */ 754 if (ctx->poic_is_empty_element) 755 goto out; 756 757 /* 758 * We don't understand any plist attributes, but Apple XML 759 * property lists often have a "version" attribute. If we 760 * see that one, we simply ignore it. 761 */ 762 if (ctx->poic_tagattr != NULL && 763 !_PROP_TAGATTR_MATCH(ctx, "version")) 764 goto out; 765 766 /* Next we expect to see <array>. */ 767 if (_prop_object_internalize_find_tag(ctx, "array", 768 _PROP_TAG_TYPE_START) == FALSE) 769 goto out; 770 771 array = _prop_array_internalize(ctx); 772 if (array == NULL) 773 goto out; 774 775 /* We've advanced past </array>. Now we want </plist>. */ 776 if (_prop_object_internalize_find_tag(ctx, "plist", 777 _PROP_TAG_TYPE_END) == FALSE) { 778 prop_object_release(array); 779 array = NULL; 780 } 781 782 out: 783 _prop_object_internalize_context_free(ctx); 784 return (array); 785 } 786 787 #if !defined(_KERNEL) && !defined(_STANDALONE) 788 /* 789 * prop_array_externalize_to_file -- 790 * Externalize an array to the specified file. 791 */ 792 boolean_t 793 prop_array_externalize_to_file(prop_array_t array, const char *fname) 794 { 795 char *xml; 796 boolean_t rv; 797 int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ 798 799 xml = prop_array_externalize(array); 800 if (xml == NULL) 801 return (FALSE); 802 rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); 803 if (rv == FALSE) 804 save_errno = errno; 805 _PROP_FREE(xml, M_TEMP); 806 if (rv == FALSE) 807 errno = save_errno; 808 809 return (rv); 810 } 811 812 /* 813 * prop_array_internalize_from_file -- 814 * Internalize an array from a file. 815 */ 816 prop_array_t 817 prop_array_internalize_from_file(const char *fname) 818 { 819 struct _prop_object_internalize_mapped_file *mf; 820 prop_array_t array; 821 822 mf = _prop_object_internalize_map_file(fname); 823 if (mf == NULL) 824 return (NULL); 825 array = prop_array_internalize(mf->poimf_xml); 826 _prop_object_internalize_unmap_file(mf); 827 828 return (array); 829 } 830 #endif /* _KERNEL && !_STANDALONE */ 831