Home | History | Annotate | Line # | Download | only in libprop
prop_data.c revision 1.18.8.1
      1  1.18.8.1  perseant /*	$NetBSD: prop_data.c,v 1.18.8.1 2025/08/02 05:18:34 perseant Exp $	*/
      2       1.1   thorpej 
      3       1.1   thorpej /*-
      4  1.18.8.1  perseant  * Copyright (c) 2006, 2020, 2025 The NetBSD Foundation, Inc.
      5       1.1   thorpej  * All rights reserved.
      6       1.1   thorpej  *
      7       1.1   thorpej  * This code is derived from software contributed to The NetBSD Foundation
      8       1.1   thorpej  * by Jason R. Thorpe.
      9       1.1   thorpej  *
     10       1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     11       1.1   thorpej  * modification, are permitted provided that the following conditions
     12       1.1   thorpej  * are met:
     13       1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     14       1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     15       1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     16       1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     17       1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     18       1.1   thorpej  *
     19       1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20       1.1   thorpej  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21       1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22       1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23       1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24       1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25       1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26       1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27       1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28       1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29       1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     30       1.1   thorpej  */
     31       1.1   thorpej 
     32      1.15   thorpej #include "prop_object_impl.h"
     33       1.1   thorpej #include <prop/prop_data.h>
     34       1.1   thorpej 
     35       1.1   thorpej #if defined(_KERNEL)
     36       1.1   thorpej #include <sys/systm.h>
     37       1.1   thorpej #elif defined(_STANDALONE)
     38       1.1   thorpej #include <sys/param.h>
     39       1.1   thorpej #include <lib/libkern/libkern.h>
     40       1.1   thorpej #else
     41       1.1   thorpej #include <errno.h>
     42       1.1   thorpej #include <limits.h>
     43       1.1   thorpej #include <stdlib.h>
     44       1.1   thorpej #endif
     45       1.1   thorpej 
     46       1.1   thorpej struct _prop_data {
     47       1.1   thorpej 	struct _prop_object	pd_obj;
     48       1.1   thorpej 	union {
     49       1.1   thorpej 		void *		pdu_mutable;
     50       1.1   thorpej 		const void *	pdu_immutable;
     51       1.1   thorpej 	} pd_un;
     52       1.1   thorpej #define	pd_mutable		pd_un.pdu_mutable
     53       1.1   thorpej #define	pd_immutable		pd_un.pdu_immutable
     54       1.1   thorpej 	size_t			pd_size;
     55       1.1   thorpej 	int			pd_flags;
     56       1.1   thorpej };
     57       1.1   thorpej 
     58       1.1   thorpej #define	PD_F_NOCOPY		0x01
     59      1.16   thorpej #define	PD_F_MUTABLE		0x02
     60       1.1   thorpej 
     61       1.1   thorpej _PROP_POOL_INIT(_prop_data_pool, sizeof(struct _prop_data), "propdata")
     62       1.1   thorpej _PROP_MALLOC_DEFINE(M_PROP_DATA, "prop data",
     63       1.1   thorpej 		    "property data container object")
     64       1.1   thorpej 
     65  1.18.8.1  perseant static const struct _prop_object_type_tags _prop_data_type_tags = {
     66  1.18.8.1  perseant 	.xml_tag		=	"data",
     67  1.18.8.1  perseant };
     68  1.18.8.1  perseant 
     69      1.13   thorpej static _prop_object_free_rv_t
     70      1.13   thorpej 		_prop_data_free(prop_stack_t, prop_object_t *);
     71       1.7   thorpej static bool	_prop_data_externalize(
     72       1.2   thorpej 				struct _prop_object_externalize_context *,
     73       1.2   thorpej 				void *);
     74      1.13   thorpej static _prop_object_equals_rv_t
     75      1.13   thorpej 		_prop_data_equals(prop_object_t, prop_object_t,
     76       1.9     joerg 				  void **, void **,
     77       1.9     joerg 				  prop_object_t *, prop_object_t *);
     78       1.2   thorpej 
     79       1.2   thorpej static const struct _prop_object_type _prop_object_type_data = {
     80       1.2   thorpej 	.pot_type	=	PROP_TYPE_DATA,
     81       1.2   thorpej 	.pot_free	=	_prop_data_free,
     82       1.2   thorpej 	.pot_extern	=	_prop_data_externalize,
     83       1.2   thorpej 	.pot_equals	=	_prop_data_equals,
     84       1.2   thorpej };
     85       1.2   thorpej 
     86       1.2   thorpej #define	prop_object_is_data(x)		\
     87       1.4   thorpej 	((x) != NULL && (x)->pd_obj.po_type == &_prop_object_type_data)
     88       1.1   thorpej 
     89       1.8     joerg /* ARGSUSED */
     90      1.13   thorpej static _prop_object_free_rv_t
     91       1.8     joerg _prop_data_free(prop_stack_t stack, prop_object_t *obj)
     92       1.1   thorpej {
     93       1.8     joerg 	prop_data_t pd = *obj;
     94       1.1   thorpej 
     95       1.1   thorpej 	if ((pd->pd_flags & PD_F_NOCOPY) == 0 && pd->pd_mutable != NULL)
     96       1.1   thorpej 	    	_PROP_FREE(pd->pd_mutable, M_PROP_DATA);
     97       1.8     joerg 	_PROP_POOL_PUT(_prop_data_pool, pd);
     98       1.8     joerg 
     99       1.8     joerg 	return (_PROP_OBJECT_FREE_DONE);
    100       1.1   thorpej }
    101       1.1   thorpej 
    102       1.1   thorpej static const char _prop_data_base64[] =
    103       1.1   thorpej     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
    104       1.1   thorpej static const char _prop_data_pad64 = '=';
    105       1.1   thorpej 
    106       1.7   thorpej static bool
    107       1.1   thorpej _prop_data_externalize(struct _prop_object_externalize_context *ctx, void *v)
    108       1.1   thorpej {
    109       1.1   thorpej 	prop_data_t pd = v;
    110       1.1   thorpej 	size_t i, srclen;
    111       1.1   thorpej 	const uint8_t *src;
    112       1.1   thorpej 	uint8_t output[4];
    113       1.1   thorpej 	uint8_t input[3];
    114       1.1   thorpej 
    115  1.18.8.1  perseant 	_PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML ||
    116  1.18.8.1  perseant 		     ctx->poec_format == PROP_FORMAT_JSON);
    117  1.18.8.1  perseant 
    118  1.18.8.1  perseant 	/*
    119  1.18.8.1  perseant 	 * JSON does not have a syntax for serialized binary data.
    120  1.18.8.1  perseant 	 */
    121  1.18.8.1  perseant 	if (ctx->poec_format == PROP_FORMAT_JSON) {
    122  1.18.8.1  perseant 		return false;
    123  1.18.8.1  perseant 	}
    124  1.18.8.1  perseant 
    125       1.1   thorpej 	if (pd->pd_size == 0)
    126  1.18.8.1  perseant 		return (_prop_extern_append_empty_tag(ctx,
    127  1.18.8.1  perseant 		    &_prop_data_type_tags));
    128       1.1   thorpej 
    129  1.18.8.1  perseant 	if (_prop_extern_append_start_tag(ctx,
    130  1.18.8.1  perseant 				&_prop_data_type_tags, NULL) == false)
    131       1.7   thorpej 		return (false);
    132       1.1   thorpej 
    133       1.1   thorpej 	for (src = pd->pd_immutable, srclen = pd->pd_size;
    134       1.1   thorpej 	     srclen > 2; srclen -= 3) {
    135       1.1   thorpej 		input[0] = *src++;
    136       1.1   thorpej 		input[1] = *src++;
    137       1.1   thorpej 		input[2] = *src++;
    138       1.1   thorpej 
    139       1.1   thorpej 		output[0] = (uint32_t)input[0] >> 2;
    140       1.1   thorpej 		output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
    141       1.1   thorpej 		    ((uint32_t)input[1] >> 4);
    142      1.10       apb 		output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
    143       1.1   thorpej 		    ((uint32_t)input[2] >> 6);
    144       1.1   thorpej 		output[3] = input[2] & 0x3f;
    145       1.1   thorpej 		_PROP_ASSERT(output[0] < 64);
    146       1.1   thorpej 		_PROP_ASSERT(output[1] < 64);
    147       1.1   thorpej 		_PROP_ASSERT(output[2] < 64);
    148       1.1   thorpej 		_PROP_ASSERT(output[3] < 64);
    149       1.1   thorpej 
    150  1.18.8.1  perseant 		if (_prop_extern_append_char(ctx,
    151       1.7   thorpej 				_prop_data_base64[output[0]]) == false ||
    152  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    153       1.7   thorpej 		    		_prop_data_base64[output[1]]) == false ||
    154  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    155       1.7   thorpej 		    		_prop_data_base64[output[2]]) == false ||
    156  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    157       1.7   thorpej 		    		_prop_data_base64[output[3]]) == false)
    158       1.7   thorpej 			return (false);
    159       1.1   thorpej 	}
    160       1.1   thorpej 
    161       1.1   thorpej 	if (srclen != 0) {
    162       1.1   thorpej 		input[0] = input[1] = input[2] = '\0';
    163       1.1   thorpej 		for (i = 0; i < srclen; i++)
    164       1.1   thorpej 			input[i] = *src++;
    165       1.1   thorpej 
    166       1.1   thorpej 		output[0] = (uint32_t)input[0] >> 2;
    167       1.1   thorpej 		output[1] = ((uint32_t)(input[0] & 0x03) << 4) +
    168       1.1   thorpej 		    ((uint32_t)input[1] >> 4);
    169      1.10       apb 		output[2] = ((uint32_t)(input[1] & 0x0f) << 2) +
    170       1.1   thorpej 		    ((uint32_t)input[2] >> 6);
    171       1.1   thorpej 		_PROP_ASSERT(output[0] < 64);
    172       1.1   thorpej 		_PROP_ASSERT(output[1] < 64);
    173       1.1   thorpej 		_PROP_ASSERT(output[2] < 64);
    174       1.1   thorpej 
    175  1.18.8.1  perseant 		if (_prop_extern_append_char(ctx,
    176       1.7   thorpej 				_prop_data_base64[output[0]]) == false ||
    177  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    178       1.7   thorpej 		    		_prop_data_base64[output[1]]) == false ||
    179  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    180       1.1   thorpej 		    		srclen == 1 ? _prop_data_pad64
    181       1.7   thorpej 				: _prop_data_base64[output[2]]) == false ||
    182  1.18.8.1  perseant 		    _prop_extern_append_char(ctx,
    183       1.7   thorpej 		    		_prop_data_pad64) == false)
    184       1.7   thorpej 			return (false);
    185       1.1   thorpej 	}
    186       1.1   thorpej 
    187  1.18.8.1  perseant 	if (_prop_extern_append_end_tag(ctx,
    188  1.18.8.1  perseant 					&_prop_data_type_tags) == false)
    189       1.7   thorpej 		return (false);
    190      1.18  riastrad 
    191       1.7   thorpej 	return (true);
    192       1.1   thorpej }
    193       1.1   thorpej 
    194       1.9     joerg /* ARGSUSED */
    195      1.13   thorpej static _prop_object_equals_rv_t
    196       1.9     joerg _prop_data_equals(prop_object_t v1, prop_object_t v2,
    197       1.9     joerg     void **stored_pointer1, void **stored_pointer2,
    198       1.9     joerg     prop_object_t *next_obj1, prop_object_t *next_obj2)
    199       1.2   thorpej {
    200       1.2   thorpej 	prop_data_t pd1 = v1;
    201       1.2   thorpej 	prop_data_t pd2 = v2;
    202       1.2   thorpej 
    203       1.2   thorpej 	if (pd1 == pd2)
    204       1.9     joerg 		return (_PROP_OBJECT_EQUALS_TRUE);
    205       1.2   thorpej 	if (pd1->pd_size != pd2->pd_size)
    206       1.9     joerg 		return (_PROP_OBJECT_EQUALS_FALSE);
    207       1.2   thorpej 	if (pd1->pd_size == 0) {
    208       1.2   thorpej 		_PROP_ASSERT(pd1->pd_immutable == NULL);
    209       1.2   thorpej 		_PROP_ASSERT(pd2->pd_immutable == NULL);
    210       1.9     joerg 		return (_PROP_OBJECT_EQUALS_TRUE);
    211       1.2   thorpej 	}
    212       1.9     joerg 	if (memcmp(pd1->pd_immutable, pd2->pd_immutable, pd1->pd_size) == 0)
    213       1.9     joerg 		return _PROP_OBJECT_EQUALS_TRUE;
    214       1.9     joerg 	else
    215       1.9     joerg 		return _PROP_OBJECT_EQUALS_FALSE;
    216       1.2   thorpej }
    217       1.2   thorpej 
    218       1.1   thorpej static prop_data_t
    219      1.16   thorpej _prop_data_alloc(int const flags)
    220       1.1   thorpej {
    221       1.1   thorpej 	prop_data_t pd;
    222       1.1   thorpej 
    223       1.1   thorpej 	pd = _PROP_POOL_GET(_prop_data_pool);
    224       1.1   thorpej 	if (pd != NULL) {
    225       1.2   thorpej 		_prop_object_init(&pd->pd_obj, &_prop_object_type_data);
    226       1.1   thorpej 
    227       1.1   thorpej 		pd->pd_mutable = NULL;
    228       1.1   thorpej 		pd->pd_size = 0;
    229      1.16   thorpej 		pd->pd_flags = flags;
    230       1.1   thorpej 	}
    231       1.1   thorpej 
    232       1.1   thorpej 	return (pd);
    233       1.1   thorpej }
    234       1.1   thorpej 
    235      1.16   thorpej static prop_data_t
    236      1.16   thorpej _prop_data_instantiate(int const flags, const void * const data,
    237      1.16   thorpej     size_t const len)
    238      1.16   thorpej {
    239      1.16   thorpej 	prop_data_t pd;
    240      1.16   thorpej 
    241      1.16   thorpej 	pd = _prop_data_alloc(flags);
    242      1.16   thorpej 	if (pd != NULL) {
    243      1.16   thorpej 		pd->pd_immutable = data;
    244      1.16   thorpej 		pd->pd_size = len;
    245      1.16   thorpej 	}
    246      1.16   thorpej 
    247      1.16   thorpej 	return (pd);
    248      1.16   thorpej }
    249      1.16   thorpej 
    250      1.16   thorpej _PROP_DEPRECATED(prop_data_create_data,
    251      1.16   thorpej     "this program uses prop_data_create_data(); all functions "
    252      1.16   thorpej     "supporting mutable prop_data objects are deprecated.")
    253  1.18.8.1  perseant _PROP_EXPORT prop_data_t
    254       1.1   thorpej prop_data_create_data(const void *v, size_t size)
    255       1.1   thorpej {
    256       1.1   thorpej 	prop_data_t pd;
    257       1.1   thorpej 	void *nv;
    258       1.1   thorpej 
    259      1.16   thorpej 	pd = _prop_data_alloc(PD_F_MUTABLE);
    260      1.12    dyoung 	if (pd != NULL && size != 0) {
    261       1.1   thorpej 		nv = _PROP_MALLOC(size, M_PROP_DATA);
    262       1.1   thorpej 		if (nv == NULL) {
    263       1.8     joerg 			prop_object_release(pd);
    264       1.1   thorpej 			return (NULL);
    265       1.1   thorpej 		}
    266       1.1   thorpej 		memcpy(nv, v, size);
    267       1.1   thorpej 		pd->pd_mutable = nv;
    268       1.1   thorpej 		pd->pd_size = size;
    269       1.1   thorpej 	}
    270       1.1   thorpej 	return (pd);
    271       1.1   thorpej }
    272       1.1   thorpej 
    273      1.16   thorpej _PROP_DEPRECATED(prop_data_create_data_nocopy,
    274      1.16   thorpej     "this program uses prop_data_create_data_nocopy(), "
    275      1.16   thorpej     "which is deprecated; use prop_data_create_nocopy() instead.")
    276  1.18.8.1  perseant _PROP_EXPORT prop_data_t
    277      1.16   thorpej prop_data_create_data_nocopy(const void *v, size_t size)
    278      1.16   thorpej {
    279      1.16   thorpej 	return prop_data_create_nocopy(v, size);
    280      1.16   thorpej }
    281      1.16   thorpej 
    282       1.1   thorpej /*
    283      1.16   thorpej  * prop_data_create_copy --
    284      1.16   thorpej  *	Create a data object with a copy of the provided data.
    285       1.1   thorpej  */
    286  1.18.8.1  perseant _PROP_EXPORT prop_data_t
    287      1.16   thorpej prop_data_create_copy(const void *v, size_t size)
    288       1.1   thorpej {
    289       1.1   thorpej 	prop_data_t pd;
    290      1.16   thorpej 	void *nv;
    291      1.16   thorpej 
    292      1.16   thorpej 	/* Tolerate the creation of empty data objects. */
    293      1.16   thorpej 	if (v != NULL && size != 0) {
    294      1.16   thorpej 		nv = _PROP_MALLOC(size, M_PROP_DATA);
    295      1.16   thorpej 		if (nv == NULL)
    296      1.16   thorpej 			return (NULL);
    297      1.16   thorpej 
    298      1.16   thorpej 		memcpy(nv, v, size);
    299      1.16   thorpej 	} else {
    300      1.16   thorpej 		nv = NULL;
    301      1.16   thorpej 		size = 0;
    302       1.1   thorpej 	}
    303      1.16   thorpej 
    304      1.16   thorpej 	pd = _prop_data_instantiate(0, nv, size);
    305      1.16   thorpej 	if (pd == NULL && nv == NULL)
    306      1.16   thorpej 		_PROP_FREE(nv, M_PROP_DATA);
    307      1.16   thorpej 
    308       1.1   thorpej 	return (pd);
    309       1.1   thorpej }
    310       1.1   thorpej 
    311       1.1   thorpej /*
    312      1.16   thorpej  * prop_data_create_nocopy --
    313      1.16   thorpej  *	Create a data object using the provided external data reference.
    314      1.16   thorpej  */
    315  1.18.8.1  perseant _PROP_EXPORT prop_data_t
    316      1.16   thorpej prop_data_create_nocopy(const void *v, size_t size)
    317      1.16   thorpej {
    318      1.16   thorpej 
    319      1.16   thorpej 	/* Tolerate the creation of empty data objects. */
    320      1.16   thorpej 	if (v == NULL || size == 0) {
    321      1.16   thorpej 		v = NULL;
    322      1.16   thorpej 		size = 0;
    323      1.16   thorpej 	}
    324      1.16   thorpej 
    325      1.16   thorpej 	return _prop_data_instantiate(PD_F_NOCOPY, v, size);
    326      1.16   thorpej }
    327      1.16   thorpej 
    328      1.16   thorpej /*
    329       1.1   thorpej  * prop_data_copy --
    330       1.1   thorpej  *	Copy a data container.  If the original data is external, then
    331       1.1   thorpej  *	the copy is also references the same external data.
    332       1.1   thorpej  */
    333  1.18.8.1  perseant _PROP_EXPORT prop_data_t
    334       1.1   thorpej prop_data_copy(prop_data_t opd)
    335       1.1   thorpej {
    336       1.1   thorpej 	prop_data_t pd;
    337       1.1   thorpej 
    338       1.3   thorpej 	if (! prop_object_is_data(opd))
    339       1.3   thorpej 		return (NULL);
    340       1.1   thorpej 
    341      1.16   thorpej 	if ((opd->pd_flags & PD_F_NOCOPY) != 0 ||
    342      1.16   thorpej 	    (opd->pd_flags & PD_F_MUTABLE) == 0) {
    343      1.16   thorpej 		/* Just retain and return the original. */
    344      1.16   thorpej 		prop_object_retain(opd);
    345      1.16   thorpej 		return (opd);
    346      1.16   thorpej 	}
    347      1.16   thorpej 
    348      1.16   thorpej 	pd = prop_data_create_copy(opd->pd_immutable, opd->pd_size);
    349       1.1   thorpej 	if (pd != NULL) {
    350      1.16   thorpej 		/* Preserve deprecated mutability semantics. */
    351      1.16   thorpej 		pd->pd_flags |= PD_F_MUTABLE;
    352       1.1   thorpej 	}
    353      1.16   thorpej 
    354       1.1   thorpej 	return (pd);
    355       1.1   thorpej }
    356       1.1   thorpej 
    357       1.1   thorpej /*
    358       1.1   thorpej  * prop_data_size --
    359       1.1   thorpej  *	Return the size of the data.
    360       1.1   thorpej  */
    361  1.18.8.1  perseant _PROP_EXPORT size_t
    362       1.1   thorpej prop_data_size(prop_data_t pd)
    363       1.1   thorpej {
    364       1.1   thorpej 
    365       1.3   thorpej 	if (! prop_object_is_data(pd))
    366       1.3   thorpej 		return (0);
    367       1.3   thorpej 
    368       1.1   thorpej 	return (pd->pd_size);
    369       1.1   thorpej }
    370       1.1   thorpej 
    371       1.1   thorpej /*
    372      1.16   thorpej  * prop_data_value --
    373      1.16   thorpej  *	Returns a pointer to the data object's value.  This pointer
    374      1.16   thorpej  *	remains valid only as long as the data object.
    375      1.16   thorpej  */
    376  1.18.8.1  perseant _PROP_EXPORT const void *
    377      1.16   thorpej prop_data_value(prop_data_t pd)
    378      1.16   thorpej {
    379      1.16   thorpej 
    380      1.16   thorpej 	if (! prop_object_is_data(pd))
    381      1.16   thorpej 		return (0);
    382      1.16   thorpej 
    383      1.16   thorpej 	return (pd->pd_immutable);
    384      1.16   thorpej }
    385      1.16   thorpej 
    386      1.16   thorpej /*
    387      1.16   thorpej  * prop_data_copy_value --
    388      1.16   thorpej  *	Copy the data object's value into the supplied buffer.
    389       1.1   thorpej  */
    390  1.18.8.1  perseant _PROP_EXPORT bool
    391      1.16   thorpej prop_data_copy_value(prop_data_t pd, void *buf, size_t buflen)
    392      1.16   thorpej {
    393      1.16   thorpej 
    394      1.16   thorpej 	if (! prop_object_is_data(pd))
    395      1.16   thorpej 		return (false);
    396      1.18  riastrad 
    397      1.16   thorpej 	if (buf == NULL || buflen < pd->pd_size)
    398      1.16   thorpej 		return (false);
    399      1.16   thorpej 
    400      1.16   thorpej 	/* Tolerate empty data objects. */
    401      1.16   thorpej 	if (pd->pd_immutable == NULL || pd->pd_size == 0)
    402      1.16   thorpej 		return (false);
    403      1.16   thorpej 
    404      1.16   thorpej 	memcpy(buf, pd->pd_immutable, pd->pd_size);
    405      1.16   thorpej 
    406      1.16   thorpej 	return (true);
    407      1.16   thorpej }
    408      1.16   thorpej 
    409      1.16   thorpej _PROP_DEPRECATED(prop_data_data,
    410      1.16   thorpej     "this program uses prop_data_data(), "
    411      1.16   thorpej     "which is deprecated; use prop_data_copy_value() instead.")
    412  1.18.8.1  perseant _PROP_EXPORT void *
    413       1.1   thorpej prop_data_data(prop_data_t pd)
    414       1.1   thorpej {
    415       1.1   thorpej 	void *v;
    416       1.1   thorpej 
    417       1.3   thorpej 	if (! prop_object_is_data(pd))
    418       1.3   thorpej 		return (NULL);
    419       1.1   thorpej 
    420       1.1   thorpej 	if (pd->pd_size == 0) {
    421       1.1   thorpej 		_PROP_ASSERT(pd->pd_immutable == NULL);
    422       1.1   thorpej 		return (NULL);
    423       1.1   thorpej 	}
    424       1.1   thorpej 
    425       1.1   thorpej 	_PROP_ASSERT(pd->pd_immutable != NULL);
    426       1.1   thorpej 
    427       1.1   thorpej 	v = _PROP_MALLOC(pd->pd_size, M_TEMP);
    428       1.1   thorpej 	if (v != NULL)
    429       1.1   thorpej 		memcpy(v, pd->pd_immutable, pd->pd_size);
    430      1.18  riastrad 
    431       1.1   thorpej 	return (v);
    432       1.1   thorpej }
    433       1.1   thorpej 
    434      1.16   thorpej _PROP_DEPRECATED(prop_data_data_nocopy,
    435      1.16   thorpej     "this program uses prop_data_data_nocopy(), "
    436      1.16   thorpej     "which is deprecated; use prop_data_value() instead.")
    437  1.18.8.1  perseant _PROP_EXPORT const void *
    438       1.1   thorpej prop_data_data_nocopy(prop_data_t pd)
    439       1.1   thorpej {
    440      1.16   thorpej 	return prop_data_value(pd);
    441       1.1   thorpej }
    442       1.1   thorpej 
    443       1.1   thorpej /*
    444       1.1   thorpej  * prop_data_equals --
    445      1.16   thorpej  *	Return true if two data objects are equivalent.
    446       1.1   thorpej  */
    447  1.18.8.1  perseant _PROP_EXPORT bool
    448       1.1   thorpej prop_data_equals(prop_data_t pd1, prop_data_t pd2)
    449       1.1   thorpej {
    450       1.9     joerg 	if (!prop_object_is_data(pd1) || !prop_object_is_data(pd2))
    451       1.9     joerg 		return (false);
    452       1.1   thorpej 
    453       1.9     joerg 	return (prop_object_equals(pd1, pd2));
    454       1.1   thorpej }
    455       1.1   thorpej 
    456       1.1   thorpej /*
    457       1.1   thorpej  * prop_data_equals_data --
    458       1.7   thorpej  *	Return true if the contained data is equivalent to the specified
    459       1.1   thorpej  *	external data.
    460       1.1   thorpej  */
    461  1.18.8.1  perseant _PROP_EXPORT bool
    462       1.1   thorpej prop_data_equals_data(prop_data_t pd, const void *v, size_t size)
    463       1.1   thorpej {
    464       1.1   thorpej 
    465       1.3   thorpej 	if (! prop_object_is_data(pd))
    466       1.7   thorpej 		return (false);
    467       1.3   thorpej 
    468      1.16   thorpej 	if (pd->pd_size != size || v == NULL)
    469       1.7   thorpej 		return (false);
    470      1.16   thorpej 
    471       1.1   thorpej 	return (memcmp(pd->pd_immutable, v, size) == 0);
    472       1.1   thorpej }
    473       1.1   thorpej 
    474       1.7   thorpej static bool
    475       1.1   thorpej _prop_data_internalize_decode(struct _prop_object_internalize_context *ctx,
    476       1.1   thorpej 			     uint8_t *target, size_t targsize, size_t *sizep,
    477       1.1   thorpej 			     const char **cpp)
    478       1.1   thorpej {
    479       1.1   thorpej 	const char *src;
    480       1.1   thorpej 	size_t tarindex;
    481       1.1   thorpej 	int state, ch;
    482       1.1   thorpej 	const char *pos;
    483       1.1   thorpej 
    484       1.1   thorpej 	state = 0;
    485       1.1   thorpej 	tarindex = 0;
    486       1.1   thorpej 	src = ctx->poic_cp;
    487       1.1   thorpej 
    488       1.1   thorpej 	for (;;) {
    489       1.1   thorpej 		ch = (unsigned char) *src++;
    490       1.1   thorpej 		if (_PROP_EOF(ch))
    491       1.7   thorpej 			return (false);
    492       1.1   thorpej 		if (_PROP_ISSPACE(ch))
    493       1.1   thorpej 			continue;
    494       1.1   thorpej 		if (ch == '<') {
    495       1.1   thorpej 			src--;
    496       1.1   thorpej 			break;
    497       1.1   thorpej 		}
    498       1.1   thorpej 		if (ch == _prop_data_pad64)
    499       1.1   thorpej 			break;
    500       1.1   thorpej 
    501       1.1   thorpej 		pos = strchr(_prop_data_base64, ch);
    502       1.1   thorpej 		if (pos == NULL)
    503       1.7   thorpej 			return (false);
    504       1.1   thorpej 
    505       1.1   thorpej 		switch (state) {
    506       1.1   thorpej 		case 0:
    507       1.1   thorpej 			if (target) {
    508       1.1   thorpej 				if (tarindex >= targsize)
    509       1.7   thorpej 					return (false);
    510       1.1   thorpej 				target[tarindex] =
    511       1.5    martin 				    (uint8_t)((pos - _prop_data_base64) << 2);
    512       1.1   thorpej 			}
    513       1.1   thorpej 			state = 1;
    514       1.1   thorpej 			break;
    515       1.1   thorpej 
    516       1.1   thorpej 		case 1:
    517       1.1   thorpej 			if (target) {
    518       1.1   thorpej 				if (tarindex + 1 >= targsize)
    519       1.7   thorpej 					return (false);
    520       1.1   thorpej 				target[tarindex] |=
    521       1.1   thorpej 				    (uint32_t)(pos - _prop_data_base64) >> 4;
    522       1.1   thorpej 				target[tarindex + 1] =
    523       1.5    martin 				    (uint8_t)(((pos - _prop_data_base64) & 0xf)
    524       1.5    martin 				        << 4);
    525       1.1   thorpej 			}
    526       1.1   thorpej 			tarindex++;
    527       1.1   thorpej 			state = 2;
    528       1.1   thorpej 			break;
    529       1.1   thorpej 
    530       1.1   thorpej 		case 2:
    531       1.1   thorpej 			if (target) {
    532       1.1   thorpej 				if (tarindex + 1 >= targsize)
    533       1.7   thorpej 					return (false);
    534       1.1   thorpej 				target[tarindex] |=
    535       1.1   thorpej 				    (uint32_t)(pos - _prop_data_base64) >> 2;
    536       1.1   thorpej 				target[tarindex + 1] =
    537       1.5    martin 				    (uint8_t)(((pos - _prop_data_base64)
    538       1.5    martin 				        & 0x3) << 6);
    539       1.1   thorpej 			}
    540       1.1   thorpej 			tarindex++;
    541       1.1   thorpej 			state = 3;
    542       1.1   thorpej 			break;
    543       1.1   thorpej 
    544       1.1   thorpej 		case 3:
    545       1.1   thorpej 			if (target) {
    546       1.1   thorpej 				if (tarindex >= targsize)
    547       1.7   thorpej 					return (false);
    548       1.5    martin 				target[tarindex] |= (uint8_t)
    549       1.5    martin 				    (pos - _prop_data_base64);
    550       1.1   thorpej 			}
    551       1.1   thorpej 			tarindex++;
    552       1.1   thorpej 			state = 0;
    553       1.1   thorpej 			break;
    554       1.1   thorpej 
    555       1.1   thorpej 		default:
    556       1.1   thorpej 			_PROP_ASSERT(/*CONSTCOND*/0);
    557       1.1   thorpej 		}
    558       1.1   thorpej 	}
    559       1.1   thorpej 
    560       1.1   thorpej 	/*
    561       1.1   thorpej 	 * We are done decoding the Base64 characters.  Let's see if we
    562       1.1   thorpej 	 * ended up on a byte boundary and/or with unrecognized trailing
    563       1.1   thorpej 	 * characters.
    564       1.1   thorpej 	 */
    565       1.1   thorpej 	if (ch == _prop_data_pad64) {
    566       1.1   thorpej 		ch = (unsigned char) *src;	/* src already advanced */
    567       1.1   thorpej 		if (_PROP_EOF(ch))
    568       1.7   thorpej 			return (false);
    569       1.1   thorpej 		switch (state) {
    570       1.1   thorpej 		case 0:		/* Invalid = in first position */
    571       1.1   thorpej 		case 1:		/* Invalid = in second position */
    572       1.7   thorpej 			return (false);
    573       1.1   thorpej 
    574       1.1   thorpej 		case 2:		/* Valid, one byte of info */
    575       1.1   thorpej 			/* Skip whitespace */
    576       1.1   thorpej 			for (ch = (unsigned char) *src++;
    577       1.1   thorpej 			     ch != '<'; ch = (unsigned char) *src++) {
    578       1.1   thorpej 				if (_PROP_EOF(ch))
    579       1.7   thorpej 					return (false);
    580       1.1   thorpej 				if (!_PROP_ISSPACE(ch))
    581       1.1   thorpej 					break;
    582       1.1   thorpej 			}
    583       1.1   thorpej 			/* Make sure there is another trailing = */
    584       1.1   thorpej 			if (ch != _prop_data_pad64)
    585       1.7   thorpej 				return (false);
    586       1.1   thorpej 			ch = (unsigned char) *src;
    587       1.1   thorpej 			/* FALLTHROUGH */
    588      1.18  riastrad 
    589       1.1   thorpej 		case 3:		/* Valid, two bytes of info */
    590       1.1   thorpej 			/*
    591       1.1   thorpej 			 * We know this char is a =.  Is there anything but
    592       1.1   thorpej 			 * whitespace after it?
    593       1.1   thorpej 			 */
    594       1.6     dillo 			for (ch = (unsigned char) *src++;
    595       1.6     dillo 			     ch != '<'; ch = (unsigned char) *src++) {
    596       1.1   thorpej 				if (_PROP_EOF(ch))
    597       1.7   thorpej 					return (false);
    598       1.1   thorpej 				if (!_PROP_ISSPACE(ch))
    599       1.7   thorpej 					return (false);
    600       1.1   thorpej 			}
    601       1.6     dillo 			/* back up to '<' */
    602       1.6     dillo 			src--;
    603       1.1   thorpej 		}
    604       1.1   thorpej 	} else {
    605       1.1   thorpej 		/*
    606       1.1   thorpej 		 * We ended by seeing the end of the Base64 string.  Make
    607       1.1   thorpej 		 * sure there are no partial bytes lying around.
    608       1.1   thorpej 		 */
    609       1.1   thorpej 		if (state != 0)
    610       1.7   thorpej 			return (false);
    611       1.1   thorpej 	}
    612       1.1   thorpej 
    613       1.1   thorpej 	_PROP_ASSERT(*src == '<');
    614       1.1   thorpej 	if (sizep != NULL)
    615       1.1   thorpej 		*sizep = tarindex;
    616       1.1   thorpej 	if (cpp != NULL)
    617       1.1   thorpej 		*cpp = src;
    618       1.1   thorpej 
    619       1.7   thorpej 	return (true);
    620       1.1   thorpej }
    621       1.1   thorpej 
    622       1.1   thorpej /*
    623       1.1   thorpej  * _prop_data_internalize --
    624       1.1   thorpej  *	Parse a <data>...</data> and return the object created from the
    625       1.1   thorpej  *	external representation.
    626       1.1   thorpej  */
    627       1.8     joerg 
    628       1.8     joerg /* strtoul is used for parsing, enforce. */
    629       1.8     joerg typedef int PROP_DATA_ASSERT[/* CONSTCOND */sizeof(size_t) == sizeof(unsigned long) ? 1 : -1];
    630       1.8     joerg 
    631       1.8     joerg /* ARGSUSED */
    632       1.8     joerg bool
    633       1.8     joerg _prop_data_internalize(prop_stack_t stack, prop_object_t *obj,
    634       1.8     joerg     struct _prop_object_internalize_context *ctx)
    635       1.1   thorpej {
    636       1.1   thorpej 	prop_data_t data;
    637       1.1   thorpej 	uint8_t *buf;
    638       1.1   thorpej 	size_t len, alen;
    639       1.1   thorpej 
    640  1.18.8.1  perseant 	/* No JSON binary data object representation. */
    641  1.18.8.1  perseant 	if (ctx->poic_format == PROP_FORMAT_JSON) {
    642  1.18.8.1  perseant 		return true;
    643  1.18.8.1  perseant 	}
    644  1.18.8.1  perseant 
    645      1.14     cyber 	/*
    646      1.14     cyber 	 * We don't accept empty elements.
    647      1.14     cyber 	 * This actually only checks for the node to be <data/>
    648      1.14     cyber 	 * (Which actually causes another error if found.)
    649      1.14     cyber 	 */
    650       1.1   thorpej 	if (ctx->poic_is_empty_element)
    651       1.8     joerg 		return (true);
    652       1.8     joerg 
    653       1.1   thorpej 	/*
    654       1.1   thorpej 	 * If we got a "size" attribute, get the size of the data blob
    655       1.1   thorpej 	 * from that.  Otherwise, we have to figure it out from the base64.
    656       1.1   thorpej 	 */
    657       1.1   thorpej 	if (ctx->poic_tagattr != NULL) {
    658       1.1   thorpej 		char *cp;
    659       1.1   thorpej 
    660       1.1   thorpej 		if (!_PROP_TAGATTR_MATCH(ctx, "size") ||
    661       1.1   thorpej 		    ctx->poic_tagattrval_len == 0)
    662       1.8     joerg 			return (true);
    663       1.1   thorpej 
    664       1.1   thorpej #ifndef _KERNEL
    665       1.1   thorpej 		errno = 0;
    666       1.1   thorpej #endif
    667       1.1   thorpej 		len = strtoul(ctx->poic_tagattrval, &cp, 0);
    668       1.1   thorpej #ifndef _KERNEL		/* XXX can't check for ERANGE in the kernel */
    669       1.1   thorpej 		if (len == ULONG_MAX && errno == ERANGE)
    670       1.8     joerg 			return (true);
    671       1.1   thorpej #endif
    672       1.1   thorpej 		if (cp != ctx->poic_tagattrval + ctx->poic_tagattrval_len)
    673       1.8     joerg 			return (true);
    674       1.1   thorpej 		_PROP_ASSERT(*cp == '\"');
    675       1.1   thorpej 	} else if (_prop_data_internalize_decode(ctx, NULL, 0, &len,
    676       1.7   thorpej 						NULL) == false)
    677       1.8     joerg 		return (true);
    678       1.1   thorpej 
    679       1.1   thorpej 	/*
    680       1.1   thorpej 	 * Always allocate one extra in case we don't land on an even byte
    681       1.1   thorpej 	 * boundary during the decode.
    682       1.1   thorpej 	 */
    683       1.1   thorpej 	buf = _PROP_MALLOC(len + 1, M_PROP_DATA);
    684       1.1   thorpej 	if (buf == NULL)
    685       1.8     joerg 		return (true);
    686      1.18  riastrad 
    687       1.1   thorpej 	if (_prop_data_internalize_decode(ctx, buf, len + 1, &alen,
    688       1.7   thorpej 					  &ctx->poic_cp) == false) {
    689       1.1   thorpej 		_PROP_FREE(buf, M_PROP_DATA);
    690       1.8     joerg 		return (true);
    691       1.1   thorpej 	}
    692       1.1   thorpej 	if (alen != len) {
    693       1.1   thorpej 		_PROP_FREE(buf, M_PROP_DATA);
    694       1.8     joerg 		return (true);
    695       1.1   thorpej 	}
    696       1.1   thorpej 
    697  1.18.8.1  perseant 	if (_prop_xml_intern_find_tag(ctx, "data",
    698  1.18.8.1  perseant 				      _PROP_TAG_TYPE_END) == false) {
    699       1.1   thorpej 		_PROP_FREE(buf, M_PROP_DATA);
    700       1.8     joerg 		return (true);
    701       1.1   thorpej 	}
    702       1.1   thorpej 
    703      1.14     cyber 	/*
    704      1.14     cyber 	 * Handle alternate type of empty node.
    705      1.14     cyber 	 * XML document could contain open/close tags, yet still be empty.
    706      1.14     cyber 	 */
    707      1.14     cyber 	if (alen == 0) {
    708      1.14     cyber 		_PROP_FREE(buf, M_PROP_DATA);
    709      1.16   thorpej 		buf = NULL;
    710      1.14     cyber 	}
    711      1.16   thorpej 
    712      1.16   thorpej 	data = _prop_data_instantiate(0, buf, len);
    713      1.16   thorpej 	if (data == NULL && buf != NULL)
    714      1.16   thorpej 		_PROP_FREE(buf, M_PROP_DATA);
    715       1.1   thorpej 
    716       1.8     joerg 	*obj = data;
    717       1.8     joerg 	return (true);
    718       1.1   thorpej }
    719