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