HelenOS sources
This source file includes following definitions.
- bithenge_init_transform
- transform_indestructible
- bithenge_transform_apply
- bithenge_transform_prefix_length
- bithenge_transform_prefix_apply
- bithenge_scope_new
- bithenge_scope_dec_ref
- bithenge_scope_outer
- bithenge_scope_get_error
- bithenge_scope_error
- bithenge_scope_get_current_node
- bithenge_scope_set_current_node
- bithenge_scope_in_node
- bithenge_scope_set_in_node
- bithenge_scope_set_barrier
- bithenge_scope_is_barrier
- bithenge_scope_alloc_params
- bithenge_scope_set_param
- bithenge_scope_get_param
- transform_as_barrier
- barrier_as_transform
- barrier_transform_apply
- barrier_transform_prefix_length
- barrier_transform_prefix_apply
- barrier_transform_destroy
- bithenge_barrier_transform_set_subtransform
- bithenge_new_barrier_transform
- ascii_apply
- bit_prefix_apply
- blob_as_bits_xe
- bits_xe_as_blob
- bits_xe_size
- reverse_byte
- bits_xe_read_bits
- bits_xe_destroy
- bits_xe_apply
- invalid_apply
- known_length_apply
- known_length_prefix_length
- nonzero_boolean_apply
- prefix_length_1
- prefix_length_2
- prefix_length_4
- prefix_length_8
- uint8_t_identity
- uint_xe_prefix_apply
- zero_terminated_apply
- zero_terminated_prefix_length
#include <assert.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <bithenge/blob.h>
#include <bithenge/print.h>
#include <bithenge/transform.h>
#include "common.h"
errno_t bithenge_init_transform(bithenge_transform_t *self,
const bithenge_transform_ops_t *ops, int num_params)
{
assert(ops);
assert(ops->apply || ops->prefix_apply);
assert(ops->destroy);
if (bithenge_should_fail())
return ENOMEM;
self->ops = ops;
self->refs = 1;
self->num_params = num_params;
return EOK;
}
static void transform_indestructible(bithenge_transform_t *self)
{
assert(false);
}
errno_t bithenge_transform_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
assert(self);
assert(self->ops);
if (self->ops->apply)
return self->ops->apply(self, scope, in, out);
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
aoff64_t self_size, whole_size;
errno_t rc = bithenge_transform_prefix_apply(self, scope,
bithenge_node_as_blob(in), out, &self_size);
if (rc != EOK)
return rc;
rc = bithenge_blob_size(bithenge_node_as_blob(in), &whole_size);
if (rc == EOK && whole_size != self_size)
rc = EINVAL;
if (rc != EOK) {
bithenge_node_dec_ref(*out);
return rc;
}
return EOK;
}
errno_t bithenge_transform_prefix_length(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
{
assert(self);
assert(self->ops);
if (self->ops->prefix_length)
return self->ops->prefix_length(self, scope, blob, out);
if (!self->ops->prefix_apply)
return ENOTSUP;
bithenge_node_t *node;
errno_t rc = bithenge_transform_prefix_apply(self, scope, blob, &node,
out);
if (rc != EOK)
return rc;
bithenge_node_dec_ref(node);
return EOK;
}
errno_t bithenge_transform_prefix_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
assert(self);
assert(self->ops);
if (self->ops->prefix_apply)
return self->ops->prefix_apply(self, scope, blob, out_node,
out_size);
if (!self->ops->prefix_length)
return ENOTSUP;
aoff64_t size;
errno_t rc = bithenge_transform_prefix_length(self, scope, blob, &size);
if (rc != EOK)
return rc;
bithenge_node_t *prefix_blob;
bithenge_blob_inc_ref(blob);
rc = bithenge_new_subblob(&prefix_blob, blob, 0, size);
if (rc != EOK)
return rc;
rc = bithenge_transform_apply(self, scope, prefix_blob, out_node);
bithenge_node_dec_ref(prefix_blob);
if (out_size)
*out_size = size;
return rc;
}
errno_t bithenge_scope_new(bithenge_scope_t **out, bithenge_scope_t *outer)
{
bithenge_scope_t *self = malloc(sizeof(*self));
if (!self)
return ENOMEM;
self->refs = 1;
if (outer)
bithenge_scope_inc_ref(outer);
self->outer = outer;
self->error = NULL;
self->barrier = false;
self->num_params = 0;
self->params = NULL;
self->current_node = NULL;
self->in_node = NULL;
*out = self;
return EOK;
}
void bithenge_scope_dec_ref(bithenge_scope_t *self)
{
if (!self)
return;
if (--self->refs)
return;
bithenge_node_dec_ref(self->current_node);
for (int i = 0; i < self->num_params; i++)
bithenge_node_dec_ref(self->params[i]);
bithenge_scope_dec_ref(self->outer);
free(self->params);
free(self->error);
free(self);
}
bithenge_scope_t *bithenge_scope_outer(bithenge_scope_t *self)
{
return self->outer;
}
const char *bithenge_scope_get_error(bithenge_scope_t *scope)
{
return scope->error;
}
errno_t bithenge_scope_error(bithenge_scope_t *scope, const char *format, ...)
{
if (scope->error)
return EINVAL;
while (scope->outer) {
scope = scope->outer;
if (scope->error)
return EINVAL;
}
size_t space_left = 256;
scope->error = malloc(space_left);
if (!scope->error)
return ENOMEM;
char *out = scope->error;
va_list ap;
va_start(ap, format);
while (*format) {
if (format[0] == '%' && format[1] == 't') {
format += 2;
errno_t rc = bithenge_print_node_to_string(&out,
&space_left, BITHENGE_PRINT_PYTHON,
va_arg(ap, bithenge_node_t *));
if (rc != EOK) {
va_end(ap);
return rc;
}
} else {
const char *end = str_chr(format, '%');
if (!end)
end = format + str_length(format);
size_t size = min((size_t)(end - format),
space_left - 1);
memcpy(out, format, size);
format = end;
out += size;
space_left -= size;
}
}
*out = '\0';
va_end(ap);
return EINVAL;
}
bithenge_node_t *bithenge_scope_get_current_node(bithenge_scope_t *scope)
{
if (scope->current_node)
bithenge_node_inc_ref(scope->current_node);
return scope->current_node;
}
void bithenge_scope_set_current_node(bithenge_scope_t *scope,
bithenge_node_t *node)
{
bithenge_node_dec_ref(scope->current_node);
scope->current_node = node;
}
bithenge_node_t *bithenge_scope_in_node(bithenge_scope_t *scope)
{
if (scope->in_node)
bithenge_node_inc_ref(scope->in_node);
return scope->in_node;
}
void bithenge_scope_set_in_node(bithenge_scope_t *scope, bithenge_node_t *node)
{
bithenge_node_dec_ref(scope->in_node);
scope->in_node = node;
}
void bithenge_scope_set_barrier(bithenge_scope_t *self)
{
self->barrier = true;
}
bool bithenge_scope_is_barrier(bithenge_scope_t *self)
{
return self->barrier;
}
errno_t bithenge_scope_alloc_params(bithenge_scope_t *scope, int num_params)
{
scope->params = malloc(sizeof(*scope->params) * num_params);
if (!scope->params)
return ENOMEM;
scope->num_params = num_params;
for (int i = 0; i < num_params; i++)
scope->params[i] = NULL;
return EOK;
}
errno_t bithenge_scope_set_param(bithenge_scope_t *scope, int i,
bithenge_node_t *node)
{
assert(scope);
assert(i >= 0 && i < scope->num_params);
if (bithenge_should_fail()) {
bithenge_node_dec_ref(node);
return ENOMEM;
}
scope->params[i] = node;
return EOK;
}
errno_t bithenge_scope_get_param(bithenge_scope_t *scope, int i,
bithenge_node_t **out)
{
assert(scope);
if (scope->num_params) {
assert(i >= 0 && i < scope->num_params);
*out = scope->params[i];
bithenge_node_inc_ref(*out);
return EOK;
} else {
return bithenge_scope_get_param(scope->outer, i, out);
}
}
typedef struct {
bithenge_transform_t base;
bithenge_transform_t *transform;
} barrier_transform_t;
static inline barrier_transform_t *transform_as_barrier(
bithenge_transform_t *base)
{
return (barrier_transform_t *)base;
}
static inline bithenge_transform_t *barrier_as_transform(
barrier_transform_t *self)
{
return &self->base;
}
static errno_t barrier_transform_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
barrier_transform_t *self = transform_as_barrier(base);
bithenge_scope_t *inner_scope;
errno_t rc = bithenge_scope_new(&inner_scope, scope);
if (rc != EOK)
return rc;
bithenge_scope_set_barrier(inner_scope);
bithenge_scope_set_in_node(inner_scope, in);
rc = bithenge_transform_apply(self->transform, inner_scope, in, out);
bithenge_scope_dec_ref(inner_scope);
return rc;
}
static errno_t barrier_transform_prefix_length(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
{
barrier_transform_t *self = transform_as_barrier(base);
bithenge_scope_t *inner_scope;
errno_t rc = bithenge_scope_new(&inner_scope, scope);
if (rc != EOK)
return rc;
bithenge_scope_set_barrier(inner_scope);
bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
rc = bithenge_transform_prefix_length(self->transform, inner_scope, in,
out);
bithenge_scope_dec_ref(inner_scope);
return rc;
}
static errno_t barrier_transform_prefix_apply(bithenge_transform_t *base,
bithenge_scope_t *scope, bithenge_blob_t *in, bithenge_node_t **out_node,
aoff64_t *out_length)
{
barrier_transform_t *self = transform_as_barrier(base);
bithenge_scope_t *inner_scope;
errno_t rc = bithenge_scope_new(&inner_scope, scope);
if (rc != EOK)
return rc;
bithenge_scope_set_barrier(inner_scope);
bithenge_scope_set_in_node(inner_scope, bithenge_blob_as_node(in));
rc = bithenge_transform_prefix_apply(self->transform, inner_scope, in,
out_node, out_length);
bithenge_scope_dec_ref(inner_scope);
return rc;
}
static void barrier_transform_destroy(bithenge_transform_t *base)
{
barrier_transform_t *self = transform_as_barrier(base);
bithenge_transform_dec_ref(self->transform);
free(self);
}
static const bithenge_transform_ops_t barrier_transform_ops = {
.apply = barrier_transform_apply,
.prefix_length = barrier_transform_prefix_length,
.prefix_apply = barrier_transform_prefix_apply,
.destroy = barrier_transform_destroy,
};
errno_t bithenge_barrier_transform_set_subtransform(bithenge_transform_t *base,
bithenge_transform_t *transform)
{
assert(transform);
assert(bithenge_transform_num_params(transform) == 0);
if (bithenge_should_fail()) {
bithenge_transform_dec_ref(transform);
return ENOMEM;
}
barrier_transform_t *self = transform_as_barrier(base);
assert(!self->transform);
self->transform = transform;
return EOK;
}
errno_t bithenge_new_barrier_transform(bithenge_transform_t **out, int num_params)
{
errno_t rc;
barrier_transform_t *self = malloc(sizeof(*self));
if (!self) {
rc = ENOMEM;
goto error;
}
rc = bithenge_init_transform(barrier_as_transform(self),
&barrier_transform_ops, num_params);
if (rc != EOK)
goto error;
self->transform = NULL;
*out = barrier_as_transform(self);
return EOK;
error:
free(self);
return rc;
}
static errno_t ascii_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_node_t *in, bithenge_node_t **out)
{
errno_t rc;
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
bithenge_blob_t *blob = bithenge_node_as_blob(in);
aoff64_t size;
rc = bithenge_blob_size(blob, &size);
if (rc != EOK)
return rc;
char *buffer = malloc(size + 1);
if (!buffer)
return ENOMEM;
aoff64_t size_read = size;
rc = bithenge_blob_read(blob, 0, buffer, &size_read);
if (rc != EOK) {
free(buffer);
return rc;
}
if (size_read != size) {
free(buffer);
return EINVAL;
}
buffer[size] = '\0';
return bithenge_new_string_node(out, buffer, true);
}
static const bithenge_transform_ops_t ascii_ops = {
.apply = ascii_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_ascii_transform = {
&ascii_ops, 1, 0
};
static errno_t bit_prefix_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
char buffer;
aoff64_t size = 1;
errno_t rc = bithenge_blob_read_bits(blob, 0, &buffer, &size, true);
if (rc != EOK)
return rc;
if (size != 1)
return EINVAL;
if (out_size)
*out_size = size;
return bithenge_new_boolean_node(out_node, (buffer & 1) != 0);
}
static const bithenge_transform_ops_t bit_ops = {
.prefix_apply = bit_prefix_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_bit_transform = {
&bit_ops, 1, 0
};
typedef struct {
bithenge_blob_t base;
bithenge_blob_t *bytes;
bool little_endian;
} bits_xe_blob_t;
static bits_xe_blob_t *blob_as_bits_xe(bithenge_blob_t *base)
{
return (bits_xe_blob_t *)base;
}
static bithenge_blob_t *bits_xe_as_blob(bits_xe_blob_t *self)
{
return &self->base;
}
static errno_t bits_xe_size(bithenge_blob_t *base, aoff64_t *out)
{
bits_xe_blob_t *self = blob_as_bits_xe(base);
errno_t rc = bithenge_blob_size(self->bytes, out);
*out *= 8;
return rc;
}
static uint8_t reverse_byte(uint8_t val)
{
val = ((val & 0x0f) << 4) ^ ((val & 0xf0) >> 4);
val = ((val & 0x33) << 2) ^ ((val & 0xcc) >> 2);
val = ((val & 0x55) << 1) ^ ((val & 0xaa) >> 1);
return val;
}
static errno_t bits_xe_read_bits(bithenge_blob_t *base, aoff64_t offset,
char *buffer, aoff64_t *size, bool little_endian)
{
bits_xe_blob_t *self = blob_as_bits_xe(base);
aoff64_t bytes_offset = offset / 8;
aoff64_t bit_offset = offset % 8;
aoff64_t output_num_bytes = (*size + 7) / 8;
aoff64_t bytes_size = (*size + bit_offset + 7) / 8;
bool separate_buffer = bit_offset != 0;
uint8_t *bytes_buffer;
if (separate_buffer) {
bytes_buffer = malloc(bytes_size + 1);
if (!bytes_buffer)
return ENOMEM;
} else
bytes_buffer = (uint8_t *)buffer;
errno_t rc = bithenge_blob_read(self->bytes, bytes_offset,
(char *)bytes_buffer, &bytes_size);
if (rc != EOK)
goto end;
*size = min(*size, bytes_size * 8 - bit_offset);
if (little_endian != self->little_endian)
for (aoff64_t i = 0; i < bytes_size; i++)
bytes_buffer[i] = reverse_byte(bytes_buffer[i]);
if (bit_offset || separate_buffer) {
for (aoff64_t i = 0; i < output_num_bytes; i++) {
uint8_t byte0 = bytes_buffer[i];
uint8_t byte1 = bytes_buffer[i + 1];
buffer[i] = little_endian ?
(byte0 >> bit_offset) ^ (byte1 << (8 - bit_offset)) :
(byte0 << bit_offset) ^ (byte1 >> (8 - bit_offset));
}
}
end:
if (separate_buffer)
free(bytes_buffer);
return rc;
}
static void bits_xe_destroy(bithenge_blob_t *base)
{
bits_xe_blob_t *self = blob_as_bits_xe(base);
bithenge_blob_dec_ref(self->bytes);
free(self);
}
static const bithenge_random_access_blob_ops_t bits_xe_blob_ops = {
.size = bits_xe_size,
.read_bits = bits_xe_read_bits,
.destroy = bits_xe_destroy,
};
static errno_t bits_xe_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_node_t *in, bithenge_node_t **out)
{
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
bits_xe_blob_t *blob = malloc(sizeof(*blob));
if (!blob)
return ENOMEM;
errno_t rc = bithenge_init_random_access_blob(bits_xe_as_blob(blob),
&bits_xe_blob_ops);
if (rc != EOK) {
free(blob);
return rc;
}
bithenge_node_inc_ref(in);
blob->bytes = bithenge_node_as_blob(in);
blob->little_endian = (self == &bithenge_bits_le_transform);
*out = bithenge_blob_as_node(bits_xe_as_blob(blob));
return EOK;
}
static const bithenge_transform_ops_t bits_xe_ops = {
.apply = bits_xe_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_bits_be_transform = {
&bits_xe_ops, 1, 0
};
bithenge_transform_t bithenge_bits_le_transform = {
&bits_xe_ops, 1, 0
};
static errno_t invalid_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_node_t *in, bithenge_node_t **out)
{
return EINVAL;
}
static const bithenge_transform_ops_t invalid_ops = {
.apply = invalid_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_invalid_transform = {
&invalid_ops, 1, 0
};
static errno_t known_length_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
bithenge_node_t *length_node;
errno_t rc = bithenge_scope_get_param(scope, 0, &length_node);
if (rc != EOK)
return rc;
if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(length_node);
return EINVAL;
}
bithenge_int_t length = bithenge_integer_node_value(length_node);
bithenge_node_dec_ref(length_node);
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
aoff64_t size;
rc = bithenge_blob_size(bithenge_node_as_blob(in), &size);
if (rc != EOK)
return rc;
if (length != (bithenge_int_t)size)
return EINVAL;
bithenge_node_inc_ref(in);
*out = in;
return EOK;
}
static errno_t known_length_prefix_length(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *in, aoff64_t *out)
{
bithenge_node_t *length_node;
errno_t rc = bithenge_scope_get_param(scope, 0, &length_node);
if (rc != EOK)
return rc;
if (bithenge_node_type(length_node) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(length_node);
return EINVAL;
}
bithenge_int_t length = bithenge_integer_node_value(length_node);
bithenge_node_dec_ref(length_node);
*out = (aoff64_t)length;
return EOK;
}
static const bithenge_transform_ops_t known_length_ops = {
.apply = known_length_apply,
.prefix_length = known_length_prefix_length,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_known_length_transform = {
&known_length_ops, 1, 1
};
static errno_t nonzero_boolean_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
if (bithenge_node_type(in) != BITHENGE_NODE_INTEGER)
return EINVAL;
bool value = bithenge_integer_node_value(in) != 0;
return bithenge_new_boolean_node(out, value);
}
static const bithenge_transform_ops_t nonzero_boolean_ops = {
.apply = nonzero_boolean_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_nonzero_boolean_transform = {
&nonzero_boolean_ops, 1, 0
};
static errno_t prefix_length_1(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_blob_t *blob, aoff64_t *out)
{
*out = 1;
return EOK;
}
static errno_t prefix_length_2(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_blob_t *blob, aoff64_t *out)
{
*out = 2;
return EOK;
}
static errno_t prefix_length_4(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_blob_t *blob, aoff64_t *out)
{
*out = 4;
return EOK;
}
static errno_t prefix_length_8(bithenge_transform_t *self, bithenge_scope_t *scope,
bithenge_blob_t *blob, aoff64_t *out)
{
*out = 8;
return EOK;
}
static uint8_t uint8_t_identity(uint8_t arg)
{
return arg;
}
#define MAKE_UINT_TRANSFORM(NAME, TYPE, ENDIAN, PREFIX_LENGTH_FUNC) \
static errno_t NAME##_apply(bithenge_transform_t *self, \
bithenge_scope_t *scope, bithenge_node_t *in, \
bithenge_node_t **out) \
{ \
errno_t rc; \
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB) \
return EINVAL; \
bithenge_blob_t *blob = bithenge_node_as_blob(in); \
\
\
TYPE val[2]; \
aoff64_t size = sizeof(val[0]) + 1; \
rc = bithenge_blob_read(blob, 0, (char *)val, &size); \
if (rc != EOK) \
return rc; \
if (size != sizeof(val[0])) \
return EINVAL; \
\
return bithenge_new_integer_node(out, ENDIAN(val[0])); \
} \
\
static const bithenge_transform_ops_t NAME##_ops = { \
.apply = NAME##_apply, \
.prefix_length = PREFIX_LENGTH_FUNC, \
.destroy = transform_indestructible, \
}; \
\
bithenge_transform_t bithenge_##NAME##_transform = { \
&NAME##_ops, 1, 0 \
}
MAKE_UINT_TRANSFORM(uint8, uint8_t, uint8_t_identity, prefix_length_1);
MAKE_UINT_TRANSFORM(uint16le, uint16_t, uint16_t_le2host, prefix_length_2);
MAKE_UINT_TRANSFORM(uint16be, uint16_t, uint16_t_be2host, prefix_length_2);
MAKE_UINT_TRANSFORM(uint32le, uint32_t, uint32_t_le2host, prefix_length_4);
MAKE_UINT_TRANSFORM(uint32be, uint32_t, uint32_t_be2host, prefix_length_4);
MAKE_UINT_TRANSFORM(uint64le, uint64_t, uint64_t_le2host, prefix_length_8);
MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint64_t_be2host, prefix_length_8);
static errno_t uint_xe_prefix_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
aoff64_t *out_size)
{
bool little_endian = (self == &bithenge_uint_le_transform);
bithenge_node_t *num_bits_node;
errno_t rc = bithenge_scope_get_param(scope, 0, &num_bits_node);
if (rc != EOK)
return rc;
if (bithenge_node_type(num_bits_node) != BITHENGE_NODE_INTEGER) {
bithenge_node_dec_ref(num_bits_node);
return EINVAL;
}
bithenge_int_t num_bits = bithenge_integer_node_value(num_bits_node);
bithenge_node_dec_ref(num_bits_node);
if (num_bits < 0)
return EINVAL;
if ((size_t)num_bits > sizeof(bithenge_int_t) * 8 - 1)
return EINVAL;
aoff64_t size = num_bits;
uint8_t buffer[sizeof(bithenge_int_t)];
rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, &size,
little_endian);
if (rc != EOK)
return rc;
if (size != (aoff64_t)num_bits)
return EINVAL;
if (out_size)
*out_size = size;
bithenge_int_t result = 0;
bithenge_int_t num_easy_bytes = num_bits / 8;
if (little_endian) {
for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
result += buffer[i] << 8 * i;
if (num_bits % 8)
result += (buffer[num_easy_bytes] &
((1 << num_bits % 8) - 1)) << 8 * num_easy_bytes;
} else {
for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
result += buffer[i] << (num_bits - 8 * (i + 1));
if (num_bits % 8)
result += buffer[num_easy_bytes] >> (8 - num_bits % 8);
}
return bithenge_new_integer_node(out_node, result);
}
static const bithenge_transform_ops_t uint_xe_ops = {
.prefix_apply = uint_xe_prefix_apply,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_uint_be_transform = {
&uint_xe_ops, 1, 1
};
bithenge_transform_t bithenge_uint_le_transform = {
&uint_xe_ops, 1, 1
};
static errno_t zero_terminated_apply(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
{
errno_t rc;
if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
return EINVAL;
bithenge_blob_t *blob = bithenge_node_as_blob(in);
aoff64_t size;
rc = bithenge_blob_size(blob, &size);
if (rc != EOK)
return rc;
if (size < 1)
return EINVAL;
char ch;
aoff64_t size_read = 1;
rc = bithenge_blob_read(blob, size - 1, &ch, &size_read);
if (rc != EOK)
return rc;
if (size_read != 1 || ch != '\0')
return EINVAL;
bithenge_blob_inc_ref(blob);
return bithenge_new_subblob(out, blob, 0, size - 1);
}
static errno_t zero_terminated_prefix_length(bithenge_transform_t *self,
bithenge_scope_t *scope, bithenge_blob_t *blob, aoff64_t *out)
{
errno_t rc;
char buffer[4096];
aoff64_t offset = 0, size_read = sizeof(buffer);
do {
rc = bithenge_blob_read(blob, offset, buffer, &size_read);
if (rc != EOK)
return rc;
char *found = memchr(buffer, '\0', size_read);
if (found) {
*out = found - buffer + offset + 1;
return EOK;
}
offset += size_read;
} while (size_read == sizeof(buffer));
return EINVAL;
}
static const bithenge_transform_ops_t zero_terminated_ops = {
.apply = zero_terminated_apply,
.prefix_length = zero_terminated_prefix_length,
.destroy = transform_indestructible,
};
bithenge_transform_t bithenge_zero_terminated_transform = {
&zero_terminated_ops, 1, 0
};
static bithenge_named_transform_t primitive_transforms[] = {
{ "ascii", &bithenge_ascii_transform },
{ "bit", &bithenge_bit_transform },
{ "bits_be", &bithenge_bits_be_transform },
{ "bits_le", &bithenge_bits_le_transform },
{ "known_length", &bithenge_known_length_transform },
{ "nonzero_boolean", &bithenge_nonzero_boolean_transform },
{ "uint8", &bithenge_uint8_transform },
{ "uint16be", &bithenge_uint16be_transform },
{ "uint16le", &bithenge_uint16le_transform },
{ "uint32be", &bithenge_uint32be_transform },
{ "uint32le", &bithenge_uint32le_transform },
{ "uint64be", &bithenge_uint64be_transform },
{ "uint64le", &bithenge_uint64le_transform },
{ "uint_be", &bithenge_uint_be_transform },
{ "uint_le", &bithenge_uint_le_transform },
{ "zero_terminated", &bithenge_zero_terminated_transform },
{ NULL, NULL }
};
bithenge_named_transform_t *bithenge_primitive_transforms = primitive_transforms;
HelenOS homepage, sources at GitHub