blob: 4499d6da8c5d39bd03aad0d096ab103d8b2d713e [file] [log] [blame]
#include <cassert>
#include "cn-cbor/cn-cbor.h"
#include <cose/cose.h>
#include <stdlib.h>
#ifdef __MBED__
#include <string.h>
#else
#include <memory.h>
#endif
#define INIT_CB(v) \
if (errp) { \
errp->err = CN_CBOR_NO_ERROR; \
} \
(v) = static_cast<cn_cbor *>(CN_CALLOC_CONTEXT()); \
if (!(v)) { \
if (errp) { \
errp->err = CN_CBOR_ERR_OUT_OF_MEMORY; \
} \
return false; \
}
#ifdef USE_CBOR_CONTEXT
#define CBOR_CONTEXT_PARAM , context
#define CBOR_CONTEXT_PARAM_COMMA context,
#if 1
#define CN_CALLOC(ctx) \
((ctx) && (ctx)->calloc_func) \
? (ctx)->calloc_func(1, sizeof(cn_cbor), (ctx)->context) \
: calloc(1, sizeof(cn_cbor))
#endif
#define CN_CALLOC_CONTEXT() CN_CALLOC(context)
#define CN_CBOR_CALLOC(c, i, ctx) \
((ctx) && (ctx)->calloc_func) ? (ctx)->calloc_func(c, i, (ctx)->context) \
: calloc(c, i)
#define COSE_FREE(ptr, ctx) \
((((ctx) && (ctx)->free_func)) ? ((ctx)->free_func((ptr), (ctx)->context)) \
: free((ptr)))
#else
#define CBOR_CONTEXT_PARAM
#define CBOR_CONTEXT_PARAM_COMMA
#define CN_CALLOC(ctx) calloc(1, sizeof(cn_cbor))
#define CN_CALLOC_CONTEXT() CN_CALLOC(context)
#define CN_CBOR_CALLOC(c, i, ctx) calloc(c, i)
#define COSE_FREE(ptr, ctx) free(ptr)
#endif
/***
* Replace the i-th element in the array.
* Extend the array if necessary so it has enough elements.
*
* @param[in] cb_array Array to use
* @param[in] cb_value New item to be placed in the array
* @param[in] index Zero based index to be used
* @param[in] CBOR_CONTEXT Context based allocation structure
* @param[in,out] errp CBOR error return on failure
* returns Did we succeed?
*/
bool cn_cbor_array_replace(cn_cbor *cb_array,
cn_cbor *cb_value,
int index,
CBOR_CONTEXT_COMMA cn_cbor_errback *errp)
{
int i;
cn_cbor *cb_temp;
cn_cbor *cb_temp2;
if (!cb_array || !cb_value || cb_array->type != CN_CBOR_ARRAY) {
if (errp != nullptr) {
errp->err = CN_CBOR_ERR_INVALID_PARAMETER;
}
return false;
}
if (index == 0) {
if (cb_array->length > 0) {
cb_temp = cb_array->first_child;
cb_value->parent = cb_array;
cb_value->next = cb_temp->next;
if (cb_array->last_child == cb_temp) {
cb_array->last_child = cb_value;
}
cb_array->first_child = cb_value;
cb_temp->parent = nullptr;
cb_temp->next = nullptr;
cn_cbor_free(cb_temp CBOR_CONTEXT_PARAM);
return true;
}
return cn_cbor_array_append(cb_array, cb_value, errp);
}
if (cb_array->first_child == nullptr) {
INIT_CB(cb_temp2);
cb_array->first_child = cb_array->last_child = cb_temp2;
cb_temp2->parent = cb_array;
cb_array->length = 1;
cb_temp2->type = CN_CBOR_INVALID;
}
cb_temp = cb_array->first_child;
for (i = 1; i < index; i++) {
if (cb_temp->next == nullptr) {
INIT_CB(cb_temp2);
cb_temp2->type = CN_CBOR_INVALID;
cb_temp->next = cb_temp2;
cb_temp2->parent = cb_array;
cb_array->last_child = cb_temp2;
cb_array->length += 1;
}
cb_temp = cb_temp->next;
}
if (cb_temp->next == nullptr) {
cb_temp->next = cb_value;
cb_value->parent = cb_array;
cb_array->last_child = cb_value;
cb_array->length += 1;
return true;
}
cb_temp2 = cb_temp->next;
cb_value->next = cb_temp2->next;
cb_temp->next = cb_value;
cb_value->parent = cb_array;
if (cb_array->last_child == cb_temp2) {
cb_array->last_child = cb_value;
}
cb_temp2->next = nullptr;
cb_temp2->parent = nullptr;
cn_cbor_free(cb_temp2 CBOR_CONTEXT_PARAM);
return true;
}
cn_cbor *cn_cbor_clone(const cn_cbor *pIn,
CBOR_CONTEXT_COMMA cn_cbor_errback *pcn_cbor_error)
{
cn_cbor *pOut = nullptr;
char *sz;
unsigned char *pb;
cn_cbor *pTemp;
cn_cbor *pLast;
int count;
switch (pIn->type) {
case CN_CBOR_TEXT:
sz = (char *)(CN_CBOR_CALLOC(pIn->length + 1, 1, context));
if (sz == nullptr) {
return nullptr;
}
memcpy(sz, pIn->v.str, pIn->length);
sz[pIn->length] = 0;
pOut = cn_cbor_string_create2(
sz, 0 CBOR_CONTEXT_PARAM, pcn_cbor_error);
if (pOut == nullptr) {
COSE_FREE(sz, context);
}
break;
case CN_CBOR_UINT:
pOut = cn_cbor_int_create(
pIn->v.sint CBOR_CONTEXT_PARAM, pcn_cbor_error);
break;
case CN_CBOR_INT:
pOut = cn_cbor_int_create(
pIn->v.uint CBOR_CONTEXT_PARAM, pcn_cbor_error);
break;
case CN_CBOR_TRUE:
pOut = cn_cbor_bool_create(true CBOR_CONTEXT_PARAM, pcn_cbor_error);
break;
case CN_CBOR_FALSE:
pOut =
cn_cbor_bool_create(false CBOR_CONTEXT_PARAM, pcn_cbor_error);
break;
case CN_CBOR_BYTES:
pb = static_cast<unsigned char *>(
CN_CBOR_CALLOC((int)pIn->length, 1, context));
if (pb == nullptr) {
return nullptr;
}
memcpy(pb, pIn->v.bytes, pIn->length);
pOut = cn_cbor_data_create2(
pb, (int)pIn->length, 0 CBOR_CONTEXT_PARAM, pcn_cbor_error);
if (pOut == nullptr) {
COSE_FREE((cn_cbor *)pb, context);
}
break;
case CN_CBOR_MAP:
pOut = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA pcn_cbor_error);
if (pOut == nullptr) {
return nullptr;
}
pTemp = pIn->first_child;
pLast = nullptr;
count = 0;
while (pTemp != nullptr) {
cn_cbor *p = cn_cbor_clone(
pTemp, CBOR_CONTEXT_PARAM_COMMA pcn_cbor_error);
if (p == nullptr) {
cn_cbor_free(pOut CBOR_CONTEXT_PARAM);
return nullptr;
}
if (pLast == nullptr) {
pOut->first_child = p;
pLast = p;
}
else {
pLast->next = p;
pLast = p;
}
p->parent = pOut;
count += 1;
pTemp = pTemp->next;
}
pOut->last_child = pLast;
pOut->length = count;
break;
default:
assert(false);
break;
}
return pOut;
}
#ifndef CN_CBOR_VERSION
cn_cbor *cn_cbor_tag_create(int tag,
cn_cbor *child,
CBOR_CONTEXT_COMMA cn_cbor_errback *perr)
{
cn_cbor *pcnTag = CN_CALLOC(context);
if (pcnTag == nullptr) {
if (perr != nullptr) {
perr->err = CN_CBOR_ERR_OUT_OF_MEMORY;
}
return nullptr;
}
pcnTag->type = CN_CBOR_TAG;
pcnTag->v.sint = tag;
pcnTag->first_child = child;
child->parent = pcnTag;
return pcnTag;
}
cn_cbor *cn_cbor_bool_create(int boolValue,
CBOR_CONTEXT_COMMA cn_cbor_errback *errp)
{
cn_cbor *pcn = CN_CALLOC(context);
if (pcn == nullptr) {
if (errp != nullptr) {
errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;
}
return nullptr;
}
pcn->type = CN_CBOR_FALSE + (boolValue != 0);
return pcn;
}
cn_cbor *cn_cbor_null_create(CBOR_CONTEXT_COMMA cn_cbor_errback *errp)
{
cn_cbor *pcn = CN_CALLOC(context);
if (pcn == nullptr) {
if (errp != nullptr) {
errp->err = CN_CBOR_ERR_OUT_OF_MEMORY;
}
return nullptr;
}
pcn->type = CN_CBOR_NULL;
return pcn;
}
#endif
size_t cn_cbor_encode_size(cn_cbor *object)
{
ssize_t size = cn_cbor_encoder_write(nullptr, 0, 0, object);
return size >= 0 ? size : 0;
}