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

Last change on this file since 08e103d4 was 08e103d4, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Use clearer naming for string length functions

This and the following commit change the names of functions, as well as
their documentation, to use unambiguous terms "bytes" and "code points"
instead of ambiguous terms "size", "length", and "characters".

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