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
);