source: mainline/uspace/app/bithenge/transform.c@ 04a7435f

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 04a7435f was 04a7435f, checked in by Sean Bartell <wingedtachikoma@…>, 13 years ago

Bithenge: add the struct transform

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2012 Sean Bartell
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup bithenge
30 * @{
31 */
32/**
33 * @file
34 * Transforms.
35 */
36
37#include <assert.h>
38#include <errno.h>
39#include <stdlib.h>
40#include "blob.h"
41#include "transform.h"
42
43/** Initialize a new transform.
44 * @param[out] xform Transform to initialize.
45 * @param[in] ops Operations provided by the transform.
46 * @return EOK or an error code from errno.h. */
47int bithenge_new_transform(bithenge_transform_t *xform,
48 const bithenge_transform_ops_t *ops)
49{
50 assert(ops);
51 assert(ops->apply);
52 assert(ops->destroy);
53 xform->ops = ops;
54 xform->refs = 1;
55 return EOK;
56}
57
58static int transform_indestructible(bithenge_transform_t *xform)
59{
60 assert(false);
61 return EOK;
62}
63
64static int uint32le_apply(bithenge_transform_t *xform, bithenge_node_t *in,
65 bithenge_node_t **out)
66{
67 int rc;
68 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
69 return EINVAL;
70 bithenge_blob_t *blob = bithenge_node_as_blob(in);
71
72 // Try to read 5 bytes and fail if the blob is too long.
73 uint32_t val[2];
74 aoff64_t size = sizeof(val[0]) + 1;
75 rc = bithenge_blob_read(blob, 0, (char *)val, &size);
76 if (rc != EOK)
77 return rc;
78 if (size != 4)
79 return EINVAL;
80
81 return bithenge_new_integer_node(out, uint32_t_le2host(val[0]));
82}
83
84static int uint32be_apply(bithenge_transform_t *xform, bithenge_node_t *in,
85 bithenge_node_t **out)
86{
87 int rc;
88 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
89 return EINVAL;
90 bithenge_blob_t *blob = bithenge_node_as_blob(in);
91
92 // Try to read 5 bytes and fail if the blob is too long.
93 uint32_t val[2];
94 aoff64_t size = sizeof(val[0]) + 1;
95 rc = bithenge_blob_read(blob, 0, (char *)val, &size);
96 if (rc != EOK)
97 return rc;
98 if (size != 4)
99 return EINVAL;
100
101 return bithenge_new_integer_node(out, uint32_t_be2host(val[0]));
102}
103
104static int prefix_length_4(bithenge_transform_t *xform, bithenge_blob_t *blob,
105 aoff64_t *out)
106{
107 *out = 4;
108 return EOK;
109}
110
111static const bithenge_transform_ops_t uint32le_ops = {
112 .apply = uint32le_apply,
113 .prefix_length = prefix_length_4,
114 .destroy = transform_indestructible,
115};
116
117static const bithenge_transform_ops_t uint32be_ops = {
118 .apply = uint32be_apply,
119 .prefix_length = prefix_length_4,
120 .destroy = transform_indestructible,
121};
122
123/** The little-endian 32-bit unsigned integer transform. */
124bithenge_transform_t bithenge_uint32le_transform = {
125 &uint32le_ops, 1
126};
127
128/** The big-endian 32-bit unsigned integer transform. */
129bithenge_transform_t bithenge_uint32be_transform = {
130 &uint32be_ops, 1
131};
132
133static bithenge_named_transform_t primitive_transforms[] = {
134 {"uint32le", &bithenge_uint32le_transform},
135 {"uint32be", &bithenge_uint32be_transform},
136 {NULL, NULL}
137};
138
139/** An array of named built-in transforms. */
140bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
141
142typedef struct {
143 bithenge_node_t base;
144 struct struct_transform *transform;
145 bithenge_blob_t *blob;
146} struct_node_t;
147
148typedef struct struct_transform {
149 bithenge_transform_t base;
150 bithenge_named_transform_t *subtransforms;
151} struct_transform_t;
152
153static bithenge_node_t *struct_as_node(struct_node_t *node)
154{
155 return &node->base;
156}
157
158static struct_node_t *node_as_struct(bithenge_node_t *node)
159{
160 return (struct_node_t *)node;
161}
162
163static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
164{
165 return &xform->base;
166}
167
168static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
169{
170 return (struct_transform_t *)xform;
171}
172
173static int struct_node_for_one(const char *name,
174 bithenge_transform_t *subxform, bithenge_blob_t **blob,
175 bithenge_for_each_func_t func, void *data)
176{
177 int rc;
178 bithenge_node_t *subxform_result = NULL;
179
180 aoff64_t sub_size;
181 rc = bithenge_transform_prefix_length(subxform, *blob, &sub_size);
182 if (rc != EOK)
183 goto error;
184
185 bithenge_node_t *subblob_node;
186 bithenge_blob_inc_ref(*blob);
187 rc = bithenge_new_subblob(&subblob_node, *blob, 0, sub_size);
188 if (rc != EOK)
189 goto error;
190
191 rc = bithenge_transform_apply(subxform, subblob_node,
192 &subxform_result);
193 bithenge_node_dec_ref(subblob_node);
194 if (rc != EOK)
195 goto error;
196
197 if (name) {
198 bithenge_node_t *name_node;
199 rc = bithenge_new_string_node(&name_node, name, false);
200 if (rc != EOK)
201 goto error;
202 rc = func(name_node, subxform_result, data);
203 subxform_result = NULL;
204 if (rc != EOK)
205 goto error;
206 } else {
207 if (bithenge_node_type(subxform_result) !=
208 BITHENGE_NODE_INTERNAL) {
209 rc = EINVAL;
210 goto error;
211 }
212 rc = bithenge_node_for_each(subxform_result, func, data);
213 if (rc != EOK)
214 goto error;
215 }
216
217 bithenge_node_t *blob_node;
218 rc = bithenge_new_offset_blob(&blob_node, *blob, sub_size);
219 *blob = NULL;
220 if (rc != EOK)
221 goto error;
222 *blob = bithenge_node_as_blob(blob_node);
223
224error:
225 bithenge_node_dec_ref(subxform_result);
226 return rc;
227}
228
229static int struct_node_for_each(bithenge_node_t *base,
230 bithenge_for_each_func_t func, void *data)
231{
232 int rc = EOK;
233 struct_node_t *struct_node = node_as_struct(base);
234 bithenge_named_transform_t *subxforms =
235 struct_node->transform->subtransforms;
236
237 bithenge_node_t *blob_node = NULL;
238 bithenge_blob_t *blob = NULL;
239 bithenge_blob_inc_ref(struct_node->blob);
240 rc = bithenge_new_offset_blob(&blob_node, struct_node->blob, 0);
241 if (rc != EOK) {
242 blob = NULL;
243 goto error;
244 }
245 blob = bithenge_node_as_blob(blob_node);
246
247 for (size_t i = 0; subxforms[i].transform; i++) {
248 rc = struct_node_for_one(subxforms[i].name,
249 subxforms[i].transform, &blob, func, data);
250 if (rc != EOK)
251 goto error;
252 }
253
254 aoff64_t remaining;
255 rc = bithenge_blob_size(blob, &remaining);
256 if (rc != EOK)
257 goto error;
258 if (remaining != 0) {
259 rc = EINVAL;
260 goto error;
261 }
262
263error:
264 bithenge_blob_dec_ref(blob);
265 return rc;
266}
267
268static int struct_node_destroy(bithenge_node_t *base)
269{
270 struct_node_t *node = node_as_struct(base);
271 bithenge_transform_dec_ref(struct_as_transform(node->transform));
272 bithenge_blob_dec_ref(node->blob);
273 free(node);
274 return EOK;
275}
276
277static const bithenge_internal_node_ops_t struct_node_ops = {
278 .for_each = struct_node_for_each,
279 .destroy = struct_node_destroy,
280};
281
282static int struct_transform_apply(bithenge_transform_t *xform,
283 bithenge_node_t *in, bithenge_node_t **out)
284{
285 struct_transform_t *struct_transform = transform_as_struct(xform);
286 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
287 return EINVAL;
288 struct_node_t *node = malloc(sizeof(*node));
289 if (!node)
290 return ENOMEM;
291 int rc = bithenge_init_internal_node(struct_as_node(node),
292 &struct_node_ops);
293 if (rc != EOK) {
294 free(node);
295 return rc;
296 }
297 bithenge_transform_inc_ref(xform);
298 node->transform = struct_transform;
299 bithenge_node_inc_ref(in);
300 node->blob = bithenge_node_as_blob(in);
301 *out = struct_as_node(node);
302 return EOK;
303}
304
305static int struct_transform_prefix_length(bithenge_transform_t *xform,
306 bithenge_blob_t *blob, aoff64_t *out)
307{
308 struct_transform_t *struct_transform = transform_as_struct(xform);
309 int rc = EOK;
310 bithenge_node_t *node;
311 bithenge_blob_inc_ref(blob);
312 rc = bithenge_new_offset_blob(&node, blob, 0);
313 blob = NULL;
314 if (rc != EOK)
315 goto error;
316 blob = bithenge_node_as_blob(node);
317 *out = 0;
318 for (size_t i = 0; struct_transform->subtransforms[i].transform; i++) {
319 bithenge_transform_t *subxform =
320 struct_transform->subtransforms[i].transform;
321 aoff64_t sub_size;
322 rc = bithenge_transform_prefix_length(subxform, blob, &sub_size);
323 if (rc != EOK)
324 goto error;
325 *out += sub_size;
326 rc = bithenge_new_offset_blob(&node, blob, sub_size);
327 blob = NULL;
328 if (rc != EOK)
329 goto error;
330 blob = bithenge_node_as_blob(node);
331 }
332error:
333 bithenge_blob_dec_ref(blob);
334 return EOK;
335}
336
337static void free_subtransforms(bithenge_named_transform_t *subtransforms)
338{
339 for (size_t i = 0; subtransforms[i].transform; i++) {
340 free((void *)subtransforms[i].name);
341 bithenge_transform_dec_ref(subtransforms[i].transform);
342 }
343 free(subtransforms);
344}
345
346static int struct_transform_destroy(bithenge_transform_t *xform)
347{
348 struct_transform_t *struct_transform = transform_as_struct(xform);
349 free_subtransforms(struct_transform->subtransforms);
350 free(struct_transform);
351 return EOK;
352}
353
354static bithenge_transform_ops_t struct_transform_ops = {
355 .apply = struct_transform_apply,
356 .prefix_length = struct_transform_prefix_length,
357 .destroy = struct_transform_destroy,
358};
359
360/** Create a struct transform. The transform will apply its subtransforms
361 * sequentially to a blob to create an internal node. Each result is either
362 * given a key from @a subtransforms or, if the name is NULL, the result's keys
363 * and values are merged into the struct transform's result. This function
364 * takes ownership of @a subtransforms and the names and references therein.
365 * @param[out] out Stores the created transform.
366 * @param subtransforms The subtransforms and field names.
367 * @return EOK on success or an error code from errno.h. */
368int bithenge_new_struct(bithenge_transform_t **out,
369 bithenge_named_transform_t *subtransforms)
370{
371 int rc;
372 struct_transform_t *struct_transform =
373 malloc(sizeof(*struct_transform));
374 if (!struct_transform) {
375 rc = ENOMEM;
376 goto error;
377 }
378 rc = bithenge_new_transform(struct_as_transform(struct_transform),
379 &struct_transform_ops);
380 if (rc != EOK)
381 goto error;
382 struct_transform->subtransforms = subtransforms;
383 *out = struct_as_transform(struct_transform);
384 return EOK;
385error:
386 free_subtransforms(subtransforms);
387 free(struct_transform);
388 return rc;
389}
390
391/** @}
392 */
Note: See TracBrowser for help on using the repository browser.