Index: common/lib/libprop/Makefile.inc
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/Makefile.inc,v
retrieving revision 1.6
diff -d -p -u -u -r1.6 Makefile.inc
--- common/lib/libprop/Makefile.inc 16 Aug 2007 21:44:06 -0000 1.6
+++ common/lib/libprop/Makefile.inc 6 Oct 2007 20:14:28 -0000
@@ -2,7 +2,7 @@
.PATH: ${.PARSEDIR}
-SRCS+= prop_array.c prop_bool.c prop_data.c prop_dictionary.c \
+SRCS+= prop_array.c prop_bool.c prop_bplist.c prop_data.c prop_dictionary.c \
prop_dictionary_util.c prop_ingest.c prop_kern.c prop_number.c \
prop_object.c prop_stack.c prop_string.c
Index: common/lib/libprop/prop_array.3
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_array.3,v
retrieving revision 1.5
diff -d -p -u -u -r1.5 prop_array.3
--- common/lib/libprop/prop_array.3 16 Aug 2007 16:30:59 -0000 1.5
+++ common/lib/libprop/prop_array.3 6 Oct 2007 20:14:28 -0000
@@ -57,6 +57,9 @@
.Nm prop_array_internalize ,
.Nm prop_array_externalize_to_file ,
.Nm prop_array_internalize_from_file ,
+.Nm prop_array_binary_externalize,
+.Nm prop_array_binary_internalize,
+.Nm prop_array_binary_externalize_to_file,
.Nm prop_array_equals
.Nd array property collection object
.Sh LIBRARY
@@ -109,6 +112,15 @@
.Fn prop_array_internalize_from_file "const char *path"
.\"
.Ft bool
+.Fn prop_array_binary_externalize "prop_array_t array" "uint8_t **bufp" \
+ "size_t *lenp"
+.Ft prop_array_t
+.Fn prop_array_binary_internalize "uint8_t *buf" "size_t len"
+.Ft bool
+.Fn prop_array_binary_externalize_to_file "prop_array_t array" \
+ "const char *path"
+.\"
+.Ft bool
.Fn prop_array_equals "prop_array_t array1" "prop_array_t array2"
.Sh DESCRIPTION
The
@@ -241,8 +253,47 @@ and is written atomically.
Returns
.Dv false
if externalizing or writing the array fails for any reason.
+.It Fn prop_array_binary_externalize "prop_array_t array" "uint8_t **bufp" \
+ "size_t *lenp"
+Externalizes an array in binary format. On success
+.Dv true
+is returned, pointer to buffer containing binary representation is filled to
+.Fa bufp
+and its size is filled to
+.Fa lenp
+arguments. The caller is responsible for freeing returned buffer. On failure
+.Dv false
+is returned and arguments are not modified.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.It Fn prop_array_binary_internalize "uint8_t *buf" "size_t len"
+Parse the binary representation of a property list in the buffer
+.Fa buf
+of size
+.Fa len
+and return the corresponding array. If parsing fails for any reason,
+.Dv NULL
+is returned.
+.It Fn prop_array_binary_externalize_to_file "prop_array_t array" \
+ "const char *path"
+Externalizes an array in binary format and writes it to the file
+specified by
+.Fa path .
+The file is saved with the mode
+.Dv 0666
+as modified by the process's file creation mask
+.Pq see Xr umask 3
+and is written atomically.
+Returns
+.Dv false
+if externalizing or writing the array fails for any reason.
.It Fn prop_array_internalize_from_file "const char *path"
-Reads the XML property list contained in the file specified by
+Reads the XML or binary property list contained in the file specified by
.Fa path ,
internalizes it, and returns the corresponding array.
.El
@@ -259,3 +310,6 @@ The
.Nm proplib
property container object library first appeared in
.Nx 4.0 .
+.Pp
+Support for binary format first appeared in
+.Nx 5.0 .
Index: common/lib/libprop/prop_array.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_array.c,v
retrieving revision 1.11
diff -d -p -u -u -r1.11 prop_array.c
--- common/lib/libprop/prop_array.c 30 Aug 2007 12:23:54 -0000 1.11
+++ common/lib/libprop/prop_array.c 6 Oct 2007 20:14:28 -0000
@@ -91,6 +91,24 @@ struct _prop_array_iterator {
#define EXPAND_STEP 16
+void
+_prop_array_rdlock(prop_object_t po)
+{
+ prop_array_t pa = po;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+ _PROP_RWLOCK_RDLOCK(pa->pa_rwlock);
+}
+
+void
+_prop_array_unlock(prop_object_t po)
+{
+ prop_array_t pa = po;
+
+ _PROP_ASSERT(prop_object_is_array(pa));
+ _PROP_RWLOCK_UNLOCK(pa->pa_rwlock);
+}
+
static int
_prop_array_free(prop_stack_t stack, prop_object_t *obj)
{
@@ -837,7 +855,7 @@ prop_array_internalize(const char *xml)
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* prop_array_externalize_to_file --
- * Externalize an array to the specified file.
+ * Externalize an array to the specified file in XML format.
*/
bool
prop_array_externalize_to_file(prop_array_t array, const char *fname)
@@ -860,6 +878,31 @@ prop_array_externalize_to_file(prop_arra
}
/*
+ * prop_array_binary_externalize_to_file --
+ * Externalize an array to the specified file in bplist format.
+ */
+bool
+prop_array_binary_externalize_to_file(prop_array_t array, const char *fname)
+{
+ uint8_t *buf;
+ size_t len;
+ bool rv;
+ int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */
+
+ if (! prop_array_binary_externalize(array, &buf, &len))
+ return (false);
+
+ rv = _prop_object_externalize_write_file(fname, (char *)buf, len);
+ if (rv == false)
+ save_errno = errno;
+ _PROP_FREE(buf, M_TEMP);
+ if (rv == false)
+ errno = save_errno;
+
+ return (rv);
+}
+
+/*
* prop_array_internalize_from_file --
* Internalize an array from a file.
*/
@@ -872,7 +915,10 @@ prop_array_internalize_from_file(const c
mf = _prop_object_internalize_map_file(fname);
if (mf == NULL)
return (NULL);
- array = prop_array_internalize(mf->poimf_xml);
+ array = prop_array_internalize((char *)mf->poimf_data);
+ if (array == NULL)
+ array = prop_array_binary_internalize(mf->poimf_data,
+ mf->poimf_datasize);
_prop_object_internalize_unmap_file(mf);
return (array);
Index: common/lib/libprop/prop_bplist.c
===================================================================
RCS file: common/lib/libprop/prop_bplist.c
diff -N common/lib/libprop/prop_bplist.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ common/lib/libprop/prop_bplist.c 6 Oct 2007 20:14:30 -0000
@@ -0,0 +1,1661 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2007 Jachym Holecek <
[email protected]>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * XXXfreza TODO:
+ * o Document public APIs & short note on bplist format
+ * o Don't allocate internalizer context on the stack
+ * o Tidy _prop_bp_decode_object() a bit, it's too long
+ * o Look at using joerg's stack management
+ *
+ * XXXfreza CAVEATS:
+ * o Mutating internalized objects is risky as objects may be arbitrarily
+ * uniquified, depending on the encoder.
+ */
+
+#include <prop/proplib.h>
+#include "prop_object_impl.h"
+
+#if defined(_KERNEL) || defined(_STANDALONE)
+#include <machine/limits.h>
+#else
+#include <limits.h>
+#endif
+
+/* Round 'x' up to the nearest multiple of 'm'. */
+#define _PROP_ROUNDUP(x, m) ((((x) + ((m) - 1))/(m)) * (m))
+
+/* General size/count increments. */
+#define BPLIST_INCREMENT_SMALL 16 /* > BPLIST_HEADER_LEN */
+#define BPLIST_INCREMENT_LARGE 128
+
+/* Maximum length of encoded integer (marker byte + 64bit value). */
+#define BPLIST_NUMBER_MAXLEN 9
+
+/*
+ * (1) Header structure. Identifies file format and version.
+ */
+
+/* Magic marker & lenght (no terminating NUL). */
+#define BPLIST_MAGIC "bplist"
+#define BPLIST_MAGIC_LEN 6
+
+/* Version is given in two bytes interpreted as ASCII characters. */
+#define BPLIST_VERSION_LEN 2
+#define BPLIST_VERSION_MAJOR_OFFS 6
+#define BPLIST_VERSION_MINOR_OFFS 7
+
+/* Total header length. */
+#define BPLIST_HEADER_LEN (BPLIST_MAGIC_LEN + BPLIST_VERSION_LEN)
+
+/*
+ * (2) Object table. Flat array describing all objects in the plist.
+ * Compound objects (array, dict) refer to their "children" via
+ * indexes to the offset table.
+ */
+
+/* Object type encoded in higher four bits. */
+#define BPLIST_TYPE_MULTI 0x00
+#define BPLIST_TYPE_UINT 0x10 /* signed int in Apple */
+#define BPLIST_TYPE_REAL 0x20 /* unsupported */
+#define BPLIST_TYPE_DATE 0x30 /* unsupported */
+#define BPLIST_TYPE_DATA 0x40
+#define BPLIST_TYPE_ASCII 0x50 /* ASCII string */
+#define BPLIST_TYPE_UNICODE 0x60 /* unsupported */
+#define BPLIST_TYPE_SINT 0x70 /* reserved in Apple */
+#define BPLIST_TYPE_UID 0x80 /* unsupported */
+#define BPLIST_TYPE_ARRAY 0xa0
+#define BPLIST_TYPE_DICT 0xd0
+
+/* Lower four bits for BPLIST_TYPE_MULTI. */
+#define BPLIST_MULTI_NULL 0x00
+#define BPLIST_MULTI_FALSE 0x08
+#define BPLIST_MULTI_TRUE 0x09
+#define BPLIST_MULTI_FILL 0x0f
+
+/* Where lower bits mean "count", this indicates (u_)integer count follows. */
+#define BPLIST_COUNT_MANY 0x0f
+
+/*
+ * (3) Offset table. Array of unsigned integers (width defined by the
+ * trailer) resolving object references to file offsets at which
+ * objects are stored.
+ */
+
+/*
+ * (4) Trailer structure. Defines byte-width of offset table entries, its
+ * offset in the file, count of offset table entries (ie. object count)
+ * and index of the toplevel array/dict.
+ */
+
+#define BPLIST_TRAILER_LEN (3*8 + 2)
+#define BPLIST_TRAILER_OFFWIDTH_OFFS 0
+#define BPLIST_TRAILER_REFWIDTH_OFFS 1
+#define BPLIST_TRAILER_OBJCNT_OFFS 2
+#define BPLIST_TRAILER_OBJTOP_OFFS 10
+#define BPLIST_TRAILER_OFFTAB_OFFS 18
+
+/*
+ * Internalizer data types.
+ */
+
+typedef struct _prop_bp_intern_frame *_prop_bp_intern_frame_t;
+typedef struct _prop_bp_intern *_prop_bp_intern_t;
+
+/* Internalizer frame, common for arrays/dicts. */
+struct _prop_bp_intern_frame {
+ prop_object_t if_container;
+ const char *if_keysym; /* Dictionary only */
+ const uint8_t *if_buffer;
+ u_int if_count; /* Object count */
+ u_int if_index; /* Current object */
+};
+
+struct _prop_bp_intern {
+ /* Trailer members. */
+ u_int bi_offtab_width; /* size 1 offset 0 */
+ u_int bi_objref_width; /* size 1 offset 1 */
+ u_int bi_object_count; /* size 8 offset 2 */
+ u_int bi_object_first; /* size 8 offset 10 */
+ u_int bi_offtab_offset; /* size 8 offset 18 */
+
+ /* Objects internalized so far, by index. */
+ prop_object_t *bi_objects;
+
+ /* Utility members. */
+ const uint8_t *bi_offtab;
+ const uint8_t *bi_buffer;
+ size_t bi_length;
+
+ /* Manipulated exclusively by _prop_bp_intern_stack_*(). */
+ u_int bi_stack_depth;
+ u_int bi_stack_top;
+ _prop_bp_intern_frame_t bi_stack; /* array */
+};
+
+/*
+ * Externalizer data types.
+ */
+
+typedef struct _prop_bp_extern *_prop_bp_extern_t;
+typedef struct _prop_bp_object *_prop_bp_object_t;
+typedef struct _prop_bp_table *_prop_bp_table_t;
+
+typedef bool (*_prop_bp_table_lookup_t)(_prop_bp_table_t, prop_object_t,
+ u_int *);
+
+/* Entry in uniqified object table. */
+struct _prop_bp_object {
+ prop_object_t bo_object;
+ u_int bo_index;
+ u_int bo_offset;
+};
+
+/* Uniquified object table. */
+struct _prop_bp_table {
+ _prop_bp_object_t bt_objects; /* array */
+ u_int bt_depth;
+ u_int bt_next;
+};
+
+/* Uniquified object tables & their count. */
+#define BPLIST_TABLE_COMPOUND 0 /* dict & array */
+#define BPLIST_TABLE_STRING 1 /* string & keysym */
+#define BPLIST_TABLE_NUMBER 2 /* signed & unsigned int */
+#define BPLIST_TABLE_SINGLE 3 /* bool & data */
+#define BPLIST_TABLE_COUNT 4 /* number of tables */
+
+struct _prop_bp_extern {
+ /* Uniquified object tables. */
+ struct _prop_bp_table be_tables[BPLIST_TABLE_COUNT];
+
+ /* Externalized plist. */
+ uint8_t *be_extern_buffer;
+ size_t be_extern_size;
+ size_t be_extern_next;
+
+ /* Unique object count (and next object index). */
+ u_int be_index_next;
+
+ /* Trailer values. */
+ u_int be_objref_width;
+ u_int be_offtab_width;
+ u_int be_offtab_start;
+};
+
+/*
+ * Internalizer stack management.
+ */
+
+static bool
+_prop_bp_intern_stack_init(_prop_bp_intern_t ic)
+{
+ u_int count = BPLIST_INCREMENT_SMALL;
+ u_int size = (count * sizeof(struct _prop_bp_intern_frame));
+
+ ic->bi_stack = _PROP_MALLOC(size, M_TEMP);
+ if (ic->bi_stack == NULL)
+ return (false);
+
+ ic->bi_stack_depth = count;
+ ic->bi_stack_top = 0;
+
+ return (true);
+}
+
+static void
+_prop_bp_intern_stack_free(_prop_bp_intern_t ic)
+{
+ /* We're done, WIP objects themselves freed via bi_objects[]. */
+ _PROP_FREE(ic->bi_stack, M_TEMP);
+}
+
+static _prop_bp_intern_frame_t
+_prop_bp_intern_stack_peek(_prop_bp_intern_t ic)
+{
+ return (&ic->bi_stack[ic->bi_stack_top]);
+}
+
+static _prop_bp_intern_frame_t
+_prop_bp_intern_stack_zerohead(_prop_bp_intern_t ic)
+{
+ _prop_bp_intern_frame_t bif = _prop_bp_intern_stack_peek(ic);
+
+ return (memset(bif, 0, sizeof(struct _prop_bp_intern_frame)));
+}
+
+static bool
+_prop_bp_intern_stack_pop(_prop_bp_intern_t ic)
+{
+ if (ic->bi_stack_top == 1)
+ return (true);
+
+ ic->bi_stack_top -= 1;
+ return (false);
+}
+
+static _prop_bp_intern_frame_t
+_prop_bp_intern_stack_push(_prop_bp_intern_t ic)
+{
+ size_t size;
+ u_int count;
+ void *p;
+
+ /* XXXfreza this leaves stack frame 0 wasted. */
+ ic->bi_stack_top += 1;
+ if (ic->bi_stack_top < ic->bi_stack_depth)
+ return (_prop_bp_intern_stack_zerohead(ic));
+
+ count = (ic->bi_stack_depth + BPLIST_INCREMENT_SMALL);
+ size = (count * sizeof(struct _prop_bp_intern_frame));
+ p = _PROP_REALLOC(ic->bi_stack, size, M_TEMP);
+ if (p == NULL)
+ return (NULL);
+
+ ic->bi_stack_depth = count;
+ ic->bi_stack = p;
+
+ return (_prop_bp_intern_stack_zerohead(ic));
+}
+
+/*
+ * Internalizer utility decoders.
+ */
+
+static const uint8_t *
+_prop_bp_object_pointer(_prop_bp_intern_t ic, u_int n)
+{
+ const uint8_t *ofp = (ic->bi_offtab + n*ic->bi_offtab_width);
+ u_int offset = 0;
+ int i;
+
+ for (i = 0; i < ic->bi_offtab_width; i++)
+ offset = (offset << 8) | ofp[i];
+
+ if (offset >= (ic->bi_length - BPLIST_TRAILER_LEN))
+ return (NULL);
+
+ return (ic->bi_buffer + offset);
+}
+
+static const uint8_t *
+_prop_bp_read_int(_prop_bp_intern_t ic, const uint8_t *obj, u_int *valp)
+{
+ uint8_t hi = (*obj & 0xf0);
+ uint8_t lo = (*obj & 0x0f);
+ u_int nbytes;
+ u_int i;
+
+ /* Check type and calculate number size in bytes. */
+ if (hi != BPLIST_TYPE_UINT)
+ return (NULL);
+
+ nbytes = (1 << lo);
+ if (nbytes > sizeof(u_int))
+ return (NULL);
+
+ /* Careful not to overflow object table. */
+ if ((obj + nbytes) > ic->bi_offtab)
+ return (NULL);
+ obj += 1;
+
+ /* Shift in big-endian value. */
+ for (*valp = 0, i = 0; i < nbytes; i++)
+ *valp = (*valp << 8) | *obj++;
+
+ return (obj);
+}
+
+static const uint8_t *
+_prop_bp_read_index(_prop_bp_intern_t ic, const uint8_t *obj, u_int *valp)
+{
+ u_int i;
+
+ /* Careful not to overflow object table. */
+ if ((obj + ic->bi_objref_width) > ic->bi_offtab)
+ return (NULL);
+
+ /* Shift in big-endian value. */
+ for (*valp = 0, i = 0; i < ic->bi_objref_width; i++)
+ *valp = (*valp << 8) | *obj++;
+
+ /* Careful not to overflow advised object count. */
+ if (*valp >= ic->bi_object_count)
+ return (NULL);
+
+ return (obj);
+}
+
+/*
+ * Internalizer object decoder routines.
+ */
+
+/*ARGSUSED*/
+static prop_number_t
+_prop_bp_decode_int(_prop_bp_intern_t ic, const uint8_t *obj, bool isuint,
+ uint8_t lo)
+{
+ uint64_t val = 0;
+ u_int nbytes = (1 << lo);
+ u_int i;
+
+ if (nbytes > 8)
+ return (NULL);
+
+ for (i = 0; i < nbytes; i++)
+ val = (val << 8) | *obj++;
+
+ if (isuint)
+ return (prop_number_create_unsigned_integer(val));
+ else
+ return (prop_number_create_integer((int64_t)val));
+}
+
+static prop_array_t
+_prop_bp_decode_array(_prop_bp_intern_t ic, const uint8_t *obj, uint8_t lo)
+{
+ _prop_bp_intern_frame_t bif;
+ prop_array_t pa;
+ u_int nelts;
+
+ /* Read array size (number of contained objects). */
+ if (lo == BPLIST_COUNT_MANY) {
+ obj = _prop_bp_read_int(ic, obj, &nelts);
+ if (obj == NULL)
+ return (NULL);
+ } else
+ nelts = lo;
+
+ /* Create the array. */
+ pa = prop_array_create_with_capacity(nelts);
+ if (pa == NULL)
+ return (NULL);
+
+ /* Initialize stack frame. */
+ bif = _prop_bp_intern_stack_push(ic);
+ if (bif == NULL) {
+ prop_object_release(pa);
+ return (NULL);
+ }
+ bif->if_container = pa;
+ bif->if_buffer = obj;
+ bif->if_count = nelts;
+ bif->if_index = 0;
+
+ return (pa);
+}
+
+static prop_dictionary_t
+_prop_bp_decode_dict(_prop_bp_intern_t ic, const uint8_t *obj, uint8_t lo)
+{
+ _prop_bp_intern_frame_t bif;
+ prop_dictionary_t pd;
+ u_int nelts;
+
+ /* Read dictionary size (number of <key, val> pairs). */
+ if (lo == BPLIST_COUNT_MANY) {
+ obj = _prop_bp_read_int(ic, obj, &nelts);
+ if (obj == NULL)
+ return (NULL);
+ } else
+ nelts = lo;
+
+ /* Create the dictionary. */
+ pd = prop_dictionary_create_with_capacity(nelts);
+ if (pd == NULL)
+ return (NULL);
+
+ /* Initialize stack frame. */
+ bif = _prop_bp_intern_stack_push(ic);
+ if (bif == NULL) {
+ prop_object_release(pd);
+ return (NULL);
+ }
+ bif->if_container = pd;
+ bif->if_keysym = NULL;
+ bif->if_buffer = obj;
+ bif->if_count = (2 * nelts);
+ bif->if_index = 0;
+
+ return (pd);
+}
+
+static prop_string_t
+_prop_bp_decode_ascii(_prop_bp_intern_t ic, const uint8_t *obj, uint8_t lo)
+{
+ prop_string_t ps;
+ u_int size;
+ char *str;
+
+ /* Read string length. */
+ if (lo == BPLIST_COUNT_MANY) {
+ obj = _prop_bp_read_int(ic, obj, &size);
+ if (obj == NULL)
+ return (NULL);
+ } else
+ size = lo;
+
+ /* Are we in bounds of the object table? */
+ if ((obj + size) > ic->bi_offtab)
+ return (NULL);
+
+ str = _PROP_MALLOC(size + 1, M_TEMP);
+ if (str == NULL)
+ return (NULL);
+
+ str[size] = '\0';
+ memcpy(str, obj, size);
+
+ /* XXXfreza this is expensive but we can't donate a buffer to ps */
+ ps = prop_string_create_cstring(str);
+ _PROP_FREE(str, M_TEMP);
+
+ return (ps);
+}
+
+static prop_data_t
+_prop_bp_decode_data(_prop_bp_intern_t ic, const uint8_t *obj, uint8_t lo)
+{
+ u_int size;
+
+ /* Read data length. */
+ if (lo == BPLIST_COUNT_MANY) {
+ obj = _prop_bp_read_int(ic, obj, &size);
+ if (obj == NULL)
+ return (NULL);
+ } else
+ size = lo;
+
+ /* Are we in bounds of the object table? */
+ if ((obj + size) > ic->bi_offtab)
+ return (NULL);
+
+ return (prop_data_create_data(obj, size));
+}
+
+static bool
+_prop_bp_decode_object(_prop_bp_intern_t ic, u_int idx)
+{
+ _prop_bp_intern_frame_t bif;
+ prop_object_t po;
+ const uint8_t *obj;
+ uint8_t hi;
+ uint8_t lo;
+
+ if (! _prop_bp_intern_stack_init(ic))
+ return (false);
+
+ nextobj:
+ /* See if we already have this object, decode otherwise. */
+ po = ic->bi_objects[idx];
+ if (po != NULL)
+ goto gotobj;
+
+ /* Get pointer to encoded object and see what we can do. */
+ obj = _prop_bp_object_pointer(ic, idx);
+ if (obj == NULL)
+ goto fail;
+
+ hi = (*obj & 0xf0); /* Object type tag */
+ lo = (*obj & 0x0f); /* Auxiliary data */
+ obj += 1;
+
+ switch (hi) {
+ case BPLIST_TYPE_MULTI:
+ switch (lo) {
+ case BPLIST_MULTI_FALSE:
+ po = prop_bool_create(false);
+ break;
+
+ case BPLIST_MULTI_TRUE:
+ po = prop_bool_create(true);
+ break;
+
+ default:
+ goto fail;
+ }
+ break;
+
+ case BPLIST_TYPE_UINT:
+ po = _prop_bp_decode_int(ic, obj, true, lo);
+ break;
+
+ case BPLIST_TYPE_SINT:
+ po = _prop_bp_decode_int(ic, obj, false, lo);
+ break;
+
+ case BPLIST_TYPE_ASCII:
+ po = _prop_bp_decode_ascii(ic, obj, lo);
+ break;
+
+ case BPLIST_TYPE_DATA:
+ po = _prop_bp_decode_data(ic, obj, lo);
+ break;
+
+ case BPLIST_TYPE_ARRAY:
+ po = _prop_bp_decode_array(ic, obj, lo);
+ break;
+
+ case BPLIST_TYPE_DICT:
+ po = _prop_bp_decode_dict(ic, obj, lo);
+ break;
+
+ default:
+ goto fail;
+ }
+
+ /* See if decoding was successful, remember object if so. */
+ if (po == NULL)
+ goto fail;
+ ic->bi_objects[idx] = po;
+
+ gotobj:
+ /* Get current compound, if it's a fresh one skip insert step. */
+ bif = _prop_bp_intern_stack_peek(ic);
+ if (bif->if_container == po)
+ goto newcompound;
+
+ insertobj:
+ /* Insert object into its container. */
+ if (prop_object_type(bif->if_container) == PROP_TYPE_DICTIONARY) {
+ if (bif->if_keysym == NULL) {
+ const char *key;
+
+ if (prop_object_type(po) != PROP_TYPE_STRING)
+ goto fail;
+
+ key = prop_string_cstring_nocopy(po);
+ bif->if_keysym = key;
+ } else {
+ if (! prop_dictionary_set(bif->if_container,
+ bif->if_keysym, po))
+ goto fail;
+
+ bif->if_keysym = NULL;
+ }
+ } else
+ if (prop_object_type(bif->if_container) == PROP_TYPE_ARRAY) {
+ if (! prop_array_set(bif->if_container, bif->if_index, po))
+ goto fail;
+ }
+ bif->if_index += 1;
+
+ newcompound:
+ /* See if we've just finished current compound object. */
+ if (bif->if_index == bif->if_count) {
+ if (_prop_bp_intern_stack_pop(ic)) {
+ _prop_bp_intern_stack_free(ic);
+ return (true);
+ }
+
+ /* Restore previous context and re-run insert path. */
+ po = bif->if_container;
+ bif = _prop_bp_intern_stack_peek(ic);
+
+ goto insertobj;
+ }
+
+ /* Get index of next object to work on, re-run decoder. */
+ obj = _prop_bp_read_index(ic, bif->if_buffer, &idx);
+ if (obj == NULL)
+ goto fail;
+ bif->if_buffer = obj;
+
+ goto nextobj;
+
+ fail:
+ _prop_bp_intern_stack_free(ic);
+ return (false);
+}
+
+static prop_object_t
+_prop_bp_internalize(const uint8_t *data, size_t len, prop_type_t type)
+{
+ struct _prop_bp_intern ic;
+ prop_object_t po;
+ const uint8_t *trbase;
+ const uint8_t *obj;
+ uint64_t big;
+ uint8_t val;
+ u_int i;
+
+ /* Is it large enough to make any sense? */
+ if (len <= (BPLIST_HEADER_LEN + BPLIST_TRAILER_LEN))
+ return (NULL);
+
+ /* Does it match the magic marker? */
+ if (memcmp(data, BPLIST_MAGIC, BPLIST_MAGIC_LEN) != 0)
+ return (NULL);
+
+ /* Can we parse this version? */
+ if (data[BPLIST_VERSION_MAJOR_OFFS] != 'Z' ||
+ data[BPLIST_VERSION_MINOR_OFFS] != 'Z')
+ return (NULL);
+
+ /* Decode the trailer, can't do much without it. */
+ trbase = (data + len - BPLIST_TRAILER_LEN);
+ ic.bi_offtab_width = *(trbase + BPLIST_TRAILER_OFFWIDTH_OFFS);
+ ic.bi_objref_width = *(trbase + BPLIST_TRAILER_REFWIDTH_OFFS);
+
+ big = be64dec(trbase + BPLIST_TRAILER_OFFTAB_OFFS);
+ if (big > UINT_MAX)
+ return (NULL);
+ ic.bi_offtab_offset = (u_int)big;
+
+ big = be64dec(trbase + BPLIST_TRAILER_OBJCNT_OFFS);
+ if (big > UINT_MAX)
+ return (NULL);
+ ic.bi_object_count = (u_int)big;
+
+ big = be64dec(trbase + BPLIST_TRAILER_OBJTOP_OFFS);
+ if (big > UINT_MAX)
+ return (NULL);
+ ic.bi_object_first = (u_int)big;
+
+#if 0
+ warnx("bi_offtab_width %u", ic.bi_offtab_width);
+ warnx("bi_objref_width %u", ic.bi_objref_width);
+ warnx("bi_offtab_offset 0x%x", ic.bi_offtab_offset);
+ warnx("bi_object_count %u", ic.bi_object_count);
+ warnx("bi_object_first %u", ic.bi_object_first);
+#endif
+
+ /* Sanity check the trailer. */
+ if (ic.bi_offtab_width == 0 || ic.bi_offtab_width > sizeof(u_int))
+ return (NULL);
+
+ if (ic.bi_objref_width == 0 || ic.bi_objref_width > sizeof(u_int))
+ return (NULL);
+
+ if (ic.bi_offtab_offset >= (len - BPLIST_TRAILER_LEN) ||
+ ic.bi_offtab_offset <= BPLIST_HEADER_LEN)
+ return (NULL);
+
+ if (ic.bi_object_count > (len - ic.bi_offtab_offset -
+ BPLIST_TRAILER_LEN)/ic.bi_offtab_width)
+ return (NULL);
+
+ if (ic.bi_object_first >= ic.bi_object_count)
+ return (NULL);
+
+ /* Setup remaining internalizer context. */
+ ic.bi_offtab = (data + ic.bi_offtab_offset);
+ ic.bi_buffer = data;
+ ic.bi_length = len;
+
+ /* Check toplevel object type before we waste more time. */
+ obj = _prop_bp_object_pointer(&ic, ic.bi_object_first);
+ if (obj == NULL)
+ return (NULL);
+ val = (*obj & 0xf0);
+
+ if ((type == PROP_TYPE_DICTIONARY && val != BPLIST_TYPE_DICT) ||
+ (type == PROP_TYPE_ARRAY && val != BPLIST_TYPE_ARRAY))
+ return (NULL);
+
+ /* Initialize object table. */
+ ic.bi_objects = _PROP_MALLOC(sizeof(prop_object_t) *
+ ic.bi_object_count, M_TEMP);
+ if (ic.bi_objects == NULL)
+ return (NULL);
+ memset(ic.bi_objects, 0, sizeof(prop_object_t) * ic.bi_object_count);
+
+ /* Parse toplevel object. */
+ if (_prop_bp_decode_object(&ic, ic.bi_object_first))
+ po = ic.bi_objects[ic.bi_object_first];
+ else
+ po = NULL;
+
+ /* Release initial object references, except for toplevel one. */
+ for (i = 0; i < ic.bi_object_count; i++)
+ if (ic.bi_objects[i] != NULL && i != ic.bi_object_first)
+ prop_object_release(ic.bi_objects[i]);
+
+ _PROP_FREE(ic.bi_objects, M_TEMP);
+ return (po);
+}
+
+/*
+ * Public internalizer interface.
+ */
+
+prop_dictionary_t
+prop_dictionary_binary_internalize(uint8_t *data, size_t len)
+{
+ return (_prop_bp_internalize(data, len, PROP_TYPE_DICTIONARY));
+}
+
+prop_array_t
+prop_array_binary_internalize(uint8_t *data, size_t len)
+{
+ return (_prop_bp_internalize(data, len, PROP_TYPE_ARRAY));
+}
+
+/*
+ * Externalizer utility routines.
+ */
+
+static uint8_t
+_prop_bp_number_logsize(uint64_t val)
+{
+ /* Calculate log2(number of bytes to represent value). */
+ if (val & 0xffffffff00000000ULL)
+ return (3);
+ else
+ if (val & 0x00000000ffff0000ULL)
+ return (2);
+ else
+ if (val & 0x000000000000ff00ULL)
+ return (1);
+
+ return (0);
+}
+
+static u_int
+_prop_bp_number_size(uint64_t val)
+{
+ if (val <= 0x00000000000000ffULL)
+ return (1);
+ else
+ if (val <= 0x000000000000ffffULL)
+ return (2);
+ else
+ if (val <= 0x0000000000ffffffULL)
+ return (3);
+ else
+ if (val <= 0x00000000ffffffffULL)
+ return (4);
+ else
+ if (val <= 0x000000ffffffffffULL)
+ return (5);
+ else
+ if (val <= 0x0000ffffffffffffULL)
+ return (6);
+ else
+ if (val <= 0x00ffffffffffffffULL)
+ return (7);
+
+ return (8);
+}
+
+static _prop_bp_extern_t
+_prop_bp_extern_init(prop_object_t po)
+{
+ _prop_bp_extern_t be;
+ _prop_bp_table_t tab;
+ size_t size;
+ u_int i;
+
+ be = _PROP_MALLOC(sizeof(struct _prop_bp_extern), M_TEMP);
+ if (be == NULL)
+ return (NULL);
+
+ size = (BPLIST_INCREMENT_SMALL * sizeof(struct _prop_bp_object));
+
+ /* Initialize object tables. */
+ for (i = 0; i < BPLIST_TABLE_COUNT; i++) {
+ tab = &be->be_tables[i];
+
+ tab->bt_objects = _PROP_MALLOC(size, M_TEMP);
+ if (tab->bt_objects == NULL)
+ goto fail;
+
+ tab->bt_depth = BPLIST_INCREMENT_SMALL;
+ tab->bt_next = 0;
+ }
+
+ /* Register toplevel compound (as object 0). */
+ tab = &be->be_tables[BPLIST_TABLE_COMPOUND];
+ tab->bt_objects[0].bo_object = po;
+ tab->bt_objects[0].bo_index = 0;
+ tab->bt_next = 1;
+
+ be->be_index_next = 1;
+
+ /* Initialize externalize buffer. */
+ be->be_extern_buffer = _PROP_MALLOC(BPLIST_INCREMENT_LARGE, M_TEMP);
+ if (be->be_extern_buffer == NULL)
+ goto fail;
+
+ be->be_extern_size = BPLIST_INCREMENT_LARGE;
+ be->be_extern_next = 0;
+
+ return (be);
+
+ fail:
+ /* Note 'i' unsigned. */
+ for (; i > 0; i--) {
+ tab = &be->be_tables[i - 1];
+
+ _PROP_FREE(tab->bt_objects, M_TEMP);
+ }
+ if (be != NULL)
+ _PROP_FREE(be, M_TEMP);
+
+ return (NULL);
+}
+
+static void
+_prop_bp_extern_free(_prop_bp_extern_t be)
+{
+ u_int i;
+
+ for (i = 0; i < BPLIST_TABLE_COUNT; i++)
+ _PROP_FREE(be->be_tables[i].bt_objects, M_TEMP);
+
+ /* Externalize buffer managed by caller. */
+ _PROP_FREE(be, M_TEMP);
+}
+
+static uint8_t *
+_prop_bp_ensure_capacity(_prop_bp_extern_t be, u_int size)
+{
+ uint8_t *start;
+ u_int newsize;
+ void *p;
+
+ retry:
+ if ((be->be_extern_next + size) < be->be_extern_size) {
+ start = &be->be_extern_buffer[be->be_extern_next];
+ be->be_extern_next += size;
+
+ return (start);
+ }
+
+ newsize = (be->be_extern_size + size);
+ newsize = _PROP_ROUNDUP(newsize, BPLIST_INCREMENT_LARGE);
+
+ /* Fail if we've gone insanely large (integer overflow). */
+ if (newsize < be->be_extern_size)
+ return (NULL);
+
+ p = _PROP_REALLOC(be->be_extern_buffer, newsize, M_TEMP);
+ if (p == NULL)
+ return (NULL);
+
+ be->be_extern_buffer = p;
+ be->be_extern_size = newsize;
+
+ /* We'll definitely make it this time. */
+ goto retry;
+}
+
+static bool
+_prop_bp_table_insert(_prop_bp_table_t tab, prop_object_t po, u_int idx)
+{
+ _prop_bp_object_t bo;
+ u_int count;
+ u_int size;
+ void *p;
+
+ retry:
+ if (tab->bt_next < tab->bt_depth) {
+ bo = &tab->bt_objects[tab->bt_next];
+ bo->bo_object = po;
+ bo->bo_index = idx;
+
+ tab->bt_next += 1;
+ return (true);
+ }
+
+ count = (tab->bt_depth + BPLIST_INCREMENT_SMALL);
+ size = (count * sizeof(struct _prop_bp_object));
+ p = _PROP_REALLOC(tab->bt_objects, size, M_TEMP);
+ if (p == NULL)
+ return (false);
+
+ tab->bt_objects = p;
+ tab->bt_depth = count;
+
+ /* We'll definitely make it this time. */
+ goto retry;
+}
+
+/*
+ * Externalizer object utility routines.
+ */
+
+static u_int
+_prop_bp_compound_count(prop_object_t po)
+{
+ if (prop_object_type(po) == PROP_TYPE_DICTIONARY)
+ return (prop_dictionary_count(po));
+
+ return (prop_array_count(po));
+}
+
+static bool
+_prop_bp_compound_equals(prop_object_t po1, prop_object_t po2)
+{
+ if (prop_object_type(po1) != prop_object_type(po2))
+ return (false);
+
+ if (_prop_bp_compound_count(po1) == 0 &&
+ _prop_bp_compound_count(po2) == 0)
+ return (true);
+
+ return (po1 == po2);
+}
+
+static size_t
+_prop_bp_string_size(prop_object_t po)
+{
+ if (prop_object_type(po) == PROP_TYPE_STRING)
+ return (prop_string_size(po));
+
+ return (strlen(prop_dictionary_keysym_cstring_nocopy(po)));
+}
+
+static const char *
+_prop_bp_string_cstring(prop_object_t po)
+{
+ if (prop_object_type(po) == PROP_TYPE_STRING)
+ return (prop_string_cstring_nocopy(po));
+
+ return (prop_dictionary_keysym_cstring_nocopy(po));
+}
+
+static bool
+_prop_bp_string_equals(prop_object_t po1, prop_object_t po2)
+{
+ const char *s1 = _prop_bp_string_cstring(po1);
+ const char *s2 = _prop_bp_string_cstring(po2);
+
+ return (strcmp(s1, s2) == 0);
+}
+
+/*
+ * Externalizer object table query routines.
+ */
+
+/* XXXfreza all _prop_bp_index_of_${table}() are O(n), optimise! */
+
+static bool
+_prop_bp_index_of_single(_prop_bp_table_t tab, prop_object_t po, u_int *np)
+{
+ u_int i;
+
+ /* Don't uniquify data --> rare occurence & unlikely duplicity. */
+ if (np == NULL) {
+ if (prop_object_type(po) != PROP_TYPE_BOOL)
+ return (false);
+ }
+
+ /* Booleans are singletons, we treat data as such too. */
+ for (i = 0; i < tab->bt_next; i++)
+ if (tab->bt_objects[i].bo_object == po) {
+ if (np != NULL)
+ *np = tab->bt_objects[i].bo_index;
+
+ return (true);
+ }
+
+ return (false);
+}
+
+static bool
+_prop_bp_index_of_number(_prop_bp_table_t tab, prop_object_t po, u_int *np)
+{
+ u_int i;
+
+ for (i = 0; i < tab->bt_next; i++)
+ if (prop_number_equals(tab->bt_objects[i].bo_object, po)) {
+ if (np != NULL)
+ *np = tab->bt_objects[i].bo_index;
+
+ return (true);
+ }
+
+ return (false);
+}
+
+static bool
+_prop_bp_index_of_string(_prop_bp_table_t tab, prop_object_t po, u_int *np)
+{
+ u_int i;
+
+ for (i = 0; i < tab->bt_next; i++)
+ if (_prop_bp_string_equals(tab->bt_objects[i].bo_object, po)) {
+ if (np != NULL)
+ *np = tab->bt_objects[i].bo_index;
+
+ return (true);
+ }
+
+ return (false);
+}
+
+static bool
+_prop_bp_index_of_compound(_prop_bp_table_t tab, prop_object_t po, u_int *np)
+{
+ u_int i;
+
+ /* Only uniquify empty compounds --> comparison too expensive. */
+ if (np == NULL) {
+ if (_prop_bp_compound_count(po) != 0)
+ return (false);
+ }
+
+ for (i = 0; i < tab->bt_next; i++)
+ if (_prop_bp_compound_equals(tab->bt_objects[i].bo_object,
+ po)) {
+ if (np != NULL)
+ *np = tab->bt_objects[i].bo_index;
+
+ return (true);
+ }
+
+ return (false);
+}
+
+static void
+_prop_bp_table_resolve(_prop_bp_extern_t be, prop_type_t type,
+ _prop_bp_table_lookup_t *lookup, _prop_bp_table_t *table)
+{
+ switch (type) {
+ case PROP_TYPE_BOOL:
+ case PROP_TYPE_DATA:
+ *lookup = _prop_bp_index_of_single;
+ *table = &be->be_tables[BPLIST_TABLE_SINGLE];
+ break;
+
+ case PROP_TYPE_NUMBER:
+ *lookup = _prop_bp_index_of_number;
+ *table = &be->be_tables[BPLIST_TABLE_NUMBER];
+ break;
+
+ case PROP_TYPE_DICT_KEYSYM:
+ case PROP_TYPE_STRING:
+ *lookup = _prop_bp_index_of_string;
+ *table = &be->be_tables[BPLIST_TABLE_STRING];
+ break;
+
+ case PROP_TYPE_ARRAY:
+ case PROP_TYPE_DICTIONARY:
+ *lookup = _prop_bp_index_of_compound;
+ *table = &be->be_tables[BPLIST_TABLE_COMPOUND];
+ break;
+
+ case PROP_TYPE_UNKNOWN: /* gcc */
+ break;
+ }
+}
+
+static u_int
+_prop_bp_index_of_object(_prop_bp_extern_t be, prop_object_t po)
+{
+ _prop_bp_table_lookup_t lookup;
+ _prop_bp_table_t tab;
+ u_int idx = UINT_MAX;
+
+ _prop_bp_table_resolve(be, prop_object_type(po), &lookup, &tab);
+
+ /* This is bound to succeed from where it's called. */
+ (void)lookup(tab, po, &idx);
+
+ /* But double-check in debug builds. */
+ _PROP_ASSERT(idx < UINT_MAX);
+
+ return (idx);
+}
+
+static bool
+_prop_bp_uniquify_object(_prop_bp_extern_t be, prop_object_t compound,
+ prop_object_t po)
+{
+ _prop_bp_table_lookup_t lookup;
+ _prop_bp_table_t tab;
+ prop_type_t type;
+
+ again:
+ type = prop_object_type(po);
+ _prop_bp_table_resolve(be, type, &lookup, &tab);
+
+ /* Make sure compound doesn't mutate or die under our hands. */
+ if (type == PROP_TYPE_DICTIONARY)
+ _prop_dictionary_rdlock(po);
+ else
+ if (type == PROP_TYPE_ARRAY)
+ _prop_array_rdlock(po);
+
+ /* If object is already held by appropriate table, we're done. */
+ if (lookup(tab, po, NULL)) {
+ if (prop_object_type(po) == PROP_TYPE_DICT_KEYSYM)
+ goto keysym;
+
+ return (true);
+ }
+
+ /* Careful to fail in insane cases. */
+ if (be->be_index_next == UINT_MAX)
+ return (false);
+
+ /* Remember a new unique object. */
+ if (! _prop_bp_table_insert(tab, po, be->be_index_next++))
+ return (false);
+
+ keysym:
+ /* If we've handled keysym, go on with object it refers to. */
+ if (prop_object_type(po) == PROP_TYPE_DICT_KEYSYM) {
+ po = prop_dictionary_get_keysym(compound, po);
+ if (po == NULL)
+ return (false);
+
+ /* Note that sane dicts mustn't hold keysym elements. */
+ goto again;
+ }
+
+ return (true);
+}
+
+/*
+ * Externalizer encoder utility routines.
+ */
+
+static uint8_t *
+_prop_bp_write_byte(uint8_t *obj, uint8_t val)
+{
+ *obj = val;
+
+ return (obj + 1);
+}
+
+static uint8_t *
+_prop_bp_write_number(uint8_t *obj, u_int val)
+{
+ uint8_t lo = _prop_bp_number_logsize(val);
+ int i;
+
+ /* Write object tag. */
+ obj = _prop_bp_write_byte(obj, BPLIST_TYPE_UINT | lo);
+
+ /* Write big-endian value. */
+ for (i = 8*((1 << lo) - 1); i >= 0; i -= 8)
+ obj = _prop_bp_write_byte(obj, val >> i);
+
+ return (obj);
+}
+
+static uint8_t *
+_prop_bp_write_reference(_prop_bp_extern_t be, uint8_t *obj, u_int val)
+{
+ int i;
+
+ _PROP_ASSERT(val < be->be_index_next);
+
+ /* Write big-endian value. */
+ for (i = 8*(be->be_objref_width - 1); i >= 0; i -= 8)
+ obj = _prop_bp_write_byte(obj, val >> i);
+
+ return (obj);
+}
+
+static void
+_prop_bp_write_offset(_prop_bp_extern_t be, uint8_t *offtab,
+ _prop_bp_object_t bo)
+{
+ uint8_t *obj = (offtab + bo->bo_index * be->be_offtab_width);
+ u_int val = bo->bo_offset;
+ int i;
+
+ /* Write big-endian value. */
+ for (i = 8*(be->be_offtab_width - 1); i >= 0; i -= 8)
+ obj = _prop_bp_write_byte(obj, val >> i);
+}
+
+static bool
+_prop_bp_write_offtab(_prop_bp_extern_t be)
+{
+ _prop_bp_table_t tab;
+ uint8_t *offtab;
+ u_int size = (be->be_offtab_width * be->be_index_next);
+ u_int i;
+ u_int j;
+
+ offtab = _prop_bp_ensure_capacity(be, size);
+ if (offtab == NULL)
+ return (false);
+
+ for (i = 0; i < BPLIST_TABLE_COUNT; i++) {
+ tab = &be->be_tables[i];
+
+ for (j = 0; j < tab->bt_next; j++)
+ _prop_bp_write_offset(be, offtab, &tab->bt_objects[j]);
+ }
+
+ return (true);
+}
+
+static uint8_t *
+_prop_bp_write_wide(uint8_t *obj, u_int val)
+{
+ be64enc(obj, val);
+
+ return (obj + 8);
+}
+
+static bool
+_prop_bp_write_trailer(_prop_bp_extern_t be)
+{
+ uint8_t *trailer;
+
+ trailer = _prop_bp_ensure_capacity(be, BPLIST_TRAILER_LEN);
+ if (trailer == NULL)
+ return (false);
+
+ /* Write trailer, note we always have toplevel object at index 0. */
+ trailer = _prop_bp_write_byte(trailer, be->be_offtab_width);
+ trailer = _prop_bp_write_byte(trailer, be->be_objref_width);
+ trailer = _prop_bp_write_wide(trailer, be->be_index_next);
+ trailer = _prop_bp_write_wide(trailer, 0);
+ trailer = _prop_bp_write_wide(trailer, be->be_offtab_start);
+
+ return (true);
+}
+
+/*
+ * Externalize object encoders.
+ */
+
+static uint8_t *
+_prop_bp_encode_bool(_prop_bp_extern_t be, prop_bool_t pb)
+{
+ uint8_t *obj;
+
+ obj = _prop_bp_ensure_capacity(be, 1);
+ if (obj == NULL)
+ return (false);
+
+ if (prop_bool_true(pb))
+ obj = _prop_bp_write_byte(obj, BPLIST_MULTI_TRUE);
+ else
+ obj = _prop_bp_write_byte(obj, BPLIST_MULTI_FALSE);
+
+ return (obj);
+}
+
+static uint8_t *
+_prop_bp_encode_number(_prop_bp_extern_t be, prop_number_t pn)
+{
+ uint64_t big;
+ uint8_t *obj;
+ uint8_t tag;
+ uint8_t low;
+ int i;
+
+ if (prop_number_unsigned(pn)) {
+ big = prop_number_unsigned_integer_value(pn);
+ low = _prop_bp_number_logsize(big);
+ tag = (low | BPLIST_TYPE_UINT);
+ } else {
+ big = (uint64_t)prop_number_integer_value(pn);
+ low = _prop_bp_number_logsize(big);
+ tag = (low | BPLIST_TYPE_SINT);
+ }
+
+ obj = _prop_bp_ensure_capacity(be, BPLIST_NUMBER_MAXLEN);
+ if (obj == NULL)
+ return (NULL);
+
+ /* Write object tag. */
+ obj = _prop_bp_write_byte(obj, tag);
+
+ /* Write big-endian value. */
+ for (i = 8*((1 << low) - 1); i >= 0; i -= 8)
+ obj = _prop_bp_write_byte(obj, (uint8_t)(big >> i));
+
+ return (obj);
+}
+
+static uint8_t *
+_prop_bp_encode_data(_prop_bp_extern_t be, prop_data_t pd)
+{
+ uint8_t *obj;
+ size_t size = prop_data_size(pd);
+ uint8_t lo;
+
+ if (size < BPLIST_COUNT_MANY)
+ lo = size;
+ else
+ lo = BPLIST_COUNT_MANY;
+
+ obj = _prop_bp_ensure_capacity(be, 1 + BPLIST_NUMBER_MAXLEN + size);
+ if (obj == NULL)
+ return (NULL);
+
+ /* Write type tag. */
+ obj = _prop_bp_write_byte(obj, BPLIST_TYPE_DATA | lo);
+
+ /* Possibly followed by integer size. */
+ if (lo == BPLIST_COUNT_MANY)
+ obj = _prop_bp_write_number(obj, size);
+
+ /* Write byte array. */
+ memcpy(obj, prop_data_data_nocopy(pd), size);
+ return (obj + size);
+}
+
+static uint8_t *
+_prop_bp_encode_string(_prop_bp_extern_t be, prop_object_t po)
+{
+ uint8_t *obj;
+ size_t size = _prop_bp_string_size(po);
+ uint8_t lo;
+
+ if (size < BPLIST_COUNT_MANY)
+ lo = size;
+ else
+ lo = BPLIST_COUNT_MANY;
+
+ obj = _prop_bp_ensure_capacity(be, 1 + BPLIST_NUMBER_MAXLEN + size);
+ if (obj == NULL)
+ return (NULL);
+
+ /* Write type tag. */
+ obj = _prop_bp_write_byte(obj, BPLIST_TYPE_ASCII | lo);
+
+ /* Possibly followed by integer size. */
+ if (lo == BPLIST_COUNT_MANY)
+ obj = _prop_bp_write_number(obj, size);
+
+ /* Write character array. */
+ memcpy(obj, _prop_bp_string_cstring(po), size);
+ return (obj + size);
+}
+
+static uint8_t *
+_prop_bp_encode_array(_prop_bp_extern_t be, prop_array_t pa)
+{
+ prop_object_iterator_t it;
+ prop_object_t po;
+ uint8_t *obj;
+ uint8_t lo;
+ u_int count = prop_array_count(pa);
+ u_int idx;
+
+ if (count < BPLIST_COUNT_MANY)
+ lo = count;
+ else
+ lo = BPLIST_COUNT_MANY;
+
+ obj = _prop_bp_ensure_capacity(be, 1 + BPLIST_NUMBER_MAXLEN +
+ count * be->be_objref_width);
+ if (obj == NULL)
+ return (NULL);
+
+ /* Write type tag. */
+ obj = _prop_bp_write_byte(obj, BPLIST_TYPE_ARRAY | lo);
+
+ /* Possibly followed by integer count. */
+ if (lo == BPLIST_COUNT_MANY)
+ obj = _prop_bp_write_number(obj, count);
+
+ /* Write object reference table. */
+ it = prop_array_iterator(pa);
+ if (it == NULL)
+ return (NULL);
+
+ while ((po = prop_object_iterator_next(it)) != NULL) {
+ idx = _prop_bp_index_of_object(be, po);
+ obj = _prop_bp_write_reference(be, obj, idx);
+ }
+
+ prop_object_iterator_release(it);
+ return (obj);
+}
+
+static uint8_t *
+_prop_bp_encode_dict(_prop_bp_extern_t be, prop_dictionary_t pd)
+{
+ prop_object_iterator_t it;
+ prop_object_t po;
+ prop_object_t qo;
+ uint8_t *obj;
+ uint8_t lo;
+ u_int count = prop_dictionary_count(pd);
+ u_int idx;
+
+ if (count < BPLIST_COUNT_MANY)
+ lo = count;
+ else
+ lo = BPLIST_COUNT_MANY;
+
+ obj = _prop_bp_ensure_capacity(be, 1 + BPLIST_NUMBER_MAXLEN +
+ 2 * count * be->be_objref_width);
+ if (obj == NULL)
+ return (NULL);
+
+ /* Write type tag. */
+ obj = _prop_bp_write_byte(obj, BPLIST_TYPE_DICT | lo);
+
+ /* Possibly followed by integer count. */
+ if (lo == BPLIST_COUNT_MANY)
+ obj = _prop_bp_write_number(obj, count);
+
+ /* Write object reference table. */
+ it = prop_dictionary_iterator(pd);
+ if (it == NULL)
+ return (NULL);
+
+ /* Write out <keyref, objref> pairs. */
+ while ((po = prop_object_iterator_next(it)) != NULL) {
+ idx = _prop_bp_index_of_object(be, po);
+ obj = _prop_bp_write_reference(be, obj, idx);
+
+ qo = prop_dictionary_get_keysym(pd, po);
+ _PROP_ASSERT(qo != NULL);
+
+ idx = _prop_bp_index_of_object(be, qo);
+ obj = _prop_bp_write_reference(be, obj, idx);
+ }
+
+ prop_object_iterator_release(it);
+ return (obj);
+}
+
+static bool
+_prop_bp_encode_object(_prop_bp_extern_t be, _prop_bp_object_t bo)
+{
+ prop_object_t po = bo->bo_object;
+ uint8_t *end = NULL; /* gcc */
+
+ /* Remember offset where object starts. */
+ bo->bo_offset = be->be_extern_next;
+
+ switch (prop_object_type(po)) {
+ case PROP_TYPE_BOOL:
+ end = _prop_bp_encode_bool(be, po);
+ break;
+
+ case PROP_TYPE_NUMBER:
+ end = _prop_bp_encode_number(be, po);
+ break;
+
+ case PROP_TYPE_DATA:
+ end = _prop_bp_encode_data(be, po);
+ break;
+
+ case PROP_TYPE_DICT_KEYSYM:
+ case PROP_TYPE_STRING:
+ end = _prop_bp_encode_string(be, po);
+ break;
+
+ case PROP_TYPE_ARRAY:
+ end = _prop_bp_encode_array(be, po);
+ break;
+
+ case PROP_TYPE_DICTIONARY:
+ end = _prop_bp_encode_dict(be, po);
+ break;
+
+ case PROP_TYPE_UNKNOWN: /* gcc */
+ return (false);
+ }
+
+ if (end == NULL)
+ return (false);
+
+ /* Adjust to real encoding length. */
+ be->be_extern_next = (end - be->be_extern_buffer);
+ return (true);
+}
+
+static void
+_prop_bp_unlock_compounds(_prop_bp_table_t compounds)
+{
+ prop_object_t compound;
+ u_int i;
+
+ /* Unlock all compounds, in reverse order (Note 'i' unsigned). */
+ for (i = compounds->bt_next; i > 0; i--) {
+ compound = compounds->bt_objects[i - 1].bo_object;
+
+ if (prop_object_type(compound) == PROP_TYPE_DICTIONARY)
+ _prop_dictionary_unlock(compound);
+ else
+ _prop_array_unlock(compound);
+ }
+}
+
+static bool
+_prop_bp_externalize(_prop_bp_extern_t be)
+{
+ prop_object_iterator_t it;
+ _prop_bp_table_t compounds = &be->be_tables[BPLIST_TABLE_COMPOUND];
+ prop_object_t compound;
+ prop_object_t po;
+ u_int i;
+ u_int j;
+
+ /* Build object tables, obtaining readlock on any compound. */
+ for (i = 0; i < compounds->bt_next; i++) {
+ compound = compounds->bt_objects[i].bo_object;
+
+ /* Get iterator for this compound. */
+ if (prop_object_type(compound) == PROP_TYPE_DICTIONARY)
+ it = prop_dictionary_iterator(compound);
+ else
+ it = prop_array_iterator(compound);
+ if (it == NULL) {
+ _prop_bp_unlock_compounds(compounds);
+ return (false);
+ }
+
+ /* Register contents, possibly mutating table's bt_next. */
+ while ((po = prop_object_iterator_next(it)) != NULL)
+ if (! _prop_bp_uniquify_object(be, compound, po)) {
+ _prop_bp_unlock_compounds(compounds);
+ return (false);
+ }
+
+ prop_object_iterator_release(it);
+ }
+
+ /* Calculate object reference width. */
+ be->be_objref_width = _prop_bp_number_size(be->be_index_next);
+
+ /* Encode header. */
+ memcpy(be->be_extern_buffer, "bplistZZ", BPLIST_HEADER_LEN);
+ be->be_extern_next = BPLIST_HEADER_LEN;
+
+ /* Encode object table, fills object offsets. */
+ for (i = 0; i < BPLIST_TABLE_COUNT; i++) {
+ _prop_bp_table_t tab = &be->be_tables[i];
+
+ for (j = 0; j < tab->bt_next; j++)
+ if (! _prop_bp_encode_object(be,
+ &tab->bt_objects[j])) {
+ _prop_bp_unlock_compounds(compounds);
+ return (false);
+ }
+ }
+
+ /* We won't touch objects any more, release locks. */
+ _prop_bp_unlock_compounds(compounds);
+
+ /* Calculate offset table width. */
+ be->be_offtab_width = _prop_bp_number_size(be->be_extern_next);
+
+ /* Emit offset table. */
+ be->be_offtab_start = be->be_extern_next;
+
+ if (! _prop_bp_write_offtab(be))
+ return (false);
+
+ /* Emit trailer structure. */
+ if (! _prop_bp_write_trailer(be))
+ return (false);
+
+ return (true);
+}
+
+static bool
+_prop_bp_externalize_object(prop_object_t po, prop_type_t type, uint8_t **dp,
+ size_t *lp)
+{
+ _prop_bp_extern_t be;
+ bool rv;
+
+ if (prop_object_type(po) != type || dp == NULL || lp == NULL)
+ return (false);
+
+ be = _prop_bp_extern_init(po);
+ if (be == NULL)
+ return (false);
+
+ rv = _prop_bp_externalize(be);
+ if (rv) {
+ *dp = be->be_extern_buffer;
+ *lp = be->be_extern_next;
+ } else {
+ _PROP_FREE(be->be_extern_buffer, M_TEMP);
+ }
+
+ _prop_bp_extern_free(be);
+ return (rv);
+}
+
+/*
+ * Public externalizer interface.
+ */
+
+bool
+prop_dictionary_binary_externalize(prop_dictionary_t pd, uint8_t **dp,
+ size_t *lp)
+{
+ return (_prop_bp_externalize_object(pd, PROP_TYPE_DICTIONARY, dp, lp));
+}
+
+bool
+prop_array_binary_externalize(prop_array_t pa, uint8_t **dp, size_t *lp)
+{
+ return (_prop_bp_externalize_object(pa, PROP_TYPE_ARRAY, dp, lp));
+}
Index: common/lib/libprop/prop_dictionary.3
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_dictionary.3,v
retrieving revision 1.8
diff -d -p -u -u -r1.8 prop_dictionary.3
--- common/lib/libprop/prop_dictionary.3 16 Aug 2007 16:31:00 -0000 1.8
+++ common/lib/libprop/prop_dictionary.3 6 Oct 2007 20:14:31 -0000
@@ -60,6 +60,9 @@
.Nm prop_dictionary_internalize ,
.Nm prop_dictionary_externalize_to_file ,
.Nm prop_dictionary_internalize_from_file ,
+.Nm prop_dictionary_binary_externalize,
+.Nm prop_dictionary_binary_internalize,
+.Nm prop_dictionary_binary_externalize_to_file,
.Nm prop_dictionary_equals ,
.Nm prop_dictionary_keysym_cstring_nocopy ,
.Nm prop_dictionary_keysym_equals
@@ -68,7 +71,6 @@
.Lb libprop
.Sh SYNOPSIS
.In prop/proplib.h
-.\"
.Ft prop_dictionary_t
.Fn prop_dictionary_create "void"
.Ft prop_dictionary_t
@@ -136,6 +138,15 @@
.Ft prop_dictionary_t
.Fn prop_dictionary_internalize_from_file "const char *path"
.\"
+.Ft bool
+.Fn prop_dictionary_binary_externalize "prop_dictionary_t dict" \
+ "uint8_t **bufp" "size_t *lenp"
+.Ft prop_dictionary_t
+.Fn prop_dictionary_binary_internalize "uint8_t *buf" "size_t len"
+.Ft bool
+.Fn prop_dictionary_binary_externalize_to_file "prop_dictionary_t dict" \
+ "const char *path"
+.\"
.Sh DESCRIPTION
The
.Nm prop_dictionary
@@ -292,7 +303,7 @@ Returns
if parsing fails for any reason.
.It Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \
"const char *path"
-Externalizes a dictionary and writes it to the file specified by
+Externalizes a dictionary in XML format and writes it to the file specified by
.Fa path .
The file is saved with the mode
.Dv 0666
@@ -303,9 +314,51 @@ Returns
.Dv false
if externalizing or writing the dictionary fails for any reason.
.It Fn prop_dictionary_internalize_from_file "const char *path"
-Reads the XML property list contained in the file specified by
+Reads the XML or binary property list contained in the file specified by
.Fa path ,
-internalizes it, and returns the corresponding array.
+internalizes it, and returns the corresponding dictionary.
+.It Fn prop_dictionary_binary_externalize "prop_dictionary_t dict" \
+ "uint8_t **bufp" "size_t *lenp"
+Externalizes a dictionary in binary format. On success
+.Dv true
+is returned, pointer to buffer containing binary representation is filled to
+.Fa bufp
+and its size is filled to
+.Fa lenp
+arguments. The caller is responsible for freeing returned buffer. On failure
+.Dv false
+is returned and arguments are not modified.
+.Pp
+In user space, the buffer is allocated using
+.Xr malloc 3 .
+In the kernel, the buffer is allocated using
+.Xr malloc 9
+using the malloc type
+.Dv M_TEMP .
+.It Fn prop_dictionary_binary_externalize_to_file "prop_dictionary_t dict" \
+ "const char *path"
+Externalizes a dictionary in binary format and writes it to the file
+specified by
+.Fa path .
+The file is saved with the mode
+.Dv 0666
+as modified by the process's file creation mask
+.Pq see Xr umask 3
+and is written atomically.
+Returns
+.Dv false
+if externalizing or writing the dictionary fails for any reason.
+.It Fn prop_dictionary_binary_internalize "uint8_t *buf" "size_t len"
+Parse the binary representation of a property list in the buffer
+.Fa buf
+of size
+.Fa len
+and return the corresponding dictionary.
+Returns
+.Dv true
+on success,
+.Dv false
+if parsing fails for any reason.
.El
.Sh SEE ALSO
.Xr prop_array 3 ,
@@ -320,3 +373,6 @@ The
.Nm proplib
property container object library first appeared in
.Nx 4.0 .
+.Pp
+Support for binary external representation appeared in
+.Nx 5.0 .
Index: common/lib/libprop/prop_dictionary.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_dictionary.c,v
retrieving revision 1.20
diff -d -p -u -u -r1.20 prop_dictionary.c
--- common/lib/libprop/prop_dictionary.c 30 Aug 2007 12:23:54 -0000 1.20
+++ common/lib/libprop/prop_dictionary.c 6 Oct 2007 20:14:32 -0000
@@ -158,6 +158,24 @@ struct _prop_dictionary_iterator {
unsigned int pdi_index;
};
+void
+_prop_dictionary_rdlock(prop_object_t po)
+{
+ prop_dictionary_t pd = po;
+
+ _PROP_ASSERT(prop_object_is_dictionary(pd));
+ _PROP_RWLOCK_RDLOCK(pd->pd_rwlock);
+}
+
+void
+_prop_dictionary_unlock(prop_object_t po)
+{
+ prop_dictionary_t pd = po;
+
+ _PROP_ASSERT(prop_object_is_dictionary(pd));
+ _PROP_RWLOCK_UNLOCK(pd->pd_rwlock);
+}
+
/*
* Dictionary key symbols are immutable, and we are likely to have many
* duplicated key symbols. So, to save memory, we unique'ify key symbols
@@ -1279,7 +1297,7 @@ prop_dictionary_internalize(const char *
#if !defined(_KERNEL) && !defined(_STANDALONE)
/*
* prop_dictionary_externalize_to_file --
- * Externalize a dictionary to the specified file.
+ * Externalize a dictionary to the specified file in XML format.
*/
bool
prop_dictionary_externalize_to_file(prop_dictionary_t dict, const char *fname)
@@ -1301,6 +1319,33 @@ prop_dictionary_externalize_to_file(prop
return (rv);
}
+
+/*
+ * prop_dictionary_binary_externalize_to_file --
+ * Externalize a dictionary to the specified file in bplist format.
+ */
+bool
+prop_dictionary_binary_externalize_to_file(prop_dictionary_t dict,
+ const char *fname)
+{
+ uint8_t *buf;
+ size_t len;
+ bool rv;
+ int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */
+
+ if (! prop_dictionary_binary_externalize(dict, &buf, &len))
+ return (false);
+
+ rv = _prop_object_externalize_write_file(fname, (char *)buf, len);
+ if (rv == false)
+ save_errno = errno;
+ _PROP_FREE(buf, M_TEMP);
+ if (rv == false)
+ errno = save_errno;
+
+ return (rv);
+}
+
/*
* prop_dictionary_internalize_from_file --
* Internalize a dictionary from a file.
@@ -1314,7 +1359,11 @@ prop_dictionary_internalize_from_file(co
mf = _prop_object_internalize_map_file(fname);
if (mf == NULL)
return (NULL);
- dict = prop_dictionary_internalize(mf->poimf_xml);
+ dict = prop_dictionary_internalize((char *)mf->poimf_data);
+ if (dict == NULL) {
+ dict = prop_dictionary_binary_internalize(mf->poimf_data,
+ mf->poimf_datasize);
+ }
_prop_object_internalize_unmap_file(mf);
return (dict);
Index: common/lib/libprop/prop_object.c
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_object.c,v
retrieving revision 1.17
diff -d -p -u -u -r1.17 prop_object.c
--- common/lib/libprop/prop_object.c 30 Aug 2007 19:12:32 -0000 1.17
+++ common/lib/libprop/prop_object.c 6 Oct 2007 20:14:33 -0000
@@ -926,6 +926,7 @@ _prop_object_internalize_map_file(const
_PROP_FREE(mf, M_TEMP);
return (NULL);
}
+ mf->poimf_datasize = (size_t)sb.st_size;
mf->poimf_mapsize = ((size_t)sb.st_size + pgmask) & ~pgmask;
if (mf->poimf_mapsize < sb.st_size) {
(void) close(fd);
@@ -941,22 +942,22 @@ _prop_object_internalize_map_file(const
if ((sb.st_size & pgmask) == 0)
need_guard = true;
- mf->poimf_xml = mmap(NULL, need_guard ? mf->poimf_mapsize + pgsize
+ mf->poimf_data = mmap(NULL, need_guard ? mf->poimf_mapsize + pgsize
: mf->poimf_mapsize,
PROT_READ, MAP_FILE|MAP_SHARED, fd, (off_t)0);
(void) close(fd);
- if (mf->poimf_xml == MAP_FAILED) {
+ if (mf->poimf_data == MAP_FAILED) {
_PROP_FREE(mf, M_TEMP);
return (NULL);
}
- (void) madvise(mf->poimf_xml, mf->poimf_mapsize, MADV_SEQUENTIAL);
+ (void) madvise(mf->poimf_data, mf->poimf_mapsize, MADV_SEQUENTIAL);
if (need_guard) {
- if (mmap(mf->poimf_xml + mf->poimf_mapsize,
+ if (mmap(mf->poimf_data + mf->poimf_mapsize,
pgsize, PROT_READ,
MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1,
(off_t)0) == MAP_FAILED) {
- (void) munmap(mf->poimf_xml, mf->poimf_mapsize);
+ (void) munmap(mf->poimf_data, mf->poimf_mapsize);
_PROP_FREE(mf, M_TEMP);
return (NULL);
}
@@ -975,8 +976,8 @@ _prop_object_internalize_unmap_file(
struct _prop_object_internalize_mapped_file *mf)
{
- (void) madvise(mf->poimf_xml, mf->poimf_mapsize, MADV_DONTNEED);
- (void) munmap(mf->poimf_xml, mf->poimf_mapsize);
+ (void) madvise(mf->poimf_data, mf->poimf_mapsize, MADV_DONTNEED);
+ (void) munmap(mf->poimf_data, mf->poimf_mapsize);
_PROP_FREE(mf, M_TEMP);
}
#endif /* !_KERNEL && !_STANDALONE */
Index: common/lib/libprop/prop_object_impl.h
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/prop_object_impl.h,v
retrieving revision 1.18
diff -d -p -u -u -r1.18 prop_object_impl.h
--- common/lib/libprop/prop_object_impl.h 30 Aug 2007 12:23:54 -0000 1.18
+++ common/lib/libprop/prop_object_impl.h 6 Oct 2007 20:14:33 -0000
@@ -45,6 +45,7 @@
#include <inttypes.h>
#endif
+#include <prop/prop_object.h>
#include "prop_stack.h"
struct _prop_object_externalize_context {
@@ -159,7 +160,8 @@ bool _prop_object_externalize_write_file
const char *, size_t);
struct _prop_object_internalize_mapped_file {
- char * poimf_xml;
+ uint8_t *poimf_data;
+ size_t poimf_datasize;
size_t poimf_mapsize;
};
@@ -232,6 +234,12 @@ struct _prop_object_iterator {
uint32_t pi_version;
};
+/* Private APIs published by prop_{array,dictionary}.c */
+void _prop_dictionary_rdlock(prop_object_t);
+void _prop_dictionary_unlock(prop_object_t);
+void _prop_array_rdlock(prop_object_t);
+void _prop_array_unlock(prop_object_t);
+
#if defined(_KERNEL)
/*
Index: common/lib/libprop/proplib.3
===================================================================
RCS file: /cvsroot/src/common/lib/libprop/proplib.3,v
retrieving revision 1.4
diff -d -p -u -u -r1.4 proplib.3
--- common/lib/libprop/proplib.3 21 Jun 2007 12:02:31 -0000 1.4
+++ common/lib/libprop/proplib.3 6 Oct 2007 20:14:34 -0000
@@ -55,12 +55,14 @@ Structure is provided by the array and d
.Pp
Property lists can be passed across protection boundaries by translating
them to an external representation.
-This external representation is an XML document whose format is described
-by the following DTD:
+This external representation is either an XML document whose format is
+described by the following DTD:
.Bd -literal -offset indent
http://www.apple.com/DTDs/PropertyList-1.0.dtd
.Ed
.Pp
+or a binary format based on Apple bplist encoding.
+.Pp
Property container objects are reference counted.
When an object is created, its reference count is set to 1.
Any code that keeps a reference to an object, including the collection
@@ -142,3 +144,22 @@ in kernel, standalone, and user space en
.Nm
parser is not a real XML parser.
It is hard-coded to parse only the property list external representation.
+.Pp
+The binary encoding differs from Apple bplist format in the following
+ways:
+.Bl -bullet
+.It
+NetBSD uses type marker 0x10 for unsigned integers while in Apple format,
+which doesn't really support unsigned integers, it is used to denote signed
+integers.
+.It
+NetBSD uses type marker 0x70 for signed integers while in Apple format
+it is reserved for future use.
+.It
+NetBSD encodes dictionary contents as <keyref objref>* while Apple uses
+<keyref* objref*>.
+.El
+.Pp
+Given the above incompatibilities, NetBSD binary plists are marked as
+version 'ZZ' of the format. Apple uses version '00' as of the time of
+this writing.
Index: common/include/prop/prop_array.h
===================================================================
RCS file: /cvsroot/src/common/include/prop/prop_array.h,v
retrieving revision 1.5
diff -d -p -u -u -r1.5 prop_array.h
--- common/include/prop/prop_array.h 16 Aug 2007 16:28:17 -0000 1.5
+++ common/include/prop/prop_array.h 6 Oct 2007 20:14:34 -0000
@@ -69,6 +69,12 @@ bool prop_array_equals(prop_array_t, pr
char * prop_array_externalize(prop_array_t);
prop_array_t prop_array_internalize(const char *);
+bool prop_array_binary_externalize(prop_array_t, uint8_t **,
+ size_t *);
+prop_array_t prop_array_binary_internalize(uint8_t *, size_t);
+
+bool prop_array_binary_externalize_to_file(prop_array_t,
+ const char *);
bool prop_array_externalize_to_file(prop_array_t, const char *);
prop_array_t prop_array_internalize_from_file(const char *);
Index: common/include/prop/prop_dictionary.h
===================================================================
RCS file: /cvsroot/src/common/include/prop/prop_dictionary.h,v
retrieving revision 1.7
diff -d -p -u -u -r1.7 prop_dictionary.h
--- common/include/prop/prop_dictionary.h 16 Aug 2007 16:28:17 -0000 1.7
+++ common/include/prop/prop_dictionary.h 6 Oct 2007 20:14:34 -0000
@@ -80,6 +80,12 @@ bool prop_dictionary_equals(prop_dictio
char * prop_dictionary_externalize(prop_dictionary_t);
prop_dictionary_t prop_dictionary_internalize(const char *);
+bool prop_dictionary_binary_externalize(prop_dictionary_t,
+ uint8_t **, size_t *);
+prop_dictionary_t prop_dictionary_binary_internalize(uint8_t *, size_t);
+
+bool prop_dictionary_binary_externalize_to_file(prop_dictionary_t,
+ const char *);
bool prop_dictionary_externalize_to_file(prop_dictionary_t,
const char *);
prop_dictionary_t prop_dictionary_internalize_from_file(const char *);
Index: lib/libprop/Makefile
===================================================================
RCS file: /cvsroot/src/lib/libprop/Makefile,v
retrieving revision 1.14
diff -d -p -u -u -r1.14 Makefile
--- lib/libprop/Makefile 27 Oct 2006 01:29:37 -0000 1.14
+++ lib/libprop/Makefile 6 Oct 2007 20:14:34 -0000
@@ -73,6 +73,9 @@ MLINKS+= prop_array.3 prop_array_make_im
MLINKS+= prop_array.3 prop_array_mutable.3
MLINKS+= prop_array.3 prop_array_remove.3
MLINKS+= prop_array.3 prop_array_set.3
+MLINKS+= prop_array.3 prop_array_binary_externalize.3
+MLINKS+= prop_array.3 prop_array_binary_internalize.3
+MLINKS+= prop_array.3 prop_array_binary_externalize_to_file.3
MLINKS+= prop_bool.3 prop_bool_copy.3
MLINKS+= prop_bool.3 prop_bool_create.3
@@ -111,6 +114,9 @@ MLINKS+= prop_dictionary.3 prop_dictiona
MLINKS+= prop_dictionary.3 prop_dictionary_remove_keysym.3
MLINKS+= prop_dictionary.3 prop_dictionary_set.3
MLINKS+= prop_dictionary.3 prop_dictionary_set_keysym.3
+MLINKS+= prop_dictionary.3 prop_dictionary_binary_externalize.3
+MLINKS+= prop_dictionary.3 prop_dictionary_binary_internalize.3
+MLINKS+= prop_dictionary.3 prop_dictionary_binary_externalize_to_file.3
MLINKS+= prop_ingest.3 prop_ingest_context_alloc.3
MLINKS+= prop_ingest.3 prop_ingest_context_error.3