2 * blob - library for generating/parsing tagged binary data
4 * Copyright (C) 2010 Felix Fietkau <nbd@openwrt.org>
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 blob_buffer_grow(struct blob_buf
*buf
, int minlen
)
25 int delta
= ((minlen
/ 256) + 1) * 256;
26 new = realloc(buf
->buf
, buf
->buflen
+ delta
);
29 memset(buf
->buf
+ buf
->buflen
, 0, delta
);
36 blob_init(struct blob_attr
*attr
, int id
, unsigned int len
)
38 len
&= BLOB_ATTR_LEN_MASK
;
39 len
|= (id
<< BLOB_ATTR_ID_SHIFT
) & BLOB_ATTR_ID_MASK
;
40 attr
->id_len
= cpu_to_be32(len
);
43 static inline struct blob_attr
*
44 offset_to_attr(struct blob_buf
*buf
, int offset
)
46 void *ptr
= (char *)buf
->buf
+ offset
- BLOB_COOKIE
;
51 attr_to_offset(struct blob_buf
*buf
, struct blob_attr
*attr
)
53 return (char *)attr
- (char *) buf
->buf
+ BLOB_COOKIE
;
57 blob_buf_grow(struct blob_buf
*buf
, int required
)
59 int offset_head
= attr_to_offset(buf
, buf
->head
);
61 if ((buf
->buflen
+ required
) > BLOB_ATTR_LEN_MASK
)
63 if (!buf
->grow
|| !buf
->grow(buf
, required
))
66 buf
->head
= offset_to_attr(buf
, offset_head
);
70 static struct blob_attr
*
71 blob_add(struct blob_buf
*buf
, struct blob_attr
*pos
, int id
, int payload
)
73 int offset
= attr_to_offset(buf
, pos
);
74 int required
= (offset
- BLOB_COOKIE
+ sizeof(struct blob_attr
) + payload
) - buf
->buflen
;
75 struct blob_attr
*attr
;
78 if (!blob_buf_grow(buf
, required
))
80 attr
= offset_to_attr(buf
, offset
);
85 blob_init(attr
, id
, payload
+ sizeof(struct blob_attr
));
91 blob_buf_init(struct blob_buf
*buf
, int id
)
94 buf
->grow
= blob_buffer_grow
;
97 if (blob_add(buf
, buf
->buf
, id
, 0) == NULL
)
104 blob_buf_free(struct blob_buf
*buf
)
113 blob_fill_pad(struct blob_attr
*attr
)
115 char *buf
= (char *) attr
;
116 int len
= blob_pad_len(attr
);
117 int delta
= len
- blob_raw_len(attr
);
120 memset(buf
+ len
- delta
, 0, delta
);
124 blob_set_raw_len(struct blob_attr
*attr
, unsigned int len
)
126 len
&= BLOB_ATTR_LEN_MASK
;
127 attr
->id_len
&= ~cpu_to_be32(BLOB_ATTR_LEN_MASK
);
128 attr
->id_len
|= cpu_to_be32(len
);
132 blob_new(struct blob_buf
*buf
, int id
, int payload
)
134 struct blob_attr
*attr
;
136 attr
= blob_add(buf
, blob_next(buf
->head
), id
, payload
);
140 blob_set_raw_len(buf
->head
, blob_pad_len(buf
->head
) + blob_pad_len(attr
));
145 blob_put_raw(struct blob_buf
*buf
, const void *ptr
, unsigned int len
)
147 struct blob_attr
*attr
;
149 if (len
< sizeof(struct blob_attr
) || !ptr
)
152 attr
= blob_add(buf
, blob_next(buf
->head
), 0, len
- sizeof(struct blob_attr
));
155 blob_set_raw_len(buf
->head
, blob_pad_len(buf
->head
) + len
);
156 memcpy(attr
, ptr
, len
);
161 blob_put(struct blob_buf
*buf
, int id
, const void *ptr
, unsigned int len
)
163 struct blob_attr
*attr
;
165 attr
= blob_new(buf
, id
, len
);
170 memcpy(blob_data(attr
), ptr
, len
);
175 blob_nest_start(struct blob_buf
*buf
, int id
)
177 unsigned long offset
= attr_to_offset(buf
, buf
->head
);
178 buf
->head
= blob_new(buf
, id
, 0);
181 return (void *) offset
;
185 blob_nest_end(struct blob_buf
*buf
, void *cookie
)
187 struct blob_attr
*attr
= offset_to_attr(buf
, (unsigned long) cookie
);
188 blob_set_raw_len(attr
, blob_pad_len(attr
) + blob_len(buf
->head
));
192 static const size_t blob_type_minlen
[BLOB_ATTR_LAST
] = {
193 [BLOB_ATTR_STRING
] = 1,
194 [BLOB_ATTR_INT8
] = sizeof(uint8_t),
195 [BLOB_ATTR_INT16
] = sizeof(uint16_t),
196 [BLOB_ATTR_INT32
] = sizeof(uint32_t),
197 [BLOB_ATTR_INT64
] = sizeof(uint64_t),
198 [BLOB_ATTR_DOUBLE
] = sizeof(double),
202 blob_check_type(const void *ptr
, unsigned int len
, int type
)
204 const char *data
= ptr
;
206 if (type
>= BLOB_ATTR_LAST
)
209 if (type
>= BLOB_ATTR_INT8
&& type
<= BLOB_ATTR_INT64
) {
210 if (len
!= blob_type_minlen
[type
])
213 if (len
< blob_type_minlen
[type
])
217 if (type
== BLOB_ATTR_STRING
&& data
[len
- 1] != 0)
224 blob_parse_attr(struct blob_attr
*attr
, size_t attr_len
, struct blob_attr
**data
, const struct blob_attr_info
*info
, int max
)
231 if (!attr
|| attr_len
< sizeof(struct blob_attr
))
238 len
= blob_raw_len(attr
);
239 if (len
> attr_len
|| len
< sizeof(struct blob_attr
))
242 data_len
= blob_len(attr
);
247 int type
= info
[id
].type
;
249 if (type
< BLOB_ATTR_LAST
) {
250 if (!blob_check_type(blob_data(attr
), data_len
, type
))
254 if (info
[id
].minlen
&& len
< info
[id
].minlen
)
257 if (info
[id
].maxlen
&& len
> info
[id
].maxlen
)
260 if (info
[id
].validate
&& !info
[id
].validate(&info
[id
], attr
))
272 blob_parse_untrusted(struct blob_attr
*attr
, size_t attr_len
, struct blob_attr
**data
, const struct blob_attr_info
*info
, int max
)
274 struct blob_attr
*pos
;
279 if (!attr
|| attr_len
< sizeof(struct blob_attr
))
282 len
= blob_raw_len(attr
);
286 memset(data
, 0, sizeof(struct blob_attr
*) * max
);
287 blob_for_each_attr_len(pos
, attr
, len
, rem
) {
288 found
+= blob_parse_attr(pos
, rem
, data
, info
, max
);
294 /* use only on trusted input, otherwise consider blob_parse_untrusted */
296 blob_parse(struct blob_attr
*attr
, struct blob_attr
**data
, const struct blob_attr_info
*info
, int max
)
298 struct blob_attr
*pos
;
302 memset(data
, 0, sizeof(struct blob_attr
*) * max
);
303 blob_for_each_attr(pos
, attr
, rem
) {
304 found
+= blob_parse_attr(pos
, rem
, data
, info
, max
);
311 blob_attr_equal(const struct blob_attr
*a1
, const struct blob_attr
*a2
)
319 if (blob_pad_len(a1
) != blob_pad_len(a2
))
322 return !memcmp(a1
, a2
, blob_pad_len(a1
));
326 blob_memdup(struct blob_attr
*attr
)
328 struct blob_attr
*ret
;
329 int size
= blob_pad_len(attr
);
335 memcpy(ret
, attr
, size
);