source: mainline/uspace/lib/bithenge/src/transform.c@ 39330200

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 39330200 was b7fd2a0, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use errno_t in all uspace and kernel code.

Change type of every variable, parameter and return value that holds an
<errno.h> constant to either errno_t (the usual case), or sys_errno_t
(some places in kernel). This is for the purpose of self-documentation,
as well as for type-checking with a bit of type definition hackery.

Although this is a massive commit, it is a simple text replacement, and thus
is very easy to verify. Simply do the following:

`
git checkout <this commit's hash>
git reset HEAD
git add .
tools/srepl '\berrno_t\b' int
git add .
tools/srepl '\bsys_errno_t\b' sysarg_t
git reset
git diff
`

While this doesn't ensure that the replacements are correct, it does ensure
that the commit doesn't do anything except those replacements. Since errno_t
is typedef'd to int in the usual case (and sys_errno_t to sysarg_t), even if
incorrect, this commit cannot change behavior.

  • Property mode set to 100644
File size: 32.6 KB
RevLine 
[d5070ef]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
[0d1a8fd]37#include <assert.h>
[d5070ef]38#include <errno.h>
[6be4142]39#include <stdarg.h>
[0d1a8fd]40#include <stdlib.h>
[8fc0f47c]41#include <bithenge/blob.h>
42#include <bithenge/print.h>
43#include <bithenge/transform.h>
[6cd10ac]44#include "common.h"
[d5070ef]45
[c9797067]46
47
48/***************** transform *****************/
49
[04a7435f]50/** Initialize a new transform.
[978ccaf1]51 * @param[out] self Transform to initialize.
[04a7435f]52 * @param[in] ops Operations provided by the transform.
[03cad47]53 * @param num_params The number of parameters required. If this is nonzero, the
54 * transform will get its own context with parameters, probably provided by a
55 * param_wrapper. If this is zero, the existing outer context will be used with
[4056ad0]56 * whatever parameters it has, so they can be passed to any param_wrappers
57 * within.
[04a7435f]58 * @return EOK or an error code from errno.h. */
[b7fd2a0]59errno_t bithenge_init_transform(bithenge_transform_t *self,
[03cad47]60 const bithenge_transform_ops_t *ops, int num_params)
[04a7435f]61{
62 assert(ops);
[cb4a66d2]63 assert(ops->apply || ops->prefix_apply);
[04a7435f]64 assert(ops->destroy);
[1a3b953]65 if (bithenge_should_fail())
66 return ENOMEM;
[978ccaf1]67 self->ops = ops;
68 self->refs = 1;
[03cad47]69 self->num_params = num_params;
[04a7435f]70 return EOK;
71}
72
[978ccaf1]73static void transform_indestructible(bithenge_transform_t *self)
[d5070ef]74{
[0d1a8fd]75 assert(false);
[d5070ef]76}
77
[cb4a66d2]78/** Apply a transform. Takes ownership of nothing.
79 * @memberof bithenge_transform_t
80 * @param self The transform.
81 * @param scope The scope.
82 * @param in The input tree.
83 * @param[out] out Where the output tree will be stored.
84 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]85errno_t bithenge_transform_apply(bithenge_transform_t *self,
[cb4a66d2]86 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
87{
88 assert(self);
89 assert(self->ops);
90 if (self->ops->apply)
91 return self->ops->apply(self, scope, in, out);
92
93 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
94 return EINVAL;
95 aoff64_t self_size, whole_size;
[b7fd2a0]96 errno_t rc = bithenge_transform_prefix_apply(self, scope,
[cb4a66d2]97 bithenge_node_as_blob(in), out, &self_size);
98 if (rc != EOK)
99 return rc;
100 rc = bithenge_blob_size(bithenge_node_as_blob(in), &whole_size);
101 if (rc == EOK && whole_size != self_size)
102 rc = EINVAL;
103 if (rc != EOK) {
104 bithenge_node_dec_ref(*out);
105 return rc;
106 }
107 return EOK;
108}
109
110/** Find the length of the prefix of a blob this transform can use as input. In
111 * other words, figure out how many bytes this transform will use up. This
112 * method is optional and can return an error, but it must succeed for struct
113 * subtransforms. Takes ownership of nothing.
114 * @memberof bithenge_transform_t
115 * @param self The transform.
116 * @param scope The scope.
117 * @param blob The blob.
118 * @param[out] out Where the prefix length will be stored.
119 * @return EOK on success, ENOTSUP if not supported, or another error code from
120 * errno.h. */
[b7fd2a0]121errno_t bithenge_transform_prefix_length(bithenge_transform_t *self,
[cb4a66d2]122 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
123{
124 assert(self);
125 assert(self->ops);
126 if (self->ops->prefix_length)
127 return self->ops->prefix_length(self, scope, blob, out);
128 if (!self->ops->prefix_apply)
129 return ENOTSUP;
130
131 bithenge_node_t *node;
[b7fd2a0]132 errno_t rc = bithenge_transform_prefix_apply(self, scope, blob, &node,
[cb4a66d2]133 out);
134 if (rc != EOK)
135 return rc;
136 bithenge_node_dec_ref(node);
137 return EOK;
138}
139
140/** Apply this transform to a prefix of a blob. In other words, feed as much of
141 * the blob into this transform as possible. Takes ownership of nothing.
142 * @memberof bithenge_transform_t
143 * @param self The transform.
144 * @param scope The scope.
145 * @param blob The blob.
146 * @param[out] out_node Holds the result of applying this transform to the
147 * prefix.
[1b6b76d]148 * @param[out] out_size Holds the size of the prefix. Can be null, in which
149 * case the size is not determined.
[cb4a66d2]150 * @return EOK on success, ENOTSUP if not supported, or another error code from
151 * errno.h. */
[b7fd2a0]152errno_t bithenge_transform_prefix_apply(bithenge_transform_t *self,
[cb4a66d2]153 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
154 aoff64_t *out_size)
155{
156 assert(self);
157 assert(self->ops);
158 if (self->ops->prefix_apply)
159 return self->ops->prefix_apply(self, scope, blob, out_node,
160 out_size);
161 if (!self->ops->prefix_length)
162 return ENOTSUP;
163
[1b6b76d]164 aoff64_t size;
[b7fd2a0]165 errno_t rc = bithenge_transform_prefix_length(self, scope, blob, &size);
[cb4a66d2]166 if (rc != EOK)
167 return rc;
168 bithenge_node_t *prefix_blob;
169 bithenge_blob_inc_ref(blob);
[1b6b76d]170 rc = bithenge_new_subblob(&prefix_blob, blob, 0, size);
[cb4a66d2]171 if (rc != EOK)
172 return rc;
173 rc = bithenge_transform_apply(self, scope, prefix_blob, out_node);
174 bithenge_node_dec_ref(prefix_blob);
[1b6b76d]175 if (out_size)
176 *out_size = size;
[cb4a66d2]177 return rc;
178}
179
[c9797067]180
181
182/***************** scope *****************/
183
[f9c314a5]184/** Create a transform scope. It must be dereferenced with @a
[0191bd3]185 * bithenge_scope_dec_ref after it is used. Takes ownership of nothing.
[0784869]186 * @memberof bithenge_scope_t
[f9c314a5]187 * @param[out] out Holds the new scope.
[0191bd3]188 * @param outer The outer scope, or NULL.
[f9c314a5]189 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]190errno_t bithenge_scope_new(bithenge_scope_t **out, bithenge_scope_t *outer)
[b8d45e9e]191{
[f9c314a5]192 bithenge_scope_t *self = malloc(sizeof(*self));
193 if (!self)
194 return ENOMEM;
195 self->refs = 1;
[0191bd3]196 if (outer)
197 bithenge_scope_inc_ref(outer);
198 self->outer = outer;
[6be4142]199 self->error = NULL;
[c12b2ae]200 self->barrier = false;
[f9c314a5]201 self->num_params = 0;
202 self->params = NULL;
203 self->current_node = NULL;
[a66ea217]204 self->in_node = NULL;
[f9c314a5]205 *out = self;
206 return EOK;
[b8d45e9e]207}
208
[f9c314a5]209/** Dereference a transform scope.
[0784869]210 * @memberof bithenge_scope_t
211 * @param self The scope to dereference, or NULL. */
[f9c314a5]212void bithenge_scope_dec_ref(bithenge_scope_t *self)
[b8d45e9e]213{
[0191bd3]214 if (!self)
215 return;
216 if (--self->refs)
217 return;
218 bithenge_node_dec_ref(self->current_node);
219 for (int i = 0; i < self->num_params; i++)
220 bithenge_node_dec_ref(self->params[i]);
221 bithenge_scope_dec_ref(self->outer);
222 free(self->params);
[6be4142]223 free(self->error);
[0191bd3]224 free(self);
[b8d45e9e]225}
226
[c12b2ae]227/** Get the outer scope of a scope, which may be NULL.
[0784869]228 * @memberof bithenge_scope_t
[c12b2ae]229 * @param self The scope to examine.
230 * @return The outer scope, which may be NULL. */
231bithenge_scope_t *bithenge_scope_outer(bithenge_scope_t *self)
232{
233 return self->outer;
234}
235
[6be4142]236/** Get the error message stored in the scope, which may be NULL. The error
237 * message only exists as long as the scope does.
[0784869]238 * @memberof bithenge_scope_t
[6be4142]239 * @param scope The scope to get the error message from.
240 * @return The error message, or NULL. */
241const char *bithenge_scope_get_error(bithenge_scope_t *scope)
242{
243 return scope->error;
244}
245
246/** Set the error message for the scope. The error message is stored in the
247 * outermost scope, but if any scope already has an error message this error
248 * message is ignored.
[0784869]249 * @memberof bithenge_scope_t
[6be4142]250 * @param scope The scope.
251 * @param format The format string.
252 * @return EINVAL normally, or another error code from errno.h. */
[b7fd2a0]253errno_t bithenge_scope_error(bithenge_scope_t *scope, const char *format, ...)
[6be4142]254{
255 if (scope->error)
256 return EINVAL;
257 while (scope->outer) {
258 scope = scope->outer;
259 if (scope->error)
260 return EINVAL;
261 }
262 size_t space_left = 256;
263 scope->error = malloc(space_left);
264 if (!scope->error)
265 return ENOMEM;
266 char *out = scope->error;
267 va_list ap;
268 va_start(ap, format);
269
270 while (*format) {
271 if (format[0] == '%' && format[1] == 't') {
272 format += 2;
[b7fd2a0]273 errno_t rc = bithenge_print_node_to_string(&out,
[6be4142]274 &space_left, BITHENGE_PRINT_PYTHON,
275 va_arg(ap, bithenge_node_t *));
276 if (rc != EOK) {
277 va_end(ap);
278 return rc;
279 }
280 } else {
281 const char *end = str_chr(format, '%');
282 if (!end)
283 end = format + str_length(format);
284 size_t size = min((size_t)(end - format),
285 space_left - 1);
286 memcpy(out, format, size);
287 format = end;
288 out += size;
289 space_left -= size;
290 }
291 }
292 *out = '\0';
293
294 va_end(ap);
295 return EINVAL;
296}
297
[a66ea217]298/** Get the current node being created, which may be NULL.
[0784869]299 * @memberof bithenge_scope_t
[a66ea217]300 * @param scope The scope to get the current node from.
301 * @return The node being created, or NULL. */
302bithenge_node_t *bithenge_scope_get_current_node(bithenge_scope_t *scope)
303{
304 if (scope->current_node)
305 bithenge_node_inc_ref(scope->current_node);
306 return scope->current_node;
307}
308
[b8d45e9e]309/** Set the current node being created. Takes a reference to @a node.
[0784869]310 * @memberof bithenge_scope_t
[b8d45e9e]311 * @param scope The scope to set the current node in.
[a66ea217]312 * @param node The current node being created, or NULL. */
[b8d45e9e]313void bithenge_scope_set_current_node(bithenge_scope_t *scope,
314 bithenge_node_t *node)
315{
316 bithenge_node_dec_ref(scope->current_node);
317 scope->current_node = node;
318}
319
[a66ea217]320/** Get the current input node, which may be NULL.
[0784869]321 * @memberof bithenge_scope_t
[a66ea217]322 * @param scope The scope to get the current input node from.
323 * @return The input node, or NULL. */
324bithenge_node_t *bithenge_scope_in_node(bithenge_scope_t *scope)
325{
326 if (scope->in_node)
327 bithenge_node_inc_ref(scope->in_node);
328 return scope->in_node;
329}
330
331/** Set the current input node. Takes a reference to @a node.
[0784869]332 * @memberof bithenge_scope_t
[a66ea217]333 * @param scope The scope to set the input node in.
334 * @param node The input node, or NULL. */
335void bithenge_scope_set_in_node(bithenge_scope_t *scope, bithenge_node_t *node)
336{
337 bithenge_node_dec_ref(scope->in_node);
338 scope->in_node = node;
339}
340
[c12b2ae]341/** Set a scope as a barrier.
[0784869]342 * @memberof bithenge_scope_t
[c12b2ae]343 * @param self The scope to change. */
344void bithenge_scope_set_barrier(bithenge_scope_t *self)
345{
346 self->barrier = true;
347}
348
349/** Check whether a scope is a barrier, meaning that variable lookup stops at
350 * it.
[0784869]351 * @memberof bithenge_scope_t
[c12b2ae]352 * @param self The scope to check.
353 * @return Whether the scope is a barrier. */
354bool bithenge_scope_is_barrier(bithenge_scope_t *self)
355{
356 return self->barrier;
357}
358
[b8d45e9e]359/** Allocate parameters. The parameters must then be set with @a
360 * bithenge_scope_set_param. This must not be called on a scope that already
361 * has parameters.
[0784869]362 * @memberof bithenge_scope_t
[b8d45e9e]363 * @param scope The scope in which to allocate parameters.
364 * @param num_params The number of parameters to allocate.
365 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]366errno_t bithenge_scope_alloc_params(bithenge_scope_t *scope, int num_params)
[b8d45e9e]367{
368 scope->params = malloc(sizeof(*scope->params) * num_params);
369 if (!scope->params)
370 return ENOMEM;
371 scope->num_params = num_params;
372 for (int i = 0; i < num_params; i++)
373 scope->params[i] = NULL;
374 return EOK;
375}
376
[0784869]377/** Set a parameter. Takes a reference to @a node. Note that range checking is
[b8d45e9e]378 * not done in release builds.
[0784869]379 * @memberof bithenge_scope_t
[b8d45e9e]380 * @param scope The scope in which to allocate parameters.
381 * @param i The index of the parameter to set.
[0784869]382 * @param node The value to store in the parameter.
[b8d45e9e]383 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]384errno_t bithenge_scope_set_param( bithenge_scope_t *scope, int i,
[b8d45e9e]385 bithenge_node_t *node)
386{
387 assert(scope);
388 assert(i >= 0 && i < scope->num_params);
[1a3b953]389 if (bithenge_should_fail()) {
390 bithenge_node_dec_ref(node);
391 return ENOMEM;
392 }
[b8d45e9e]393 scope->params[i] = node;
394 return EOK;
395}
396
397/** Get a parameter. Note that range checking is not done in release builds.
[0784869]398 * @memberof bithenge_scope_t
[b8d45e9e]399 * @param scope The scope to get the parameter from.
400 * @param i The index of the parameter to set.
401 * @param[out] out Stores a new reference to the parameter.
402 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]403errno_t bithenge_scope_get_param(bithenge_scope_t *scope, int i,
[b8d45e9e]404 bithenge_node_t **out)
405{
406 assert(scope);
[0191bd3]407 if (scope->num_params) {
408 assert(i >= 0 && i < scope->num_params);
409 *out = scope->params[i];
410 bithenge_node_inc_ref(*out);
411 return EOK;
412 } else {
413 return bithenge_scope_get_param(scope->outer, i, out);
414 }
[b8d45e9e]415}
416
[c9797067]417
418
419/***************** barrier_transform *****************/
420
[4056ad0]421typedef struct {
422 bithenge_transform_t base;
423 bithenge_transform_t *transform;
[c12b2ae]424} barrier_transform_t;
[4056ad0]425
[c12b2ae]426static inline barrier_transform_t *transform_as_barrier(
[4056ad0]427 bithenge_transform_t *base)
428{
[c12b2ae]429 return (barrier_transform_t *)base;
[4056ad0]430}
431
[c12b2ae]432static inline bithenge_transform_t *barrier_as_transform(
433 barrier_transform_t *self)
[4056ad0]434{
435 return &self->base;
436}
437
[b7fd2a0]438static errno_t barrier_transform_apply(bithenge_transform_t *base,
[4056ad0]439 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
440{
[c12b2ae]441 barrier_transform_t *self = transform_as_barrier(base);
[f9c314a5]442 bithenge_scope_t *inner_scope;
[b7fd2a0]443 errno_t rc = bithenge_scope_new(&inner_scope, scope);
[f9c314a5]444 if (rc != EOK)
445 return rc;
[c12b2ae]446 bithenge_scope_set_barrier(inner_scope);
[c9797067]447 bithenge_scope_set_in_node(inner_scope, in);
448 rc = bithenge_transform_apply(self->transform, inner_scope, in, out);
[f9c314a5]449 bithenge_scope_dec_ref(inner_scope);
[b8d45e9e]450 return rc;
[4056ad0]451}
452
[b7fd2a0]453static errno_t barrier_transform_prefix_length(bithenge_transform_t *base,
[4056ad0]454 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
455{
[c12b2ae]456 barrier_transform_t *self = transform_as_barrier(base);
457 bithenge_scope_t *inner_scope;
[b7fd2a0]458 errno_t rc = bithenge_scope_new(&inner_scope, scope);
[c12b2ae]459 if (rc != EOK)
460 return rc;
461 bithenge_scope_set_barrier(inner_scope);
[c9797067]462 bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
463 rc = bithenge_transform_prefix_length(self->transform, inner_scope, in,
464 out);
[c12b2ae]465 bithenge_scope_dec_ref(inner_scope);
466 return rc;
467}
468
[b7fd2a0]469static errno_t barrier_transform_prefix_apply(bithenge_transform_t *base,
[c12b2ae]470 bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
471 aoff64_t *out_length)
472{
473 barrier_transform_t *self = transform_as_barrier(base);
474 bithenge_scope_t *inner_scope;
[b7fd2a0]475 errno_t rc = bithenge_scope_new(&inner_scope, scope);
[c12b2ae]476 if (rc != EOK)
477 return rc;
478 bithenge_scope_set_barrier(inner_scope);
[c9797067]479 bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
480 rc = bithenge_transform_prefix_apply(self->transform, inner_scope, in,
[c12b2ae]481 out_node, out_length);
482 bithenge_scope_dec_ref(inner_scope);
483 return rc;
[4056ad0]484}
485
[c12b2ae]486static void barrier_transform_destroy(bithenge_transform_t *base)
[4056ad0]487{
[c12b2ae]488 barrier_transform_t *self = transform_as_barrier(base);
[4056ad0]489 bithenge_transform_dec_ref(self->transform);
490 free(self);
491}
492
[c12b2ae]493static const bithenge_transform_ops_t barrier_transform_ops = {
494 .apply = barrier_transform_apply,
495 .prefix_length = barrier_transform_prefix_length,
496 .prefix_apply = barrier_transform_prefix_apply,
497 .destroy = barrier_transform_destroy,
[4056ad0]498};
499
[2988aec7]500/** Set the subtransform of a barrier transform. This must be done before the
501 * barrier transform is used. Takes a reference to @a transform.
502 * @param base The barrier transform.
503 * @param transform The subtransform to use for all operations.
504 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]505errno_t bithenge_barrier_transform_set_subtransform(bithenge_transform_t *base,
[2988aec7]506 bithenge_transform_t *transform)
507{
508 assert(transform);
509 assert(bithenge_transform_num_params(transform) == 0);
510
[1a3b953]511 if (bithenge_should_fail()) {
512 bithenge_transform_dec_ref(transform);
513 return ENOMEM;
514 }
515
[2988aec7]516 barrier_transform_t *self = transform_as_barrier(base);
517 assert(!self->transform);
518 self->transform = transform;
519 return EOK;
520}
521
[c12b2ae]522/** Create a wrapper transform that creates a new scope. This ensures nothing
523 * from the outer scope is passed in, other than parameters. The wrapper may
[2988aec7]524 * have a different value for num_params. The subtransform must be set with @a
525 * bithenge_barrier_transform_set_subtransform before the result is used.
[4056ad0]526 * @param[out] out Holds the created transform.
[b8d45e9e]527 * @param num_params The number of parameters to require, which may be 0.
[4056ad0]528 * @return EOK on success or an error code from errno.h. */
[b7fd2a0]529errno_t bithenge_new_barrier_transform(bithenge_transform_t **out, int num_params)
[4056ad0]530{
[b7fd2a0]531 errno_t rc;
[c12b2ae]532 barrier_transform_t *self = malloc(sizeof(*self));
[4056ad0]533 if (!self) {
534 rc = ENOMEM;
535 goto error;
536 }
[c12b2ae]537 rc = bithenge_init_transform(barrier_as_transform(self),
538 &barrier_transform_ops, num_params);
[4056ad0]539 if (rc != EOK)
540 goto error;
[2988aec7]541 self->transform = NULL;
[c12b2ae]542 *out = barrier_as_transform(self);
[4056ad0]543 return EOK;
544error:
545 free(self);
546 return rc;
547}
548
[0ce0103]549
550
551/***************** ascii *****************/
552
[b7fd2a0]553static errno_t ascii_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
[5a7c0e6]554 bithenge_node_t *in, bithenge_node_t **out)
[600f5d1]555{
[b7fd2a0]556 errno_t rc;
[600f5d1]557 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
558 return EINVAL;
559 bithenge_blob_t *blob = bithenge_node_as_blob(in);
560 aoff64_t size;
561 rc = bithenge_blob_size(blob, &size);
562 if (rc != EOK)
563 return rc;
564
565 char *buffer = malloc(size + 1);
566 if (!buffer)
567 return ENOMEM;
568 aoff64_t size_read = size;
569 rc = bithenge_blob_read(blob, 0, buffer, &size_read);
570 if (rc != EOK) {
571 free(buffer);
572 return rc;
573 }
574 if (size_read != size) {
575 free(buffer);
576 return EINVAL;
577 }
578 buffer[size] = '\0';
579
580 /* TODO: what if the OS encoding is incompatible with ASCII? */
581 return bithenge_new_string_node(out, buffer, true);
582}
583
584static const bithenge_transform_ops_t ascii_ops = {
585 .apply = ascii_apply,
586 .destroy = transform_indestructible,
587};
588
589/** The ASCII text transform. */
590bithenge_transform_t bithenge_ascii_transform = {
[03cad47]591 &ascii_ops, 1, 0
[600f5d1]592};
593
[0ce0103]594
595
596/***************** bit *****************/
597
[b7fd2a0]598static errno_t bit_prefix_apply(bithenge_transform_t *self,
[0ce0103]599 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
600 aoff64_t *out_size)
601{
602 char buffer;
[1b6b76d]603 aoff64_t size = 1;
[b7fd2a0]604 errno_t rc = bithenge_blob_read_bits(blob, 0, &buffer, &size, true);
[0ce0103]605 if (rc != EOK)
606 return rc;
[1b6b76d]607 if (size != 1)
[0ce0103]608 return EINVAL;
[1b6b76d]609 if (out_size)
610 *out_size = size;
[0ce0103]611 return bithenge_new_boolean_node(out_node, (buffer & 1) != 0);
612}
613
614static const bithenge_transform_ops_t bit_ops = {
615 .prefix_apply = bit_prefix_apply,
616 .destroy = transform_indestructible,
617};
618
619/** A transform that decodes a bit as a boolean. */
620bithenge_transform_t bithenge_bit_transform = {
621 &bit_ops, 1, 0
622};
623
624
625
626/***************** bits_be, bits_le *****************/
627
628typedef struct {
629 bithenge_blob_t base;
630 bithenge_blob_t *bytes;
631 bool little_endian;
632} bits_xe_blob_t;
633
634static bits_xe_blob_t *blob_as_bits_xe(bithenge_blob_t *base)
635{
636 return (bits_xe_blob_t *)base;
637}
638
639static bithenge_blob_t *bits_xe_as_blob(bits_xe_blob_t *self)
640{
641 return &self->base;
642}
643
[b7fd2a0]644static errno_t bits_xe_size(bithenge_blob_t *base, aoff64_t *out)
[0ce0103]645{
646 bits_xe_blob_t *self = blob_as_bits_xe(base);
[b7fd2a0]647 errno_t rc = bithenge_blob_size(self->bytes, out);
[0ce0103]648 *out *= 8;
649 return rc;
650}
651
652static uint8_t reverse_byte(uint8_t val)
653{
654 val = ((val & 0x0f) << 4) ^ ((val & 0xf0) >> 4);
655 val = ((val & 0x33) << 2) ^ ((val & 0xcc) >> 2);
656 val = ((val & 0x55) << 1) ^ ((val & 0xaa) >> 1);
657 return val;
658}
659
[b7fd2a0]660static errno_t bits_xe_read_bits(bithenge_blob_t *base, aoff64_t offset,
[0ce0103]661 char *buffer, aoff64_t *size, bool little_endian)
662{
663 bits_xe_blob_t *self = blob_as_bits_xe(base);
664 aoff64_t bytes_offset = offset / 8;
665 aoff64_t bit_offset = offset % 8;
666 aoff64_t output_num_bytes = (*size + 7) / 8;
667 aoff64_t bytes_size = (*size + bit_offset + 7) / 8;
668 bool separate_buffer = bit_offset != 0;
669 uint8_t *bytes_buffer;
670 if (separate_buffer) {
671 /* Allocate an extra byte, to make sure byte1 can be read. */
672 bytes_buffer = malloc(bytes_size + 1);
673 if (!bytes_buffer)
674 return ENOMEM;
675 } else
676 bytes_buffer = (uint8_t *)buffer;
677
[b7fd2a0]678 errno_t rc = bithenge_blob_read(self->bytes, bytes_offset,
[0ce0103]679 (char *)bytes_buffer, &bytes_size);
680 if (rc != EOK)
681 goto end;
682 *size = min(*size, bytes_size * 8 - bit_offset);
683
684 if (little_endian != self->little_endian)
685 for (aoff64_t i = 0; i < bytes_size; i++)
686 bytes_buffer[i] = reverse_byte(bytes_buffer[i]);
687
688 if (bit_offset || separate_buffer) {
689 for (aoff64_t i = 0; i < output_num_bytes; i++) {
690 uint8_t byte0 = bytes_buffer[i];
691 uint8_t byte1 = bytes_buffer[i + 1];
692 buffer[i] = little_endian ?
693 (byte0 >> bit_offset) ^ (byte1 << (8 - bit_offset)) :
694 (byte0 << bit_offset) ^ (byte1 >> (8 - bit_offset));
695 }
696 }
697
698end:
699 if (separate_buffer)
700 free(bytes_buffer);
701 return rc;
702}
703
704static void bits_xe_destroy(bithenge_blob_t *base)
705{
706 bits_xe_blob_t *self = blob_as_bits_xe(base);
707 bithenge_blob_dec_ref(self->bytes);
708 free(self);
709}
710
711static const bithenge_random_access_blob_ops_t bits_xe_blob_ops = {
712 .size = bits_xe_size,
713 .read_bits = bits_xe_read_bits,
714 .destroy = bits_xe_destroy,
715};
716
[b7fd2a0]717static errno_t bits_xe_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
[0ce0103]718 bithenge_node_t *in, bithenge_node_t **out)
719{
720 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
721 return EINVAL;
722 bits_xe_blob_t *blob = malloc(sizeof(*blob));
723 if (!blob)
724 return ENOMEM;
[b7fd2a0]725 errno_t rc = bithenge_init_random_access_blob(bits_xe_as_blob(blob),
[0ce0103]726 &bits_xe_blob_ops);
727 if (rc != EOK) {
728 free(blob);
729 return rc;
730 }
731 bithenge_node_inc_ref(in);
732 blob->bytes = bithenge_node_as_blob(in);
733 blob->little_endian = (self == &bithenge_bits_le_transform);
734 *out = bithenge_blob_as_node(bits_xe_as_blob(blob));
735 return EOK;
736}
737
738static const bithenge_transform_ops_t bits_xe_ops = {
739 .apply = bits_xe_apply,
740 .destroy = transform_indestructible,
741};
742
743/** A transform that converts a byte blob to a bit blob, most-significant bit
744 * first. */
745bithenge_transform_t bithenge_bits_be_transform = {
746 &bits_xe_ops, 1, 0
747};
748
749/** A transform that converts a byte blob to a bit blob, least-significant bit
750 * first. */
751bithenge_transform_t bithenge_bits_le_transform = {
752 &bits_xe_ops, 1, 0
753};
754
755
756
757/***************** invalid *****************/
758
[b7fd2a0]759static errno_t invalid_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
[78d3a00]760 bithenge_node_t *in, bithenge_node_t **out)
761{
762 return EINVAL;
763}
764
765static const bithenge_transform_ops_t invalid_ops = {
766 .apply = invalid_apply,
767 .destroy = transform_indestructible,
768};
769
770/** A transform that always raises an error. */
771bithenge_transform_t bithenge_invalid_transform = {
772 &invalid_ops, 1, 0
773};
774
[0ce0103]775
776
777/***************** known_length *****************/
778
[b7fd2a0]779static errno_t known_length_apply(bithenge_transform_t *self,
[4056ad0]780 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
781{
782 bithenge_node_t *length_node;
[b7fd2a0]783 errno_t rc = bithenge_scope_get_param(scope, 0, &length_node);
[4056ad0]784 if (rc != EOK)
785 return rc;
786 if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
787 bithenge_node_dec_ref(length_node);
788 return EINVAL;
789 }
790 bithenge_int_t length = bithenge_integer_node_value(length_node);
791 bithenge_node_dec_ref(length_node);
792
793 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
794 return EINVAL;
795 aoff64_t size;
796 rc = bithenge_blob_size(bithenge_node_as_blob(in), &size);
797 if (rc != EOK)
798 return rc;
799 if (length != (bithenge_int_t)size)
800 return EINVAL;
801
802 bithenge_node_inc_ref(in);
803 *out = in;
804 return EOK;
805}
806
[b7fd2a0]807static errno_t known_length_prefix_length(bithenge_transform_t *self,
[4056ad0]808 bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
809{
810 bithenge_node_t *length_node;
[b7fd2a0]811 errno_t rc = bithenge_scope_get_param(scope, 0, &length_node);
[4056ad0]812 if (rc != EOK)
813 return rc;
814 if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
815 bithenge_node_dec_ref(length_node);
816 return EINVAL;
817 }
818 bithenge_int_t length = bithenge_integer_node_value(length_node);
819 bithenge_node_dec_ref(length_node);
820
821 *out = (aoff64_t)length;
822 return EOK;
823}
824
825static const bithenge_transform_ops_t known_length_ops = {
826 .apply = known_length_apply,
827 .prefix_length = known_length_prefix_length,
828 .destroy = transform_indestructible,
829};
830
831/** Pass through a blob, but require its length to equal the first argument. */
832bithenge_transform_t bithenge_known_length_transform = {
833 &known_length_ops, 1, 1
834};
835
[b7fd2a0]836static errno_t nonzero_boolean_apply(bithenge_transform_t *self,
[c3437d9]837 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
838{
839 if (bithenge_node_type(in) != BITHENGE_NODE_INTEGER)
840 return EINVAL;
841 bool value = bithenge_integer_node_value(in) != 0;
842 return bithenge_new_boolean_node(out, value);
843}
844
845static const bithenge_transform_ops_t nonzero_boolean_ops = {
846 .apply = nonzero_boolean_apply,
847 .destroy = transform_indestructible,
848};
849
850/** A transform that converts integers to booleans, true if nonzero. */
851bithenge_transform_t bithenge_nonzero_boolean_transform = {
852 &nonzero_boolean_ops, 1, 0
853};
854
[b7fd2a0]855static errno_t prefix_length_1(bithenge_transform_t *self, bithenge_scope_t *scope,
[5a7c0e6]856 bithenge_blob_t *blob, aoff64_t *out)
[d5070ef]857{
[5f4cf872]858 *out = 1;
859 return EOK;
[d5070ef]860}
861
[b7fd2a0]862static errno_t prefix_length_2(bithenge_transform_t *self, bithenge_scope_t *scope,
[5a7c0e6]863 bithenge_blob_t *blob, aoff64_t *out)
[0d1a8fd]864{
[5f4cf872]865 *out = 2;
866 return EOK;
[0d1a8fd]867}
868
[b7fd2a0]869static errno_t prefix_length_4(bithenge_transform_t *self, bithenge_scope_t *scope,
[5a7c0e6]870 bithenge_blob_t *blob, aoff64_t *out)
[d5070ef]871{
872 *out = 4;
873 return EOK;
874}
875
[b7fd2a0]876static errno_t prefix_length_8(bithenge_transform_t *self, bithenge_scope_t *scope,
[5a7c0e6]877 bithenge_blob_t *blob, aoff64_t *out)
[5f4cf872]878{
879 *out = 8;
880 return EOK;
881}
[d5070ef]882
[0784869]883/** @cond internal */
[5f4cf872]884#define MAKE_UINT_TRANSFORM(NAME, TYPE, ENDIAN, PREFIX_LENGTH_FUNC) \
[b7fd2a0]885 static errno_t NAME##_apply(bithenge_transform_t *self, \
[5a7c0e6]886 bithenge_scope_t *scope, bithenge_node_t *in, \
[43788b2]887 bithenge_node_t **out) \
[5f4cf872]888 { \
[b7fd2a0]889 errno_t rc; \
[5f4cf872]890 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB) \
891 return EINVAL; \
892 bithenge_blob_t *blob = bithenge_node_as_blob(in); \
893 \
894 /* Read too many bytes; success means the blob is too long. */ \
895 TYPE val[2]; \
896 aoff64_t size = sizeof(val[0]) + 1; \
897 rc = bithenge_blob_read(blob, 0, (char *)val, &size); \
898 if (rc != EOK) \
899 return rc; \
900 if (size != sizeof(val[0])) \
901 return EINVAL; \
902 \
903 return bithenge_new_integer_node(out, ENDIAN(val[0])); \
904 } \
905 \
906 static const bithenge_transform_ops_t NAME##_ops = { \
907 .apply = NAME##_apply, \
908 .prefix_length = PREFIX_LENGTH_FUNC, \
909 .destroy = transform_indestructible, \
910 }; \
911 \
912 bithenge_transform_t bithenge_##NAME##_transform = { \
[03cad47]913 &NAME##_ops, 1, 0 \
[5f4cf872]914 }
[d5070ef]915
[5f4cf872]916MAKE_UINT_TRANSFORM(uint8 , uint8_t , , prefix_length_1);
917MAKE_UINT_TRANSFORM(uint16le, uint16_t, uint16_t_le2host, prefix_length_2);
918MAKE_UINT_TRANSFORM(uint16be, uint16_t, uint16_t_be2host, prefix_length_2);
919MAKE_UINT_TRANSFORM(uint32le, uint32_t, uint32_t_le2host, prefix_length_4);
920MAKE_UINT_TRANSFORM(uint32be, uint32_t, uint32_t_be2host, prefix_length_4);
[1c79996]921MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint64_t_le2host, prefix_length_8);
922MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint64_t_be2host, prefix_length_8);
[0784869]923/** @endcond */
[0d1a8fd]924
[0ce0103]925
926
927/***************** uint_be, uint_le *****************/
928
[b7fd2a0]929static errno_t uint_xe_prefix_apply(bithenge_transform_t *self,
[0ce0103]930 bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
931 aoff64_t *out_size)
932{
933 bool little_endian = (self == &bithenge_uint_le_transform);
934 bithenge_node_t *num_bits_node;
[b7fd2a0]935 errno_t rc = bithenge_scope_get_param(scope, 0, &num_bits_node);
[0ce0103]936 if (rc != EOK)
937 return rc;
938 if (bithenge_node_type(num_bits_node) != BITHENGE_NODE_INTEGER) {
939 bithenge_node_dec_ref(num_bits_node);
940 return EINVAL;
941 }
942 bithenge_int_t num_bits = bithenge_integer_node_value(num_bits_node);
943 bithenge_node_dec_ref(num_bits_node);
944 if (num_bits < 0)
945 return EINVAL;
946 if ((size_t)num_bits > sizeof(bithenge_int_t) * 8 - 1)
947 return EINVAL;
948
[1b6b76d]949 aoff64_t size = num_bits;
[0ce0103]950 uint8_t buffer[sizeof(bithenge_int_t)];
[1b6b76d]951 rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, &size,
[0ce0103]952 little_endian);
953 if (rc != EOK)
954 return rc;
[1b6b76d]955 if (size != (aoff64_t)num_bits)
[0ce0103]956 return EINVAL;
[1b6b76d]957 if (out_size)
958 *out_size = size;
[0ce0103]959
960 bithenge_int_t result = 0;
961 bithenge_int_t num_easy_bytes = num_bits / 8;
962 if (little_endian) {
963 for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
964 result += buffer[i] << 8 * i;
965 if (num_bits % 8)
966 result += (buffer[num_easy_bytes] &
967 ((1 << num_bits % 8) - 1)) << 8 * num_easy_bytes;
968 } else {
969 for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
970 result += buffer[i] << (num_bits - 8 * (i + 1));
971 if (num_bits % 8)
972 result += buffer[num_easy_bytes] >> (8 - num_bits % 8);
973 }
974
975 return bithenge_new_integer_node(out_node, result);
976}
977
978static const bithenge_transform_ops_t uint_xe_ops = {
979 .prefix_apply = uint_xe_prefix_apply,
980 .destroy = transform_indestructible,
981};
982
983/** A transform that reads an unsigned integer from an arbitrary number of
984 * bits, most-significant bit first. */
985bithenge_transform_t bithenge_uint_be_transform = {
986 &uint_xe_ops, 1, 1
987};
988
989/** A transform that reads an unsigned integer from an arbitrary number of
990 * bits, least-significant bit first. */
991bithenge_transform_t bithenge_uint_le_transform = {
992 &uint_xe_ops, 1, 1
993};
994
995
996
997/***************** zero_terminated *****************/
998
[b7fd2a0]999static errno_t zero_terminated_apply(bithenge_transform_t *self,
[5a7c0e6]1000 bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
[600f5d1]1001{
[b7fd2a0]1002 errno_t rc;
[600f5d1]1003 if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
1004 return EINVAL;
1005 bithenge_blob_t *blob = bithenge_node_as_blob(in);
1006 aoff64_t size;
1007 rc = bithenge_blob_size(blob, &size);
1008 if (rc != EOK)
1009 return rc;
1010 if (size < 1)
1011 return EINVAL;
1012 char ch;
1013 aoff64_t size_read = 1;
1014 rc = bithenge_blob_read(blob, size - 1, &ch, &size_read);
1015 if (rc != EOK)
1016 return rc;
1017 if (size_read != 1 || ch != '\0')
1018 return EINVAL;
1019 bithenge_blob_inc_ref(blob);
1020 return bithenge_new_subblob(out, blob, 0, size - 1);
1021}
1022
[b7fd2a0]1023static errno_t zero_terminated_prefix_length(bithenge_transform_t *self,
[5a7c0e6]1024 bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
[600f5d1]1025{
[b7fd2a0]1026 errno_t rc;
[600f5d1]1027 char buffer[4096];
1028 aoff64_t offset = 0, size_read = sizeof(buffer);
1029 do {
1030 rc = bithenge_blob_read(blob, offset, buffer, &size_read);
1031 if (rc != EOK)
1032 return rc;
1033 char *found = memchr(buffer, '\0', size_read);
1034 if (found) {
1035 *out = found - buffer + offset + 1;
1036 return EOK;
1037 }
1038 offset += size_read;
1039 } while (size_read == sizeof(buffer));
1040 return EINVAL;
1041}
1042
1043static const bithenge_transform_ops_t zero_terminated_ops = {
1044 .apply = zero_terminated_apply,
1045 .prefix_length = zero_terminated_prefix_length,
1046 .destroy = transform_indestructible,
1047};
1048
1049/** The zero-terminated data transform. */
1050bithenge_transform_t bithenge_zero_terminated_transform = {
[03cad47]1051 &zero_terminated_ops, 1, 0
[600f5d1]1052};
1053
[0d1a8fd]1054static bithenge_named_transform_t primitive_transforms[] = {
[600f5d1]1055 {"ascii", &bithenge_ascii_transform},
[0ce0103]1056 {"bit", &bithenge_bit_transform},
1057 {"bits_be", &bithenge_bits_be_transform},
1058 {"bits_le", &bithenge_bits_le_transform},
[4056ad0]1059 {"known_length", &bithenge_known_length_transform},
[c3437d9]1060 {"nonzero_boolean", &bithenge_nonzero_boolean_transform},
[5f4cf872]1061 {"uint8", &bithenge_uint8_transform},
1062 {"uint16be", &bithenge_uint16be_transform},
[0ce0103]1063 {"uint16le", &bithenge_uint16le_transform},
[0d1a8fd]1064 {"uint32be", &bithenge_uint32be_transform},
[0ce0103]1065 {"uint32le", &bithenge_uint32le_transform},
[5f4cf872]1066 {"uint64be", &bithenge_uint64be_transform},
[0ce0103]1067 {"uint64le", &bithenge_uint64le_transform},
1068 {"uint_be", &bithenge_uint_be_transform},
1069 {"uint_le", &bithenge_uint_le_transform},
[600f5d1]1070 {"zero_terminated", &bithenge_zero_terminated_transform},
[0d1a8fd]1071 {NULL, NULL}
1072};
1073
1074/** An array of named built-in transforms. */
1075bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
[d5070ef]1076
1077/** @}
1078 */
Note: See TracBrowser for help on using the repository browser.