Home | History | Annotate | Line # | Download | only in cbor
      1 /*
      2  * Copyright (c) 2014-2019 Pavel Kalvoda <me (at) pavelkalvoda.com>
      3  *
      4  * libcbor is free software; you can redistribute it and/or modify
      5  * it under the terms of the MIT license. See LICENSE for details.
      6  */
      7 
      8 #include "serialization.h"
      9 #include <string.h>
     10 #include "cbor/arrays.h"
     11 #include "cbor/bytestrings.h"
     12 #include "cbor/floats_ctrls.h"
     13 #include "cbor/ints.h"
     14 #include "cbor/maps.h"
     15 #include "cbor/strings.h"
     16 #include "cbor/tags.h"
     17 #include "encoding.h"
     18 #include "internal/memory_utils.h"
     19 
     20 size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,
     21                       size_t buffer_size) {
     22   switch (cbor_typeof(item)) {
     23     case CBOR_TYPE_UINT:
     24       return cbor_serialize_uint(item, buffer, buffer_size);
     25     case CBOR_TYPE_NEGINT:
     26       return cbor_serialize_negint(item, buffer, buffer_size);
     27     case CBOR_TYPE_BYTESTRING:
     28       return cbor_serialize_bytestring(item, buffer, buffer_size);
     29     case CBOR_TYPE_STRING:
     30       return cbor_serialize_string(item, buffer, buffer_size);
     31     case CBOR_TYPE_ARRAY:
     32       return cbor_serialize_array(item, buffer, buffer_size);
     33     case CBOR_TYPE_MAP:
     34       return cbor_serialize_map(item, buffer, buffer_size);
     35     case CBOR_TYPE_TAG:
     36       return cbor_serialize_tag(item, buffer, buffer_size);
     37     case CBOR_TYPE_FLOAT_CTRL:
     38       return cbor_serialize_float_ctrl(item, buffer, buffer_size);
     39     default:
     40       return 0;
     41   }
     42 }
     43 
     44 size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,
     45                             size_t *buffer_size) {
     46   size_t bfr_size = 32;
     47   unsigned char *bfr = _CBOR_MALLOC(bfr_size), *tmp_bfr;
     48   if (bfr == NULL) {
     49     return 0;
     50   }
     51 
     52   size_t written;
     53 
     54   /* This is waaay too optimistic - figure out something smarter (eventually) */
     55   while ((written = cbor_serialize(item, bfr, bfr_size)) == 0) {
     56     if (!_cbor_safe_to_multiply(CBOR_BUFFER_GROWTH, bfr_size)) {
     57       _CBOR_FREE(bfr);
     58       return 0;
     59     }
     60 
     61     tmp_bfr = _CBOR_REALLOC(bfr, bfr_size *= 2);
     62 
     63     if (tmp_bfr == NULL) {
     64       _CBOR_FREE(bfr);
     65       return 0;
     66     }
     67     bfr = tmp_bfr;
     68   }
     69   *buffer = bfr;
     70   *buffer_size = bfr_size;
     71   return written;
     72 }
     73 
     74 size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,
     75                            size_t buffer_size) {
     76   assert(cbor_isa_uint(item));
     77   switch (cbor_int_get_width(item)) {
     78     case CBOR_INT_8:
     79       return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);
     80     case CBOR_INT_16:
     81       return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);
     82     case CBOR_INT_32:
     83       return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);
     84     case CBOR_INT_64:
     85       return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);
     86     default:
     87       return 0;
     88   }
     89 }
     90 
     91 size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,
     92                              size_t buffer_size) {
     93   assert(cbor_isa_negint(item));
     94   switch (cbor_int_get_width(item)) {
     95     case CBOR_INT_8:
     96       return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);
     97     case CBOR_INT_16:
     98       return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);
     99     case CBOR_INT_32:
    100       return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);
    101     case CBOR_INT_64:
    102       return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);
    103     default:
    104       return 0;
    105   }
    106 }
    107 
    108 size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,
    109                                  size_t buffer_size) {
    110   assert(cbor_isa_bytestring(item));
    111   if (cbor_bytestring_is_definite(item)) {
    112     size_t length = cbor_bytestring_length(item);
    113     size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);
    114     if (written && (buffer_size - written >= length)) {
    115       memcpy(buffer + written, cbor_bytestring_handle(item), length);
    116       return written + length;
    117     } else
    118       return 0;
    119   } else {
    120     assert(cbor_bytestring_is_indefinite(item));
    121     size_t chunk_count = cbor_bytestring_chunk_count(item);
    122     size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);
    123 
    124     if (written == 0) return 0;
    125 
    126     cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);
    127     for (size_t i = 0; i < chunk_count; i++) {
    128       size_t chunk_written = cbor_serialize_bytestring(
    129           chunks[i], buffer + written, buffer_size - written);
    130       if (chunk_written == 0)
    131         return 0;
    132       else
    133         written += chunk_written;
    134     }
    135     if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
    136       return written + 1;
    137     else
    138       return 0;
    139   }
    140 }
    141 
    142 size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,
    143                              size_t buffer_size) {
    144   assert(cbor_isa_string(item));
    145   if (cbor_string_is_definite(item)) {
    146     size_t length = cbor_string_length(item);
    147     size_t written = cbor_encode_string_start(length, buffer, buffer_size);
    148     if (written && (buffer_size - written >= length)) {
    149       memcpy(buffer + written, cbor_string_handle(item), length);
    150       return written + length;
    151     } else
    152       return 0;
    153   } else {
    154     assert(cbor_string_is_indefinite(item));
    155     size_t chunk_count = cbor_string_chunk_count(item);
    156     size_t written = cbor_encode_indef_string_start(buffer, buffer_size);
    157 
    158     if (written == 0) return 0;
    159 
    160     cbor_item_t **chunks = cbor_string_chunks_handle(item);
    161     for (size_t i = 0; i < chunk_count; i++) {
    162       size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,
    163                                                    buffer_size - written);
    164       if (chunk_written == 0)
    165         return 0;
    166       else
    167         written += chunk_written;
    168     }
    169     if (cbor_encode_break(buffer + written, buffer_size - written) > 0)
    170       return written + 1;
    171     else
    172       return 0;
    173   }
    174 }
    175 
    176 size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,
    177                             size_t buffer_size) {
    178   assert(cbor_isa_array(item));
    179   size_t size = cbor_array_size(item), written = 0;
    180   cbor_item_t **handle = cbor_array_handle(item);
    181   if (cbor_array_is_definite(item)) {
    182     written = cbor_encode_array_start(size, buffer, buffer_size);
    183   } else {
    184     assert(cbor_array_is_indefinite(item));
    185     written = cbor_encode_indef_array_start(buffer, buffer_size);
    186   }
    187   if (written == 0) return 0;
    188 
    189   size_t item_written;
    190   for (size_t i = 0; i < size; i++) {
    191     item_written =
    192         cbor_serialize(*(handle++), buffer + written, buffer_size - written);
    193     if (item_written == 0)
    194       return 0;
    195     else
    196       written += item_written;
    197   }
    198 
    199   if (cbor_array_is_definite(item)) {
    200     return written;
    201   } else {
    202     assert(cbor_array_is_indefinite(item));
    203     item_written = cbor_encode_break(buffer + written, buffer_size - written);
    204     if (item_written == 0)
    205       return 0;
    206     else
    207       return written + 1;
    208   }
    209 }
    210 
    211 size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,
    212                           size_t buffer_size) {
    213   assert(cbor_isa_map(item));
    214   size_t size = cbor_map_size(item), written = 0;
    215   struct cbor_pair *handle = cbor_map_handle(item);
    216 
    217   if (cbor_map_is_definite(item)) {
    218     written = cbor_encode_map_start(size, buffer, buffer_size);
    219   } else {
    220     assert(cbor_map_is_indefinite(item));
    221     written = cbor_encode_indef_map_start(buffer, buffer_size);
    222   }
    223   if (written == 0) return 0;
    224 
    225   size_t item_written;
    226   for (size_t i = 0; i < size; i++) {
    227     item_written =
    228         cbor_serialize(handle->key, buffer + written, buffer_size - written);
    229     if (item_written == 0)
    230       return 0;
    231     else
    232       written += item_written;
    233     item_written = cbor_serialize((handle++)->value, buffer + written,
    234                                   buffer_size - written);
    235     if (item_written == 0)
    236       return 0;
    237     else
    238       written += item_written;
    239   }
    240 
    241   if (cbor_map_is_definite(item)) {
    242     return written;
    243   } else {
    244     assert(cbor_map_is_indefinite(item));
    245     item_written = cbor_encode_break(buffer + written, buffer_size - written);
    246     if (item_written == 0)
    247       return 0;
    248     else
    249       return written + 1;
    250   }
    251 }
    252 
    253 size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,
    254                           size_t buffer_size) {
    255   assert(cbor_isa_tag(item));
    256   size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);
    257   if (written == 0) return 0;
    258 
    259   size_t item_written = cbor_serialize(cbor_tag_item(item), buffer + written,
    260                                        buffer_size - written);
    261   if (item_written == 0)
    262     return 0;
    263   else
    264     return written + item_written;
    265 }
    266 
    267 size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,
    268                                  size_t buffer_size) {
    269   assert(cbor_isa_float_ctrl(item));
    270   switch (cbor_float_get_width(item)) {
    271     case CBOR_FLOAT_0:
    272       /* CTRL - special treatment */
    273       return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);
    274     case CBOR_FLOAT_16:
    275       return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);
    276     case CBOR_FLOAT_32:
    277       return cbor_encode_single(cbor_float_get_float4(item), buffer,
    278                                 buffer_size);
    279     case CBOR_FLOAT_64:
    280       return cbor_encode_double(cbor_float_get_float8(item), buffer,
    281                                 buffer_size);
    282   }
    283 
    284   /* Should never happen - make the compiler happy */
    285   return 0;
    286 }
    287