1 /* $NetBSD: prop_array.c,v 1.20 2008/08/11 05:54:21 christos Exp $ */
4 * Copyright (c) 2010 Juan Romero Pardines (zlib/gzip support).
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 2006, 2007 The NetBSD Foundation, Inc.
30 * All rights reserved.
32 * This code is derived from software contributed to The NetBSD Foundation
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
44 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
45 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
47 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54 * POSSIBILITY OF SUCH DAMAGE.
57 #include <prop/prop_array.h>
58 #include "prop_object_impl.h"
64 struct _prop_object pa_obj
;
65 _PROP_RWLOCK_DECL(pa_rwlock
)
66 prop_object_t
* pa_array
;
67 unsigned int pa_capacity
;
68 unsigned int pa_count
;
74 #define PA_F_IMMUTABLE 0x01 /* array is immutable */
76 _PROP_POOL_INIT(_prop_array_pool
, sizeof(struct _prop_array
), "proparay")
77 _PROP_MALLOC_DEFINE(M_PROP_ARRAY
, "prop array",
78 "property array container object")
80 static _prop_object_free_rv_t
81 _prop_array_free(prop_stack_t
, prop_object_t
*);
82 static void _prop_array_emergency_free(prop_object_t
);
83 static bool _prop_array_externalize(
84 struct _prop_object_externalize_context
*,
86 static _prop_object_equals_rv_t
87 _prop_array_equals(prop_object_t
, prop_object_t
,
89 prop_object_t
*, prop_object_t
*);
90 static void _prop_array_equals_finish(prop_object_t
, prop_object_t
);
91 static prop_object_iterator_t
92 _prop_array_iterator_locked(prop_array_t
);
94 _prop_array_iterator_next_object_locked(void *);
95 static void _prop_array_iterator_reset_locked(void *);
97 static const struct _prop_object_type _prop_object_type_array
= {
98 .pot_type
= PROP_TYPE_ARRAY
,
99 .pot_free
= _prop_array_free
,
100 .pot_emergency_free
= _prop_array_emergency_free
,
101 .pot_extern
= _prop_array_externalize
,
102 .pot_equals
= _prop_array_equals
,
103 .pot_equals_finish
= _prop_array_equals_finish
,
106 #define prop_object_is_array(x) \
107 ((x) != NULL && (x)->pa_obj.po_type == &_prop_object_type_array)
109 #define prop_array_is_immutable(x) (((x)->pa_flags & PA_F_IMMUTABLE) != 0)
111 struct _prop_array_iterator
{
112 struct _prop_object_iterator pai_base
;
113 unsigned int pai_index
;
116 #define EXPAND_STEP 16
118 static _prop_object_free_rv_t
119 _prop_array_free(prop_stack_t stack
, prop_object_t
*obj
)
121 prop_array_t pa
= *obj
;
124 _PROP_ASSERT(pa
->pa_count
<= pa
->pa_capacity
);
125 _PROP_ASSERT((pa
->pa_capacity
== 0 && pa
->pa_array
== NULL
) ||
126 (pa
->pa_capacity
!= 0 && pa
->pa_array
!= NULL
));
128 /* The easy case is an empty array, just free and return. */
129 if (pa
->pa_count
== 0) {
130 if (pa
->pa_array
!= NULL
)
131 _PROP_FREE(pa
->pa_array
, M_PROP_ARRAY
);
133 _PROP_RWLOCK_DESTROY(pa
->pa_rwlock
);
135 _PROP_POOL_PUT(_prop_array_pool
, pa
);
137 return (_PROP_OBJECT_FREE_DONE
);
140 po
= pa
->pa_array
[pa
->pa_count
- 1];
141 _PROP_ASSERT(po
!= NULL
);
145 * If we are in emergency release mode,
146 * just let caller recurse down.
149 return (_PROP_OBJECT_FREE_FAILED
);
152 /* Otherwise, try to push the current object on the stack. */
153 if (!_prop_stack_push(stack
, pa
, NULL
, NULL
, NULL
)) {
154 /* Push failed, entering emergency release mode. */
155 return (_PROP_OBJECT_FREE_FAILED
);
157 /* Object pushed on stack, caller will release it. */
160 return (_PROP_OBJECT_FREE_RECURSE
);
164 _prop_array_emergency_free(prop_object_t obj
)
166 prop_array_t pa
= obj
;
168 _PROP_ASSERT(pa
->pa_count
!= 0);
173 _prop_array_externalize(struct _prop_object_externalize_context
*ctx
,
177 struct _prop_object
*po
;
178 prop_object_iterator_t pi
;
182 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
184 if (pa
->pa_count
== 0) {
185 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
186 return (_prop_object_externalize_empty_tag(ctx
, "array"));
189 /* XXXJRT Hint "count" for the internalize step? */
190 if (_prop_object_externalize_start_tag(ctx
, "array") == false ||
191 _prop_object_externalize_append_char(ctx
, '\n') == false)
194 pi
= _prop_array_iterator_locked(pa
);
199 _PROP_ASSERT(ctx
->poec_depth
!= 0);
201 while ((po
= _prop_array_iterator_next_object_locked(pi
)) != NULL
) {
202 if ((*po
->po_type
->pot_extern
)(ctx
, po
) == false) {
203 prop_object_iterator_release(pi
);
208 prop_object_iterator_release(pi
);
211 for (i
= 0; i
< ctx
->poec_depth
; i
++) {
212 if (_prop_object_externalize_append_char(ctx
, '\t') == false)
215 if (_prop_object_externalize_end_tag(ctx
, "array") == false)
221 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
226 static _prop_object_equals_rv_t
227 _prop_array_equals(prop_object_t v1
, prop_object_t v2
,
228 void **stored_pointer1
, void **stored_pointer2
,
229 prop_object_t
*next_obj1
, prop_object_t
*next_obj2
)
231 prop_array_t array1
= v1
;
232 prop_array_t array2
= v2
;
234 _prop_object_equals_rv_t rv
= _PROP_OBJECT_EQUALS_FALSE
;
236 if (array1
== array2
)
237 return (_PROP_OBJECT_EQUALS_TRUE
);
239 _PROP_ASSERT(*stored_pointer1
== *stored_pointer2
);
240 idx
= (uintptr_t)*stored_pointer1
;
242 /* For the first iteration, lock the objects. */
244 if ((uintptr_t)array1
< (uintptr_t)array2
) {
245 _PROP_RWLOCK_RDLOCK(array1
->pa_rwlock
);
246 _PROP_RWLOCK_RDLOCK(array2
->pa_rwlock
);
248 _PROP_RWLOCK_RDLOCK(array2
->pa_rwlock
);
249 _PROP_RWLOCK_RDLOCK(array1
->pa_rwlock
);
253 if (array1
->pa_count
!= array2
->pa_count
)
255 if (idx
== array1
->pa_count
) {
256 rv
= _PROP_OBJECT_EQUALS_TRUE
;
259 _PROP_ASSERT(idx
< array1
->pa_count
);
261 *stored_pointer1
= (void *)(idx
+ 1);
262 *stored_pointer2
= (void *)(idx
+ 1);
264 *next_obj1
= array1
->pa_array
[idx
];
265 *next_obj2
= array2
->pa_array
[idx
];
267 return (_PROP_OBJECT_EQUALS_RECURSE
);
270 _PROP_RWLOCK_UNLOCK(array1
->pa_rwlock
);
271 _PROP_RWLOCK_UNLOCK(array2
->pa_rwlock
);
276 _prop_array_equals_finish(prop_object_t v1
, prop_object_t v2
)
278 _PROP_RWLOCK_UNLOCK(((prop_array_t
)v1
)->pa_rwlock
);
279 _PROP_RWLOCK_UNLOCK(((prop_array_t
)v2
)->pa_rwlock
);
283 _prop_array_alloc(unsigned int capacity
)
286 prop_object_t
*array
;
289 array
= _PROP_CALLOC(capacity
* sizeof(prop_object_t
),
296 pa
= _PROP_POOL_GET(_prop_array_pool
);
298 _prop_object_init(&pa
->pa_obj
, &_prop_object_type_array
);
299 pa
->pa_obj
.po_type
= &_prop_object_type_array
;
301 _PROP_RWLOCK_INIT(pa
->pa_rwlock
);
302 pa
->pa_array
= array
;
303 pa
->pa_capacity
= capacity
;
308 } else if (array
!= NULL
)
309 _PROP_FREE(array
, M_PROP_ARRAY
);
315 _prop_array_expand(prop_array_t pa
, unsigned int capacity
)
317 prop_object_t
*array
, *oarray
;
320 * Array must be WRITE-LOCKED.
323 oarray
= pa
->pa_array
;
325 array
= _PROP_CALLOC(capacity
* sizeof(*array
), M_PROP_ARRAY
);
329 memcpy(array
, oarray
, pa
->pa_capacity
* sizeof(*array
));
330 pa
->pa_array
= array
;
331 pa
->pa_capacity
= capacity
;
334 _PROP_FREE(oarray
, M_PROP_ARRAY
);
340 _prop_array_iterator_next_object_locked(void *v
)
342 struct _prop_array_iterator
*pai
= v
;
343 prop_array_t pa
= pai
->pai_base
.pi_obj
;
344 prop_object_t po
= NULL
;
346 _PROP_ASSERT(prop_object_is_array(pa
));
348 if (pa
->pa_version
!= pai
->pai_base
.pi_version
)
349 goto out
; /* array changed during iteration */
351 _PROP_ASSERT(pai
->pai_index
<= pa
->pa_count
);
353 if (pai
->pai_index
== pa
->pa_count
)
354 goto out
; /* we've iterated all objects */
356 po
= pa
->pa_array
[pai
->pai_index
];
364 _prop_array_iterator_next_object(void *v
)
366 struct _prop_array_iterator
*pai
= v
;
367 prop_array_t pa
= pai
->pai_base
.pi_obj
;
370 _PROP_ASSERT(prop_object_is_array(pa
));
372 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
373 po
= _prop_array_iterator_next_object_locked(pai
);
374 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
379 _prop_array_iterator_reset_locked(void *v
)
381 struct _prop_array_iterator
*pai
= v
;
382 prop_array_t pa
= pai
->pai_base
.pi_obj
;
384 _PROP_ASSERT(prop_object_is_array(pa
));
387 pai
->pai_base
.pi_version
= pa
->pa_version
;
391 _prop_array_iterator_reset(void *v
)
393 struct _prop_array_iterator
*pai
= v
;
394 prop_array_t pa
= pai
->pai_base
.pi_obj
;
396 _PROP_ASSERT(prop_object_is_array(pa
));
398 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
399 _prop_array_iterator_reset_locked(pai
);
400 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
404 * prop_array_create --
405 * Create an empty array.
408 prop_array_create(void)
411 return (_prop_array_alloc(0));
415 * prop_array_create_with_capacity --
416 * Create an array with the capacity to store N objects.
419 prop_array_create_with_capacity(unsigned int capacity
)
422 return (_prop_array_alloc(capacity
));
427 * Copy an array. The new array has an initial capacity equal to
428 * the number of objects stored in the original array. The new
429 * array contains references to the original array's objects, not
430 * copies of those objects (i.e. a shallow copy).
433 prop_array_copy(prop_array_t opa
)
439 if (! prop_object_is_array(opa
))
442 _PROP_RWLOCK_RDLOCK(opa
->pa_rwlock
);
444 pa
= _prop_array_alloc(opa
->pa_count
);
446 for (idx
= 0; idx
< opa
->pa_count
; idx
++) {
447 po
= opa
->pa_array
[idx
];
448 prop_object_retain(po
);
449 pa
->pa_array
[idx
] = po
;
451 pa
->pa_count
= opa
->pa_count
;
452 pa
->pa_flags
= opa
->pa_flags
;
454 _PROP_RWLOCK_UNLOCK(opa
->pa_rwlock
);
459 * prop_array_copy_mutable --
460 * Like prop_array_copy(), but the resulting array is mutable.
463 prop_array_copy_mutable(prop_array_t opa
)
467 pa
= prop_array_copy(opa
);
469 pa
->pa_flags
&= ~PA_F_IMMUTABLE
;
475 * prop_array_capacity --
476 * Return the capacity of the array.
479 prop_array_capacity(prop_array_t pa
)
483 if (! prop_object_is_array(pa
))
486 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
487 rv
= pa
->pa_capacity
;
488 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
494 * prop_array_count --
495 * Return the number of objects stored in the array.
498 prop_array_count(prop_array_t pa
)
502 if (! prop_object_is_array(pa
))
505 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
507 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
513 * prop_array_ensure_capacity --
514 * Ensure that the array has the capacity to store the specified
515 * total number of objects (inluding the objects already stored
519 prop_array_ensure_capacity(prop_array_t pa
, unsigned int capacity
)
523 if (! prop_object_is_array(pa
))
526 _PROP_RWLOCK_WRLOCK(pa
->pa_rwlock
);
527 if (capacity
> pa
->pa_capacity
)
528 rv
= _prop_array_expand(pa
, capacity
);
531 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
536 static prop_object_iterator_t
537 _prop_array_iterator_locked(prop_array_t pa
)
539 struct _prop_array_iterator
*pai
;
541 if (! prop_object_is_array(pa
))
544 pai
= _PROP_CALLOC(sizeof(*pai
), M_TEMP
);
547 pai
->pai_base
.pi_next_object
= _prop_array_iterator_next_object
;
548 pai
->pai_base
.pi_reset
= _prop_array_iterator_reset
;
549 prop_object_retain(pa
);
550 pai
->pai_base
.pi_obj
= pa
;
551 _prop_array_iterator_reset_locked(pai
);
553 return (&pai
->pai_base
);
557 * prop_array_iterator --
558 * Return an iterator for the array. The array is retained by
561 prop_object_iterator_t
562 prop_array_iterator(prop_array_t pa
)
564 prop_object_iterator_t pi
;
566 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
567 pi
= _prop_array_iterator_locked(pa
);
568 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
573 * prop_array_make_immutable --
574 * Make the array immutable.
577 prop_array_make_immutable(prop_array_t pa
)
580 _PROP_RWLOCK_WRLOCK(pa
->pa_rwlock
);
581 if (prop_array_is_immutable(pa
) == false)
582 pa
->pa_flags
|= PA_F_IMMUTABLE
;
583 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
587 * prop_array_mutable --
588 * Returns true if the array is mutable.
591 prop_array_mutable(prop_array_t pa
)
595 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
596 rv
= prop_array_is_immutable(pa
) == false;
597 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
604 * Return the object stored at the specified array index.
607 prop_array_get(prop_array_t pa
, unsigned int idx
)
609 prop_object_t po
= NULL
;
611 if (! prop_object_is_array(pa
))
614 _PROP_RWLOCK_RDLOCK(pa
->pa_rwlock
);
615 if (idx
>= pa
->pa_count
)
617 po
= pa
->pa_array
[idx
];
618 _PROP_ASSERT(po
!= NULL
);
620 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
625 _prop_array_add(prop_array_t pa
, prop_object_t po
)
629 * Array must be WRITE-LOCKED.
632 _PROP_ASSERT(pa
->pa_count
<= pa
->pa_capacity
);
634 if (prop_array_is_immutable(pa
) ||
635 (pa
->pa_count
== pa
->pa_capacity
&&
636 _prop_array_expand(pa
, pa
->pa_capacity
+ EXPAND_STEP
) == false))
639 prop_object_retain(po
);
640 pa
->pa_array
[pa
->pa_count
++] = po
;
648 * Store a reference to an object at the specified array index.
649 * This method is not allowed to create holes in the array; the
650 * caller must either be setting the object just beyond the existing
651 * count or replacing an already existing object reference.
654 prop_array_set(prop_array_t pa
, unsigned int idx
, prop_object_t po
)
659 if (! prop_object_is_array(pa
))
662 _PROP_RWLOCK_WRLOCK(pa
->pa_rwlock
);
664 if (prop_array_is_immutable(pa
))
667 if (idx
== pa
->pa_count
) {
668 rv
= _prop_array_add(pa
, po
);
672 _PROP_ASSERT(idx
< pa
->pa_count
);
674 opo
= pa
->pa_array
[idx
];
675 _PROP_ASSERT(opo
!= NULL
);
677 prop_object_retain(po
);
678 pa
->pa_array
[idx
] = po
;
681 prop_object_release(opo
);
686 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
692 * Add a reference to an object to the specified array, appending
693 * to the end and growing the array's capacity, if necessary.
696 prop_array_add(prop_array_t pa
, prop_object_t po
)
700 if (! prop_object_is_array(pa
))
703 _PROP_RWLOCK_WRLOCK(pa
->pa_rwlock
);
704 rv
= _prop_array_add(pa
, po
);
705 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
711 * prop_array_remove --
712 * Remove the reference to an object from an array at the specified
713 * index. The array will be compacted following the removal.
716 prop_array_remove(prop_array_t pa
, unsigned int idx
)
720 if (! prop_object_is_array(pa
))
723 _PROP_RWLOCK_WRLOCK(pa
->pa_rwlock
);
725 _PROP_ASSERT(idx
< pa
->pa_count
);
727 /* XXX Should this be a _PROP_ASSERT()? */
728 if (prop_array_is_immutable(pa
)) {
729 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
733 po
= pa
->pa_array
[idx
];
734 _PROP_ASSERT(po
!= NULL
);
736 for (++idx
; idx
< pa
->pa_count
; idx
++)
737 pa
->pa_array
[idx
- 1] = pa
->pa_array
[idx
];
741 _PROP_RWLOCK_UNLOCK(pa
->pa_rwlock
);
743 prop_object_release(po
);
747 * prop_array_equals --
748 * Return true if the two arrays are equivalent. Note we do a
749 * by-value comparison of the objects in the array.
752 prop_array_equals(prop_array_t array1
, prop_array_t array2
)
754 if (!prop_object_is_array(array1
) || !prop_object_is_array(array2
))
757 return (prop_object_equals(array1
, array2
));
761 * prop_array_externalize --
762 * Externalize an array, return a NUL-terminated buffer
763 * containing the XML-style representation. The buffer is allocated
764 * with the M_TEMP memory type.
767 prop_array_externalize(prop_array_t pa
)
769 struct _prop_object_externalize_context
*ctx
;
772 ctx
= _prop_object_externalize_context_alloc();
776 if (_prop_object_externalize_header(ctx
) == false ||
777 (*pa
->pa_obj
.po_type
->pot_extern
)(ctx
, pa
) == false ||
778 _prop_object_externalize_footer(ctx
) == false) {
779 /* We are responsible for releasing the buffer. */
780 _PROP_FREE(ctx
->poec_buf
, M_TEMP
);
781 _prop_object_externalize_context_free(ctx
);
786 _prop_object_externalize_context_free(ctx
);
792 * _prop_array_internalize --
793 * Parse an <array>...</array> and return the object created from the
794 * external representation.
796 static bool _prop_array_internalize_body(prop_stack_t
, prop_object_t
*,
797 struct _prop_object_internalize_context
*);
800 _prop_array_internalize(prop_stack_t stack
, prop_object_t
*obj
,
801 struct _prop_object_internalize_context
*ctx
)
803 /* We don't currently understand any attributes. */
804 if (ctx
->poic_tagattr
!= NULL
)
807 *obj
= prop_array_create();
809 * We are done if the create failed or no child elements exist.
811 if (*obj
== NULL
|| ctx
->poic_is_empty_element
)
815 * Opening tag is found, now continue to the first element.
817 return (_prop_array_internalize_body(stack
, obj
, ctx
));
821 _prop_array_internalize_continue(prop_stack_t stack
,
823 struct _prop_object_internalize_context
*ctx
,
824 void *data
, prop_object_t child
)
828 _PROP_ASSERT(data
== NULL
);
831 goto bad
; /* Element could not be parsed. */
835 if (prop_array_add(array
, child
) == false) {
836 prop_object_release(child
);
839 prop_object_release(child
);
842 * Current element is processed and added, look for next.
844 return (_prop_array_internalize_body(stack
, obj
, ctx
));
847 prop_object_release(*obj
);
853 _prop_array_internalize_body(prop_stack_t stack
, prop_object_t
*obj
,
854 struct _prop_object_internalize_context
*ctx
)
856 prop_array_t array
= *obj
;
858 _PROP_ASSERT(array
!= NULL
);
860 /* Fetch the next tag. */
861 if (_prop_object_internalize_find_tag(ctx
, NULL
,
862 _PROP_TAG_TYPE_EITHER
) == false)
865 /* Check to see if this is the end of the array. */
866 if (_PROP_TAG_MATCH(ctx
, "array") &&
867 ctx
->poic_tag_type
== _PROP_TAG_TYPE_END
) {
868 /* It is, so don't iterate any further. */
872 if (_prop_stack_push(stack
, array
,
873 _prop_array_internalize_continue
, NULL
, NULL
))
877 prop_object_release(array
);
883 * prop_array_internalize --
884 * Create an array by parsing the XML-style representation.
887 prop_array_internalize(const char *xml
)
889 return _prop_generic_internalize(xml
, "array");
893 * prop_array_externalize_to_file --
894 * Externalize an array to the specified file.
897 prop_array_externalize_to_file(prop_array_t array
, const char *fname
)
901 int save_errno
= 0; /* XXXGCC -Wuninitialized [mips, ...] */
903 xml
= prop_array_externalize(array
);
906 rv
= _prop_object_externalize_write_file(fname
, xml
,
910 _PROP_FREE(xml
, M_TEMP
);
918 * prop_array_externalize_to_zfile ---
919 * Externalize an array to the specified file, and on the fly
920 * compressing the result with gzip (via zlib).
923 prop_array_externalize_to_zfile(prop_array_t array
, const char *fname
)
929 xml
= prop_array_externalize(array
);
932 rv
= _prop_object_externalize_write_file(fname
, xml
, strlen(xml
), true);
935 _PROP_FREE(xml
, M_TEMP
);
943 * prop_array_internalize_from_file --
944 * Internalize an array from a file.
947 prop_array_internalize_from_file(const char *fname
)
949 struct _prop_object_internalize_mapped_file
*mf
;
952 mf
= _prop_object_internalize_map_file(fname
);
955 array
= prop_array_internalize(mf
->poimf_xml
);
956 _prop_object_internalize_unmap_file(mf
);
961 #define _READ_CHUNK 512
963 * prop_array_internalize_from_zfile ---
964 * Internalize an array from a compressed gzip file.
967 prop_array_internalize_from_zfile(const char *fname
)
969 struct _prop_object_internalize_mapped_file
*mf
;
972 unsigned char out
[_READ_CHUNK
];
973 char *uncomp_xml
= NULL
;
975 ssize_t totalsize
= 0;
978 mf
= _prop_object_internalize_map_file(fname
);
982 /* Decompress the mmap'ed buffer with zlib */
983 strm
.zalloc
= Z_NULL
;
985 strm
.opaque
= Z_NULL
;
987 strm
.next_in
= Z_NULL
;
989 /* 15+16 to use gzip method */
990 if (inflateInit2(&strm
, 15+16) != Z_OK
) {
991 _prop_object_internalize_unmap_file(mf
);
995 strm
.avail_in
= mf
->poimf_mapsize
;
996 strm
.next_in
= mf
->poimf_xml
;
998 /* Output buffer (decompressed) */
999 uncomp_xml
= _PROP_MALLOC(_READ_CHUNK
, M_TEMP
);
1000 if (uncomp_xml
== NULL
) {
1001 _prop_object_internalize_unmap_file(mf
);
1002 (void)inflateEnd(&strm
);
1006 /* Inflate the input buffer and copy into 'dest' */
1008 strm
.avail_out
= _READ_CHUNK
;
1009 strm
.next_out
= out
;
1010 rv
= inflate(&strm
, Z_NO_FLUSH
);
1014 * Wrong compressed data or uncompressed, try
1015 * normal method as last resort.
1017 (void)inflateEnd(&strm
);
1018 _PROP_FREE(uncomp_xml
, M_TEMP
);
1019 array
= prop_array_internalize(mf
->poimf_xml
);
1020 _prop_object_internalize_unmap_file(mf
);
1022 case Z_STREAM_ERROR
:
1025 (void)inflateEnd(&strm
);
1026 _PROP_FREE(uncomp_xml
, M_TEMP
);
1027 _prop_object_internalize_unmap_file(mf
);
1031 have
= _READ_CHUNK
- strm
.avail_out
;
1033 uncomp_xml
= _PROP_REALLOC(uncomp_xml
, totalsize
, M_TEMP
);
1034 memcpy(uncomp_xml
+ totalsize
- have
, out
, have
);
1035 } while (strm
.avail_out
== 0);
1038 (void)inflateEnd(&strm
);
1039 array
= prop_array_internalize(uncomp_xml
);
1040 _PROP_FREE(uncomp_xml
, M_TEMP
);
1041 _prop_object_internalize_unmap_file(mf
);