Path: blob/main/contrib/libcbor/src/cbor/serialization.c
39562 views
/*1* Copyright (c) 2014-2020 Pavel Kalvoda <[email protected]>2*3* libcbor is free software; you can redistribute it and/or modify4* it under the terms of the MIT license. See LICENSE for details.5*/67#include "serialization.h"8#include <string.h>9#include "cbor/arrays.h"10#include "cbor/bytestrings.h"11#include "cbor/floats_ctrls.h"12#include "cbor/ints.h"13#include "cbor/maps.h"14#include "cbor/strings.h"15#include "cbor/tags.h"16#include "encoding.h"17#include "internal/memory_utils.h"1819size_t cbor_serialize(const cbor_item_t *item, unsigned char *buffer,20size_t buffer_size) {21// cppcheck-suppress missingReturn22switch (cbor_typeof(item)) {23case CBOR_TYPE_UINT:24return cbor_serialize_uint(item, buffer, buffer_size);25case CBOR_TYPE_NEGINT:26return cbor_serialize_negint(item, buffer, buffer_size);27case CBOR_TYPE_BYTESTRING:28return cbor_serialize_bytestring(item, buffer, buffer_size);29case CBOR_TYPE_STRING:30return cbor_serialize_string(item, buffer, buffer_size);31case CBOR_TYPE_ARRAY:32return cbor_serialize_array(item, buffer, buffer_size);33case CBOR_TYPE_MAP:34return cbor_serialize_map(item, buffer, buffer_size);35case CBOR_TYPE_TAG:36return cbor_serialize_tag(item, buffer, buffer_size);37case CBOR_TYPE_FLOAT_CTRL:38return cbor_serialize_float_ctrl(item, buffer, buffer_size);39}40}4142/** Largest integer that can be encoded as embedded in the item leading byte. */43const uint64_t kMaxEmbeddedInt = 23;4445/** How many bytes will a tag for a nested item of a given `size` take when46* encoded.*/47size_t _cbor_encoded_header_size(uint64_t size) {48if (size <= kMaxEmbeddedInt)49return 1;50else if (size <= UINT8_MAX)51return 2;52else if (size <= UINT16_MAX)53return 3;54else if (size <= UINT32_MAX)55return 5;56else57return 9;58}5960size_t cbor_serialized_size(const cbor_item_t *item) {61// cppcheck-suppress missingReturn62switch (cbor_typeof(item)) {63case CBOR_TYPE_UINT:64case CBOR_TYPE_NEGINT:65switch (cbor_int_get_width(item)) {66case CBOR_INT_8:67if (cbor_get_uint8(item) <= kMaxEmbeddedInt) return 1;68return 2;69case CBOR_INT_16:70return 3;71case CBOR_INT_32:72return 5;73case CBOR_INT_64:74return 9;75}76// Note: We do not _cbor_safe_signaling_add zero-length definite strings,77// they would cause zeroes to propagate. All other items are at least one78// byte.79case CBOR_TYPE_BYTESTRING: {80if (cbor_bytestring_is_definite(item)) {81size_t header_size =82_cbor_encoded_header_size(cbor_bytestring_length(item));83if (cbor_bytestring_length(item) == 0) return header_size;84return _cbor_safe_signaling_add(header_size,85cbor_bytestring_length(item));86}87size_t indef_bytestring_size = 2; // Leading byte + break88cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);89for (size_t i = 0; i < cbor_bytestring_chunk_count(item); i++) {90indef_bytestring_size = _cbor_safe_signaling_add(91indef_bytestring_size, cbor_serialized_size(chunks[i]));92}93return indef_bytestring_size;94}95case CBOR_TYPE_STRING: {96if (cbor_string_is_definite(item)) {97size_t header_size =98_cbor_encoded_header_size(cbor_string_length(item));99if (cbor_string_length(item) == 0) return header_size;100return _cbor_safe_signaling_add(header_size, cbor_string_length(item));101}102size_t indef_string_size = 2; // Leading byte + break103cbor_item_t **chunks = cbor_string_chunks_handle(item);104for (size_t i = 0; i < cbor_string_chunk_count(item); i++) {105indef_string_size = _cbor_safe_signaling_add(106indef_string_size, cbor_serialized_size(chunks[i]));107}108return indef_string_size;109}110case CBOR_TYPE_ARRAY: {111size_t array_size = cbor_array_is_definite(item)112? _cbor_encoded_header_size(cbor_array_size(item))113: 2; // Leading byte + break114cbor_item_t **items = cbor_array_handle(item);115for (size_t i = 0; i < cbor_array_size(item); i++) {116array_size = _cbor_safe_signaling_add(array_size,117cbor_serialized_size(items[i]));118}119return array_size;120}121case CBOR_TYPE_MAP: {122size_t map_size = cbor_map_is_definite(item)123? _cbor_encoded_header_size(cbor_map_size(item))124: 2; // Leading byte + break125struct cbor_pair *items = cbor_map_handle(item);126for (size_t i = 0; i < cbor_map_size(item); i++) {127map_size = _cbor_safe_signaling_add(128map_size,129_cbor_safe_signaling_add(cbor_serialized_size(items[i].key),130cbor_serialized_size(items[i].value)));131}132return map_size;133}134case CBOR_TYPE_TAG: {135return _cbor_safe_signaling_add(136_cbor_encoded_header_size(cbor_tag_value(item)),137cbor_serialized_size(cbor_move(cbor_tag_item(item))));138}139case CBOR_TYPE_FLOAT_CTRL:140switch (cbor_float_get_width(item)) {141case CBOR_FLOAT_0:142return _cbor_encoded_header_size(cbor_ctrl_value(item));143case CBOR_FLOAT_16:144return 3;145case CBOR_FLOAT_32:146return 5;147case CBOR_FLOAT_64:148return 9;149}150}151}152153size_t cbor_serialize_alloc(const cbor_item_t *item, unsigned char **buffer,154size_t *buffer_size) {155*buffer = NULL;156size_t serialized_size = cbor_serialized_size(item);157if (serialized_size == 0) {158if (buffer_size != NULL) *buffer_size = 0;159return 0;160}161*buffer = _cbor_malloc(serialized_size);162if (*buffer == NULL) {163if (buffer_size != NULL) *buffer_size = 0;164return 0;165}166167size_t written = cbor_serialize(item, *buffer, serialized_size);168CBOR_ASSERT(written == serialized_size);169if (buffer_size != NULL) *buffer_size = serialized_size;170return written;171}172173size_t cbor_serialize_uint(const cbor_item_t *item, unsigned char *buffer,174size_t buffer_size) {175CBOR_ASSERT(cbor_isa_uint(item));176// cppcheck-suppress missingReturn177switch (cbor_int_get_width(item)) {178case CBOR_INT_8:179return cbor_encode_uint8(cbor_get_uint8(item), buffer, buffer_size);180case CBOR_INT_16:181return cbor_encode_uint16(cbor_get_uint16(item), buffer, buffer_size);182case CBOR_INT_32:183return cbor_encode_uint32(cbor_get_uint32(item), buffer, buffer_size);184case CBOR_INT_64:185return cbor_encode_uint64(cbor_get_uint64(item), buffer, buffer_size);186}187}188189size_t cbor_serialize_negint(const cbor_item_t *item, unsigned char *buffer,190size_t buffer_size) {191CBOR_ASSERT(cbor_isa_negint(item));192// cppcheck-suppress missingReturn193switch (cbor_int_get_width(item)) {194case CBOR_INT_8:195return cbor_encode_negint8(cbor_get_uint8(item), buffer, buffer_size);196case CBOR_INT_16:197return cbor_encode_negint16(cbor_get_uint16(item), buffer, buffer_size);198case CBOR_INT_32:199return cbor_encode_negint32(cbor_get_uint32(item), buffer, buffer_size);200case CBOR_INT_64:201return cbor_encode_negint64(cbor_get_uint64(item), buffer, buffer_size);202}203}204205size_t cbor_serialize_bytestring(const cbor_item_t *item, unsigned char *buffer,206size_t buffer_size) {207CBOR_ASSERT(cbor_isa_bytestring(item));208if (cbor_bytestring_is_definite(item)) {209size_t length = cbor_bytestring_length(item);210size_t written = cbor_encode_bytestring_start(length, buffer, buffer_size);211if (written > 0 && (buffer_size - written >= length)) {212memcpy(buffer + written, cbor_bytestring_handle(item), length);213return written + length;214}215return 0;216} else {217CBOR_ASSERT(cbor_bytestring_is_indefinite(item));218size_t chunk_count = cbor_bytestring_chunk_count(item);219size_t written = cbor_encode_indef_bytestring_start(buffer, buffer_size);220if (written == 0) return 0;221222cbor_item_t **chunks = cbor_bytestring_chunks_handle(item);223for (size_t i = 0; i < chunk_count; i++) {224size_t chunk_written = cbor_serialize_bytestring(225chunks[i], buffer + written, buffer_size - written);226if (chunk_written == 0) return 0;227written += chunk_written;228}229230size_t break_written =231cbor_encode_break(buffer + written, buffer_size - written);232if (break_written == 0) return 0;233return written + break_written;234}235}236237size_t cbor_serialize_string(const cbor_item_t *item, unsigned char *buffer,238size_t buffer_size) {239CBOR_ASSERT(cbor_isa_string(item));240if (cbor_string_is_definite(item)) {241size_t length = cbor_string_length(item);242size_t written = cbor_encode_string_start(length, buffer, buffer_size);243if (written && (buffer_size - written >= length)) {244memcpy(buffer + written, cbor_string_handle(item), length);245return written + length;246}247return 0;248} else {249CBOR_ASSERT(cbor_string_is_indefinite(item));250size_t chunk_count = cbor_string_chunk_count(item);251size_t written = cbor_encode_indef_string_start(buffer, buffer_size);252if (written == 0) return 0;253254cbor_item_t **chunks = cbor_string_chunks_handle(item);255for (size_t i = 0; i < chunk_count; i++) {256size_t chunk_written = cbor_serialize_string(chunks[i], buffer + written,257buffer_size - written);258if (chunk_written == 0) return 0;259written += chunk_written;260}261262size_t break_written =263cbor_encode_break(buffer + written, buffer_size - written);264if (break_written == 0) return 0;265return written + break_written;266}267}268269size_t cbor_serialize_array(const cbor_item_t *item, unsigned char *buffer,270size_t buffer_size) {271CBOR_ASSERT(cbor_isa_array(item));272size_t size = cbor_array_size(item), written = 0;273cbor_item_t **handle = cbor_array_handle(item);274if (cbor_array_is_definite(item)) {275written = cbor_encode_array_start(size, buffer, buffer_size);276} else {277CBOR_ASSERT(cbor_array_is_indefinite(item));278written = cbor_encode_indef_array_start(buffer, buffer_size);279}280if (written == 0) return 0;281282for (size_t i = 0; i < size; i++) {283size_t item_written =284cbor_serialize(*(handle++), buffer + written, buffer_size - written);285if (item_written == 0) return 0;286written += item_written;287}288289if (cbor_array_is_definite(item)) {290return written;291} else {292CBOR_ASSERT(cbor_array_is_indefinite(item));293size_t break_written =294cbor_encode_break(buffer + written, buffer_size - written);295if (break_written == 0) return 0;296return written + break_written;297}298}299300size_t cbor_serialize_map(const cbor_item_t *item, unsigned char *buffer,301size_t buffer_size) {302CBOR_ASSERT(cbor_isa_map(item));303size_t size = cbor_map_size(item), written = 0;304struct cbor_pair *handle = cbor_map_handle(item);305306if (cbor_map_is_definite(item)) {307written = cbor_encode_map_start(size, buffer, buffer_size);308} else {309CBOR_ASSERT(cbor_map_is_indefinite(item));310written = cbor_encode_indef_map_start(buffer, buffer_size);311}312if (written == 0) return 0;313314for (size_t i = 0; i < size; i++) {315size_t item_written =316cbor_serialize(handle->key, buffer + written, buffer_size - written);317if (item_written == 0) {318return 0;319}320written += item_written;321item_written = cbor_serialize((handle++)->value, buffer + written,322buffer_size - written);323if (item_written == 0) return 0;324written += item_written;325}326327if (cbor_map_is_definite(item)) {328return written;329} else {330CBOR_ASSERT(cbor_map_is_indefinite(item));331size_t break_written =332cbor_encode_break(buffer + written, buffer_size - written);333if (break_written == 0) return 0;334return written + break_written;335}336}337338size_t cbor_serialize_tag(const cbor_item_t *item, unsigned char *buffer,339size_t buffer_size) {340CBOR_ASSERT(cbor_isa_tag(item));341size_t written = cbor_encode_tag(cbor_tag_value(item), buffer, buffer_size);342if (written == 0) return 0;343344size_t item_written = cbor_serialize(cbor_move(cbor_tag_item(item)),345buffer + written, buffer_size - written);346if (item_written == 0) return 0;347return written + item_written;348}349350size_t cbor_serialize_float_ctrl(const cbor_item_t *item, unsigned char *buffer,351size_t buffer_size) {352CBOR_ASSERT(cbor_isa_float_ctrl(item));353// cppcheck-suppress missingReturn354switch (cbor_float_get_width(item)) {355case CBOR_FLOAT_0:356/* CTRL - special treatment */357return cbor_encode_ctrl(cbor_ctrl_value(item), buffer, buffer_size);358case CBOR_FLOAT_16:359return cbor_encode_half(cbor_float_get_float2(item), buffer, buffer_size);360case CBOR_FLOAT_32:361return cbor_encode_single(cbor_float_get_float4(item), buffer,362buffer_size);363case CBOR_FLOAT_64:364return cbor_encode_double(cbor_float_get_float8(item), buffer,365buffer_size);366}367}368369370