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 27 Oct 2007 15:47:14 -0000 @@ -66,9 +66,15 @@ void prop_array_remove(prop_array_t, un bool prop_array_equals(prop_array_t, prop_array_t); -char * prop_array_externalize(prop_array_t); -prop_array_t prop_array_internalize(const char *); +char *prop_array_externalize(prop_array_t); +prop_array_t prop_array_internalize(const uint8_t *, size_t); +bool prop_array_externalize_with_encoding(prop_array_t, uint8_t **, + size_t *, + prop_encoding_t); +bool prop_array_externalize_to_file_with_encoding(prop_array_t, + const char *, + prop_encoding_t); 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 27 Oct 2007 15:47:14 -0000 @@ -77,9 +77,17 @@ void prop_dictionary_remove_keysym(prop bool prop_dictionary_equals(prop_dictionary_t, prop_dictionary_t); -char * prop_dictionary_externalize(prop_dictionary_t); -prop_dictionary_t prop_dictionary_internalize(const char *); +prop_dictionary_t prop_dictionary_internalize(const uint8_t *, size_t); +char *prop_dictionary_externalize(prop_dictionary_t); +bool prop_dictionary_externalize_with_encoding(prop_dictionary_t, + uint8_t **, + size_t *, + prop_encoding_t); +bool prop_dictionary_externalize_to_file_with_encoding( + prop_dictionary_t, + const char *, + prop_encoding_t); bool prop_dictionary_externalize_to_file(prop_dictionary_t, const char *); prop_dictionary_t prop_dictionary_internalize_from_file(const char *); Index: common/include/prop/prop_number.h =================================================================== RCS file: /cvsroot/src/common/include/prop/prop_number.h,v retrieving revision 1.5 diff -d -p -u -u -r1.5 prop_number.h --- common/include/prop/prop_number.h 16 Aug 2007 16:28:17 -0000 1.5 +++ common/include/prop/prop_number.h 27 Oct 2007 15:47:14 -0000 @@ -58,6 +58,7 @@ bool prop_number_unsigned(prop_number_t int64_t prop_number_integer_value(prop_number_t); uint64_t prop_number_unsigned_integer_value(prop_number_t); +int prop_number_compare(prop_number_t, prop_number_t); bool prop_number_equals(prop_number_t, prop_number_t); bool prop_number_equals_integer(prop_number_t, int64_t); bool prop_number_equals_unsigned_integer(prop_number_t, uint64_t); Index: common/include/prop/prop_object.h =================================================================== RCS file: /cvsroot/src/common/include/prop/prop_object.h,v retrieving revision 1.6 diff -d -p -u -u -r1.6 prop_object.h --- common/include/prop/prop_object.h 30 Aug 2007 12:23:53 -0000 1.6 +++ common/include/prop/prop_object.h 27 Oct 2007 15:47:14 -0000 @@ -58,6 +58,12 @@ typedef enum { PROP_TYPE_DICT_KEYSYM = 0x646b6579 /* 'dkey' */ } prop_type_t; +typedef enum { + PROP_ENCODING_DEFAULT = 0, + PROP_ENCODING_XML = 1, + PROP_ENCODING_BINARY = 2 +} prop_encoding_t; + __BEGIN_DECLS void prop_object_retain(prop_object_t); void prop_object_release(prop_object_t); 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 27 Oct 2007 15:47:14 -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 27 Oct 2007 15:47:14 -0000 @@ -54,8 +54,10 @@ .Nm prop_array_add , .Nm prop_array_remove , .Nm prop_array_externalize , +.Nm prop_array_externalize_with_encoding , .Nm prop_array_internalize , .Nm prop_array_externalize_to_file , +.Nm prop_array_externalize_to_file_with_encoding , .Nm prop_array_internalize_from_file , .Nm prop_array_equals .Nd array property collection object @@ -101,7 +103,14 @@ .Ft char * .Fn prop_array_externalize "prop_array_t array" .Ft prop_array_t -.Fn prop_array_internalize "const char *xml" +.Fn prop_array_internalize "const uint8_t *buf" "size_t len" +.\" +.Ft bool +.Fn prop_array_externalize_with_encoding "prop_array_t array" \ + "uint8_t **bufp" "size_t *lenp" "prop_encoding_t enc" +.Ft bool +.Fn prop_array_externalize_to_file_with_encoding "prop_array_t array" \ + "const char *path" "prop_encoding_t enc" .\" .Ft bool .Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" @@ -222,16 +231,31 @@ In the kernel, the buffer is allocated u .Xr malloc 9 using the malloc type .Dv M_TEMP . -.It Fn prop_array_internalize "const char *xml" -Parse the XML representation of a property list in the NUL-terminated -buffer -.Fa xml -and return the corresponding array. +.It Fn prop_array_externalize_with_encoding "prop_array_t array" \ + "uint8_t **bufp" "size_t *lenp" "prop_encoding_t enc" +Externalizes an array using encoding +.Fa enc . +On success returns +.Dv true +and fills buffer address and length to +.Fa bufp +and +.Fa lenp +respectively. On failure, +.Dv false +is returned and no arguments are modified. +.It Fn prop_array_internalize "const uint8_t *buf" "size_t len" +Parse any supported encoding of a property list in the buffer +.Fa buf +of length +.Fa len +bytes and return the corresponding array. Returns .Dv NULL if parsing fails for any reason. .It Fn prop_array_externalize_to_file "prop_array_t array" "const char *path" -Externalizes an array and writes it to the file specified by +Externalizes an array in default encoding and writes it to the file specified +by .Fa path . The file is saved with the mode .Dv 0666 @@ -241,10 +265,19 @@ and is written atomically. Returns .Dv false if externalizing or writing the array fails for any reason. +.It Fn prop_array_externalize_to_file_with_encoding "prop_array_t array" \ + "const char *path" "prop_encoding_t enc" +Like +.Xr prop_array_externalize_to_file 3 +but use encoding +.Fa enc . .It Fn prop_array_internalize_from_file "const char *path" -Reads the XML property list contained in the file specified by -.Fa path , -internalizes it, and returns the corresponding array. +Reads the property list contained in the file specified by +.Fa path +regardless of its encoding, internalizes it, and returns the corresponding +array. Should reading or parsing fail for any reason, +.Dv NULL +is returned. .El .Sh SEE ALSO .Xr prop_bool 3 , 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 27 Oct 2007 15:47:14 -0000 @@ -91,6 +91,28 @@ struct _prop_array_iterator { #define EXPAND_STEP 16 +void +_prop_array_rdlock(prop_object_t po) +{ +#if !defined(_STANDALONE) + prop_array_t pa = po; + + _PROP_ASSERT(prop_object_is_array(pa)); + _PROP_RWLOCK_RDLOCK(pa->pa_rwlock); +#endif +} + +void +_prop_array_unlock(prop_object_t po) +{ +#if !defined(_STANDALONE) + prop_array_t pa = po; + + _PROP_ASSERT(prop_object_is_array(pa)); + _PROP_RWLOCK_UNLOCK(pa->pa_rwlock); +#endif +} + static int _prop_array_free(prop_stack_t stack, prop_object_t *obj) { @@ -702,21 +724,14 @@ prop_array_equals(prop_array_t array1, p return (prop_object_equals(array1, array2)); } -/* - * prop_array_externalize -- - * Externalize an array, return a NUL-terminated buffer - * containing the XML-style representation. The buffer is allocated - * with the M_TEMP memory type. - */ -char * -prop_array_externalize(prop_array_t pa) +static bool +_prop_array_xml_externalize(prop_array_t pa, uint8_t **bufp, size_t *lenp) { struct _prop_object_externalize_context *ctx; - char *cp; ctx = _prop_object_externalize_context_alloc(); if (ctx == NULL) - return (NULL); + return (false); if (_prop_object_externalize_header(ctx) == false || (*pa->pa_obj.po_type->pot_extern)(ctx, pa) == false || @@ -724,13 +739,61 @@ prop_array_externalize(prop_array_t pa) /* We are responsible for releasing the buffer. */ _PROP_FREE(ctx->poec_buf, M_TEMP); _prop_object_externalize_context_free(ctx); - return (NULL); + return (false); } - cp = ctx->poec_buf; + *bufp = (uint8_t *)ctx->poec_buf; + *lenp = ctx->poec_len; _prop_object_externalize_context_free(ctx); - return (cp); + return (true); +} + +/* + * prop_array_externalize -- + * Like prop_array_externalize_with_encoding() below, using XML. + */ +char * +prop_array_externalize(prop_array_t pa) +{ + uint8_t *buf; + size_t len; + + if (! prop_array_externalize_with_encoding(pa, &buf, &len, + PROP_ENCODING_XML)) + return (NULL); + + return ((char *)buf); +} + +/* + * prop_array_externalize_with_encoding -- + * Externalize an array in given encoding, on success return true + * and set buffer pointer and length arguments; otherwise return + * false and don't fill any values. The buffer is allocated with + * the M_TEMP memory type. + */ +bool +prop_array_externalize_with_encoding(prop_array_t pa, uint8_t **bufp, + size_t *lenp, prop_encoding_t enc) +{ + _PROP_ASSERT(bufp != NULL && lenp != NULL); + + if (! prop_object_is_array(pa)) + return (false); + + switch (enc) { + case PROP_ENCODING_BINARY: + return (_prop_bp_externalize_object(pa, PROP_TYPE_ARRAY, bufp, + lenp)); + + case PROP_ENCODING_DEFAULT: + case PROP_ENCODING_XML: + return (_prop_array_xml_externalize(pa, bufp, lenp)); + } + + /* LINTED silly gcc */ + return (false); } /* @@ -829,30 +892,54 @@ _prop_array_internalize_body(prop_stack_ * Create an array by parsing the XML-style representation. */ prop_array_t -prop_array_internalize(const char *xml) +prop_array_internalize(const uint8_t *buf, size_t len) { - return _prop_generic_internalize(xml, "array"); + _PROP_ASSERT(buf != NULL && len > 0); + + switch (buf[0]) { + case 'b': + return (_prop_bp_internalize(buf, len, PROP_TYPE_ARRAY)); + case '<': + return (_prop_generic_internalize((const char *)buf, "array")); + } + + return (NULL); } #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) { - char *xml; + return (prop_array_externalize_to_file_with_encoding(array, + fname, PROP_ENCODING_DEFAULT)); +} + +/* + * prop_array_externalize_to_file_with_encoding -- + * Externalize an array to the specified file in XML format. + */ +bool +prop_array_externalize_to_file_with_encoding(prop_array_t array, + const char *fname, prop_encoding_t enc) +{ + uint8_t *buf; + size_t len; bool rv; int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ - xml = prop_array_externalize(array); - if (xml == NULL) + if (! prop_array_externalize_with_encoding(array, &buf, &len, enc)) { + errno = EINVAL; return (false); - rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); + } + + rv = _prop_object_externalize_write_file(fname, buf, len); if (rv == false) save_errno = errno; - _PROP_FREE(xml, M_TEMP); + _PROP_FREE(buf, M_TEMP); if (rv == false) errno = save_errno; @@ -872,7 +959,8 @@ 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(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 27 Oct 2007 15:47:15 -0000 @@ -0,0 +1,1810 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2007 Jachym Holecek . + * 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 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 + +#include +#include "prop_object_impl.h" +#include "prop_rb_impl.h" + +#if defined(_KERNEL) || defined(_STANDALONE) +#include +#else +#include +#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_node *_prop_bp_object_t; +typedef struct _prop_bp_table *_prop_bp_table_t; +typedef struct _prop_bp_uniq_node *_prop_bp_uniq_node_t; +typedef struct _prop_bp_uniq_list *_prop_bp_uniq_list_t; +typedef union _prop_bp_uniq_value *_prop_bp_uniq_value_t; + +/* Entry in uniqified object table. */ +struct _prop_bp_node { + prop_object_t bo_object; + u_int *bo_reftab; /* compounds */ + u_int bo_index; + u_int bo_offset; +}; + +/* Uniquified RB-tree string/integer value. */ +union _prop_bp_uniq_value { + struct { + const char *bsv_string; + uint32_t bsv_hash; + } bv__string; + prop_number_t bv_number; +}; + +#define bv_string bv__string.bsv_string +#define bv_hash bv__string.bsv_hash + +/* Entry in uniquified string/integer RB-tree. */ +struct _prop_bp_uniq_node { + struct rb_node bu_rb; /* must be head */ + SLIST_ENTRY(_prop_bp_uniq_node) bu_link; + union _prop_bp_uniq_value bu_value; + u_int bu_index; + u_int bu_offset; +}; + +#define _PROP_UNCONST(a) \ + ((void *)(unsigned long)(const void *)(a)) + +/* Unique node/value accessors and conversions. */ +#define BPLIST_UNODE_TO_VALUE(node) \ + (&((_prop_bp_uniq_node_t)_PROP_UNCONST(node))->bu_value) + +#define BPLIST_UNODE_TO_INDEX(node) \ + (((_prop_bp_uniq_node_t)(void *)node)->bu_index) + +#define BPLIST_VOIDP_TO_VALUE(ptr) \ + ((_prop_bp_uniq_value_t)_PROP_UNCONST(ptr)) + +SLIST_HEAD(_prop_bp_uniq_list, _prop_bp_uniq_node); + +/* 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_SINGLE 1 /* bool & data */ +#define BPLIST_TABLE_COUNT 2 /* number of tables */ + +struct _prop_bp_extern { + /* Uniquified compounds (only empty collections unique). */ + struct _prop_bp_table ec_compounds; + u_int ec_empty_array; + u_int ec_empty_dict; + + /* Uniquified booleans and data (only booleans unique). */ + struct _prop_bp_table ec_others; + u_int ec_true; + u_int ec_false; + + /* Uniquified string RB-tree. */ + struct _prop_bp_uniq_list ec_str_list; + struct rb_tree ec_str_tree; + + /* Uniquified numer RB-tree. */ + struct _prop_bp_uniq_list ec_num_list; + struct rb_tree ec_num_tree; + + /* Externalized plist. */ + uint8_t *ec_extern_buffer; + size_t ec_extern_size; + size_t ec_extern_next; + + /* Unique object count (and next object index). */ + u_int ec_index_next; + + /* Trailer values. */ + u_int ec_objref_width; + u_int ec_offtab_width; + u_int ec_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 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); +} + +/* + * Internal API to encoding dispatcher. + */ + +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); +} + +/* + * Externalizer RB-tree comparison routines. + */ + +static int +_prop_rb_str_compare_key(const struct rb_node *node, const void *key) +{ + const _prop_bp_uniq_value_t uv1 = BPLIST_UNODE_TO_VALUE(node); + const _prop_bp_uniq_value_t uv2 = BPLIST_VOIDP_TO_VALUE(key); + + if (uv1->bv_hash > uv2->bv_hash) + return (1); + else + if (uv1->bv_hash < uv2->bv_hash) + return (-1); + + return (strcmp(uv1->bv_string, uv2->bv_string)); +} + +static int +_prop_rb_str_compare_node(const struct rb_node *node1, + const struct rb_node *node2) +{ + const _prop_bp_uniq_value_t uv = BPLIST_UNODE_TO_VALUE(node2); + + return (_prop_rb_str_compare_key(node1, uv)); +} + +static const struct rb_tree_ops _prop_bp_str_rbops = { + .rbto_compare_nodes = _prop_rb_str_compare_node, + .rbto_compare_key = _prop_rb_str_compare_key, +}; + +static int +_prop_rb_num_compare_key(const struct rb_node *node, const void *key) +{ + const _prop_bp_uniq_value_t uv1 = BPLIST_UNODE_TO_VALUE(node); + const _prop_bp_uniq_value_t uv2 = BPLIST_VOIDP_TO_VALUE(key); + + return (prop_number_compare(uv1->bv_number, uv2->bv_number)); +} + +static int +_prop_rb_num_compare_node(const struct rb_node *node1, + const struct rb_node *node2) +{ + const _prop_bp_uniq_value_t uv = BPLIST_UNODE_TO_VALUE(node2); + + return (_prop_rb_num_compare_key(node1, uv)); +} + +static const struct rb_tree_ops _prop_bp_num_rbops = { + .rbto_compare_nodes = _prop_rb_num_compare_node, + .rbto_compare_key = _prop_rb_num_compare_key, +}; + +/* + * 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 bool +_prop_bp_table_init(_prop_bp_table_t tab) +{ + size_t size; + + size = (BPLIST_INCREMENT_SMALL * sizeof(struct _prop_bp_node)); + + tab->bt_objects = _PROP_MALLOC(size, M_TEMP); + if (tab->bt_objects == NULL) + return (false); + + tab->bt_depth = BPLIST_INCREMENT_SMALL; + tab->bt_next = 0; + + return (true); +} + +static _prop_bp_extern_t +_prop_bp_extern_init(prop_object_t po) +{ + _prop_bp_extern_t be; + + be = _PROP_MALLOC(sizeof(struct _prop_bp_extern), M_TEMP); + if (be == NULL) + return (NULL); + + /* Initialize object tables. */ + if (! _prop_bp_table_init(&be->ec_compounds) || + ! _prop_bp_table_init(&be->ec_others)) + goto fail; + + /* Invalidate singular objects references. */ + be->ec_empty_array = UINT_MAX; + be->ec_empty_dict = UINT_MAX; + be->ec_true = UINT_MAX; + be->ec_false = UINT_MAX; + + /* Initialize object RB-trees and lists. */ + _prop_rb_tree_init(&be->ec_str_tree, &_prop_bp_str_rbops); + _prop_rb_tree_init(&be->ec_num_tree, &_prop_bp_num_rbops); + + SLIST_INIT(&be->ec_str_list); + SLIST_INIT(&be->ec_num_list); + + /* Initialize externalize buffer. */ + be->ec_extern_buffer = _PROP_MALLOC(BPLIST_INCREMENT_LARGE, M_TEMP); + if (be->ec_extern_buffer == NULL) + goto fail; + + be->ec_extern_size = BPLIST_INCREMENT_LARGE; + be->ec_extern_next = 0; + + /* Register toplevel compound. */ + be->ec_compounds.bt_objects[0].bo_object = po; + be->ec_compounds.bt_objects[0].bo_index = 0; + be->ec_compounds.bt_next = 1; + + /* Lock toplevel compound so that it doesn't dance under our hands. */ + if (prop_object_type(po) == PROP_TYPE_DICTIONARY) + _prop_dictionary_rdlock(po); + else + _prop_array_rdlock(po); + + /* Toplevel compound has index 0, continue from 1 on. */ + be->ec_index_next = 1; + + return (be); + + fail: + if (be->ec_compounds.bt_objects != NULL) + _PROP_FREE(be->ec_compounds.bt_objects, M_TEMP); + if (be->ec_others.bt_objects != NULL) + _PROP_FREE(be->ec_others.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) +{ + _prop_bp_uniq_node_t unode; + _prop_bp_table_t comptab = &be->ec_compounds; + u_int i; + + /* Free tables of contents for compound objects. */ + for (i = 0; i < comptab->bt_next; i++) + if (comptab->bt_objects[i].bo_reftab != NULL) + _PROP_FREE(comptab->bt_objects[i].bo_reftab, M_TEMP); + + /* Free all uniquification tables. */ + _PROP_ASSERT(be->ec_compounds.bt_objects != NULL); + _PROP_FREE(be->ec_compounds.bt_objects, M_TEMP); + + if (be->ec_others.bt_objects != NULL) + _PROP_FREE(be->ec_others.bt_objects, M_TEMP); + + /* Free all uniquification lists (and thus RB nodes). */ + while ((unode = SLIST_FIRST(&be->ec_str_list)) != NULL) { + SLIST_REMOVE_HEAD(&be->ec_str_list, bu_link); + _PROP_FREE(unode, M_TEMP); + } + + while ((unode = SLIST_FIRST(&be->ec_num_list)) != NULL) { + SLIST_REMOVE_HEAD(&be->ec_num_list, bu_link); + _PROP_FREE(unode, 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->ec_extern_next + size) < be->ec_extern_size) { + start = &be->ec_extern_buffer[be->ec_extern_next]; + be->ec_extern_next += size; + + return (start); + } + + newsize = (be->ec_extern_size + size); + newsize = _PROP_ROUNDUP(newsize, BPLIST_INCREMENT_LARGE); + + /* Fail if we've gone insanely large (integer overflow). */ + if (newsize < be->ec_extern_size) + return (NULL); + + p = _PROP_REALLOC(be->ec_extern_buffer, newsize, M_TEMP); + if (p == NULL) + return (NULL); + + be->ec_extern_buffer = p; + be->ec_extern_size = newsize; + + /* We'll definitely make it this time. */ + goto retry; +} + +static uint32_t +_prop_bp_hash32_string(const char *cstring) +{ + /* XXXfreza cut'n'paste from */ + const uint8_t *s = (const uint8_t *)cstring; + uint32_t hash = 5381; + uint8_t c; + + while ((c = *s++) != 0) + hash = hash * 33 + c; /* "perl": k=33, r=r+r/32 */ + + return (hash + (hash >> 5)); +} + +/* + * Externalizer object uniquifying process. + */ + +static u_int +_prop_bp_put_uniq(_prop_bp_extern_t be, struct rb_tree *tree, + _prop_bp_uniq_list_t list, _prop_bp_uniq_value_t uvp) +{ + _prop_bp_uniq_node_t unode; + struct rb_node *node; + + /* Nothing to do if it's already there. */ + node = _prop_rb_tree_find(tree, uvp); + if (node != NULL) + return (BPLIST_UNODE_TO_INDEX(node)); + + /* Create and insert a new unique object. */ + unode = _PROP_MALLOC(sizeof(struct _prop_bp_uniq_node), M_TEMP); + if (unode == NULL) + return (UINT_MAX); + + unode->bu_value = (*uvp); /* struct copy */ + unode->bu_index = (be->ec_index_next++); + + _prop_rb_tree_insert_node(tree, &unode->bu_rb); + SLIST_INSERT_HEAD(list, unode, bu_link); + + return (unode->bu_index); +} + +static u_int +_prop_bp_put_table(_prop_bp_extern_t be, _prop_bp_table_t tab, + prop_object_t po) +{ + _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 = (be->ec_index_next++); + + tab->bt_next += 1; + return (bo->bo_index); + } + + count = (tab->bt_depth + BPLIST_INCREMENT_SMALL); + size = (count * sizeof(struct _prop_bp_node)); + p = _PROP_REALLOC(tab->bt_objects, size, M_TEMP); + if (p == NULL) + return (UINT_MAX); + + tab->bt_objects = p; + tab->bt_depth = count; + + /* We'll definitely make it this time. */ + goto retry; +} + +static bool +_prop_bp_uniquify(_prop_bp_extern_t be, _prop_bp_object_t bo, + prop_object_t po, u_int np) +{ + union _prop_bp_uniq_value uv; + u_int n = UINT_MAX; /* gcc */ + bool yesno; + bool empty; + + switch (prop_object_type(po)) { + case PROP_TYPE_STRING: + uv.bv_string = prop_string_cstring_nocopy(po); + uv.bv_hash = _prop_bp_hash32_string(uv.bv_string); + + n = _prop_bp_put_uniq(be, &be->ec_str_tree, &be->ec_str_list, + &uv); + break; + + case PROP_TYPE_DICT_KEYSYM: + uv.bv_string = prop_dictionary_keysym_cstring_nocopy(po); + uv.bv_hash = _prop_bp_hash32_string(uv.bv_string); + + n = _prop_bp_put_uniq(be, &be->ec_str_tree, &be->ec_str_list, + &uv); + break; + + case PROP_TYPE_NUMBER: + uv.bv_number = po; + n = _prop_bp_put_uniq(be, &be->ec_num_tree, &be->ec_num_list, + &uv); + break; + + case PROP_TYPE_DICTIONARY: + /* Make sure dict doesn't mutate or die under our hands. */ + _prop_dictionary_rdlock(po); + + empty = (prop_dictionary_count(po) == 0); + if (empty && be->ec_empty_dict != UINT_MAX) { + n = be->ec_empty_dict; + break; + } + + n = _prop_bp_put_table(be, &be->ec_compounds, po); + if (n == UINT_MAX) + _prop_dictionary_unlock(po); + + if (empty) + be->ec_empty_dict = n; + break; + + case PROP_TYPE_ARRAY: + /* Make sure array doesn't mutate or die under our hands. */ + _prop_array_rdlock(po); + + empty = (prop_array_count(po) == 0); + if (empty && be->ec_empty_array != UINT_MAX) { + n = be->ec_empty_array; + break; + } + + n = _prop_bp_put_table(be, &be->ec_compounds, po); + if (n == UINT_MAX) + _prop_array_unlock(po); + + if (empty) + be->ec_empty_array = n; + break; + + case PROP_TYPE_BOOL: + yesno = prop_bool_true(po); + + if (be->ec_true != UINT_MAX && yesno) { + n = be->ec_true; + break; + } + if (be->ec_false != UINT_MAX && !yesno) { + n = be->ec_false; + break; + } + + n = _prop_bp_put_table(be, &be->ec_others, po); + + if (yesno) + be->ec_true = n; + else + be->ec_false = n; + break; + + case PROP_TYPE_DATA: + n = _prop_bp_put_table(be, &be->ec_others, po); + break; + + case PROP_TYPE_UNKNOWN: + /* gcc */ + break; + } + + if (n == UINT_MAX) + return (false); + + bo->bo_reftab[np] = n; + 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->ec_index_next); + + /* Write big-endian value. */ + for (i = 8*(be->ec_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, + u_int idx, u_int offs) +{ + uint8_t *obj = (offtab + idx * be->ec_offtab_width); + int i; + + /* Write big-endian value. */ + for (i = 8*(be->ec_offtab_width - 1); i >= 0; i -= 8) + obj = _prop_bp_write_byte(obj, offs >> i); +} + +static bool +_prop_bp_write_offtab(_prop_bp_extern_t be) +{ + _prop_bp_uniq_node_t uo; + _prop_bp_object_t bo; + uint8_t *offtab; + u_int size = (be->ec_offtab_width * be->ec_index_next); + u_int i; + + offtab = _prop_bp_ensure_capacity(be, size); + if (offtab == NULL) + return (false); + + for (i = 0; i < be->ec_compounds.bt_next; i++) { + bo = &be->ec_compounds.bt_objects[i]; + + _prop_bp_write_offset(be, offtab, bo->bo_index, bo->bo_offset); + } + + for (i = 0; i < be->ec_others.bt_next; i++) { + bo = &be->ec_others.bt_objects[i]; + + _prop_bp_write_offset(be, offtab, bo->bo_index, bo->bo_offset); + } + + SLIST_FOREACH(uo, &be->ec_num_list, bu_link) + _prop_bp_write_offset(be, offtab, uo->bu_index, uo->bu_offset); + + SLIST_FOREACH(uo, &be->ec_str_list, bu_link) + _prop_bp_write_offset(be, offtab, uo->bu_index, uo->bu_offset); + + 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->ec_offtab_width); + trailer = _prop_bp_write_byte(trailer, be->ec_objref_width); + trailer = _prop_bp_write_wide(trailer, be->ec_index_next); + trailer = _prop_bp_write_wide(trailer, 0); + trailer = _prop_bp_write_wide(trailer, be->ec_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_bp_uniq_value_t uv) +{ + uint64_t big; + uint8_t *obj; + uint8_t tag; + uint8_t low; + int i; + + if (prop_number_unsigned(uv->bv_number)) { + big = prop_number_unsigned_integer_value(uv->bv_number); + low = _prop_bp_number_logsize(big); + tag = (low | BPLIST_TYPE_UINT); + } else { + big = prop_number_integer_value(uv->bv_number); + 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_bp_uniq_value_t uv) +{ + uint8_t *obj; + size_t size = strlen(uv->bv_string); + 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, uv->bv_string, size); + return (obj + size); +} + +static uint8_t * +_prop_bp_encode_array(_prop_bp_extern_t be, _prop_bp_object_t bo) +{ + prop_array_t pa = bo->bo_object; + uint8_t *obj; + uint8_t lo; + u_int count; + u_int i; + + count = prop_array_count(pa); + if (count < BPLIST_COUNT_MANY) + lo = count; + else + lo = BPLIST_COUNT_MANY; + + obj = _prop_bp_ensure_capacity(be, 1 + BPLIST_NUMBER_MAXLEN + + count * be->ec_objref_width); + if (obj == NULL) + return (NULL); + + /* Write type tag. */ + obj = _prop_bp_write_byte(obj, BPLIST_TYPE_ARRAY | lo); + + /* For empty array, we're done. */ + if (count == 0) + return (obj); + + /* Possibly followed by integer count. */ + if (lo == BPLIST_COUNT_MANY) + obj = _prop_bp_write_number(obj, count); + + /* Write object reference table. */ + for (i = 0; i < count; i++) + obj = _prop_bp_write_reference(be, obj, bo->bo_reftab[i]); + + return (obj); +} + +static uint8_t * +_prop_bp_encode_dict(_prop_bp_extern_t be, _prop_bp_object_t bo) +{ + prop_dictionary_t pd = bo->bo_object; + uint8_t *obj; + uint8_t lo; + u_int count; + u_int i; + + count = prop_dictionary_count(pd); + 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->ec_objref_width); + if (obj == NULL) + return (NULL); + + /* Write type tag. */ + obj = _prop_bp_write_byte(obj, BPLIST_TYPE_DICT | lo); + + /* For empty dictionary, we're done. */ + if (count == 0) + return (obj); + + /* Possibly followed by integer count. */ + if (lo == BPLIST_COUNT_MANY) + obj = _prop_bp_write_number(obj, count); + + /* Write out pairs. */ + count *= 2; + for (i = 0; i < count; i += 2) { + obj = _prop_bp_write_reference(be, obj, bo->bo_reftab[i]); + obj = _prop_bp_write_reference(be, obj, bo->bo_reftab[i + 1]); + } + + return (obj); +} + +static bool +_prop_bp_encode(_prop_bp_extern_t be) +{ + _prop_bp_uniq_node_t uo; + _prop_bp_object_t bo; + prop_object_t po; + uint8_t *end; + u_int i; + + /* Encode all arrays and dicts. */ + for (i = 0; i < be->ec_compounds.bt_next; i++) { + bo = &be->ec_compounds.bt_objects[i]; + + /* Remember offset where object starts. */ + bo->bo_offset = be->ec_extern_next; + + if (prop_object_type(bo->bo_object) == PROP_TYPE_ARRAY) + end = _prop_bp_encode_array(be, bo); + else + end = _prop_bp_encode_dict(be, bo); + if (end == NULL) + return (false); + + /* Adjust to real encoding length. */ + be->ec_extern_next = (end - be->ec_extern_buffer); + } + + /* Encode all booleans and data. */ + for (i = 0; i < be->ec_others.bt_next; i++) { + bo = &be->ec_others.bt_objects[i]; + po = bo->bo_object; + + /* Remember offset where object starts. */ + bo->bo_offset = be->ec_extern_next; + + if (prop_object_type(po) == PROP_TYPE_BOOL) + end = _prop_bp_encode_bool(be, po); + else + end = _prop_bp_encode_data(be, po); + if (end == NULL) + return (false); + + /* Adjust to real encoding length. */ + be->ec_extern_next = (end - be->ec_extern_buffer); + } + + /* Encode all numbers. */ + SLIST_FOREACH(uo, &be->ec_num_list, bu_link) { + /* Remember offset where object starts. */ + uo->bu_offset = be->ec_extern_next; + + end = _prop_bp_encode_number(be, &uo->bu_value); + if (end == NULL) + return (false); + + /* Adjust to real encoding length. */ + be->ec_extern_next = (end - be->ec_extern_buffer); + } + + /* Encode all strings. */ + SLIST_FOREACH(uo, &be->ec_str_list, bu_link) { + /* Remember offset where object starts. */ + uo->bu_offset = be->ec_extern_next; + + end = _prop_bp_encode_string(be, &uo->bu_value); + if (end == NULL) + return (false); + + /* Adjust to real encoding length. */ + be->ec_extern_next = (end - be->ec_extern_buffer); + } + + return (true); +} + +/* + * Externalizer toplevel routines. + */ + +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_unpack_array(_prop_bp_extern_t be, _prop_bp_object_t bo, + prop_array_t pa) +{ + prop_object_iterator_t it; + prop_object_t po; + size_t size; + u_int count; + u_int j; + + count = prop_array_count(pa); + if (count > 0) { + size = (count * sizeof(u_int)); + + bo->bo_reftab = _PROP_MALLOC(size, M_TEMP); + if (bo->bo_reftab == NULL) + return (false); + } else { + bo->bo_reftab = NULL; + return (true); + } + + it = prop_array_iterator(pa); + if (it == NULL) { + _prop_array_unlock(pa); + return (false); + } + j = 0; + + /* Register contents, possibly mutating compounds' bt_next. */ + while ((po = prop_object_iterator_next(it)) != NULL) + if (! _prop_bp_uniquify(be, bo, po, j++)) { + prop_object_iterator_release(it); + _prop_array_unlock(pa); + return (false); + } + + prop_object_iterator_release(it); + return (true); +} + +static bool +_prop_bp_unpack_dict(_prop_bp_extern_t be, _prop_bp_object_t bo, + prop_dictionary_t pd) +{ + prop_object_iterator_t it; + prop_object_t po; + size_t size; + u_int count; + u_int j; + + count = (2 * prop_dictionary_count(pd)); + if (count > 0) { + size = (count * sizeof(u_int)); + bo->bo_reftab = _PROP_MALLOC(size, M_TEMP); + if (bo->bo_reftab == NULL) + return (false); + } else { + bo->bo_reftab = NULL; + return (true); + } + + it = prop_dictionary_iterator(pd); + if (it == NULL) { + _prop_dictionary_unlock(pd); + return (false); + } + j = 0; + + /* Register contents, possibly mutating compounds' bt_next. */ + while ((po = prop_object_iterator_next(it)) != NULL) { + /* Store keysym at odd index. */ + if (! _prop_bp_uniquify(be, bo, po, j++)) { + prop_object_iterator_release(it); + _prop_dictionary_unlock(pd); + return (false); + } + + /* Store keysym's value at even index. */ + po = prop_dictionary_get_keysym(pd, po); + + if (! _prop_bp_uniquify(be, bo, po, j++)) { + prop_object_iterator_release(it); + _prop_dictionary_unlock(pd); + return (false); + } + } + + prop_object_iterator_release(it); + return (true); +} + +static bool +_prop_bp_externalize(_prop_bp_extern_t be) +{ + _prop_bp_object_t bo; + prop_object_t po; + u_int i; + bool ok; + + /* Build object tables, obtaining readlock on any compound. */ + for (i = 0; i < be->ec_compounds.bt_next; i++) { + bo = &be->ec_compounds.bt_objects[i]; + po = bo->bo_object; + + if (prop_object_type(po) == PROP_TYPE_DICTIONARY) { + _prop_dictionary_rdlock(po); + ok = _prop_bp_unpack_dict(be, bo, po); + } else { + _prop_array_rdlock(po); + ok = _prop_bp_unpack_array(be, bo, po); + } + if (! ok) { + _prop_bp_unlock_compounds(&be->ec_compounds); + return (false); + } + } + + /* Calculate object reference width. */ + be->ec_objref_width = _prop_bp_number_size(be->ec_index_next); + + /* Encode header. */ + memcpy(be->ec_extern_buffer, "bplistZZ", BPLIST_HEADER_LEN); + be->ec_extern_next = BPLIST_HEADER_LEN; + + _PROP_ASSERT(be); + /* Encode object table, fills object offsets. */ + if (! _prop_bp_encode(be)) { + _prop_bp_unlock_compounds(&be->ec_compounds); + return (false); + } + + /* We won't touch objects any more, release locks. */ + _prop_bp_unlock_compounds(&be->ec_compounds); + + /* Calculate offset table width. */ + be->ec_offtab_width = _prop_bp_number_size(be->ec_extern_next); + + /* Emit offset table. */ + be->ec_offtab_start = be->ec_extern_next; + + if (! _prop_bp_write_offtab(be)) + return (false); + + /* Emit trailer structure. */ + if (! _prop_bp_write_trailer(be)) + return (false); + + return (true); +} + +/* + * Internal API to encoding dispatcher. + */ + +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->ec_extern_buffer; + *lp = be->ec_extern_next; + } else { + _PROP_FREE(be->ec_extern_buffer, M_TEMP); + } + + _prop_bp_extern_free(be); + return (rv); +} Index: common/lib/libprop/prop_dictionary.3 =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_dictionary.3,v retrieving revision 1.9 diff -d -p -u -u -r1.9 prop_dictionary.3 --- common/lib/libprop/prop_dictionary.3 11 Oct 2007 03:10:28 -0000 1.9 +++ common/lib/libprop/prop_dictionary.3 27 Oct 2007 15:47:15 -0000 @@ -57,8 +57,9 @@ .Nm prop_dictionary_set_keysym , .Nm prop_dictionary_remove_keysym , .Nm prop_dictionary_externalize , +.Nm prop_dictionary_externalize_with_encoding , .Nm prop_dictionary_internalize , -.Nm prop_dictionary_externalize_to_file , +.Nm prop_dictionary_externalize_to_file_with_encoding , .Nm prop_dictionary_internalize_from_file , .Nm prop_dictionary_equals , .Nm prop_dictionary_keysym_cstring_nocopy , @@ -68,7 +69,6 @@ .Lb libprop .Sh SYNOPSIS .In prop/proplib.h -.\" .Ft prop_dictionary_t .Fn prop_dictionary_create "void" .Ft prop_dictionary_t @@ -127,12 +127,18 @@ .\" .Ft char * .Fn prop_dictionary_externalize "prop_dictionary_t dict" +.Ft bool +.Fn prop_dictionary_externalize_with_encoding "prop_dictionary_t dict" \ + "uint8_t **bufp" "size_t *len" "prop_encoding_t enc" .Ft prop_dictionary_t -.Fn prop_dictionary_internalize "const char *xml" +.Fn prop_dictionary_internalize "const uint8_t *buf" "size_t len" .\" .Ft bool .Fn prop_dictionary_externalize_to_file "prop_dictionary_t dict" \ "const char *path" +.Ft bool +.Fn prop_dictionary_externalize_to_file_with_encoding "prop_dictionary_t dict" \ + "const char *path" "prop_encoding_t enc" .Ft prop_dictionary_t .Fn prop_dictionary_internalize_from_file "const char *path" .\" @@ -282,17 +288,42 @@ In the kernel, the buffer is allocated u .Xr malloc 9 using the malloc type .Dv M_TEMP . -.It Fn prop_dictionary_internalize "const char *xml" -Parse the XML representation of a property list in the NUL-terminated -buffer -.Fa xml +.It Fn prop_dictionary_externalize_with_encoding "prop_dictionary_t dict" \ + "uint8_t **bufp" "size_t *lenp" "prop_encoding_t enc" +Externalize +.Fa dict +using encoding +.Fa enc . +Returs +.Dv true +on success, in which case +.Fa bufp +and +.Fa lenp +arguments are filled with buffer address and length. 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 . +The user is responsible for freeing the buffer. +.It Fn prop_dictionary_internalize "const uint8_t *buf" "size_t len" +Parse any supported representation of a property list in buffer +.Fa buf +of length +.Fa len and return the corresponding dictionary. Returns .Dv NULL 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 default encoding and writes it to the file +specified by .Fa path . The file is saved with the mode .Dv 0666 @@ -302,10 +333,19 @@ and is written atomically. Returns .Dv false if externalizing or writing the dictionary fails for any reason. +.It Fn prop_dictionary_externalize_to_file_with_encoding \ + "prop_dictionary_t dict" "const char *path" "prop_encoding_t enc" +Like +.Xr prop_dictionary_externalize_to_file 3 +but uses encoding +.Fa enc . .It Fn prop_dictionary_internalize_from_file "const char *path" -Reads the XML property list contained in the file specified by +Reads any supported encoding of property list contained in the file specified +by .Fa path , -internalizes it, and returns the corresponding array. +internalizes it, and returns the corresponding dictionary. Returns +.Dv NULL +if reading or parsing fails for any reason. .El .Sh SEE ALSO .Xr prop_array 3 , 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 27 Oct 2007 15:47:16 -0000 @@ -158,6 +158,28 @@ struct _prop_dictionary_iterator { unsigned int pdi_index; }; +void +_prop_dictionary_rdlock(prop_object_t po) +{ +#if !defined(_STANDALONE) + prop_dictionary_t pd = po; + + _PROP_ASSERT(prop_object_is_dictionary(pd)); + _PROP_RWLOCK_RDLOCK(pd->pd_rwlock); +#endif +} + +void +_prop_dictionary_unlock(prop_object_t po) +{ +#if !defined(_STANDALONE) + prop_dictionary_t pd = po; + + _PROP_ASSERT(prop_object_is_dictionary(pd)); + _PROP_RWLOCK_UNLOCK(pd->pd_rwlock); +#endif +} + /* * Dictionary key symbols are immutable, and we are likely to have many * duplicated key symbols. So, to save memory, we unique'ify key symbols @@ -1100,21 +1122,15 @@ prop_dictionary_keysym_equals(prop_dicti return (prop_object_equals(pdk1, pdk2)); } -/* - * prop_dictionary_externalize -- - * Externalize a dictionary, returning a NUL-terminated buffer - * containing the XML-style representation. The buffer is allocated - * with the M_TEMP memory type. - */ -char * -prop_dictionary_externalize(prop_dictionary_t pd) +static bool +_prop_dictionary_xml_externalize(prop_dictionary_t pd, uint8_t **bufp, + size_t *lenp) { struct _prop_object_externalize_context *ctx; - char *cp; ctx = _prop_object_externalize_context_alloc(); if (ctx == NULL) - return (NULL); + return (false); if (_prop_object_externalize_header(ctx) == false || (*pd->pd_obj.po_type->pot_extern)(ctx, pd) == false || @@ -1122,13 +1138,61 @@ prop_dictionary_externalize(prop_diction /* We are responsible for releasing the buffer. */ _PROP_FREE(ctx->poec_buf, M_TEMP); _prop_object_externalize_context_free(ctx); - return (NULL); + return (false); } - cp = ctx->poec_buf; + *bufp = (uint8_t *)ctx->poec_buf; + *lenp = ctx->poec_len; _prop_object_externalize_context_free(ctx); - return (cp); + return (true); +} + +/* + * prop_dictionary_externalize -- + * Like prop_dictionary_externalize_with_encoding(), using XML. + */ +char * +prop_dictionary_externalize(prop_dictionary_t pd) +{ + uint8_t *buf; + size_t len; + + if (! prop_dictionary_externalize_with_encoding(pd, &buf, &len, + PROP_ENCODING_XML)) + return (NULL); + + return ((char *)buf); +} + +/* + * prop_dictionary_externalize_with_encoding -- + * Externalize a dictionary, on success return true and fill buffer + * pointer and length arguments; on failure return false and don't + * modify arguments. The buffer is allocated with the M_TEMP memory + * type. + */ +bool +prop_dictionary_externalize_with_encoding(prop_dictionary_t pd, uint8_t **bufp, + size_t *lenp, prop_encoding_t enc) +{ + _PROP_ASSERT(bufp != NULL && lenp != NULL); + + if (! prop_object_is_dictionary(pd)) + return (false); + + switch (enc) { + case PROP_ENCODING_BINARY: + return (_prop_bp_externalize_object(pd, PROP_TYPE_DICTIONARY, + bufp, lenp)); + + case PROP_ENCODING_DEFAULT: + case PROP_ENCODING_XML: + return (_prop_dictionary_xml_externalize(pd, bufp, lenp)); + } + + /* LINTED silly gcc */ + return (false); } /* @@ -1267,40 +1331,62 @@ _prop_dictionary_internalize_body(prop_s /* * prop_dictionary_internalize -- - * Create a dictionary by parsing the NUL-terminated XML-style - * representation. + * Create a dictionary by decoding any supported representation. */ prop_dictionary_t -prop_dictionary_internalize(const char *xml) +prop_dictionary_internalize(const uint8_t *buf, size_t len) { - return _prop_generic_internalize(xml, "dict"); + _PROP_ASSERT(buf != NULL && len > 0); + + switch (buf[0]) { + case '<': + return (_prop_generic_internalize((const char *)buf, "dict")); + + case 'b': + return (_prop_bp_internalize(buf, len, PROP_TYPE_DICTIONARY)); + } + + return (NULL); } #if !defined(_KERNEL) && !defined(_STANDALONE) +bool +prop_dictionary_externalize_to_file(prop_dictionary_t dict, const char *fname) +{ + return (prop_dictionary_externalize_to_file_with_encoding(dict, + fname, PROP_ENCODING_DEFAULT)); +} + /* * 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) +prop_dictionary_externalize_to_file_with_encoding(prop_dictionary_t dict, + const char *fname, prop_encoding_t enc) { - char *xml; + uint8_t *buf; + size_t len; bool rv; int save_errno = 0; /* XXXGCC -Wuninitialized [mips, ...] */ - xml = prop_dictionary_externalize(dict); - if (xml == NULL) + if (! prop_dictionary_externalize_with_encoding(dict, &buf, &len, + enc)) { + errno = EINVAL; return (false); - rv = _prop_object_externalize_write_file(fname, xml, strlen(xml)); + } + + rv = _prop_object_externalize_write_file(fname, buf, len); if (rv == false) save_errno = errno; - _PROP_FREE(xml, M_TEMP); + _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 +1400,8 @@ 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(mf->poimf_data, mf->poimf_datasize); _prop_object_internalize_unmap_file(mf); return (dict); Index: common/lib/libprop/prop_kern.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_kern.c,v retrieving revision 1.8 diff -d -p -u -u -r1.8 prop_kern.c --- common/lib/libprop/prop_kern.c 16 Aug 2007 21:44:07 -0000 1.8 +++ common/lib/libprop/prop_kern.c 27 Oct 2007 15:47:16 -0000 @@ -125,13 +125,13 @@ _prop_object_unpack_pref(const struct pl prop_object_t *objp) { prop_object_t obj = NULL; - char *buf; + uint8_t *buf; int error = 0; if (pref->pref_len == 0) { /* - * This should never happen; we should always get the XML - * for an empty dictionary if it's really empty. + * This should never happen; even empty objects encode + * on nonzero bytes. */ error = EIO; goto out; @@ -140,10 +140,10 @@ _prop_object_unpack_pref(const struct pl buf[pref->pref_len - 1] = '\0'; /* extra insurance */ switch (type) { case PROP_TYPE_DICTIONARY: - obj = prop_dictionary_internalize(buf); + obj = prop_dictionary_internalize(buf, pref->pref_len); break; case PROP_TYPE_ARRAY: - obj = prop_array_internalize(buf); + obj = prop_array_internalize(buf, pref->pref_len); break; default: error = ENOTSUP; Index: common/lib/libprop/prop_number.c =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_number.c,v retrieving revision 1.14 diff -d -p -u -u -r1.14 prop_number.c --- common/lib/libprop/prop_number.c 30 Aug 2007 12:23:54 -0000 1.14 +++ common/lib/libprop/prop_number.c 27 Oct 2007 15:47:16 -0000 @@ -450,6 +450,20 @@ prop_number_equals(prop_number_t num1, p } /* + * prop_number_compare -- + * Return positive value when pn1 > pn2, zero when pn1 == pn2, negative + * value when pn1 < pn2. + */ +int +prop_number_compare(prop_number_t pn1, prop_number_t pn2) +{ + _PROP_ASSERT(prop_object_is_number(pn1) && prop_object_is_number(pn2)); + + return (_prop_number_compare_values(&pn1->pn_value, &pn2->pn_value)); +} + + +/* * prop_number_equals_integer -- * Return true if the number is equivalent to the specified integer. */ Index: common/lib/libprop/prop_object.3 =================================================================== RCS file: /cvsroot/src/common/lib/libprop/prop_object.3,v retrieving revision 1.6 diff -d -p -u -u -r1.6 prop_object.3 --- common/lib/libprop/prop_object.3 16 Aug 2007 16:31:00 -0000 1.6 +++ common/lib/libprop/prop_object.3 27 Oct 2007 15:47:16 -0000 @@ -132,6 +132,23 @@ by the iterator Release the iterator .Fa iter . .El +.Pp +The library supports external representations described by +.Dv prop_encoding_t +enumeration type: +.Pp +.Bl -tag -width "PROP_ENCODING_DEFAULT" -compact +.It Dv PROP_ENCODING_XML +XML conforming to Apple DTD. Stored in C strings. +.It Dv PROP_ENCODING_BINARY +Derived from Apple "bplist" format. Stored in raw byte arrays. +.It Dv PROP_ENCODING_DEFAULT +Any of the above depending on implementation. +.El +.Pp +Refer to +.Xr proplib 3 +for notes on encoding compatibility. .Sh SEE ALSO .Xr prop_array 3 , .Xr prop_bool 3 , @@ -145,3 +162,6 @@ The .Nm proplib property container object library first appeared in .Nx 4.0 . +.Pp +Support for binary external format first appeared in +.Nx 5.0 . 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 27 Oct 2007 15:47:16 -0000 @@ -841,7 +841,7 @@ _prop_object_externalize_file_dirname(co * and the mode set to 0666 modified by the caller's umask. */ bool -_prop_object_externalize_write_file(const char *fname, const char *xml, +_prop_object_externalize_write_file(const char *fname, const uint8_t *buf, size_t len) { char tname[PATH_MAX]; @@ -874,7 +874,7 @@ _prop_object_externalize_write_file(cons return (false); } - if (write(fd, xml, len) != (ssize_t)len) + if (write(fd, buf, len) != (ssize_t)len) goto bad; if (fsync(fd) == -1) @@ -926,8 +926,10 @@ _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) { + if (mf->poimf_mapsize < mf->poimf_datasize || + mf->poimf_datasize == 0) { (void) close(fd); _PROP_FREE(mf, M_TEMP); return (NULL); @@ -941,22 +943,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 +977,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 27 Oct 2007 15:47:16 -0000 @@ -45,6 +45,7 @@ #include #endif +#include #include "prop_stack.h" struct _prop_object_externalize_context { @@ -155,11 +156,12 @@ void _prop_object_internalize_context_f struct _prop_object_internalize_context *); #if !defined(_KERNEL) && !defined(_STANDALONE) -bool _prop_object_externalize_write_file(const char *, - const char *, size_t); +bool _prop_object_externalize_write_file(const char *, const uint8_t *, + 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,17 @@ 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); + +/* Private APIs publised by prop_bplist.c to encoding dispatchers. */ +prop_object_t _prop_bp_internalize(const uint8_t *, size_t, prop_type_t); +bool _prop_bp_externalize_object(prop_object_t, prop_type_t, + uint8_t **, size_t *); + #if defined(_KERNEL) /* @@ -395,4 +408,6 @@ void * _prop_standalone_realloc(void *, #define _PROP_ARG_UNUSED /* delete */ #endif /* __NetBSD__ */ +#define _PROP_UNCONST(a) ((void *)(unsigned long)(const void *)(a)) + #endif /* _PROPLIB_PROP_OBJECT_IMPL_H_ */ 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 27 Oct 2007 15:47:16 -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 * while Apple uses +. +.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: distrib/sets/lists/comp/mi =================================================================== RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v retrieving revision 1.1071 diff -d -p -u -u -r1.1071 mi --- distrib/sets/lists/comp/mi 7 Oct 2007 13:38:53 -0000 1.1071 +++ distrib/sets/lists/comp/mi 27 Oct 2007 15:47:21 -0000 @@ -5710,7 +5710,9 @@ ./usr/share/man/cat3/prop_array_ensure_capacity.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_equals.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_externalize.0 comp-c-catman .cat +./usr/share/man/cat3/prop_array_externalize_with_encoding.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_externalize_to_file.0 comp-c-catman .cat +./usr/share/man/cat3/prop_array_externalize_to_file_with_encoding.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_get.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_internalize.0 comp-c-catman .cat ./usr/share/man/cat3/prop_array_internalize_from_file.0 comp-c-catman .cat @@ -5745,7 +5747,9 @@ ./usr/share/man/cat3/prop_dictionary_ensure_capacity.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_equals.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_externalize.0 comp-c-catman .cat +./usr/share/man/cat3/prop_dictionary_externalize_with_encoding.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_externalize_to_file.0 comp-c-catman .cat +./usr/share/man/cat3/prop_dictionary_externalize_to_file_with_encoding.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_get.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_get_bool.0 comp-c-catman .cat ./usr/share/man/cat3/prop_dictionary_get_cstring.0 comp-c-catman .cat @@ -10295,7 +10299,9 @@ ./usr/share/man/man3/prop_array_ensure_capacity.3 comp-c-man .man ./usr/share/man/man3/prop_array_equals.3 comp-c-man .man ./usr/share/man/man3/prop_array_externalize.3 comp-c-man .man +./usr/share/man/man3/prop_array_externalize_with_encoding.3 comp-c-man .man ./usr/share/man/man3/prop_array_externalize_to_file.3 comp-c-man .man +./usr/share/man/man3/prop_array_externalize_to_file_with_encoding.3 comp-c-man .man ./usr/share/man/man3/prop_array_get.3 comp-c-man .man ./usr/share/man/man3/prop_array_internalize.3 comp-c-man .man ./usr/share/man/man3/prop_array_internalize_from_file.3 comp-c-man .man @@ -10330,7 +10336,9 @@ ./usr/share/man/man3/prop_dictionary_ensure_capacity.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_equals.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_externalize.3 comp-c-man .man +./usr/share/man/man3/prop_dictionary_externalize_with_encoding.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_externalize_to_file.3 comp-c-man .man +./usr/share/man/man3/prop_dictionary_externalize_to_file_with_encoding.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_get.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_get_bool.3 comp-c-man .man ./usr/share/man/man3/prop_dictionary_get_cstring.3 comp-c-man .man 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 27 Oct 2007 15:47:23 -0000 @@ -64,7 +64,9 @@ MLINKS+= prop_array.3 prop_array_create_ MLINKS+= prop_array.3 prop_array_ensure_capacity.3 MLINKS+= prop_array.3 prop_array_equals.3 MLINKS+= prop_array.3 prop_array_externalize.3 +MLINKS+= prop_array.3 prop_array_externalize_with_encoding.3 MLINKS+= prop_array.3 prop_array_externalize_to_file.3 +MLINKS+= prop_array.3 prop_array_externalize_to_file_with_encoding.3 MLINKS+= prop_array.3 prop_array_get.3 MLINKS+= prop_array.3 prop_array_internalize.3 MLINKS+= prop_array.3 prop_array_internalize_from_file.3 @@ -97,7 +99,9 @@ MLINKS+= prop_dictionary.3 prop_dictiona MLINKS+= prop_dictionary.3 prop_dictionary_ensure_capacity.3 MLINKS+= prop_dictionary.3 prop_dictionary_equals.3 MLINKS+= prop_dictionary.3 prop_dictionary_externalize.3 +MLINKS+= prop_dictionary.3 prop_dictionary_externalize_with_encoding.3 MLINKS+= prop_dictionary.3 prop_dictionary_externalize_to_file.3 +MLINKS+= prop_dictionary.3 prop_dictionary_externalize_to_file_with_encoding.3 MLINKS+= prop_dictionary.3 prop_dictionary_get.3 MLINKS+= prop_dictionary.3 prop_dictionary_get_keysym.3 MLINKS+= prop_dictionary.3 prop_dictionary_internalize.3 Index: regress/lib/libprop/Makefile =================================================================== RCS file: regress/lib/libprop/Makefile diff -N regress/lib/libprop/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/Makefile 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,5 @@ +# $NetBSD$ + +SUBDIR= propbench propconv + +.include Index: regress/lib/libprop/propbench/Makefile =================================================================== RCS file: regress/lib/libprop/propbench/Makefile diff -N regress/lib/libprop/propbench/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/propbench/Makefile 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,32 @@ +# $NetBSD$ + +NOMAN= # set +PROG= plbench +SRCS= main.c + +CPPFLAGS+= -I${NETBSDSRCDIR}/common/include +CPPFLAGS+= -I${NETBSDSRCDIR}/common/lib/libprop + +LDADD+= -static +DPADD+= ${LIBPTHREAD} ${LIBM} +LDADD+= -lpthread -lm +CFLAGS+= -Wall -Werror -g + +.if defined(LOOPS) +PLARGS+= -n ${LOOPS} +.endif + +.if defined(TIMES) +PLARGS+= -v +.endif + +regress: .PHONY ${PROG} + for sample in ${.CURDIR}/../samples/*.xml ;{ \ + ./${PROG} ${PLARGS} $${sample} \ + ;} + +gdb: .PHONY + gdb ${PROG} ${PROG}.core + +.include "${NETBSDSRCDIR}/common/lib/libprop/Makefile.inc" +.include Index: regress/lib/libprop/propbench/main.c =================================================================== RCS file: regress/lib/libprop/propbench/main.c diff -N regress/lib/libprop/propbench/main.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/propbench/main.c 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,423 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2007 Jachym Holecek . + * 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. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const char *path; +static const char *name; +static u_long nloops = 10000; + +static double time_ioctl_xml = 0.0; +static double time_ioctl_bin = 0.0; +static double time_intern_xml = 0.0; +static double time_intern_bin = 0.0; +static double time_extern_xml = 0.0; +static double time_extern_bin = 0.0; +static size_t size_extern_xml; +static size_t size_extern_bin; + +/* + * Utilities. + */ +static prop_object_t +internalize(const char *path) +{ + prop_object_t po; + + po = prop_dictionary_internalize_from_file(path); + if (po == NULL) + po = prop_array_internalize_from_file(path); + + return (po); +} + +static prop_object_t +decode(uint8_t *buf, size_t len) +{ + prop_object_t po; + + po = prop_dictionary_internalize(buf, len); + if (po == NULL) + po = prop_array_internalize(buf, len); + + return (po); +} + +static bool +blistify(prop_object_t po, uint8_t **buf, size_t *len) +{ + if (prop_object_type(po) == PROP_TYPE_DICTIONARY) { + if (prop_dictionary_externalize_with_encoding(po, buf, len, + PROP_ENCODING_BINARY)) + return (true); + } else { + if (prop_array_externalize_with_encoding(po, buf, len, + PROP_ENCODING_BINARY)) + return (true); + } + + return (false); +} + +static bool +xmlify(prop_object_t po, uint8_t **buf, size_t *len) +{ + if (prop_object_type(po) == PROP_TYPE_DICTIONARY) { + if (prop_dictionary_externalize_with_encoding(po, buf, len, + PROP_ENCODING_XML)) + return (true); + } else { + if (prop_array_externalize_with_encoding(po, buf, len, + PROP_ENCODING_XML)) + return (true); + } + + return (false); +} + +double +getpoint(void) +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru) == -1) + err(1, "getrusage"); + + return ((double)ru.ru_utime.tv_sec + + (double)ru.ru_utime.tv_usec/1000000.0); +} + +static void +failed(const char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "FAILED %s ", name); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + + fprintf(stderr, "\n"); + exit(EXIT_FAILURE); +} + +/* + * Regression test, assumes input file is XML. + */ + +static void +regression(void) +{ + prop_object_t po1; /* plist from XML file */ + prop_object_t po2; + uint8_t *buf; + size_t len; + + po1 = internalize(path); + if (po1 == NULL) + failed("internalize XML file"); + + if (! xmlify(po1, &buf, &len)) + failed("externalize XML"); + + po2 = decode(buf, len); + if (po2 == NULL) + failed("internalize XML"); + free(buf); + + if (! prop_object_equals(po1, po2)) + failed("compare XML"); + prop_object_release(po2); + + if (! blistify(po1, &buf, &len)) + failed("externalize binary"); + + po2 = decode(buf, len); + if (po2 == NULL) + failed("internalize binary"); + + if (! prop_object_equals(po1, po2)) + failed("compare binary"); + prop_object_release(po2); + + prop_object_release(po1); +} + +static void +benchmark(void) +{ + prop_object_t po1; + prop_object_t po2; + uint8_t *buf; + uint8_t *tmp; + size_t len; + double beg; + int i; + + po1 = internalize(path); + if (po1 == NULL) + failed("benchmark: internalize XML file"); + + /* How long does XML internalize take? */ + if (! xmlify(po1, &buf, &len)) + failed("benchmark: prepare XML"); + size_extern_xml = len; + + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + po2 = decode(buf, len); + if (po2 == NULL) + failed("benchmark: internalize XML"); + + time_intern_xml += (getpoint() - beg); + prop_object_release(po2); + } + free(buf); + + /* How long does binary internalize take? */ + if (! blistify(po1, &buf, &len)) + failed("benchmark: prepare binary"); + size_extern_bin = len; + + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + po2 = decode(buf, len); + if (po2 == NULL) + failed("benchmark: internalize binary"); + + time_intern_bin += (getpoint() - beg); + prop_object_release(po2); + } + free(buf); + + /* How long does XML externalize take? */ + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + if (! xmlify(po1, &buf, &len)) + failed("benchmark: externalize XML"); + + time_extern_xml += (getpoint() - beg); + free(buf); + } + + /* How long does binary externalize take? */ + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + if (! blistify(po1, &buf, &len)) + failed("benchmark: externalize binary"); + + time_extern_bin += (getpoint() - beg); + free(buf); + } + + /* How long does full XML transport take? */ + tmp = malloc(size_extern_xml); + if (tmp == NULL) + failed("benchmark: transport XML buffer alloc"); + + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + if (! xmlify(po1, &buf, &len)) + failed("benchmark: transport XML send"); + + if (len != size_extern_xml) + failed("banchmark: transport size mismatch"); + + memcpy(tmp, buf, len); + po2 = decode(tmp, len); + if (po2 == NULL) + failed("benchmark: transport XML recv"); + + time_ioctl_xml += (getpoint() - beg); + prop_object_release(po2); + free(buf); + } + + free(tmp); + + /* How long does full binary transport take? */ + tmp = malloc(size_extern_bin); + if (tmp == NULL) + failed("benchmark: transport binary buffer alloc"); + + for (i = 0; i < nloops; i++) { + beg = getpoint(); + + if (! blistify(po1, &buf, &len)) + failed("benchmark: transport binary send"); + + if (len != size_extern_bin) + failed("benchmark: transport binary size mismatch"); + + memcpy(tmp, buf, len); + po2 = decode(tmp, len); + if (po2 == NULL) + failed("benchmark: transport binary recv"); + + time_ioctl_bin += (getpoint() - beg); + prop_object_release(po2); + free(buf); + } + + free(tmp); +} + +static double +percentage(double big, double small) +{ + /* percentage = small / (big / 100) = (100 * small) / big */ + return ((100 * small) / big); +} + +int +xstrtoul(char *str, u_long *val) +{ + char *end; + int base = 10; + u_long v; + + if (str[0] == '0') + switch (str[1]) { + case 'x': + base = 16; + str += 2; + break; + case 'd': + base = 10; + str += 2; + break; + case 'o': + base = 8; + str += 2; + break; + case 'b': + base = 2; + str += 2; + break; + } + + v = (u_long) strtoul(str, &end, base); + if (*end != '\0' || str[0] == '\0') + return (EINVAL); + + *val = v; + return (0); +} + +int +main(int argc, char *argv[]) +{ + double val1; + double val2; + int verbose = 0; + int c; + + while ((c = getopt(argc, argv, "hn:v")) != -1) + switch (c) { + case 'h': + warnx("Usage: plbench -h"); + warnx(" plbench [-n ] [-v]"); + exit(EXIT_SUCCESS); + + case 'n': + if (xstrtoul(optarg, &nloops)) + errx(EXIT_FAILURE, "integer expected"); + break; + + case 'v': + verbose = 1; + break; + + default: + errx(EXIT_FAILURE, "invalid or misused option -%c", + optopt); + } + + argc -= optind; + argv += optind; + + if (argc != 1) + errx(1, "need exactly one XML plist file argument"); + + path = argv[0]; + name = basename(argv[0]); + + regression(); + benchmark(); + + printf("PASSED %s ", name); + + + if (verbose) + printf("(" + "XML %3.2fs %3.2fs %3.2f %6uB " + "BIN %3.2fs %3.2fs %3.2f %6uB" + ")", + time_intern_xml, time_extern_xml, time_ioctl_xml, + (u_int)size_extern_xml, + time_intern_bin, time_extern_bin, time_ioctl_bin, + (u_int)size_extern_bin); + else { + /* Relative results for full transport benchmark. */ + printf("TRANSPORT %3.0f%% ", + percentage(time_ioctl_xml, time_ioctl_bin)); + + /* Relative results for raw intern/extern benchmark. */ + val1 = (time_intern_xml + time_extern_xml); + val2 = (time_intern_bin + time_extern_bin); + printf("RAW %3.0f%% ", percentage(val1, val2)); + + /* Relative results for encoding size benchmark. */ + printf("SIZE %3.0f%% ", + percentage(size_extern_xml, size_extern_bin)); + } + + printf("\n"); + return (0); +} Index: regress/lib/libprop/propconv/Makefile =================================================================== RCS file: regress/lib/libprop/propconv/Makefile diff -N regress/lib/libprop/propconv/Makefile --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/propconv/Makefile 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,45 @@ +# $NetBSD$ + +NOMAN= # set +PROG= plconv +SRCS= main.c + +CPPFLAGS+= -I${NETBSDSRCDIR}/common/include +CPPFLAGS+= -I${NETBSDSRCDIR}/common/lib/libprop + +LDADD+= -static + +DPADD+= ${LIBPTHREAD} +LDADD+= -lpthread # -pg +CFLAGS+= -g -Wall -Werror # -pg + +.include "${NETBSDSRCDIR}/common/lib/libprop/Makefile.inc" + +SAMPLEDIR= ${.CURDIR}/../samples +SAMPLES!= cd ${SAMPLEDIR} && ls *.xml + +.for file in ${SAMPLES} +. for codec in xml bplist +${file}.${codec}: ${SAMPLEDIR}/${file} ${PROG} + @if ./${PROG} -O ${codec} -o ./${.TARGET} ${SAMPLEDIR}/${file} ; \ + then \ + echo PASSED convert ${.TARGET} ; \ + else \ + echo FAILED convert ${.TARGET} ; \ + fi + @if ./${PROG} ${.TARGET} ${SAMPLEDIR}/${file} ; \ + then \ + echo PASSED compare ${.TARGET} ; \ + else \ + echo FAILED compare ${.TARGET} ; \ + fi + +CLEANFILES+= ${file}.${codec} +CONVERSIONS+= ${file}.${codec} +. endfor +.endfor + +# Run the full cartesian product. +regress: .PHONY ${CONVERSIONS} + +.include Index: regress/lib/libprop/propconv/main.c =================================================================== RCS file: regress/lib/libprop/propconv/main.c diff -N regress/lib/libprop/propconv/main.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/propconv/main.c 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,157 @@ +/* $NetBSD$ */ + +/*- + * Copyright (c) 2007 Jachym Holecek . + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +static prop_object_t +internalize(const char *path) +{ + prop_object_t po; + + po = prop_dictionary_internalize_from_file(path); + if (po == NULL) { + po = prop_array_internalize_from_file(path); + if (po == NULL) + errx(EXIT_FAILURE, "could not internalize %s", path); + } + + return (po); +} + +static void +externalize(int fd, prop_object_t po, const char *format) +{ + uint8_t *buf; + size_t len; + + if (strcasecmp(format, "xml") == 0) { + if (! prop_dictionary_externalize_with_encoding(po, &buf, &len, + PROP_ENCODING_XML) && + ! prop_array_externalize_with_encoding(po, &buf, &len, + PROP_ENCODING_XML)) + errx(EXIT_FAILURE, "could not externalize"); + } else + if (strcasecmp(format, "bplist") == 0) { + if (! prop_dictionary_externalize_with_encoding(po, &buf, &len, + PROP_ENCODING_BINARY) && + ! prop_array_externalize_with_encoding(po, &buf, &len, + PROP_ENCODING_BINARY)) + errx(EXIT_FAILURE, "could not externalize"); + } + + /* Not prop_*_externalize_to_file(), stdout may be pipe/terminal. */ + if (write(fd, buf, len) == -1) + err(EXIT_FAILURE, "could not write"); +} + +#define OPTIONS "ho:O:" + +static void +usage(void) +{ + const char *me = getprogname(); + + printf("Usage: %s [-o file] [-O format] file\n", me); + printf(" %s file0 file1\n", me); + printf("-h \t Print (this) help\n"); + printf("-o file \t Output file [stdout]\n"); + printf("-O format \t Externalize format [xml bplist]\n"); + + exit(EXIT_SUCCESS); +} + +int +main(int argc, char *argv[]) +{ + const char *oformat = "xml"; + const char *opath = NULL; + int fdo = STDOUT_FILENO; + int c; + + while ((c = getopt(argc, argv, OPTIONS)) != -1) + switch (c) { + case 'h': /* Help. */ + usage(); + /* UNREACHED */ + + case 'o': /* Output file. */ + opath = optarg; + break; + + case 'O': /* Externalize format. */ + oformat = optarg; + break; + + case '?': + errx(EXIT_FAILURE, "uknown option -%c", optopt); + /* UNREACHED */ + + case ':': + errx(EXIT_FAILURE, "missing argument to -%c", optopt); + /* UNREACHED */ + } + + argc -= optind; + argv += optind; + + if (argc == 2) { + if (prop_object_equals(internalize(argv[0]), + internalize(argv[1]))) + return (EXIT_SUCCESS); + + return (EXIT_FAILURE); + } else + if (argc == 1) { + prop_object_t po; + + po = internalize(argv[0]); + + if (opath != NULL) { + fdo = open(opath, O_WRONLY|O_CREAT|O_TRUNC, 0644); + if (fdo == -1) + errx(EXIT_FAILURE, "could not open %s", opath); + } + + externalize(fdo, po, oformat); + return (EXIT_SUCCESS); + } + + warnx("unknown mode of operation"); + return (EXIT_FAILURE); +} Index: regress/lib/libprop/samples/aa.xml =================================================================== RCS file: regress/lib/libprop/samples/aa.xml diff -N regress/lib/libprop/samples/aa.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/aa.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,62 @@ + + + prep-pci-intrmap + + devfunc-11 + + pin-A + 0x0 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-12 + + pin-A + 0x0 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-13 + + pin-A + 0x0 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-14 + + pin-A + 0x11 + pin-B + 0x13 + pin-C + 0x12 + pin-D + 0x13 + + devfunc-15 + + pin-A + 0x14 + pin-B + 0x15 + pin-C + 0x14 + pin-D + 0x15 + + + + Index: regress/lib/libprop/samples/ab.xml =================================================================== RCS file: regress/lib/libprop/samples/ab.xml diff -N regress/lib/libprop/samples/ab.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ab.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,66 @@ + + + prep-pci-intrmap + + devfunc-0 + + pin-A + 0x11 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-1 + + pin-A + 0x18 + pin-B + 0x19 + pin-C + 0x18 + pin-D + 0x19 + + devfunc-2 + + pin-A + 0x1a + pin-B + 0x1b + pin-C + 0x1a + pin-D + 0x1b + + devfunc-3 + + pin-A + 0x1c + pin-B + 0x1d + pin-C + 0x1c + pin-D + 0x1d + + devfunc-4 + + pin-A + 0x1e + pin-B + 0x1f + pin-C + 0x1e + pin-D + 0x1f + + + prep-pcibus-parent + 0x0 + prep-pcibus-rawdevnum + 0xc + + Index: regress/lib/libprop/samples/ac.xml =================================================================== RCS file: regress/lib/libprop/samples/ac.xml diff -N regress/lib/libprop/samples/ac.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ac.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,84 @@ + + + prep-pci-intrmap + + devfunc-11 + + pin-A + 0x10 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-12 + + pin-A + 0x13 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-14 + + pin-A + 0x12 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-16 + + pin-A + 0x19 + pin-B + 0x1a + pin-C + 0x1b + pin-D + 0x1c + + devfunc-17 + + pin-A + 0x1a + pin-B + 0x1b + pin-C + 0x1c + pin-D + 0x19 + + devfunc-18 + + pin-A + 0x1b + pin-B + 0x1c + pin-C + 0x19 + pin-D + 0x1a + + devfunc-19 + + pin-A + 0x1c + pin-B + 0x19 + pin-C + 0x1a + pin-D + 0x1b + + + + Index: regress/lib/libprop/samples/ad.xml =================================================================== RCS file: regress/lib/libprop/samples/ad.xml diff -N regress/lib/libprop/samples/ad.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ad.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,8 @@ + + + prep-pcibus-parent + 0x0 + prep-pcibus-rawdevnum + 0x10 + + Index: regress/lib/libprop/samples/ae.xml =================================================================== RCS file: regress/lib/libprop/samples/ae.xml diff -N regress/lib/libprop/samples/ae.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ae.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,62 @@ + + + prep-pci-intrmap + + devfunc-11 + + pin-A + 0x10 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-12 + + pin-A + 0x13 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-13 + + pin-A + 0x15 + pin-B + 0x16 + pin-C + 0x17 + pin-D + 0x18 + + devfunc-14 + + pin-A + 0x12 + pin-B + 0x0 + pin-C + 0x0 + pin-D + 0x0 + + devfunc-16 + + pin-A + 0x19 + pin-B + 0x1a + pin-C + 0x1b + pin-D + 0x1c + + + + Index: regress/lib/libprop/samples/af.xml =================================================================== RCS file: regress/lib/libprop/samples/af.xml diff -N regress/lib/libprop/samples/af.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/af.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,196 @@ + + + id + NetBSD-UP2006-0001 + + date + 2006-06-08 + + class + security + + priority + medium + + title + FPU Information leak on i386/amd64/Xen platforms with AMD CPUs + + brief + + Due to the documented behavior of AMD processors when running amd64, i386 + and Xen NetBSD kernels, processors using floating point operations can leak + information. This may allow a local attacker to gain sensitive privileged + information. + + + references + + + type + NetBSD security advisory + data + NetBSD-SA2006-015 + + + + type + CVE reference + data + CVE-2006-1056 + + + + affected + + + branch + head + + archs + + + arch + amd64 + files + + + file + src/sys/arch/amd64/amd64/fpu.c + revision + 1.115 + + + + + + arch + i386 + files + + + file + src/sys/arch/i386/isa/npx.c + revision + 1.112 + + + + + + arch + xen + files + + + file + src/sys/arch/xen/i386/npx.c + revision + 1.8 + + + + + + + + branch + netbsd-3 + + archs + + + arch + amd64 + files + + + file + src/sys/arch/amd64/amd64/fpu.c + revision + 1.12.10.2 + + + + + + arch + i386 + files + + + file + src/sys/arch/i386/isa/npx.c + revision + 1.107.4.1 + + + + + + arch + xen + files + + + file + src/sys/arch/xen/i386/npx.c + revision + 1.3.14.3 + + + + + + + + branch + netbsd-2 + + archs + + + arch + amd64 + files + + + file + src/sys/arch/amd64/amd64/fpu.c + revision + 1.11.4.2 + + + + + + arch + i386 + files + + + file + src/sys/arch/i386/isa/npx.c + revision + 1.103.2.2.2.1 + + + + + + arch + xen + files + + + file + src/sys/arch/xen/i386/npx.c + revision + 1.1.2.1.2.1 + + + + + + + + Index: regress/lib/libprop/samples/ag.xml =================================================================== RCS file: regress/lib/libprop/samples/ag.xml diff -N regress/lib/libprop/samples/ag.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ag.xml 27 Oct 2007 15:47:23 -0000 @@ -0,0 +1,161 @@ + + + id + NetBSD-UP2006-0002 + + date + 2006-08-10 + + class + security + + priority + medium + + title + sail(6), dm(8) and tetris(6) buffer overflows + + brief + + The sail, dungeon master arbiter and tetris games all contain buffer + overflows. These programs are installed sgid games, and when + successfully exploited the vulnerabilities may allow an attacker to + elevate their privileges to the games group. + + + references + + + type + NetBSD security advisory + data + NetBSD-SA2006-018 + + + + type + CVE reference for sail(6) + data + CVE-2006-1744 + + + + type + CVE reference for tetris(6) + data + CVE-2006-1539 + + + + affected + + + branch + head + + archs + + + arch + all + files + + + file + src/games/dm/dm.c + revision + 1.23 + + + + file + src/games/sail/pl_main.c + revision + 1.17 + + + + file + src/games/tetris/scores.c + revision + 1.14 + + + + + + + + branch + netbsd-3 + + archs + + + arch + all + files + + + file + src/games/dm/dm.c + revision + 1.21.2.1 + + + + file + src/games/sail/pl_main.c + revision + 1.16.6.1 + + + + file + src/games/tetris/scores.c + revision + 1.13.6.1 + + + + + + + + branch + netbsd-2 + + archs + + + arch + all + files + + + file + src/games/dm/dm.c + revision + 1.20.4.1 + + + + file + src/games/sail/pl_main.c + revision + 1.16.4.1 + + + + file + src/games/tetris/scores.c + revision + 1.13.4.1 + + + + + + + + Index: regress/lib/libprop/samples/ah.xml =================================================================== RCS file: regress/lib/libprop/samples/ah.xml diff -N regress/lib/libprop/samples/ah.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ah.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,20 @@ + + + + + AB21vCardEncoding + MACINTOSH + ABDefaultAddressCountryCode + us + ABImportTipCards + + ABMetaDataChangeCount + 3 + ABNameDisplay + 0 + ABNameSorting + 1 + ABSKCompactionHint + 5 + + Index: regress/lib/libprop/samples/ai.xml =================================================================== RCS file: regress/lib/libprop/samples/ai.xml diff -N regress/lib/libprop/samples/ai.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ai.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,24 @@ + + + + + AppendAMPM + + ClockDigital + + ClockEnabled + + DisplaySeconds + + FlashSeparators + + LastSavedGlobalTimeString + h:mm:ss a + PreferencesVersion + 2 + ShowDay + + Use24HourClock + + + Index: regress/lib/libprop/samples/aj.xml =================================================================== RCS file: regress/lib/libprop/samples/aj.xml diff -N regress/lib/libprop/samples/aj.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/aj.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,8 @@ + + + + + AgentLastLaunched + 174413322 + + Index: regress/lib/libprop/samples/ak.xml =================================================================== RCS file: regress/lib/libprop/samples/ak.xml diff -N regress/lib/libprop/samples/ak.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ak.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,10 @@ + + + + + LastExpireCheck + 732504 + LastIntegrityCheck + 732504 + + Index: regress/lib/libprop/samples/al.xml =================================================================== RCS file: regress/lib/libprop/samples/al.xml diff -N regress/lib/libprop/samples/al.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/al.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,16 @@ + + + + + NSRecentDocumentRecords + + + _NSLocator + + _NSPath + /afs/ms.mff.cuni.cz/u/c/cahyp8am/diplomka/clanek/V.doc + + + + + Index: regress/lib/libprop/samples/am.xml =================================================================== RCS file: regress/lib/libprop/samples/am.xml diff -N regress/lib/libprop/samples/am.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/am.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,10 @@ + + + + + WebIconDatabaseEnabled + + __NSEnableTSMDocumentWindowLevel + + + Index: regress/lib/libprop/samples/an.xml =================================================================== RCS file: regress/lib/libprop/samples/an.xml diff -N regress/lib/libprop/samples/an.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/an.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,20 @@ + + + + + com.apple.TextEdit + + + TextEditHelp + file://localhost/Applications/TextEdit.app/Contents/Resources/English.lproj/TextEditHelp/ + + + hu.mplayerhq.mplayerosx + + + MPlayer OSX Help + file://localhost/Applications/MPlayer%20OSX.app/Contents/Resources/English.lproj/MPlayer%20OSX%20Help/ + + + + Index: regress/lib/libprop/samples/ao.xml =================================================================== RCS file: regress/lib/libprop/samples/ao.xml diff -N regress/lib/libprop/samples/ao.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ao.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,12 @@ + + + + + HVIncludesKBSearches + + NSRecentDocumentRecords + + WebIconDatabaseDirectoryDefaultsKey + ~/Library/Icons + + Index: regress/lib/libprop/samples/ap.xml =================================================================== RCS file: regress/lib/libprop/samples/ap.xml diff -N regress/lib/libprop/samples/ap.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/ap.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,8 @@ + + + + + WWWHomePage + http://livepage.apple.com/ + + Index: regress/lib/libprop/samples/aq.xml =================================================================== RCS file: regress/lib/libprop/samples/aq.xml diff -N regress/lib/libprop/samples/aq.xml --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ regress/lib/libprop/samples/aq.xml 27 Oct 2007 15:47:24 -0000 @@ -0,0 +1,902 @@ + + + + + WebPluginLocalizationName + en_US + WebPluginMIMETypes + + application/pdf + + WebPluginExtensions + + pdf + + WebPluginTypeDescription + PDF Image + WebPluginTypeEnabled + + + application/sdp + + WebPluginExtensions + + sdp + + WebPluginTypeDescription + SDP stream descriptor + WebPluginTypeEnabled + + + application/smil + + WebPluginExtensions + + smi + sml + smil + + WebPluginTypeDescription + SMIL 1.0 + WebPluginTypeEnabled + + + application/x-mpeg + + WebPluginExtensions + + amc + + WebPluginTypeDescription + AMC media + WebPluginTypeEnabled + + + application/x-quicktimeplayer + + WebPluginExtensions + + qtl + + WebPluginTypeDescription + QuickTime Player Movie + WebPluginTypeEnabled + + + application/x-quicktimeupdater + + WebPluginExtensions + + qup + + WebPluginTypeDescription + QuickTime Update Package + WebPluginTypeEnabled + + + application/x-rtsp + + WebPluginExtensions + + rtsp + rts + + WebPluginTypeDescription + RTSP stream descriptor + WebPluginTypeEnabled + + + application/x-sdp + + WebPluginExtensions + + sdp + + WebPluginTypeDescription + SDP stream descriptor + WebPluginTypeEnabled + + + application/x-shockwave-flash + + WebPluginExtensions + + swf + + WebPluginTypeDescription + Flash media + WebPluginTypeEnabled + + + audio/3gpp + + WebPluginExtensions + + 3gp + 3gpp + + WebPluginTypeDescription + 3GPP media + WebPluginTypeEnabled + + + audio/3gpp2 + + WebPluginExtensions + + 3g2 + 3gp2 + + WebPluginTypeDescription + 3GPP2 media + WebPluginTypeEnabled + + + audio/AMR + + WebPluginExtensions + + AMR + + WebPluginTypeDescription + AMR audio + WebPluginTypeEnabled + + + audio/aac + + WebPluginExtensions + + aac + adts + + WebPluginTypeDescription + AAC audio + WebPluginTypeEnabled + + + audio/aiff + + WebPluginExtensions + + aiff + aif + aifc + cdda + + WebPluginTypeDescription + AIFF audio + WebPluginTypeEnabled + + + audio/basic + + WebPluginExtensions + + au + snd + ulw + + WebPluginTypeDescription + uLaw/AU audio + WebPluginTypeEnabled + + + audio/mid + + WebPluginExtensions + + mid + midi + smf + kar + + WebPluginTypeDescription + MIDI + WebPluginTypeEnabled + + + audio/midi + + WebPluginExtensions + + mid + midi + smf + kar + + WebPluginTypeDescription + MIDI + WebPluginTypeEnabled + + + audio/mp3 + + WebPluginExtensions + + mp3 + swa + + WebPluginTypeDescription + MP3 audio + WebPluginTypeEnabled + + + audio/mp4 + + WebPluginExtensions + + mp4 + + WebPluginTypeDescription + MPEG-4 media + WebPluginTypeEnabled + + + audio/mpeg + + WebPluginExtensions + + mpeg + mpg + m1s + m1a + mp2 + mpm + mpa + m2a + mp3 + swa + + WebPluginTypeDescription + MPEG audio + WebPluginTypeEnabled + + + audio/mpeg3 + + WebPluginExtensions + + mp3 + swa + + WebPluginTypeDescription + MP3 audio + WebPluginTypeEnabled + + + audio/mpegurl + + WebPluginExtensions + + m3u + m3url + + WebPluginTypeDescription + MP3 playlist + WebPluginTypeEnabled + + + audio/vnd.qcelp + + WebPluginExtensions + + qcp + qcp + + WebPluginTypeDescription + QUALCOMM PureVoice audio + WebPluginTypeEnabled + + + audio/wav + + WebPluginExtensions + + wav + bwf + + WebPluginTypeDescription + WAVE audio + WebPluginTypeEnabled + + + audio/x-aac + + WebPluginExtensions + + aac + adts + + WebPluginTypeDescription + AAC audio + WebPluginTypeEnabled + + + audio/x-aiff + + WebPluginExtensions + + aiff + aif + aifc + cdda + + WebPluginTypeDescription + AIFF audio + WebPluginTypeEnabled + + + audio/x-caf + + WebPluginExtensions + + caf + + WebPluginTypeDescription + CAF audio + WebPluginTypeEnabled + + + audio/x-gsm + + WebPluginExtensions + + gsm + + WebPluginTypeDescription + GSM audio + WebPluginTypeEnabled + + + audio/x-m4a + + WebPluginExtensions + + m4a + + WebPluginTypeDescription + AAC audio + WebPluginTypeEnabled + + + audio/x-m4b + + WebPluginExtensions + + m4b + + WebPluginTypeDescription + AAC audio book + WebPluginTypeEnabled + + + audio/x-m4p + + WebPluginExtensions + + m4p + + WebPluginTypeDescription + AAC audio (prot