Home | History | Annotate | Line # | Download | only in libprop
      1  1.23   thorpej /*	$NetBSD: prop_data.c,v 1.23 2025/05/14 03:25:45 thorpej Exp $	*/
      2   1.1   thorpej 
      3   1.1   thorpej /*-
      4  1.19   thorpej  * 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.19   thorpej static const struct _prop_object_type_tags _prop_data_type_tags = {
     66  1.19   thorpej 	.xml_tag		=	"data",
     67  1.19   thorpej };
     68  1.19   thorpej 
     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.19   thorpej 	_PROP_ASSERT(ctx->poec_format == PROP_FORMAT_XML ||
    116  1.19   thorpej 		     ctx->poec_format == PROP_FORMAT_JSON);
    117  1.19   thorpej 
    118  1.19   thorpej 	/*
    119  1.19   thorpej 	 * JSON does not have a syntax for serialized binary data.
    120  1.19   thorpej 	 */
    121  1.19   thorpej 	if (ctx->poec_format == PROP_FORMAT_JSON) {
    122  1.19   thorpej 		return false;
    123  1.19   thorpej 	}
    124  1.19   thorpej 
    125   1.1   thorpej 	if (pd->pd_size == 0)
    126  1.23   thorpej 		return (_prop_extern_append_empty_tag(ctx,
    127  1.19   thorpej 		    &_prop_data_type_tags));
    128   1.1   thorpej 
    129  1.23   thorpej 	if (_prop_extern_append_start_tag(ctx,
    130  1.19   thorpej 				&_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.23   thorpej 		if (_prop_extern_append_char(ctx,
    151   1.7   thorpej 				_prop_data_base64[output[0]]) == false ||
    152  1.23   thorpej 		    _prop_extern_append_char(ctx,
    153   1.7   thorpej 		    		_prop_data_base64[output[1]]) == false ||
    154  1.23   thorpej 		    _prop_extern_append_char(ctx,
    155   1.7   thorpej 		    		_prop_data_base64[output[2]]) == false ||
    156  1.23   thorpej 		    _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.23   thorpej 		if (_prop_extern_append_char(ctx,
    176   1.7   thorpej 				_prop_data_base64[output[0]]) == false ||
    177  1.23   thorpej 		    _prop_extern_append_char(ctx,
    178   1.7   thorpej 		    		_prop_data_base64[output[1]]) == false ||
    179  1.23   thorpej 		    _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.23   thorpej 		    _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.23   thorpej 	if (_prop_extern_append_end_tag(ctx,
    188  1.19   thorpej 					&_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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.20   thorpej _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.19   thorpej 	/* No JSON binary data object representation. */
    641  1.19   thorpej 	if (ctx->poic_format == PROP_FORMAT_JSON) {
    642  1.19   thorpej 		return true;
    643  1.19   thorpej 	}
    644  1.19   thorpej 
    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.23   thorpej 	if (_prop_xml_intern_find_tag(ctx, "data",
    698  1.23   thorpej 				      _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