2 * Copyright (c) 2003 Matthew Dillon <dillon@backplane.com>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $DragonFly: src/lib/libcaps/caps_struct.c,v 1.1 2004/03/07 23:36:44 dillon Exp $
33 parsehex32(const u_int8_t *ptr, int len)
39 if (len && ptr[0] == '-') {
47 if (c >= '0' && c <= '9')
49 if (c >= 'a' && c <= 'f')
61 parsehex64(const u_int8_t *ptr, int len)
66 if (len && ptr[0] == '-') {
73 v = parsehex32(ptr + len - 4, 4) |
74 ((int64_t)parsehex32(ptr, len - 4) << 32);
76 v = (int64_t)parsehex32(ptr, len);
84 caps_find_label(caps_struct_t cs, caps_fid_t fid, const struct caps_label **pcache)
88 if ((label = *pcache) != NULL) {
89 if (label->fid == fid)
92 if (label->fid == fid && label->offset >= 0) {
97 if (label != cs->labels) {
99 if (label->fid == fid && label->offset >= 0) {
105 for (label = cs->labels; label->offset >= 0; ++label) {
106 if (label->fid == fid) {
115 * Generic structural encoder. The number of bytes that would be stored in
116 * buf if it were infinitely-sized is returned.
119 caps_encode(void *buf, int bytes, void *data, caps_struct_t cs)
121 struct caps_msgbuf msgbuf;
123 caps_init_msgbuf(&msgbuf, buf, bytes);
124 caps_msg_encode_structure(&msgbuf, data, cs);
125 return(msgbuf.index);
129 * Encode a structure into a message using the supplied label data. The
130 * message's index is updated to reflect the actual number of bytes that
131 * would be consumed, even if the message buffer would overflow (but we don't
132 * overflow the buffer, obviously).
135 caps_msg_encode_structure(caps_msgbuf_t msg, void *data, caps_struct_t cs)
140 caps_msgbuf_printf(msg, "S%s{", cs->name);
141 for (label = cs->labels; label->offset >= 0; ++label) {
142 if (label != cs->labels)
143 caps_msgbuf_putc(msg, ',');
144 caps_msgbuf_printf(msg, "F%x", label->fid);
145 ptr = (char *)data + label->offset;
147 caps_msg_encode_array(msg, ptr, label);
148 else if (label->csinfo)
149 caps_msg_encode_structure(msg, ptr, label->csinfo);
151 caps_msg_encode_data(msg, ptr, label->type, label->size);
153 caps_msgbuf_putc(msg, '}');
157 caps_msg_encode_array(caps_msgbuf_t msg, void *data, caps_label_t label)
162 caps_msgbuf_printf(msg, "A%x{", label->nary);
163 for (i = 0; i < label->nary; ++i) {
164 ptr = (char *)data + i *
165 ((label->type & CAPS_OPF_PTR) ? sizeof(void *) : label->size);
167 caps_msg_encode_structure(msg, ptr, label->csinfo);
169 caps_msg_encode_data(msg, ptr, label->type, label->size);
171 caps_msgbuf_putc(msg, '}');
175 caps_msg_encode_data(caps_msgbuf_t msg, void *data, int type, int size)
184 if (*(int8_t *)data < 0)
185 caps_msgbuf_printf(msg, "D-%x", -*(int8_t *)data);
187 caps_msgbuf_printf(msg, "D%x", *(u_int8_t *)data);
190 if (*(int16_t *)data < 0)
191 caps_msgbuf_printf(msg, "D%x", -*(int16_t *)data);
193 caps_msgbuf_printf(msg, "D%x", *(u_int16_t *)data);
196 if (*(int32_t *)data < 0)
197 caps_msgbuf_printf(msg, "D%x", -*(int32_t *)data);
199 caps_msgbuf_printf(msg, "D%x", *(u_int32_t *)data);
202 if (*(int64_t *)data < 0)
203 caps_msgbuf_printf(msg, "D%llx", -*(int64_t *)data);
205 caps_msgbuf_printf(msg, "D%llx", *(u_int64_t *)data);
208 caps_msgbuf_putc(msg, 'D');
209 caps_msgbuf_putc(msg, '?');
216 caps_msgbuf_printf(msg, "D%x", *(u_int8_t *)data);
219 caps_msgbuf_printf(msg, "D%x", *(u_int16_t *)data);
222 caps_msgbuf_printf(msg, "D%x", *(u_int32_t *)data);
225 caps_msgbuf_printf(msg, "D%llx", *(u_int64_t *)data);
228 caps_msgbuf_putc(msg, 'D');
229 caps_msgbuf_putc(msg, '?');
233 case CAPS_OP_STRPTR_T:
234 data = *(void **)data;
236 caps_msgbuf_printf(msg, "D"); /* represents NULL */
241 /* fall through, size is the 'limit' */
242 case CAPS_OP_STRBUF_T:
243 caps_msgbuf_putc(msg, 'D');
244 caps_msgbuf_putc(msg, '"'); /* string designator */
245 for (i = 0; i < size && (c = ((u_int8_t *)data)[i]) != 0; ++i) {
246 if ((c >= 'a' && c <= 'z') ||
247 (c >= 'A' && c <= 'Z') ||
248 (c >= '0' && c <= '9') ||
249 c == '_' || c == '.' || c == '/' || c == '+' || c == '-'
251 caps_msgbuf_putc(msg, c);
253 caps_msgbuf_printf(msg, "%%%02x", (int)c);
256 caps_msgbuf_putc(msg, '"');
258 case CAPS_OP_OPAQUE_T:
259 caps_msgbuf_putc(msg, 'D');
260 caps_msgbuf_putc(msg, '"');
261 for (i = 0; i < size; ++i) {
262 c = ((u_int8_t *)data)[i];
263 if ((c >= 'a' && c <= 'z') ||
264 (c >= 'A' && c <= 'Z') ||
265 (c >= '0' && c <= '9') ||
266 c == '_' || c == '.' || c == '/' || c == '+' || c == '-'
268 caps_msgbuf_putc(msg, c);
270 caps_msgbuf_printf(msg, "%%%02x", (int)c);
273 caps_msgbuf_putc(msg, '"');
276 caps_msgbuf_putc(msg, 'D');
277 caps_msgbuf_putc(msg, '?');
283 * Generic structural decoder. The number of bytes that were decoded from
284 * the buffer are returned, the structure is populated, and the error code
285 * is set unconditionally as a side effect.
288 caps_decode(const void *buf, int bytes, void *data, caps_struct_t cs, int *error)
290 struct caps_msgbuf msgbuf;
295 caps_init_msgbuf(&msgbuf, (void *)buf, bytes);
296 while ((c = caps_msgbuf_getclass(&msgbuf, &ptr, &len)) != 0) {
297 if (c == 'S' && len == strlen(cs->name) &&
298 strncmp(ptr, cs->name, len) == 0
300 caps_msg_decode_structure(&msgbuf, data, cs);
301 *error = msgbuf.error;
302 return(msgbuf.index);
305 * Skip substructures.
308 caps_msgbuf_error(&msgbuf, 0, 1);
309 caps_msg_decode_structure(&msgbuf, NULL, NULL);
312 if (msgbuf.error == 0)
314 *error = msgbuf.error;
315 return(msgbuf.index);
319 * Decode a message buffer into a structure, return the number of bytes
320 * chomped and set *error to 0 on success, or an error code on failure.
321 * The 'Sname' has already been snarfed. We are responsible for snarfing
324 * Note that the structural specification, cs, may be NULL, indicating and
325 * unknown structure which causes us to skip the structure.
328 caps_msg_decode_structure(caps_msgbuf_t msg, void *data, caps_struct_t cs)
339 * A structure must contain an open brace
341 if (caps_msgbuf_getc(msg) != '{') {
342 caps_msgbuf_error(msg, EINVAL, 1);
347 * Parse data elements within the structure
351 * Parse class info for the next element. Note that the label
352 * specification may be NULL.
355 while ((c = caps_msgbuf_getclass(msg, &ptr, &len)) != 0) {
358 label = caps_find_label(cs, parsehex32(ptr, len), &cache);
361 caps_msg_decode_array(msg,
362 (char *)data + label->offset,
363 parsehex32(ptr, len),
367 if (label && label->csinfo &&
368 strlen(label->csinfo->name) == len &&
369 strncmp(label->csinfo->name, ptr, len) == 0
371 caps_msg_decode_structure(msg,
372 (char *)data + label->offset,
375 caps_msg_decode_structure(msg, NULL, NULL);
380 caps_msg_decode_data(ptr, len,
381 (char *)data + label->offset,
388 * This case occurs when we previously hit an unknown class
389 * which has a sub-structure associated with it. Parseskip
392 caps_msgbuf_error(msg, 0, 1);
393 caps_msg_decode_structure(msg, NULL, NULL);
399 /* unknown classes are ignored */
407 * A structure must end with a close brace
410 caps_msgbuf_error(msg, EINVAL, 1);
414 caps_msg_decode_array(caps_msgbuf_t msg, void *data, int nary, caps_label_t label)
424 * An array must contain an open brace
426 if (caps_msgbuf_getc(msg) != '{') {
427 caps_msgbuf_error(msg, EINVAL, 1);
430 for (i = 0; i < nary && (label == NULL || i < label->nary); ++i) {
431 while ((c = caps_msgbuf_getclass(msg, &ptr, &len)) != 0) {
434 /* a field id for an array element is not expected */
437 /* nested arrays are not yet supported */
440 if (label && label->csinfo &&
441 strlen(label->csinfo->name) == len &&
442 strncmp(label->csinfo->name, ptr, len) == 0
444 caps_msg_decode_structure(msg, data, label->csinfo);
446 caps_msg_decode_structure(msg, NULL, NULL);
451 caps_msg_decode_data(ptr, len, data,
452 label->type, label->size);
457 * This case occurs when we previously hit an unknown class
458 * which has a sub-structure associated with it. Parseskip
461 caps_msgbuf_error(msg, 0, 1);
462 caps_msg_decode_structure(msg, NULL, NULL);
468 /* unknown classes are ignored */
475 data = (char *)data +
476 ((label->type & CAPS_OPF_PTR) ? sizeof(void *) : label->size);
480 * I really expected a comma here
483 caps_msgbuf_error(msg, EINVAL, 0);
489 * Our array was too small, exhaust any remaining elements
491 for (; i < nary; ++i) {
492 while ((c = caps_msgbuf_getclass(msg, &ptr, &len)) != 0) {
495 caps_msg_decode_structure(msg, NULL, NULL);
498 /* data is embedded, no additional decoding needed to skip */
501 caps_msgbuf_error(msg, 0, 1);
502 caps_msg_decode_structure(msg, NULL, NULL);
508 /* unknown classes are ignored */
514 caps_msgbuf_error(msg, EINVAL, 0);
520 * Finish up. Note degenerate case (c not loaded) if nary is 0
523 c = caps_msgbuf_getc(msg);
525 caps_msgbuf_error(msg, EINVAL, 1);
529 caps_msg_decode_data(char *ptr, int len, void *data, int type, int size)
539 *(int8_t *)data = parsehex32(ptr, len);
542 *(int16_t *)data = parsehex32(ptr, len);
545 *(int32_t *)data = parsehex32(ptr, len);
548 *(int64_t *)data = parsehex64(ptr, len);
551 /* unknown data type */
555 case CAPS_OP_STRPTR_T:
557 * Assume NULL if not a quoted string (the actual encoding for NULL
558 * is a completely empty 'D' specification).
560 if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
561 *(void **)data = NULL;
564 for (i = j = 0; i < len; ++j) {
571 if (size == 0 || size > j)
573 *(void **)data = malloc(size);
574 data = *(void **)data;
575 assert(data != NULL);
577 case CAPS_OP_STRBUF_T:
578 case CAPS_OP_OPAQUE_T:
582 if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
589 * Parse the contents of the string
591 for (i = j = 0; i < len && j < size; ++j) {
594 ((char *)data)[j] = parsehex32(ptr + 1, 2);
601 ((char *)data)[j] = ptr[i];
605 if (type == CAPS_OP_OPAQUE_T) {
607 bzero((char *)data + j, size - j);
610 ((char *)data)[j] = 0;
612 ((char *)data)[size - 1] = 0; /* XXX error */
621 * Free string pointers dynamically allocated by caps_msg_decode_structure().
624 caps_struct_free_pointers(void *data, caps_struct_t cs)
629 for (label = cs->labels; label->offset >= 0; ++label) {
630 ptr = (char *)data + label->offset;
631 if (label->nary > 1) {
632 caps_array_free_pointers(ptr, label);
633 } else if (label->csinfo) {
634 caps_struct_free_pointers(ptr, label->csinfo);
635 } else if (label->type & CAPS_OPF_PTR) {
638 *(void **)ptr = NULL;
645 caps_array_free_pointers(void *data, caps_label_t label)
649 for (i = 0; i < label->nary; ++i) {
651 caps_struct_free_pointers(data, label->csinfo);
652 } else if (label->type & CAPS_OPF_PTR) {
653 if (*(void **)data) {
654 free(*(void **)data);
655 *(void **)data = NULL;
658 data = (char *)data +
659 ((label->type & CAPS_OPF_PTR) ? sizeof(void *) : label->size);