1437 lines
40 KiB
C
1437 lines
40 KiB
C
/*******************************************************************************
|
|
*
|
|
* Copyright (c) 2015 Intel Corporation and others.
|
|
* All rights reserved. This program and the accompanying materials
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
* and Eclipse Distribution License v1.0 which accompany this distribution.
|
|
*
|
|
* The Eclipse Public License is available at
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
* The Eclipse Distribution License is available at
|
|
* http://www.eclipse.org/org/documents/edl-v10.php.
|
|
*
|
|
* Contributors:
|
|
* David Navarro, Intel Corporation - initial API and implementation
|
|
*
|
|
*******************************************************************************/
|
|
|
|
|
|
#include "internals.h"
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <inttypes.h>
|
|
|
|
|
|
#ifdef LWM2M_SUPPORT_JSON
|
|
|
|
#define PRV_JSON_BUFFER_SIZE 1024
|
|
|
|
#define JSON_MIN_ARRAY_LEN 21 // e":[{"n":"N","v":X}]}
|
|
#define JSON_MIN_BASE_LEN 7 // n":"N",
|
|
#define JSON_ITEM_MAX_SIZE 36 // with ten characters for value
|
|
#define JSON_MIN_BX_LEN 5 // bt":1
|
|
|
|
#define JSON_FALSE_STRING "false"
|
|
#define JSON_TRUE_STRING "true"
|
|
|
|
#define JSON_RES_ITEM_URI "{\"n\":\""
|
|
#define JSON_RES_ITEM_URI_SIZE 6
|
|
#define JSON_ITEM_BOOL_TRUE "\",\"bv\":true},"
|
|
#define JSON_ITEM_BOOL_TRUE_SIZE 13
|
|
#define JSON_ITEM_BOOL_FALSE "\",\"bv\":false},"
|
|
#define JSON_ITEM_BOOL_FALSE_SIZE 14
|
|
#define JSON_ITEM_NUM "\",\"v\":"
|
|
#define JSON_ITEM_NUM_SIZE 6
|
|
#define JSON_ITEM_NUM_END "},"
|
|
#define JSON_ITEM_NUM_END_SIZE 2
|
|
#define JSON_ITEM_STRING_BEGIN "\",\"sv\":\""
|
|
#define JSON_ITEM_STRING_BEGIN_SIZE 8
|
|
#define JSON_ITEM_STRING_END "\"},"
|
|
#define JSON_ITEM_STRING_END_SIZE 3
|
|
|
|
#define JSON_BN_HEADER_1 "{\"bn\":\""
|
|
#define JSON_BN_HEADER_1_SIZE 7
|
|
#define JSON_BN_HEADER_2 "\",\"e\":["
|
|
#define JSON_BN_HEADER_2_SIZE 7
|
|
#define JSON_HEADER "{\"e\":["
|
|
#define JSON_HEADER_SIZE 6
|
|
#define JSON_FOOTER "]}"
|
|
#define JSON_FOOTER_SIZE 2
|
|
|
|
|
|
#define _GO_TO_NEXT_CHAR(I,B,L) \
|
|
{ \
|
|
I++; \
|
|
I += prv_skipSpace(B+I, L-I); \
|
|
if (I == L) goto error; \
|
|
}
|
|
|
|
typedef enum
|
|
{
|
|
_STEP_START,
|
|
_STEP_TOKEN,
|
|
_STEP_ANY_SEPARATOR,
|
|
_STEP_SEPARATOR,
|
|
_STEP_QUOTED_VALUE,
|
|
_STEP_VALUE,
|
|
_STEP_DONE
|
|
} _itemState;
|
|
|
|
typedef enum
|
|
{
|
|
_TYPE_UNSET,
|
|
_TYPE_FALSE,
|
|
_TYPE_TRUE,
|
|
_TYPE_FLOAT,
|
|
_TYPE_STRING
|
|
} _type;
|
|
|
|
typedef struct
|
|
{
|
|
uint16_t ids[4];
|
|
_type type;
|
|
uint8_t * value;
|
|
size_t valueLen;
|
|
} _record_t;
|
|
|
|
static int prv_isReserved(char sign)
|
|
{
|
|
if (sign == '['
|
|
|| sign == '{'
|
|
|| sign == ']'
|
|
|| sign == '}'
|
|
|| sign == ':'
|
|
|| sign == ','
|
|
|| sign == '"')
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int prv_isWhiteSpace(uint8_t sign)
|
|
{
|
|
if (sign == 0x20
|
|
|| sign == 0x09
|
|
|| sign == 0x0A
|
|
|| sign == 0x0D)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static size_t prv_skipSpace(uint8_t * buffer,
|
|
size_t bufferLen)
|
|
{
|
|
size_t i;
|
|
|
|
i = 0;
|
|
while ((i < bufferLen)
|
|
&& prv_isWhiteSpace(buffer[i]))
|
|
{
|
|
i++;
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
static int prv_split(uint8_t * buffer,
|
|
size_t bufferLen,
|
|
int * tokenStartP,
|
|
int * tokenLenP,
|
|
int * valueStartP,
|
|
int * valueLenP)
|
|
{
|
|
size_t index;
|
|
_itemState step;
|
|
|
|
index = 0;
|
|
step = _STEP_START;
|
|
|
|
index = prv_skipSpace(buffer + index, bufferLen - index);
|
|
if (index == bufferLen) return -1;
|
|
|
|
while ((index < bufferLen)
|
|
&& (buffer[index] != ','))
|
|
{
|
|
switch (step)
|
|
{
|
|
case _STEP_START:
|
|
if (buffer[index] != '"') return -1;
|
|
*tokenStartP = index+1;
|
|
step = _STEP_TOKEN;
|
|
break;
|
|
|
|
case _STEP_TOKEN:
|
|
if (buffer[index] == '"')
|
|
{
|
|
*tokenLenP = index - *tokenStartP;
|
|
step = _STEP_ANY_SEPARATOR;
|
|
}
|
|
break;
|
|
|
|
case _STEP_ANY_SEPARATOR:
|
|
if (buffer[index] != ':') return -1;
|
|
step = _STEP_SEPARATOR;
|
|
break;
|
|
|
|
case _STEP_SEPARATOR:
|
|
if (buffer[index] == '"')
|
|
{
|
|
*valueStartP = index;
|
|
step = _STEP_QUOTED_VALUE;
|
|
} else if (!prv_isReserved(buffer[index]))
|
|
{
|
|
*valueStartP = index;
|
|
step = _STEP_VALUE;
|
|
} else
|
|
{
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case _STEP_QUOTED_VALUE:
|
|
if (buffer[index] == '"' && buffer[index-1] != '\\' )
|
|
{
|
|
*valueLenP = index - *valueStartP + 1;
|
|
step = _STEP_DONE;
|
|
}
|
|
break;
|
|
|
|
case _STEP_VALUE:
|
|
if (prv_isWhiteSpace(buffer[index]))
|
|
{
|
|
*valueLenP = index - *valueStartP;
|
|
step = _STEP_DONE;
|
|
}
|
|
break;
|
|
|
|
case _STEP_DONE:
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
index++;
|
|
if (step == _STEP_START
|
|
|| step == _STEP_ANY_SEPARATOR
|
|
|| step == _STEP_SEPARATOR
|
|
|| step == _STEP_DONE)
|
|
{
|
|
index += prv_skipSpace(buffer + index, bufferLen - index);
|
|
}
|
|
}
|
|
|
|
if (step == _STEP_VALUE)
|
|
{
|
|
*valueLenP = index - *valueStartP;
|
|
step = _STEP_DONE;
|
|
}
|
|
|
|
if (step != _STEP_DONE) return -1;
|
|
|
|
return (int)index;
|
|
}
|
|
|
|
static int prv_countItems(uint8_t * buffer,
|
|
size_t bufferLen)
|
|
{
|
|
int count;
|
|
size_t index;
|
|
int in;
|
|
|
|
count = 0;
|
|
index = 0;
|
|
in = 0;
|
|
|
|
while (index < bufferLen)
|
|
{
|
|
if (in == 0)
|
|
{
|
|
if (buffer[index] != '{') return -1;
|
|
in = 1;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
}
|
|
else
|
|
{
|
|
if (buffer[index] == '{') return -1;
|
|
if (buffer[index] == '}')
|
|
{
|
|
in = 0;
|
|
count++;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
if (buffer[index] == ']')
|
|
{
|
|
break;
|
|
}
|
|
if (buffer[index] != ',') return -1;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
}
|
|
else
|
|
{
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
}
|
|
}
|
|
}
|
|
if (in == 1) return -1;
|
|
|
|
return count;
|
|
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
static int prv_parseItem(uint8_t * buffer,
|
|
size_t bufferLen,
|
|
_record_t * recordP)
|
|
{
|
|
size_t index;
|
|
|
|
memset(recordP->ids, 0xFF, 4*sizeof(uint16_t));
|
|
recordP->type = _TYPE_UNSET;
|
|
recordP->value = NULL;
|
|
recordP->valueLen = 0;
|
|
|
|
index = 0;
|
|
do
|
|
{
|
|
int tokenStart;
|
|
int tokenLen;
|
|
int valueStart;
|
|
int valueLen;
|
|
int next;
|
|
|
|
next = prv_split(buffer+index, bufferLen-index, &tokenStart, &tokenLen, &valueStart, &valueLen);
|
|
if (next < 0) return -1;
|
|
|
|
switch (tokenLen)
|
|
{
|
|
case 1:
|
|
{
|
|
switch (buffer[index+tokenStart])
|
|
{
|
|
case 'n':
|
|
{
|
|
int i;
|
|
int j;
|
|
|
|
if (recordP->ids[0] != LWM2M_MAX_ID) return -1;
|
|
|
|
// Check for " around URI
|
|
if (valueLen < 3
|
|
|| buffer[index+valueStart] != '"'
|
|
|| buffer[index+valueStart+valueLen-1] != '"')
|
|
{
|
|
return -1;
|
|
}
|
|
// Ignore starting /
|
|
if (buffer[index + valueStart + 1] == '/')
|
|
{
|
|
if (valueLen < 4)
|
|
{
|
|
return -1;
|
|
}
|
|
valueStart += 1;
|
|
valueLen -= 1;
|
|
}
|
|
i = 0;
|
|
j = 0;
|
|
do {
|
|
uint32_t readId;
|
|
|
|
readId = 0;
|
|
i++;
|
|
while (i < valueLen-1 && buffer[index+valueStart+i] != '/')
|
|
{
|
|
if (buffer[index+valueStart+i] < '0'
|
|
|| buffer[index+valueStart+i] > '9')
|
|
{
|
|
return -1;
|
|
}
|
|
readId *= 10;
|
|
readId += buffer[index+valueStart+i] - '0';
|
|
if (readId > LWM2M_MAX_ID) return -1;
|
|
i++;
|
|
}
|
|
recordP->ids[j] = readId;
|
|
j++;
|
|
} while (i < valueLen-1 && j < 4 && buffer[index+valueStart+i] == '/');
|
|
if (i < valueLen-1 ) return -1;
|
|
}
|
|
break;
|
|
|
|
case 'v':
|
|
if (recordP->type != _TYPE_UNSET) return -1;
|
|
recordP->type = _TYPE_FLOAT;
|
|
recordP->value = buffer + index + valueStart;
|
|
recordP->valueLen = valueLen;
|
|
break;
|
|
|
|
case 't':
|
|
// TODO: support time
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
{
|
|
// "bv", "ov", or "sv"
|
|
if (buffer[index+tokenStart+1] != 'v') return -1;
|
|
switch (buffer[index+tokenStart])
|
|
{
|
|
case 'b':
|
|
if (recordP->type != _TYPE_UNSET) return -1;
|
|
if (0 == lwm2m_strncmp(JSON_TRUE_STRING, (char *)buffer + index + valueStart, valueLen))
|
|
{
|
|
recordP->type = _TYPE_TRUE;
|
|
}
|
|
else if (0 == lwm2m_strncmp(JSON_FALSE_STRING, (char *)buffer + index + valueStart, valueLen))
|
|
{
|
|
recordP->type = _TYPE_FALSE;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
break;
|
|
|
|
case 'o':
|
|
if (recordP->type != _TYPE_UNSET) return -1;
|
|
// TODO: support object link
|
|
break;
|
|
|
|
case 's':
|
|
if (recordP->type != _TYPE_UNSET) return -1;
|
|
// Check for " around value
|
|
if (valueLen < 2
|
|
|| buffer[index+valueStart] != '"'
|
|
|| buffer[index+valueStart+valueLen-1] != '"')
|
|
{
|
|
return -1;
|
|
}
|
|
recordP->type = _TYPE_STRING;
|
|
recordP->value = buffer + index + valueStart + 1;
|
|
recordP->valueLen = valueLen - 2;
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
index += next + 1;
|
|
} while (index < bufferLen);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static bool prv_convertValue(_record_t * recordP,
|
|
lwm2m_data_t * targetP)
|
|
{
|
|
switch (recordP->type)
|
|
{
|
|
case _TYPE_FALSE:
|
|
lwm2m_data_encode_bool(false, targetP);
|
|
break;
|
|
case _TYPE_TRUE:
|
|
lwm2m_data_encode_bool(true, targetP);
|
|
break;
|
|
case _TYPE_FLOAT:
|
|
{
|
|
size_t i;
|
|
|
|
i = 0;
|
|
while (i < recordP->valueLen
|
|
&& recordP->value[i] != '.')
|
|
{
|
|
i++;
|
|
}
|
|
if (i == recordP->valueLen)
|
|
{
|
|
int64_t value;
|
|
|
|
if ( 1 != utils_textToInt(recordP->value,
|
|
recordP->valueLen,
|
|
&value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lwm2m_data_encode_int(value, targetP);
|
|
}
|
|
else
|
|
{
|
|
double value;
|
|
|
|
if ( 1 != utils_textToFloat(recordP->value,
|
|
recordP->valueLen,
|
|
&value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
lwm2m_data_encode_float(value, targetP);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case _TYPE_STRING:
|
|
lwm2m_data_encode_opaque(recordP->value, recordP->valueLen, targetP);
|
|
targetP->type = LWM2M_TYPE_STRING;
|
|
break;
|
|
|
|
case _TYPE_UNSET:
|
|
default:
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
static lwm2m_data_t * prv_findDataItem(lwm2m_data_t * listP,
|
|
int count,
|
|
uint16_t id)
|
|
{
|
|
int i;
|
|
|
|
i = 0;
|
|
while (i < count)
|
|
{
|
|
if (listP[i].type != LWM2M_TYPE_UNDEFINED && listP[i].id == id)
|
|
{
|
|
return listP + i;
|
|
}
|
|
i++;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static uri_depth_t prv_decreaseLevel(uri_depth_t level)
|
|
{
|
|
switch(level)
|
|
{
|
|
case URI_DEPTH_OBJECT:
|
|
return URI_DEPTH_OBJECT_INSTANCE;
|
|
case URI_DEPTH_OBJECT_INSTANCE:
|
|
return URI_DEPTH_RESOURCE;
|
|
case URI_DEPTH_RESOURCE:
|
|
return URI_DEPTH_RESOURCE_INSTANCE;
|
|
case URI_DEPTH_RESOURCE_INSTANCE:
|
|
return URI_DEPTH_RESOURCE_INSTANCE;
|
|
default:
|
|
return URI_DEPTH_RESOURCE;
|
|
}
|
|
}
|
|
|
|
static lwm2m_data_t * prv_extendData(lwm2m_data_t * parentP)
|
|
{
|
|
lwm2m_data_t * newP;
|
|
|
|
newP = lwm2m_data_new(parentP->value.asChildren.count + 1);
|
|
if (newP == NULL) return NULL;
|
|
if (parentP->value.asChildren.array != NULL)
|
|
{
|
|
memcpy(newP, parentP->value.asChildren.array, parentP->value.asChildren.count * sizeof(lwm2m_data_t));
|
|
lwm2m_free(parentP->value.asChildren.array); // do not use lwm2m_data_free() to keep pointed values
|
|
}
|
|
parentP->value.asChildren.array = newP;
|
|
parentP->value.asChildren.count += 1;
|
|
|
|
return newP + parentP->value.asChildren.count - 1;
|
|
}
|
|
|
|
static int prv_convertRecord(lwm2m_uri_t * uriP,
|
|
_record_t * recordArray,
|
|
int count,
|
|
lwm2m_data_t ** dataP)
|
|
{
|
|
int index;
|
|
int freeIndex;
|
|
lwm2m_data_t * rootP;
|
|
int size;
|
|
uri_depth_t rootLevel;
|
|
|
|
if (uriP == NULL)
|
|
{
|
|
size = count;
|
|
*dataP = lwm2m_data_new(count);
|
|
if (NULL == *dataP) return -1;
|
|
rootLevel = URI_DEPTH_OBJECT;
|
|
rootP = *dataP;
|
|
}
|
|
else
|
|
{
|
|
lwm2m_data_t * parentP;
|
|
size = 1;
|
|
|
|
*dataP = lwm2m_data_new(1);
|
|
if (NULL == *dataP) return -1;
|
|
(*dataP)->type = LWM2M_TYPE_OBJECT;
|
|
(*dataP)->id = uriP->objectId;
|
|
rootLevel = URI_DEPTH_OBJECT_INSTANCE;
|
|
parentP = *dataP;
|
|
if (LWM2M_URI_IS_SET_INSTANCE(uriP))
|
|
{
|
|
parentP->value.asChildren.count = 1;
|
|
parentP->value.asChildren.array = lwm2m_data_new(1);
|
|
if (NULL == parentP->value.asChildren.array) goto error;
|
|
parentP = parentP->value.asChildren.array;
|
|
parentP->type = LWM2M_TYPE_OBJECT_INSTANCE;
|
|
parentP->id = uriP->instanceId;
|
|
rootLevel = URI_DEPTH_RESOURCE;
|
|
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
|
|
{
|
|
parentP->value.asChildren.count = 1;
|
|
parentP->value.asChildren.array = lwm2m_data_new(1);
|
|
if (NULL == parentP->value.asChildren.array) goto error;
|
|
parentP = parentP->value.asChildren.array;
|
|
parentP->type = LWM2M_TYPE_UNDEFINED;
|
|
parentP->id = uriP->resourceId;
|
|
rootLevel = URI_DEPTH_RESOURCE_INSTANCE;
|
|
}
|
|
}
|
|
parentP->value.asChildren.count = count;
|
|
parentP->value.asChildren.array = lwm2m_data_new(count);
|
|
if (NULL == parentP->value.asChildren.array) goto error;
|
|
rootP = parentP->value.asChildren.array;
|
|
}
|
|
|
|
freeIndex = 0;
|
|
for (index = 0 ; index < count ; index++)
|
|
{
|
|
lwm2m_data_t * targetP;
|
|
int resSegmentIndex;
|
|
int i;
|
|
|
|
// check URI depth
|
|
// resSegmentIndex is set to the resource segment position
|
|
switch(rootLevel)
|
|
{
|
|
case URI_DEPTH_OBJECT:
|
|
resSegmentIndex = 2;
|
|
break;
|
|
case URI_DEPTH_OBJECT_INSTANCE:
|
|
resSegmentIndex = 1;
|
|
break;
|
|
case URI_DEPTH_RESOURCE:
|
|
resSegmentIndex = 0;
|
|
break;
|
|
case URI_DEPTH_RESOURCE_INSTANCE:
|
|
resSegmentIndex = -1;
|
|
break;
|
|
default:
|
|
goto error;
|
|
}
|
|
for (i = 0 ; i <= resSegmentIndex ; i++)
|
|
{
|
|
if (recordArray[index].ids[i] == LWM2M_MAX_ID) goto error;
|
|
}
|
|
if (resSegmentIndex < 2)
|
|
{
|
|
if (recordArray[index].ids[resSegmentIndex + 2] != LWM2M_MAX_ID) goto error;
|
|
}
|
|
|
|
targetP = prv_findDataItem(rootP, count, recordArray[index].ids[0]);
|
|
if (targetP == NULL)
|
|
{
|
|
targetP = rootP + freeIndex;
|
|
freeIndex++;
|
|
targetP->id = recordArray[index].ids[0];
|
|
targetP->type = utils_depthToDatatype(rootLevel);
|
|
}
|
|
if (recordArray[index].ids[1] != LWM2M_MAX_ID)
|
|
{
|
|
lwm2m_data_t * parentP;
|
|
uri_depth_t level;
|
|
|
|
parentP = targetP;
|
|
level = prv_decreaseLevel(rootLevel);
|
|
for (i = 1 ; i <= resSegmentIndex ; i++)
|
|
{
|
|
targetP = prv_findDataItem(parentP->value.asChildren.array, parentP->value.asChildren.count, recordArray[index].ids[i]);
|
|
if (targetP == NULL)
|
|
{
|
|
targetP = prv_extendData(parentP);
|
|
if (targetP == NULL) goto error;
|
|
targetP->id = recordArray[index].ids[i];
|
|
targetP->type = utils_depthToDatatype(level);
|
|
}
|
|
level = prv_decreaseLevel(level);
|
|
parentP = targetP;
|
|
}
|
|
if (recordArray[index].ids[resSegmentIndex + 1] != LWM2M_MAX_ID)
|
|
{
|
|
targetP->type = LWM2M_TYPE_MULTIPLE_RESOURCE;
|
|
targetP = prv_extendData(targetP);
|
|
if (targetP == NULL) goto error;
|
|
targetP->id = recordArray[index].ids[resSegmentIndex + 1];
|
|
targetP->type = LWM2M_TYPE_UNDEFINED;
|
|
}
|
|
}
|
|
|
|
if (true != prv_convertValue(recordArray + index, targetP)) goto error;
|
|
}
|
|
|
|
return size;
|
|
|
|
error:
|
|
lwm2m_data_free(size, *dataP);
|
|
*dataP = NULL;
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int prv_dataStrip(int size,
|
|
lwm2m_data_t * dataP,
|
|
lwm2m_data_t ** resultP)
|
|
{
|
|
int i;
|
|
int j;
|
|
int realSize;
|
|
|
|
realSize = 0;
|
|
for (i = 0 ; i < size ; i++)
|
|
{
|
|
if (dataP[i].type != LWM2M_TYPE_UNDEFINED)
|
|
{
|
|
realSize++;
|
|
}
|
|
}
|
|
|
|
*resultP = lwm2m_data_new(realSize);
|
|
if (*resultP == NULL) return -1;
|
|
|
|
j = 0;
|
|
for (i = 0 ; i < size ; i++)
|
|
{
|
|
if (dataP[i].type != LWM2M_TYPE_UNDEFINED)
|
|
{
|
|
memcpy((*resultP) + j, dataP + i, sizeof(lwm2m_data_t));
|
|
|
|
if (dataP[i].type == LWM2M_TYPE_OBJECT
|
|
|| dataP[i].type == LWM2M_TYPE_OBJECT_INSTANCE
|
|
|| dataP[i].type == LWM2M_TYPE_MULTIPLE_RESOURCE)
|
|
{
|
|
int childLen;
|
|
|
|
childLen = prv_dataStrip(dataP[i].value.asChildren.count, dataP[i].value.asChildren.array, &((*resultP)[j].value.asChildren.array));
|
|
if (childLen <= 0)
|
|
{
|
|
// skip this one
|
|
j--;
|
|
}
|
|
else
|
|
{
|
|
(*resultP)[j].value.asChildren.count = childLen;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dataP[i].value.asBuffer.buffer = NULL;
|
|
}
|
|
|
|
j++;
|
|
}
|
|
}
|
|
|
|
return realSize;
|
|
}
|
|
|
|
int json_parse(lwm2m_uri_t * uriP,
|
|
uint8_t * buffer,
|
|
size_t bufferLen,
|
|
lwm2m_data_t ** dataP)
|
|
{
|
|
size_t index;
|
|
int count = 0;
|
|
bool eFound = false;
|
|
bool bnFound = false;
|
|
bool btFound = false;
|
|
int bnStart;
|
|
int bnLen;
|
|
_record_t * recordArray;
|
|
lwm2m_data_t * parsedP;
|
|
|
|
LOG_ARG("bufferLen: %d, buffer: \"%s\"", bufferLen, (char *)buffer);
|
|
LOG_URI(uriP);
|
|
*dataP = NULL;
|
|
recordArray = NULL;
|
|
parsedP = NULL;
|
|
|
|
index = prv_skipSpace(buffer, bufferLen);
|
|
if (index == bufferLen) return -1;
|
|
|
|
if (buffer[index] != '{') return -1;
|
|
do
|
|
{
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
if (buffer[index] != '"') goto error;
|
|
if (index++ >= bufferLen) goto error;
|
|
switch (buffer[index])
|
|
{
|
|
case 'e':
|
|
{
|
|
int recordIndex;
|
|
|
|
if (bufferLen-index < JSON_MIN_ARRAY_LEN) goto error;
|
|
index++;
|
|
if (buffer[index] != '"') goto error;
|
|
if (eFound == true) goto error;
|
|
eFound = true;
|
|
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
if (buffer[index] != ':') goto error;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
if (buffer[index] != '[') goto error;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
count = prv_countItems(buffer + index, bufferLen - index);
|
|
if (count <= 0) goto error;
|
|
recordArray = (_record_t*)lwm2m_malloc(count * sizeof(_record_t));
|
|
if (recordArray == NULL) goto error;
|
|
// at this point we are sure buffer[index] is '{' and all { and } are matching
|
|
recordIndex = 0;
|
|
while (recordIndex < count)
|
|
{
|
|
int itemLen;
|
|
|
|
if (buffer[index] != '{') goto error;
|
|
itemLen = 0;
|
|
while (buffer[index + itemLen] != '}') itemLen++;
|
|
if (0 != prv_parseItem(buffer + index + 1, itemLen - 1, recordArray + recordIndex))
|
|
{
|
|
goto error;
|
|
}
|
|
recordIndex++;
|
|
index += itemLen;
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
switch (buffer[index])
|
|
{
|
|
case ',':
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
break;
|
|
case ']':
|
|
if (recordIndex == count) break;
|
|
// else this is an error
|
|
default:
|
|
goto error;
|
|
}
|
|
}
|
|
if (buffer[index] != ']') goto error;
|
|
}
|
|
break;
|
|
|
|
case 'b':
|
|
if (bufferLen-index < JSON_MIN_BX_LEN) goto error;
|
|
index++;
|
|
switch (buffer[index])
|
|
{
|
|
case 't':
|
|
index++;
|
|
if (buffer[index] != '"') goto error;
|
|
if (btFound == true) goto error;
|
|
btFound = true;
|
|
|
|
// TODO: handle timed values
|
|
// temp: skip this token
|
|
while(index < bufferLen && buffer[index] != ',' && buffer[index] != '}') index++;
|
|
if (index == bufferLen) goto error;
|
|
index--;
|
|
// end temp
|
|
break;
|
|
case 'n':
|
|
{
|
|
int next;
|
|
int tokenStart;
|
|
int tokenLen;
|
|
int itemLen;
|
|
|
|
index++;
|
|
if (buffer[index] != '"') goto error;
|
|
if (bnFound == true) goto error;
|
|
bnFound = true;
|
|
index -= 3;
|
|
itemLen = 0;
|
|
while (buffer[index + itemLen] != '}'
|
|
&& buffer[index + itemLen] != ','
|
|
&& index + itemLen < bufferLen)
|
|
{
|
|
itemLen++;
|
|
}
|
|
if (index + itemLen == bufferLen) goto error;
|
|
next = prv_split(buffer+index, itemLen, &tokenStart, &tokenLen, &bnStart, &bnLen);
|
|
if (next < 0) goto error;
|
|
bnStart += index;
|
|
index += next - 1;
|
|
}
|
|
break;
|
|
default:
|
|
goto error;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
goto error;
|
|
}
|
|
|
|
_GO_TO_NEXT_CHAR(index, buffer, bufferLen);
|
|
} while (buffer[index] == ',');
|
|
|
|
if (buffer[index] != '}') goto error;
|
|
|
|
if (eFound == true)
|
|
{
|
|
lwm2m_uri_t baseURI;
|
|
lwm2m_uri_t * baseUriP;
|
|
lwm2m_data_t * resultP;
|
|
int size;
|
|
|
|
memset(&baseURI, 0, sizeof(lwm2m_uri_t));
|
|
if (bnFound == false)
|
|
{
|
|
baseUriP = uriP;
|
|
}
|
|
else
|
|
{
|
|
int res;
|
|
|
|
// we ignore the request URI and use the bn one.
|
|
|
|
// Check for " around URI
|
|
if (bnLen < 3
|
|
|| buffer[bnStart] != '"'
|
|
|| buffer[bnStart+bnLen-1] != '"')
|
|
{
|
|
goto error;
|
|
}
|
|
bnStart += 1;
|
|
bnLen -= 2;
|
|
|
|
if (bnLen == 1)
|
|
{
|
|
if (buffer[bnStart] != '/') goto error;
|
|
baseUriP = NULL;
|
|
}
|
|
else
|
|
{
|
|
res = lwm2m_stringToUri((char *)buffer + bnStart, bnLen, &baseURI);
|
|
if (res < 0 || res != bnLen) goto error;
|
|
baseUriP = &baseURI;
|
|
}
|
|
}
|
|
|
|
count = prv_convertRecord(baseUriP, recordArray, count, &parsedP);
|
|
lwm2m_free(recordArray);
|
|
recordArray = NULL;
|
|
|
|
if (count > 0 && uriP != NULL)
|
|
{
|
|
if (parsedP->type != LWM2M_TYPE_OBJECT || parsedP->id != uriP->objectId) goto error;
|
|
if (!LWM2M_URI_IS_SET_INSTANCE(uriP))
|
|
{
|
|
size = parsedP->value.asChildren.count;
|
|
resultP = parsedP->value.asChildren.array;
|
|
}
|
|
else
|
|
{
|
|
int i;
|
|
|
|
resultP = NULL;
|
|
// be permissive and allow full object JSON when requesting for a single instance
|
|
for (i = 0 ; i < (int)parsedP->value.asChildren.count && resultP == NULL; i++)
|
|
{
|
|
lwm2m_data_t * targetP;
|
|
|
|
targetP = parsedP->value.asChildren.array + i;
|
|
if (targetP->id == uriP->instanceId)
|
|
{
|
|
resultP = targetP->value.asChildren.array;
|
|
size = targetP->value.asChildren.count;
|
|
}
|
|
}
|
|
if (resultP == NULL) goto error;
|
|
if (LWM2M_URI_IS_SET_RESOURCE(uriP))
|
|
{
|
|
lwm2m_data_t * resP;
|
|
|
|
resP = NULL;
|
|
for (i = 0 ; i < size && resP == NULL; i++)
|
|
{
|
|
lwm2m_data_t * targetP;
|
|
|
|
targetP = resultP + i;
|
|
if (targetP->id == uriP->resourceId)
|
|
{
|
|
if (targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE)
|
|
{
|
|
resP = targetP->value.asChildren.array;
|
|
size = targetP->value.asChildren.count;
|
|
}
|
|
else
|
|
{
|
|
size = prv_dataStrip(1, targetP, &resP);
|
|
if (size <= 0) goto error;
|
|
lwm2m_data_free(count, parsedP);
|
|
parsedP = NULL;
|
|
}
|
|
}
|
|
}
|
|
if (resP == NULL) goto error;
|
|
resultP = resP;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
resultP = parsedP;
|
|
size = count;
|
|
}
|
|
|
|
if (parsedP != NULL)
|
|
{
|
|
lwm2m_data_t * tempP;
|
|
|
|
size = prv_dataStrip(size, resultP, &tempP);
|
|
if (size <= 0) goto error;
|
|
lwm2m_data_free(count, parsedP);
|
|
resultP = tempP;
|
|
}
|
|
count = size;
|
|
*dataP = resultP;
|
|
}
|
|
|
|
LOG_ARG("Parsing successful. count: %d", count);
|
|
return count;
|
|
|
|
error:
|
|
LOG("Parsing failed");
|
|
if (parsedP != NULL)
|
|
{
|
|
lwm2m_data_free(count, parsedP);
|
|
parsedP = NULL;
|
|
}
|
|
if (recordArray != NULL)
|
|
{
|
|
lwm2m_free(recordArray);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static int prv_serializeValue(lwm2m_data_t * tlvP,
|
|
uint8_t * buffer,
|
|
size_t bufferLen)
|
|
{
|
|
int res;
|
|
int head;
|
|
|
|
switch (tlvP->type)
|
|
{
|
|
case LWM2M_TYPE_STRING:
|
|
if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE);
|
|
head = JSON_ITEM_STRING_BEGIN_SIZE;
|
|
|
|
if (bufferLen - head < tlvP->value.asBuffer.length) return -1;
|
|
memcpy(buffer + head, tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length);
|
|
head += tlvP->value.asBuffer.length;
|
|
|
|
if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1;
|
|
memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE);
|
|
head += JSON_ITEM_STRING_END_SIZE;
|
|
|
|
break;
|
|
|
|
case LWM2M_TYPE_INTEGER:
|
|
{
|
|
int64_t value;
|
|
|
|
if (0 == lwm2m_data_decode_int(tlvP, &value)) return -1;
|
|
|
|
if (bufferLen < JSON_ITEM_NUM_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE);
|
|
head = JSON_ITEM_NUM_SIZE;
|
|
|
|
res = utils_intToText(value, buffer + head, bufferLen - head);
|
|
if (res <= 0) return -1;
|
|
head += res;
|
|
|
|
if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1;
|
|
memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE);
|
|
head += JSON_ITEM_NUM_END_SIZE;
|
|
}
|
|
break;
|
|
|
|
case LWM2M_TYPE_FLOAT:
|
|
{
|
|
double value;
|
|
|
|
if (0 == lwm2m_data_decode_float(tlvP, &value)) return -1;
|
|
|
|
if (bufferLen < JSON_ITEM_NUM_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_NUM, JSON_ITEM_NUM_SIZE);
|
|
head = JSON_ITEM_NUM_SIZE;
|
|
|
|
res = utils_floatToText(value, buffer + head, bufferLen - head);
|
|
if (res <= 0) return -1;
|
|
head += res;
|
|
|
|
if (bufferLen - head < JSON_ITEM_NUM_END_SIZE) return -1;
|
|
memcpy(buffer + head, JSON_ITEM_NUM_END, JSON_ITEM_NUM_END_SIZE);
|
|
head += JSON_ITEM_NUM_END_SIZE;
|
|
}
|
|
break;
|
|
|
|
case LWM2M_TYPE_BOOLEAN:
|
|
{
|
|
bool value;
|
|
|
|
if (0 == lwm2m_data_decode_bool(tlvP, &value)) return -1;
|
|
|
|
if (value == true)
|
|
{
|
|
if (bufferLen < JSON_ITEM_BOOL_TRUE_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_BOOL_TRUE, JSON_ITEM_BOOL_TRUE_SIZE);
|
|
head = JSON_ITEM_BOOL_TRUE_SIZE;
|
|
}
|
|
else
|
|
{
|
|
if (bufferLen < JSON_ITEM_BOOL_FALSE_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_BOOL_FALSE, JSON_ITEM_BOOL_FALSE_SIZE);
|
|
head = JSON_ITEM_BOOL_FALSE_SIZE;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LWM2M_TYPE_OPAQUE:
|
|
if (bufferLen < JSON_ITEM_STRING_BEGIN_SIZE) return -1;
|
|
memcpy(buffer, JSON_ITEM_STRING_BEGIN, JSON_ITEM_STRING_BEGIN_SIZE);
|
|
head = JSON_ITEM_STRING_BEGIN_SIZE;
|
|
|
|
res = utils_base64Encode(tlvP->value.asBuffer.buffer, tlvP->value.asBuffer.length, buffer+head, bufferLen - head);
|
|
if (res == 0) return -1;
|
|
head += res;
|
|
|
|
if (bufferLen - head < JSON_ITEM_STRING_END_SIZE) return -1;
|
|
memcpy(buffer + head, JSON_ITEM_STRING_END, JSON_ITEM_STRING_END_SIZE);
|
|
head += JSON_ITEM_STRING_END_SIZE;
|
|
break;
|
|
|
|
case LWM2M_TYPE_OBJECT_LINK:
|
|
// TODO: implement
|
|
return -1;
|
|
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
int prv_serializeData(lwm2m_data_t * tlvP,
|
|
uint8_t * parentUriStr,
|
|
size_t parentUriLen,
|
|
uint8_t * buffer,
|
|
size_t bufferLen)
|
|
{
|
|
int head;
|
|
int res;
|
|
|
|
head = 0;
|
|
|
|
switch (tlvP->type)
|
|
{
|
|
case LWM2M_TYPE_OBJECT:
|
|
case LWM2M_TYPE_OBJECT_INSTANCE:
|
|
case LWM2M_TYPE_MULTIPLE_RESOURCE:
|
|
{
|
|
uint8_t uriStr[URI_MAX_STRING_LEN];
|
|
size_t uriLen;
|
|
size_t index;
|
|
|
|
if (parentUriLen > 0)
|
|
{
|
|
if (URI_MAX_STRING_LEN < parentUriLen) return -1;
|
|
memcpy(uriStr, parentUriStr, parentUriLen);
|
|
uriLen = parentUriLen;
|
|
}
|
|
else
|
|
{
|
|
uriLen = 0;
|
|
}
|
|
res = utils_intToText(tlvP->id, uriStr + uriLen, URI_MAX_STRING_LEN - uriLen);
|
|
if (res <= 0) return -1;
|
|
uriLen += res;
|
|
uriStr[uriLen] = '/';
|
|
uriLen++;
|
|
|
|
head = 0;
|
|
for (index = 0 ; index < tlvP->value.asChildren.count; index++)
|
|
{
|
|
res = prv_serializeData(tlvP->value.asChildren.array + index, uriStr, uriLen, buffer + head, bufferLen - head);
|
|
if (res < 0) return -1;
|
|
head += res;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if (bufferLen < JSON_RES_ITEM_URI_SIZE) return -1;
|
|
memcpy(buffer, JSON_RES_ITEM_URI, JSON_RES_ITEM_URI_SIZE);
|
|
head = JSON_RES_ITEM_URI_SIZE;
|
|
|
|
if (parentUriLen > 0)
|
|
{
|
|
if (bufferLen - head < parentUriLen) return -1;
|
|
memcpy(buffer + head, parentUriStr, parentUriLen);
|
|
head += parentUriLen;
|
|
}
|
|
|
|
res = utils_intToText(tlvP->id, buffer + head, bufferLen - head);
|
|
if (res <= 0) return -1;
|
|
head += res;
|
|
|
|
res = prv_serializeValue(tlvP, buffer + head, bufferLen - head);
|
|
if (res < 0) return -1;
|
|
head += res;
|
|
break;
|
|
}
|
|
|
|
return head;
|
|
}
|
|
|
|
static int prv_findAndCheckData(lwm2m_uri_t * uriP,
|
|
uri_depth_t level,
|
|
size_t size,
|
|
lwm2m_data_t * tlvP,
|
|
lwm2m_data_t ** targetP)
|
|
{
|
|
size_t index;
|
|
int result;
|
|
|
|
if (size == 0) return 0;
|
|
|
|
if (size > 1)
|
|
{
|
|
if (tlvP[0].type == LWM2M_TYPE_OBJECT || tlvP[0].type == LWM2M_TYPE_OBJECT_INSTANCE)
|
|
{
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].type != tlvP[0].type)
|
|
{
|
|
*targetP = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].type == LWM2M_TYPE_OBJECT || tlvP[index].type == LWM2M_TYPE_OBJECT_INSTANCE)
|
|
{
|
|
*targetP = NULL;
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
*targetP = NULL;
|
|
result = -1;
|
|
switch (level)
|
|
{
|
|
case URI_DEPTH_OBJECT:
|
|
if (tlvP[0].type == LWM2M_TYPE_OBJECT)
|
|
{
|
|
*targetP = tlvP;
|
|
result = (int)size;
|
|
}
|
|
break;
|
|
|
|
case URI_DEPTH_OBJECT_INSTANCE:
|
|
switch (tlvP[0].type)
|
|
{
|
|
case LWM2M_TYPE_OBJECT:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->objectId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
case LWM2M_TYPE_OBJECT_INSTANCE:
|
|
*targetP = tlvP;
|
|
result = (int)size;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case URI_DEPTH_RESOURCE:
|
|
switch (tlvP[0].type)
|
|
{
|
|
case LWM2M_TYPE_OBJECT:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->objectId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
case LWM2M_TYPE_OBJECT_INSTANCE:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->instanceId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
*targetP = tlvP;
|
|
result = (int)size;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case URI_DEPTH_RESOURCE_INSTANCE:
|
|
switch (tlvP[0].type)
|
|
{
|
|
case LWM2M_TYPE_OBJECT:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->objectId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
case LWM2M_TYPE_OBJECT_INSTANCE:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->instanceId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
case LWM2M_TYPE_MULTIPLE_RESOURCE:
|
|
for (index = 0; index < size; index++)
|
|
{
|
|
if (tlvP[index].id == uriP->resourceId)
|
|
{
|
|
return prv_findAndCheckData(uriP, level, tlvP[index].value.asChildren.count, tlvP[index].value.asChildren.array, targetP);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
*targetP = tlvP;
|
|
result = (int)size;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int json_serialize(lwm2m_uri_t * uriP,
|
|
int size,
|
|
lwm2m_data_t * tlvP,
|
|
uint8_t ** bufferP)
|
|
{
|
|
int index;
|
|
size_t head;
|
|
uint8_t bufferJSON[PRV_JSON_BUFFER_SIZE];
|
|
uint8_t baseUriStr[URI_MAX_STRING_LEN];
|
|
int baseUriLen;
|
|
uri_depth_t rootLevel;
|
|
int num;
|
|
lwm2m_data_t * targetP;
|
|
|
|
LOG_ARG("size: %d", size);
|
|
LOG_URI(uriP);
|
|
if (size != 0 && tlvP == NULL) return -1;
|
|
|
|
baseUriLen = uri_toString(uriP, baseUriStr, URI_MAX_STRING_LEN, &rootLevel);
|
|
if (baseUriLen < 0) return -1;
|
|
|
|
num = prv_findAndCheckData(uriP, rootLevel, size, tlvP, &targetP);
|
|
if (num < 0) return -1;
|
|
|
|
while (num == 1
|
|
&& (targetP->type == LWM2M_TYPE_OBJECT
|
|
|| targetP->type == LWM2M_TYPE_OBJECT_INSTANCE
|
|
|| targetP->type == LWM2M_TYPE_MULTIPLE_RESOURCE))
|
|
{
|
|
int res;
|
|
|
|
res = utils_intToText(targetP->id, baseUriStr + baseUriLen, URI_MAX_STRING_LEN - baseUriLen);
|
|
if (res <= 0) return 0;
|
|
baseUriLen += res;
|
|
if (baseUriLen >= URI_MAX_STRING_LEN -1) return 0;
|
|
num = targetP->value.asChildren.count;
|
|
targetP = targetP->value.asChildren.array;
|
|
baseUriStr[baseUriLen] = '/';
|
|
baseUriLen++;
|
|
}
|
|
|
|
if (baseUriLen > 0)
|
|
{
|
|
memcpy(bufferJSON, JSON_BN_HEADER_1, JSON_BN_HEADER_1_SIZE);
|
|
head = JSON_BN_HEADER_1_SIZE;
|
|
memcpy(bufferJSON + head, baseUriStr, baseUriLen);
|
|
head += baseUriLen;
|
|
memcpy(bufferJSON + head, JSON_BN_HEADER_2, JSON_BN_HEADER_2_SIZE);
|
|
head += JSON_BN_HEADER_2_SIZE;
|
|
}
|
|
else
|
|
{
|
|
memcpy(bufferJSON, JSON_HEADER, JSON_HEADER_SIZE);
|
|
head = JSON_HEADER_SIZE;
|
|
}
|
|
|
|
for (index = 0 ; index < num && head < PRV_JSON_BUFFER_SIZE ; index++)
|
|
{
|
|
int res;
|
|
|
|
res = prv_serializeData(targetP + index, NULL, 0, bufferJSON + head, PRV_JSON_BUFFER_SIZE - head);
|
|
if (res < 0) return 0;
|
|
head += res;
|
|
}
|
|
|
|
if (head + JSON_FOOTER_SIZE - 1 > PRV_JSON_BUFFER_SIZE) return 0;
|
|
|
|
if (num > 0) head = head - 1;
|
|
|
|
memcpy(bufferJSON + head, JSON_FOOTER, JSON_FOOTER_SIZE);
|
|
head = head + JSON_FOOTER_SIZE;
|
|
|
|
*bufferP = (uint8_t *)lwm2m_malloc(head);
|
|
if (*bufferP == NULL) return 0;
|
|
memcpy(*bufferP, bufferJSON, head);
|
|
|
|
return head;
|
|
}
|
|
|
|
#endif
|
|
|