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