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