Changeset 0ce0103 in mainline for uspace/app/bithenge/transform.c


Ignore:
Timestamp:
2012-08-06T04:15:33Z (12 years ago)
Author:
Sean Bartell <wingedtachikoma@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
f9c314a5
Parents:
c3437d9
Message:

Bithenge: implement bitfields

File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/app/bithenge/transform.c

    rc3437d9 r0ce0103  
    363363}
    364364
     365
     366
     367/***************** ascii                                     *****************/
     368
    365369static int ascii_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
    366370    bithenge_node_t *in, bithenge_node_t **out)
     
    404408};
    405409
     410
     411
     412/***************** bit                                       *****************/
     413
     414static int bit_prefix_apply(bithenge_transform_t *self,
     415    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
     416    aoff64_t *out_size)
     417{
     418        char buffer;
     419        *out_size = 1;
     420        int rc = bithenge_blob_read_bits(blob, 0, &buffer, out_size, true);
     421        if (rc != EOK)
     422                return rc;
     423        if (*out_size != 1)
     424                return EINVAL;
     425        return bithenge_new_boolean_node(out_node, (buffer & 1) != 0);
     426}
     427
     428static const bithenge_transform_ops_t bit_ops = {
     429        .prefix_apply = bit_prefix_apply,
     430        .destroy = transform_indestructible,
     431};
     432
     433/** A transform that decodes a bit as a boolean. */
     434bithenge_transform_t bithenge_bit_transform = {
     435        &bit_ops, 1, 0
     436};
     437
     438
     439
     440/***************** bits_be, bits_le                          *****************/
     441
     442typedef struct {
     443        bithenge_blob_t base;
     444        bithenge_blob_t *bytes;
     445        bool little_endian;
     446} bits_xe_blob_t;
     447
     448static bits_xe_blob_t *blob_as_bits_xe(bithenge_blob_t *base)
     449{
     450        return (bits_xe_blob_t *)base;
     451}
     452
     453static bithenge_blob_t *bits_xe_as_blob(bits_xe_blob_t *self)
     454{
     455        return &self->base;
     456}
     457
     458static int bits_xe_size(bithenge_blob_t *base, aoff64_t *out)
     459{
     460        bits_xe_blob_t *self = blob_as_bits_xe(base);
     461        int rc = bithenge_blob_size(self->bytes, out);
     462        *out *= 8;
     463        return rc;
     464}
     465
     466static uint8_t reverse_byte(uint8_t val)
     467{
     468        val = ((val & 0x0f) << 4) ^ ((val & 0xf0) >> 4);
     469        val = ((val & 0x33) << 2) ^ ((val & 0xcc) >> 2);
     470        val = ((val & 0x55) << 1) ^ ((val & 0xaa) >> 1);
     471        return val;
     472}
     473
     474static int bits_xe_read_bits(bithenge_blob_t *base, aoff64_t offset,
     475    char *buffer, aoff64_t *size, bool little_endian)
     476{
     477        bits_xe_blob_t *self = blob_as_bits_xe(base);
     478        aoff64_t bytes_offset = offset / 8;
     479        aoff64_t bit_offset = offset % 8;
     480        aoff64_t output_num_bytes = (*size + 7) / 8;
     481        aoff64_t bytes_size = (*size + bit_offset + 7) / 8;
     482        bool separate_buffer = bit_offset != 0;
     483        uint8_t *bytes_buffer;
     484        if (separate_buffer) {
     485                /* Allocate an extra byte, to make sure byte1 can be read. */
     486                bytes_buffer = malloc(bytes_size + 1);
     487                if (!bytes_buffer)
     488                        return ENOMEM;
     489        } else
     490                bytes_buffer = (uint8_t *)buffer;
     491
     492        int rc = bithenge_blob_read(self->bytes, bytes_offset,
     493            (char *)bytes_buffer, &bytes_size);
     494        if (rc != EOK)
     495                goto end;
     496        *size = min(*size, bytes_size * 8 - bit_offset);
     497
     498        if (little_endian != self->little_endian)
     499                for (aoff64_t i = 0; i < bytes_size; i++)
     500                        bytes_buffer[i] = reverse_byte(bytes_buffer[i]);
     501
     502        if (bit_offset || separate_buffer) {
     503                for (aoff64_t i = 0; i < output_num_bytes; i++) {
     504                        uint8_t byte0 = bytes_buffer[i];
     505                        uint8_t byte1 = bytes_buffer[i + 1];
     506                        buffer[i] = little_endian ?
     507                            (byte0 >> bit_offset) ^ (byte1 << (8 - bit_offset)) :
     508                            (byte0 << bit_offset) ^ (byte1 >> (8 - bit_offset));
     509                }
     510        }
     511
     512end:
     513        if (separate_buffer)
     514                free(bytes_buffer);
     515        return rc;
     516}
     517
     518static void bits_xe_destroy(bithenge_blob_t *base)
     519{
     520        bits_xe_blob_t *self = blob_as_bits_xe(base);
     521        bithenge_blob_dec_ref(self->bytes);
     522        free(self);
     523}
     524
     525static const bithenge_random_access_blob_ops_t bits_xe_blob_ops = {
     526        .size = bits_xe_size,
     527        .read_bits = bits_xe_read_bits,
     528        .destroy = bits_xe_destroy,
     529};
     530
     531static int bits_xe_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
     532    bithenge_node_t *in, bithenge_node_t **out)
     533{
     534        if (bithenge_node_type(in) != BITHENGE_NODE_BLOB)
     535                return EINVAL;
     536        bits_xe_blob_t *blob = malloc(sizeof(*blob));
     537        if (!blob)
     538                return ENOMEM;
     539        int rc = bithenge_init_random_access_blob(bits_xe_as_blob(blob),
     540            &bits_xe_blob_ops);
     541        if (rc != EOK) {
     542                free(blob);
     543                return rc;
     544        }
     545        bithenge_node_inc_ref(in);
     546        blob->bytes = bithenge_node_as_blob(in);
     547        blob->little_endian = (self == &bithenge_bits_le_transform);
     548        *out = bithenge_blob_as_node(bits_xe_as_blob(blob));
     549        return EOK;
     550}
     551
     552static const bithenge_transform_ops_t bits_xe_ops = {
     553        .apply = bits_xe_apply,
     554        .destroy = transform_indestructible,
     555};
     556
     557/** A transform that converts a byte blob to a bit blob, most-significant bit
     558 * first. */
     559bithenge_transform_t bithenge_bits_be_transform = {
     560        &bits_xe_ops, 1, 0
     561};
     562
     563/** A transform that converts a byte blob to a bit blob, least-significant bit
     564 * first. */
     565bithenge_transform_t bithenge_bits_le_transform = {
     566        &bits_xe_ops, 1, 0
     567};
     568
     569
     570
     571/***************** invalid                                   *****************/
     572
    406573static int invalid_apply(bithenge_transform_t *self, bithenge_scope_t *scope,
    407574    bithenge_node_t *in, bithenge_node_t **out)
     
    419586        &invalid_ops, 1, 0
    420587};
     588
     589
     590
     591/***************** known_length                              *****************/
    421592
    422593static int known_length_apply(bithenge_transform_t *self,
     
    564735MAKE_UINT_TRANSFORM(uint64be, uint64_t, uint32_t_be2host, prefix_length_8);
    565736
     737
     738
     739/***************** uint_be, uint_le                          *****************/
     740
     741static int uint_xe_prefix_apply(bithenge_transform_t *self,
     742    bithenge_scope_t *scope, bithenge_blob_t *blob, bithenge_node_t **out_node,
     743    aoff64_t *out_size)
     744{
     745        bool little_endian = (self == &bithenge_uint_le_transform);
     746        bithenge_node_t *num_bits_node;
     747        int rc = bithenge_scope_get_param(scope, 0, &num_bits_node);
     748        if (rc != EOK)
     749                return rc;
     750        if (bithenge_node_type(num_bits_node) != BITHENGE_NODE_INTEGER) {
     751                bithenge_node_dec_ref(num_bits_node);
     752                return EINVAL;
     753        }
     754        bithenge_int_t num_bits = bithenge_integer_node_value(num_bits_node);
     755        bithenge_node_dec_ref(num_bits_node);
     756        if (num_bits < 0)
     757                return EINVAL;
     758        if ((size_t)num_bits > sizeof(bithenge_int_t) * 8 - 1)
     759                return EINVAL;
     760
     761        *out_size = num_bits;
     762        uint8_t buffer[sizeof(bithenge_int_t)];
     763        rc = bithenge_blob_read_bits(blob, 0, (char *)buffer, out_size,
     764            little_endian);
     765        if (rc != EOK)
     766                return rc;
     767        if (*out_size != (aoff64_t)num_bits)
     768                return EINVAL;
     769
     770        bithenge_int_t result = 0;
     771        bithenge_int_t num_easy_bytes = num_bits / 8;
     772        if (little_endian) {
     773                for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
     774                        result += buffer[i] << 8 * i;
     775                if (num_bits % 8)
     776                        result += (buffer[num_easy_bytes] &
     777                            ((1 << num_bits % 8) - 1)) << 8 * num_easy_bytes;
     778        } else {
     779                for (bithenge_int_t i = 0; i < num_easy_bytes; i++)
     780                        result += buffer[i] << (num_bits - 8 * (i + 1));
     781                if (num_bits % 8)
     782                        result += buffer[num_easy_bytes] >> (8 - num_bits % 8);
     783        }
     784
     785        return bithenge_new_integer_node(out_node, result);
     786}
     787
     788static const bithenge_transform_ops_t uint_xe_ops = {
     789        .prefix_apply = uint_xe_prefix_apply,
     790        .destroy = transform_indestructible,
     791};
     792
     793/** A transform that reads an unsigned integer from an arbitrary number of
     794 * bits, most-significant bit first. */
     795bithenge_transform_t bithenge_uint_be_transform = {
     796        &uint_xe_ops, 1, 1
     797};
     798
     799/** A transform that reads an unsigned integer from an arbitrary number of
     800 * bits, least-significant bit first. */
     801bithenge_transform_t bithenge_uint_le_transform = {
     802        &uint_xe_ops, 1, 1
     803};
     804
     805
     806
     807/***************** zero_terminated                           *****************/
     808
    566809static int zero_terminated_apply(bithenge_transform_t *self,
    567810    bithenge_scope_t *scope, bithenge_node_t *in, bithenge_node_t **out)
     
    621864static bithenge_named_transform_t primitive_transforms[] = {
    622865        {"ascii", &bithenge_ascii_transform},
     866        {"bit", &bithenge_bit_transform},
     867        {"bits_be", &bithenge_bits_be_transform},
     868        {"bits_le", &bithenge_bits_le_transform},
    623869        {"known_length", &bithenge_known_length_transform},
    624870        {"nonzero_boolean", &bithenge_nonzero_boolean_transform},
    625871        {"uint8", &bithenge_uint8_transform},
     872        {"uint16be", &bithenge_uint16be_transform},
    626873        {"uint16le", &bithenge_uint16le_transform},
    627         {"uint16be", &bithenge_uint16be_transform},
     874        {"uint32be", &bithenge_uint32be_transform},
    628875        {"uint32le", &bithenge_uint32le_transform},
    629         {"uint32be", &bithenge_uint32be_transform},
     876        {"uint64be", &bithenge_uint64be_transform},
    630877        {"uint64le", &bithenge_uint64le_transform},
    631         {"uint64be", &bithenge_uint64be_transform},
     878        {"uint_be", &bithenge_uint_be_transform},
     879        {"uint_le", &bithenge_uint_le_transform},
    632880        {"zero_terminated", &bithenge_zero_terminated_transform},
    633881        {NULL, NULL}
Note: See TracChangeset for help on using the changeset viewer.