source: mainline/uspace/app/bithenge/transform.c@ 978ccaf1

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

Bithenge: various cleanup and tweaks

  • Property mode set to 100644
File size: 10.3 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] self Transform to initialize.
45 * @param[in] ops Operations provided by the transform.
46 * @return EOK or an error code from errno.h. */
47int bithenge_init_transform(bithenge_transform_t *self,
48 const bithenge_transform_ops_t *ops)
49{
50 assert(ops);
51 assert(ops->apply);
52 assert(ops->destroy);
53 self->ops = ops;
54 self->refs = 1;
55 return EOK;
56}
57
58static void transform_indestructible(bithenge_transform_t *self)
59{
60 assert(false);
61}
62
63static int uint32le_apply(bithenge_transform_t *self, bithenge_node_t *in,
64 bithenge_node_t **out)
65{
66 int rc;
67 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
68 return EINVAL;
69 bithenge_blob_t *blob = bithenge_node_as_blob(in);
70
71 // Try to read 5 bytes and fail if the blob is too long.
72 uint32_t val[2];
73 aoff64_t size = sizeof(val[0]) + 1;
74 rc = bithenge_blob_read(blob, 0, (char *)val, &size);
75 if (rc != EOK)
76 return rc;
77 if (size != 4)
78 return EINVAL;
79
80 return bithenge_new_integer_node(out, uint32_t_le2host(val[0]));
81}
82
83static int uint32be_apply(bithenge_transform_t *self, bithenge_node_t *in,
84 bithenge_node_t **out)
85{
86 int rc;
87 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
88 return EINVAL;
89 bithenge_blob_t *blob = bithenge_node_as_blob(in);
90
91 // Try to read 5 bytes and fail if the blob is too long.
92 uint32_t val[2];
93 aoff64_t size = sizeof(val[0]) + 1;
94 rc = bithenge_blob_read(blob, 0, (char *)val, &size);
95 if (rc != EOK)
96 return rc;
97 if (size != 4)
98 return EINVAL;
99
100 return bithenge_new_integer_node(out, uint32_t_be2host(val[0]));
101}
102
103static int prefix_length_4(bithenge_transform_t *self, bithenge_blob_t *blob,
104 aoff64_t *out)
105{
106 *out = 4;
107 return EOK;
108}
109
110static const bithenge_transform_ops_t uint32le_ops = {
111 .apply = uint32le_apply,
112 .prefix_length = prefix_length_4,
113 .destroy = transform_indestructible,
114};
115
116static const bithenge_transform_ops_t uint32be_ops = {
117 .apply = uint32be_apply,
118 .prefix_length = prefix_length_4,
119 .destroy = transform_indestructible,
120};
121
122/** The little-endian 32-bit unsigned integer transform. */
123bithenge_transform_t bithenge_uint32le_transform = {
124 &uint32le_ops, 1
125};
126
127/** The big-endian 32-bit unsigned integer transform. */
128bithenge_transform_t bithenge_uint32be_transform = {
129 &uint32be_ops, 1
130};
131
132static bithenge_named_transform_t primitive_transforms[] = {
133 {"uint32le", &bithenge_uint32le_transform},
134 {"uint32be", &bithenge_uint32be_transform},
135 {NULL, NULL}
136};
137
138/** An array of named built-in transforms. */
139bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
140
141typedef struct {
142 bithenge_node_t base;
143 struct struct_transform *transform;
144 bithenge_blob_t *blob;
145} struct_node_t;
146
147typedef struct struct_transform {
148 bithenge_transform_t base;
149 bithenge_named_transform_t *subtransforms;
150} struct_transform_t;
151
152static bithenge_node_t *struct_as_node(struct_node_t *node)
153{
154 return &node->base;
155}
156
157static struct_node_t *node_as_struct(bithenge_node_t *node)
158{
159 return (struct_node_t *)node;
160}
161
162static bithenge_transform_t *struct_as_transform(struct_transform_t *xform)
163{
164 return &xform->base;
165}
166
167static struct_transform_t *transform_as_struct(bithenge_transform_t *xform)
168{
169 return (struct_transform_t *)xform;
170}
171
172static int struct_node_for_one(const char *name,
173 bithenge_transform_t *subxform, bithenge_blob_t **blob,
174 bithenge_for_each_func_t func, void *data)
175{
176 int rc;
177 bithenge_node_t *subxform_result = NULL;
178
179 aoff64_t sub_size;
180 rc = bithenge_transform_prefix_length(subxform, *blob, &sub_size);
181 if (rc != EOK)
182 goto error;
183
184 bithenge_node_t *subblob_node;
185 bithenge_blob_inc_ref(*blob);
186 rc = bithenge_new_subblob(&subblob_node, *blob, 0, sub_size);
187 if (rc != EOK)
188 goto error;
189
190 rc = bithenge_transform_apply(subxform, subblob_node,
191 &subxform_result);
192 bithenge_node_dec_ref(subblob_node);
193 if (rc != EOK)
194 goto error;
195
196 if (name) {
197 bithenge_node_t *name_node;
198 rc = bithenge_new_string_node(&name_node, name, false);
199 if (rc != EOK)
200 goto error;
201 rc = func(name_node, subxform_result, data);
202 subxform_result = NULL;
203 if (rc != EOK)
204 goto error;
205 } else {
206 if (bithenge_node_type(subxform_result) !=
207 BITHENGE_NODE_INTERNAL) {
208 rc = EINVAL;
209 goto error;
210 }
211 rc = bithenge_node_for_each(subxform_result, func, data);
212 if (rc != EOK)
213 goto error;
214 }
215
216 bithenge_node_t *blob_node;
217 rc = bithenge_new_offset_blob(&blob_node, *blob, sub_size);
218 *blob = NULL;
219 if (rc != EOK)
220 goto error;
221 *blob = bithenge_node_as_blob(blob_node);
222
223error:
224 bithenge_node_dec_ref(subxform_result);
225 return rc;
226}
227
228static int struct_node_for_each(bithenge_node_t *base,
229 bithenge_for_each_func_t func, void *data)
230{
231 int rc = EOK;
232 struct_node_t *struct_node = node_as_struct(base);
233 bithenge_named_transform_t *subxforms =
234 struct_node->transform->subtransforms;
235
236 bithenge_node_t *blob_node = NULL;
237 bithenge_blob_t *blob = NULL;
238 bithenge_blob_inc_ref(struct_node->blob);
239 rc = bithenge_new_offset_blob(&blob_node, struct_node->blob, 0);
240 if (rc != EOK) {
241 blob = NULL;
242 goto error;
243 }
244 blob = bithenge_node_as_blob(blob_node);
245
246 for (size_t i = 0; subxforms[i].transform; i++) {
247 rc = struct_node_for_one(subxforms[i].name,
248 subxforms[i].transform, &blob, func, data);
249 if (rc != EOK)
250 goto error;
251 }
252
253 aoff64_t remaining;
254 rc = bithenge_blob_size(blob, &remaining);
255 if (rc != EOK)
256 goto error;
257 if (remaining != 0) {
258 rc = EINVAL;
259 goto error;
260 }
261
262error:
263 bithenge_blob_dec_ref(blob);
264 return rc;
265}
266
267static void struct_node_destroy(bithenge_node_t *base)
268{
269 struct_node_t *node = node_as_struct(base);
270 bithenge_transform_dec_ref(struct_as_transform(node->transform));
271 bithenge_blob_dec_ref(node->blob);
272 free(node);
273}
274
275static const bithenge_internal_node_ops_t struct_node_ops = {
276 .for_each = struct_node_for_each,
277 .destroy = struct_node_destroy,
278};
279
280static int struct_transform_apply(bithenge_transform_t *base,
281 bithenge_node_t *in, bithenge_node_t **out)
282{
283 struct_transform_t *self = transform_as_struct(base);
284 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
285 return EINVAL;
286 struct_node_t *node = malloc(sizeof(*node));
287 if (!node)
288 return ENOMEM;
289 int rc = bithenge_init_internal_node(struct_as_node(node),
290 &struct_node_ops);
291 if (rc != EOK) {
292 free(node);
293 return rc;
294 }
295 bithenge_transform_inc_ref(base);
296 node->transform = self;
297 bithenge_node_inc_ref(in);
298 node->blob = bithenge_node_as_blob(in);
299 *out = struct_as_node(node);
300 return EOK;
301}
302
303static int struct_transform_prefix_length(bithenge_transform_t *base,
304 bithenge_blob_t *blob, aoff64_t *out)
305{
306 struct_transform_t *self = transform_as_struct(base);
307 int rc = EOK;
308 bithenge_node_t *node;
309 bithenge_blob_inc_ref(blob);
310 rc = bithenge_new_offset_blob(&node, blob, 0);
311 blob = NULL;
312 if (rc != EOK)
313 goto error;
314 blob = bithenge_node_as_blob(node);
315 *out = 0;
316 for (size_t i = 0; self->subtransforms[i].transform; i++) {
317 bithenge_transform_t *subxform =
318 self->subtransforms[i].transform;
319 aoff64_t sub_size;
320 rc = bithenge_transform_prefix_length(subxform, blob, &sub_size);
321 if (rc != EOK)
322 goto error;
323 *out += sub_size;
324 rc = bithenge_new_offset_blob(&node, blob, sub_size);
325 blob = NULL;
326 if (rc != EOK)
327 goto error;
328 blob = bithenge_node_as_blob(node);
329 }
330error:
331 bithenge_blob_dec_ref(blob);
332 return EOK;
333}
334
335static void free_subtransforms(bithenge_named_transform_t *subtransforms)
336{
337 for (size_t i = 0; subtransforms[i].transform; i++) {
338 free((void *)subtransforms[i].name);
339 bithenge_transform_dec_ref(subtransforms[i].transform);
340 }
341 free(subtransforms);
342}
343
344static void struct_transform_destroy(bithenge_transform_t *base)
345{
346 struct_transform_t *self = transform_as_struct(base);
347 free_subtransforms(self->subtransforms);
348 free(self);
349}
350
351static bithenge_transform_ops_t struct_transform_ops = {
352 .apply = struct_transform_apply,
353 .prefix_length = struct_transform_prefix_length,
354 .destroy = struct_transform_destroy,
355};
356
357/** Create a struct transform. The transform will apply its subtransforms
358 * sequentially to a blob to create an internal node. Each result is either
359 * given a key from @a subtransforms or, if the name is NULL, the result's keys
360 * and values are merged into the struct transform's result. This function
361 * takes ownership of @a subtransforms and the names and references therein.
362 * @param[out] out Stores the created transform.
363 * @param subtransforms The subtransforms and field names.
364 * @return EOK on success or an error code from errno.h. */
365int bithenge_new_struct(bithenge_transform_t **out,
366 bithenge_named_transform_t *subtransforms)
367{
368 int rc;
369 struct_transform_t *self =
370 malloc(sizeof(*self));
371 if (!self) {
372 rc = ENOMEM;
373 goto error;
374 }
375 rc = bithenge_init_transform(struct_as_transform(self),
376 &struct_transform_ops);
377 if (rc != EOK)
378 goto error;
379 self->subtransforms = subtransforms;
380 *out = struct_as_transform(self);
381 return EOK;
382error:
383 free_subtransforms(subtransforms);
384 free(self);
385 return rc;
386}
387
388/** @}
389 */
Note: See TracBrowser for help on using the repository browser.