2017-07-25 20:04:16 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2017 Linaro Limited
|
2019-01-24 23:40:23 +01:00
|
|
|
* Copyright (c) 2018-2019 Foundries.io
|
2017-07-25 20:04:16 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
|
|
*/
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2016, Eistec AB.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
* 3. Neither the name of the copyright holder nor the names of its
|
|
|
|
* contributors may be used to endorse or promote products derived
|
|
|
|
* from this software without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
|
|
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
|
|
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
|
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
|
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
|
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
|
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Original Authors:
|
|
|
|
* Joakim Nohlgård <joakim.nohlgard@eistec.se>
|
|
|
|
* Joakim Eriksson <joakime@sics.se> added JSON reader parts
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Zephyr Contribution by Michael Scott <michael.scott@linaro.org>
|
|
|
|
* - Zephyr code style changes / code cleanup
|
|
|
|
* - Move to Zephyr APIs where possible
|
|
|
|
* - Convert to Zephyr int/uint types
|
|
|
|
* - Remove engine dependency (replace with writer/reader context)
|
|
|
|
* - Add write / read int64 functions
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO:
|
|
|
|
* - Debug formatting errors in Leshan
|
|
|
|
* - Replace magic #'s with defines
|
|
|
|
* - Research using Zephyr JSON lib for json_next_token()
|
|
|
|
*/
|
|
|
|
|
2018-09-19 10:22:19 +02:00
|
|
|
#define LOG_MODULE_NAME net_lwm2m_json
|
|
|
|
#define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
|
|
|
|
|
|
|
|
#include <logging/log.h>
|
|
|
|
LOG_MODULE_REGISTER(LOG_MODULE_NAME);
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <inttypes.h>
|
2017-10-11 22:37:02 +02:00
|
|
|
#include <ctype.h>
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#include "lwm2m_object.h"
|
|
|
|
#include "lwm2m_rw_json.h"
|
|
|
|
#include "lwm2m_rw_plain_text.h"
|
|
|
|
#include "lwm2m_engine.h"
|
2021-07-22 14:38:42 +02:00
|
|
|
#include "lwm2m_util.h"
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
#define T_OBJECT_BEGIN BIT(0)
|
|
|
|
#define T_OBJECT_END BIT(1)
|
|
|
|
#define T_STRING_BEGIN BIT(2)
|
|
|
|
#define T_STRING_END BIT(3)
|
|
|
|
#define T_VALUE BIT(4)
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
#define SEPARATOR(f) ((f & WRITER_OUTPUT_VALUE) ? "," : "")
|
|
|
|
|
|
|
|
/* writer modes */
|
|
|
|
#define MODE_NONE 0
|
|
|
|
#define MODE_INSTANCE 1
|
|
|
|
#define MODE_VALUE 2
|
|
|
|
#define MODE_READY 3
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
#define TOKEN_BUF_LEN 64
|
|
|
|
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data {
|
2019-01-25 23:13:07 +01:00
|
|
|
/* offset position storage */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t mark_pos_ri;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* flags */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t writer_flags;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* path storage */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t path_level;
|
2018-08-29 22:58:01 +02:00
|
|
|
};
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
struct json_in_formatter_data {
|
|
|
|
/* name info */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t name_offset;
|
|
|
|
uint16_t name_len;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* value info */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t value_offset;
|
|
|
|
uint16_t value_len;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* state */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint16_t offset;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* flags */
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t json_flags;
|
2019-01-26 00:56:23 +01:00
|
|
|
};
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
/* some temporary buffer space for format conversions */
|
2019-01-26 00:56:23 +01:00
|
|
|
static char json_buffer[TOKEN_BUF_LEN];
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
static void json_add_char(struct lwm2m_input_context *in,
|
|
|
|
struct json_in_formatter_data *fd)
|
2017-10-20 01:27:32 +02:00
|
|
|
{
|
2019-01-26 00:56:23 +01:00
|
|
|
if ((fd->json_flags & T_VALUE) ||
|
|
|
|
((fd->json_flags & T_STRING_BEGIN) &&
|
|
|
|
!(fd->json_flags & T_STRING_END))) {
|
|
|
|
if (fd->json_flags & T_VALUE) {
|
|
|
|
fd->value_len++;
|
2019-03-27 02:57:45 +01:00
|
|
|
if (fd->value_len == 1U) {
|
2019-01-26 00:56:23 +01:00
|
|
|
fd->value_offset = fd->offset;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
fd->name_len++;
|
2019-03-27 02:57:45 +01:00
|
|
|
if (fd->name_len == 1U) {
|
2019-01-26 00:56:23 +01:00
|
|
|
fd->name_offset = fd->offset;
|
|
|
|
}
|
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-16 22:07:43 +01:00
|
|
|
/* Simplified JSON style reader for reading in values from a LWM2M JSON string */
|
2017-10-20 01:27:32 +02:00
|
|
|
static int json_next_token(struct lwm2m_input_context *in,
|
2019-01-26 00:56:23 +01:00
|
|
|
struct json_in_formatter_data *fd)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-03-04 17:24:04 +01:00
|
|
|
uint8_t cont, c = 0;
|
2017-10-20 01:27:32 +02:00
|
|
|
bool escape = false;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
(void)memset(fd, 0, sizeof(*fd));
|
2018-11-29 20:23:03 +01:00
|
|
|
cont = 1U;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
/* We will be either at start, or at a specific position */
|
2019-01-25 23:13:07 +01:00
|
|
|
while (in->offset < in->in_cpkt->offset && cont) {
|
2019-01-26 00:56:23 +01:00
|
|
|
fd->offset = in->offset;
|
2019-01-25 23:13:07 +01:00
|
|
|
if (buf_read_u8(&c, CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&in->offset) < 0) {
|
2017-10-20 01:27:32 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c == '\\') {
|
|
|
|
escape = true;
|
2019-01-26 00:56:23 +01:00
|
|
|
/* Keep track of the escape codes */
|
|
|
|
json_add_char(in, fd);
|
2017-10-20 01:27:32 +02:00
|
|
|
continue;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
switch (c) {
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
case '[':
|
|
|
|
if (!escape) {
|
|
|
|
fd->json_flags |= T_OBJECT_BEGIN;
|
2019-03-27 02:57:45 +01:00
|
|
|
cont = 0U;
|
2019-01-26 00:56:23 +01:00
|
|
|
} else {
|
|
|
|
json_add_char(in, fd);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ']':
|
|
|
|
if (!escape) {
|
|
|
|
fd->json_flags |= T_OBJECT_END;
|
2019-03-27 02:57:45 +01:00
|
|
|
cont = 0U;
|
2019-01-26 00:56:23 +01:00
|
|
|
} else {
|
|
|
|
json_add_char(in, fd);
|
|
|
|
}
|
|
|
|
break;
|
2017-07-07 20:04:03 +02:00
|
|
|
case '{':
|
2017-10-20 01:27:32 +02:00
|
|
|
if (!escape) {
|
2019-01-26 00:56:23 +01:00
|
|
|
fd->json_flags |= T_OBJECT_BEGIN;
|
2017-10-20 01:27:32 +02:00
|
|
|
} else {
|
2019-01-26 00:56:23 +01:00
|
|
|
json_add_char(in, fd);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
case '}':
|
|
|
|
case ',':
|
|
|
|
if (!escape) {
|
2019-03-27 02:57:45 +01:00
|
|
|
cont = 0U;
|
2017-10-20 01:27:32 +02:00
|
|
|
} else {
|
2019-01-26 00:56:23 +01:00
|
|
|
json_add_char(in, fd);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '"':
|
2019-01-26 00:56:23 +01:00
|
|
|
if (!escape) {
|
|
|
|
if (fd->json_flags & T_STRING_BEGIN) {
|
|
|
|
fd->json_flags &= ~T_STRING_BEGIN;
|
|
|
|
fd->json_flags |= T_STRING_END;
|
|
|
|
} else {
|
|
|
|
fd->json_flags &= ~T_STRING_END;
|
|
|
|
fd->json_flags |= T_STRING_BEGIN;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
} else {
|
2019-01-26 00:56:23 +01:00
|
|
|
json_add_char(in, fd);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ':':
|
2019-01-26 00:56:23 +01:00
|
|
|
if (!escape) {
|
|
|
|
fd->json_flags &= ~T_STRING_END;
|
|
|
|
fd->json_flags |= T_VALUE;
|
2017-07-07 20:04:03 +02:00
|
|
|
} else {
|
2019-01-26 00:56:23 +01:00
|
|
|
json_add_char(in, fd);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* ignore whitespace */
|
|
|
|
case ' ':
|
|
|
|
case '\n':
|
|
|
|
case '\t':
|
2019-01-26 00:56:23 +01:00
|
|
|
if (!(fd->json_flags & T_STRING_BEGIN)) {
|
2017-10-20 01:27:32 +02:00
|
|
|
break;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2020-08-21 22:45:52 +02:00
|
|
|
__fallthrough;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
default:
|
2019-01-26 00:56:23 +01:00
|
|
|
json_add_char(in, fd);
|
2017-07-07 20:04:03 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
if (escape) {
|
|
|
|
escape = false;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2022-03-16 22:07:43 +01:00
|
|
|
/* OK if cont == 0 otherwise we failed */
|
2019-03-27 02:57:45 +01:00
|
|
|
return (cont == 0U);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_begin(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int len = -1, res;
|
2018-08-29 23:20:05 +02:00
|
|
|
|
2019-03-27 02:57:45 +01:00
|
|
|
if (path->level >= 2U) {
|
2018-08-29 23:20:05 +02:00
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"{\"bn\":\"/%u/%u/\",\"e\":[",
|
|
|
|
path->obj_id, path->obj_inst_id);
|
|
|
|
} else {
|
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"{\"bn\":\"/%u/\",\"e\":[",
|
|
|
|
path->obj_id);
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
if (len < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return len;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), json_buffer, len);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
return len;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_end(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res;
|
|
|
|
|
|
|
|
res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), "]}", 2);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
return 2;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_begin_ri(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 22:58:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fd->writer_flags |= WRITER_RESOURCE_INSTANCE;
|
2017-07-07 20:04:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_end_ri(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 22:58:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
fd->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
|
2017-07-07 20:04:03 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_char(struct lwm2m_output_context *out, char c)
|
2019-01-25 23:13:07 +01:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res;
|
|
|
|
|
|
|
|
res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &c, sizeof(c));
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
2019-01-25 23:13:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_json_prefix(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, const char *format)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data *fd;
|
|
|
|
char *sep;
|
2021-12-20 12:08:53 +01:00
|
|
|
int len = 0, res;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2018-08-29 22:58:01 +02:00
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 22:58:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
sep = SEPARATOR(fd->writer_flags);
|
2019-03-27 02:57:45 +01:00
|
|
|
if (fd->path_level >= 2U) {
|
2018-08-29 23:20:05 +02:00
|
|
|
if (fd->writer_flags & WRITER_RESOURCE_INSTANCE) {
|
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"%s{\"n\":\"%u/%u\",%s:",
|
|
|
|
sep, path->res_id, path->res_inst_id,
|
|
|
|
format);
|
|
|
|
} else {
|
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"%s{\"n\":\"%u\",%s:",
|
|
|
|
sep, path->res_id, format);
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
} else {
|
2018-08-29 23:20:05 +02:00
|
|
|
if (fd->writer_flags & WRITER_RESOURCE_INSTANCE) {
|
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"%s{\"n\":\"%u/%u/%u\",%s:",
|
|
|
|
sep, path->obj_inst_id, path->res_id,
|
|
|
|
path->res_inst_id, format);
|
|
|
|
} else {
|
|
|
|
len = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"%s{\"n\":\"%u/%u\",%s:",
|
|
|
|
sep, path->obj_inst_id, path->res_id,
|
|
|
|
format);
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
if (len < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return len;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), json_buffer, len);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_json_postfix(struct lwm2m_output_context *out)
|
2017-10-20 01:27:32 +02:00
|
|
|
{
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data *fd;
|
2021-12-20 12:08:53 +01:00
|
|
|
int res;
|
2018-08-29 22:58:01 +02:00
|
|
|
|
|
|
|
fd = engine_get_out_user_data(out);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2018-08-29 22:58:01 +02:00
|
|
|
}
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_char(out, '}');
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2018-08-29 22:58:01 +02:00
|
|
|
fd->writer_flags |= WRITER_OUTPUT_VALUE;
|
2017-10-20 01:27:32 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s32(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int32_t value)
|
2017-10-20 01:27:32 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_json_prefix(out, path, "\"v\"");
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len = res;
|
|
|
|
|
|
|
|
res = plain_text_put_format(out, "%d", value);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
|
|
|
res = put_json_postfix(out);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
return len;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s16(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int16_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
return put_s32(out, path, (int32_t)value);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
|
|
|
|
int8_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
return put_s32(out, path, (int32_t)value);
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_s64(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, int64_t value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_json_prefix(out, path, "\"v\"");
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len = res;
|
|
|
|
|
|
|
|
res = plain_text_put_format(out, "%lld", value);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
|
|
|
res = put_json_postfix(out);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
|
|
|
return len;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_string(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, char *buf, size_t buflen)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
|
|
|
size_t i;
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
res = put_json_prefix(out, path, "\"sv\"");
|
|
|
|
if (res < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
2021-12-20 12:08:53 +01:00
|
|
|
len = res;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_char(out, '"');
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
len += res;
|
2017-10-20 01:27:32 +02:00
|
|
|
|
|
|
|
for (i = 0; i < buflen; ++i) {
|
2017-07-07 20:04:03 +02:00
|
|
|
/* Escape special characters */
|
|
|
|
/* TODO: Handle UTF-8 strings */
|
2017-10-11 21:48:06 +02:00
|
|
|
if (buf[i] < '\x20') {
|
2017-10-20 01:27:32 +02:00
|
|
|
res = snprintk(json_buffer, sizeof(json_buffer),
|
|
|
|
"\\x%x", buf[i]);
|
|
|
|
if (res < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return res;
|
2017-10-20 01:27:32 +02:00
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2019-01-25 23:13:07 +01:00
|
|
|
if (buf_append(CPKT_BUF_WRITE(out->out_cpkt),
|
|
|
|
json_buffer, res) < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -ENOMEM;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
len += res;
|
|
|
|
continue;
|
2017-10-11 21:48:06 +02:00
|
|
|
} else if (buf[i] == '"' || buf[i] == '\\') {
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_char(out, '\\');
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_char(out, buf[i]);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
res = put_char(out, '"');
|
|
|
|
if (res < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return res;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
2021-12-20 12:08:53 +01:00
|
|
|
len += res;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_json_postfix(out);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
len += res;
|
2021-12-20 12:08:53 +01:00
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_float(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, double *value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
|
|
|
|
|
|
|
res = put_json_prefix(out, path, "\"v\"");
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len = res;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2021-07-23 16:38:23 +02:00
|
|
|
len += plain_text_put_float(out, path, value);
|
2021-12-20 12:08:53 +01:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
len += put_json_postfix(out);
|
2021-12-20 12:08:53 +01:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_bool(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, bool value)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
|
|
|
|
|
|
|
res = put_json_prefix(out, path, "\"bv\"");
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len = res;
|
2017-07-07 20:04:03 +02:00
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
len += plain_text_put_format(out, "%s", value ? "true" : "false");
|
2021-12-20 12:08:53 +01:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
2017-10-20 01:27:32 +02:00
|
|
|
len += put_json_postfix(out);
|
2021-12-20 12:08:53 +01:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
|
|
|
return len;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int put_objlnk(struct lwm2m_output_context *out,
|
|
|
|
struct lwm2m_obj_path *path, struct lwm2m_objlnk *value)
|
2020-05-19 12:37:02 +02:00
|
|
|
{
|
2021-12-20 12:08:53 +01:00
|
|
|
int res, len;
|
2020-05-19 12:37:02 +02:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
res = put_json_prefix(out, path, "\"ov\"");
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len = res;
|
|
|
|
|
|
|
|
res = plain_text_put_format(out, "\"%u:%u\"", value->obj_id,
|
2020-05-19 12:37:02 +02:00
|
|
|
value->obj_inst);
|
2021-12-20 12:08:53 +01:00
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
|
|
|
|
|
|
|
res = put_json_postfix(out);
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
len += res;
|
2020-05-19 12:37:02 +02:00
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int read_int(struct lwm2m_input_context *in, int64_t *value,
|
|
|
|
bool accept_sign)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
|
|
|
struct json_in_formatter_data *fd;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t *buf;
|
2021-12-20 12:08:53 +01:00
|
|
|
int i = 0;
|
2019-01-26 00:56:23 +01:00
|
|
|
bool neg = false;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
/* initialize values to 0 */
|
2021-07-22 14:38:42 +02:00
|
|
|
*value = 0;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
fd = engine_get_in_user_data(in);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd->value_len == 0) {
|
|
|
|
return -ENODATA;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
buf = in->in_cpkt->data + fd->value_offset;
|
|
|
|
while (*(buf + i) && i < fd->value_len) {
|
|
|
|
c = *(buf + i);
|
|
|
|
if (c == '-' && accept_sign && i == 0) {
|
|
|
|
neg = true;
|
|
|
|
} else if (isdigit(c)) {
|
2021-07-22 14:38:42 +02:00
|
|
|
*value = *value * 10 + (c - '0');
|
2019-01-26 00:56:23 +01:00
|
|
|
} else {
|
|
|
|
/* anything else stop reading */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (neg) {
|
2021-07-22 14:38:42 +02:00
|
|
|
*value = -*value;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_s64(struct lwm2m_input_context *in, int64_t *value)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
2021-07-22 14:38:42 +02:00
|
|
|
return read_int(in, value, true);
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_s32(struct lwm2m_input_context *in, int32_t *value)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
2020-05-27 18:26:57 +02:00
|
|
|
int64_t tmp = 0;
|
2021-12-20 12:08:53 +01:00
|
|
|
int len = 0;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
2021-07-22 14:38:42 +02:00
|
|
|
len = read_int(in, &tmp, true);
|
2019-01-26 00:56:23 +01:00
|
|
|
if (len > 0) {
|
2020-05-27 18:26:57 +02:00
|
|
|
*value = (int32_t)tmp;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_string(struct lwm2m_input_context *in, uint8_t *buf,
|
|
|
|
size_t buflen)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
|
|
|
struct json_in_formatter_data *fd;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
fd = engine_get_in_user_data(in);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (fd->value_len > buflen) {
|
2021-12-20 12:08:53 +01:00
|
|
|
LOG_WRN("Buffer too small to accommodate string, truncating");
|
2019-01-26 00:56:23 +01:00
|
|
|
fd->value_len = buflen - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* TODO: Handle escape codes */
|
|
|
|
ret = buf_read(buf, fd->value_len, CPKT_BUF_READ(in->in_cpkt),
|
|
|
|
&fd->value_offset);
|
|
|
|
if (ret < 0) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return ret;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return fd->value_len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_float(struct lwm2m_input_context *in, double *value)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
2021-07-22 14:38:42 +02:00
|
|
|
struct json_in_formatter_data *fd;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
int i = 0, len = 0;
|
2021-07-22 14:38:42 +02:00
|
|
|
bool has_dot = false;
|
|
|
|
uint8_t tmp, buf[24];
|
|
|
|
uint8_t *json_buf;
|
|
|
|
|
|
|
|
fd = engine_get_in_user_data(in);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fd->value_len == 0) {
|
|
|
|
return -ENODATA;
|
2021-07-22 14:38:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
json_buf = in->in_cpkt->data + fd->value_offset;
|
|
|
|
while (*(json_buf + len) && len < fd->value_len) {
|
|
|
|
tmp = *(json_buf + len);
|
|
|
|
|
|
|
|
if ((tmp == '-' && i == 0) || (tmp == '.' && !has_dot) ||
|
|
|
|
isdigit(tmp)) {
|
|
|
|
len++;
|
|
|
|
|
|
|
|
/* Copy only if it fits into provided buffer - we won't
|
|
|
|
* get better precision anyway.
|
|
|
|
*/
|
|
|
|
if (i < sizeof(buf) - 1) {
|
|
|
|
buf[i++] = tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tmp == '.') {
|
|
|
|
has_dot = true;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
buf[i] = '\0';
|
|
|
|
|
2021-07-23 16:38:23 +02:00
|
|
|
if (lwm2m_atof(buf, value) != 0) {
|
2021-07-22 14:38:42 +02:00
|
|
|
LOG_ERR("Failed to parse float value");
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EBADMSG;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_bool(struct lwm2m_input_context *in, bool *value)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
|
|
|
struct json_in_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_in_user_data(in);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(in->in_cpkt->data + fd->value_offset,
|
|
|
|
"true", 4) == 0) {
|
|
|
|
*value = true;
|
|
|
|
} else if (strncmp(in->in_cpkt->data + fd->value_offset,
|
|
|
|
"false", 5) == 0) {
|
|
|
|
*value = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fd->value_len;
|
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_opaque(struct lwm2m_input_context *in, uint8_t *value,
|
|
|
|
size_t buflen, struct lwm2m_opaque_context *opaque,
|
|
|
|
bool *last_block)
|
2019-01-26 00:56:23 +01:00
|
|
|
{
|
|
|
|
/* TODO */
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EOPNOTSUPP;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
2021-12-16 16:26:22 +01:00
|
|
|
static int get_objlnk(struct lwm2m_input_context *in,
|
|
|
|
struct lwm2m_objlnk *value)
|
2020-05-19 12:37:02 +02:00
|
|
|
{
|
|
|
|
int64_t tmp;
|
2021-12-20 12:08:53 +01:00
|
|
|
int len, total_len;
|
2020-05-19 12:37:02 +02:00
|
|
|
uint16_t value_offset;
|
|
|
|
struct json_in_formatter_data *fd;
|
|
|
|
|
|
|
|
fd = engine_get_in_user_data(in);
|
|
|
|
if (!fd) {
|
2021-12-20 12:08:53 +01:00
|
|
|
return -EINVAL;
|
2020-05-19 12:37:02 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the original value offset. */
|
|
|
|
value_offset = fd->value_offset;
|
|
|
|
|
2021-07-22 14:38:42 +02:00
|
|
|
len = read_int(in, &tmp, false);
|
2021-12-20 12:08:53 +01:00
|
|
|
if (len <= 0) {
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_len = len;
|
2020-05-19 12:37:02 +02:00
|
|
|
value->obj_id = (uint16_t)tmp;
|
|
|
|
|
2022-03-16 22:07:43 +01:00
|
|
|
len++; /* +1 for ':' delimiter. */
|
2020-05-19 12:37:02 +02:00
|
|
|
fd->value_offset += len;
|
|
|
|
|
2021-12-20 12:08:53 +01:00
|
|
|
len = read_int(in, &tmp, false);
|
|
|
|
if (len <= 0) {
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
|
|
|
|
|
|
|
total_len += len;
|
2020-05-19 12:37:02 +02:00
|
|
|
value->obj_inst = (uint16_t)tmp;
|
|
|
|
|
|
|
|
/* Restore the original value offset. */
|
|
|
|
fd->value_offset = value_offset;
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2017-07-07 20:04:03 +02:00
|
|
|
const struct lwm2m_writer json_writer = {
|
2018-08-30 17:59:23 +02:00
|
|
|
.put_begin = put_begin,
|
|
|
|
.put_end = put_end,
|
|
|
|
.put_begin_ri = put_begin_ri,
|
|
|
|
.put_end_ri = put_end_ri,
|
|
|
|
.put_s8 = put_s8,
|
|
|
|
.put_s16 = put_s16,
|
|
|
|
.put_s32 = put_s32,
|
|
|
|
.put_s64 = put_s64,
|
|
|
|
.put_string = put_string,
|
2021-07-23 16:38:23 +02:00
|
|
|
.put_float = put_float,
|
2022-01-13 15:24:47 +01:00
|
|
|
.put_time = put_s64,
|
2018-08-30 17:59:23 +02:00
|
|
|
.put_bool = put_bool,
|
2020-05-19 12:37:02 +02:00
|
|
|
.put_objlnk = put_objlnk,
|
2017-07-07 20:04:03 +02:00
|
|
|
};
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
const struct lwm2m_reader json_reader = {
|
|
|
|
.get_s32 = get_s32,
|
|
|
|
.get_s64 = get_s64,
|
|
|
|
.get_string = get_string,
|
2022-01-13 15:24:47 +01:00
|
|
|
.get_time = get_s64,
|
2021-07-23 16:38:23 +02:00
|
|
|
.get_float = get_float,
|
2019-01-26 00:56:23 +01:00
|
|
|
.get_bool = get_bool,
|
|
|
|
.get_opaque = get_opaque,
|
2020-05-19 12:37:02 +02:00
|
|
|
.get_objlnk = get_objlnk,
|
2019-01-26 00:56:23 +01:00
|
|
|
};
|
|
|
|
|
2019-07-29 19:08:00 +02:00
|
|
|
int do_read_op_json(struct lwm2m_message *msg, int content_format)
|
2018-08-29 22:35:50 +02:00
|
|
|
{
|
2018-08-29 22:58:01 +02:00
|
|
|
struct json_out_formatter_data fd;
|
|
|
|
int ret;
|
|
|
|
|
2018-09-12 04:09:03 +02:00
|
|
|
(void)memset(&fd, 0, sizeof(fd));
|
2019-01-24 23:40:23 +01:00
|
|
|
engine_set_out_user_data(&msg->out, &fd);
|
2018-08-29 23:20:05 +02:00
|
|
|
/* save the level for output processing */
|
2019-01-24 23:40:23 +01:00
|
|
|
fd.path_level = msg->path.level;
|
2019-07-29 19:08:00 +02:00
|
|
|
ret = lwm2m_perform_read_op(msg, content_format);
|
2019-01-24 23:40:23 +01:00
|
|
|
engine_clear_out_user_data(&msg->out);
|
2018-08-29 22:58:01 +02:00
|
|
|
|
|
|
|
return ret;
|
2018-08-29 22:35:50 +02:00
|
|
|
}
|
|
|
|
|
2019-07-29 19:08:00 +02:00
|
|
|
int do_write_op_json(struct lwm2m_message *msg)
|
2017-07-07 20:04:03 +02:00
|
|
|
{
|
2019-07-29 19:09:00 +02:00
|
|
|
struct lwm2m_engine_obj_field *obj_field = NULL;
|
2017-07-07 20:04:03 +02:00
|
|
|
struct lwm2m_engine_obj_inst *obj_inst = NULL;
|
2019-07-29 19:09:00 +02:00
|
|
|
struct lwm2m_engine_res *res = NULL;
|
|
|
|
struct lwm2m_engine_res_inst *res_inst = NULL;
|
2019-01-26 00:56:23 +01:00
|
|
|
struct lwm2m_obj_path orig_path;
|
|
|
|
struct json_in_formatter_data fd;
|
2022-02-14 08:49:31 +01:00
|
|
|
int ret = 0;
|
2020-05-27 18:26:57 +02:00
|
|
|
uint8_t value[TOKEN_BUF_LEN];
|
|
|
|
uint8_t base_name[MAX_RESOURCE_LEN];
|
|
|
|
uint8_t full_name[MAX_RESOURCE_LEN];
|
|
|
|
uint8_t created;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
(void)memset(&fd, 0, sizeof(fd));
|
|
|
|
engine_set_in_user_data(&msg->in, &fd);
|
|
|
|
|
|
|
|
/* store a copy of the original path */
|
|
|
|
memcpy(&orig_path, &msg->path, sizeof(msg->path));
|
|
|
|
|
|
|
|
/* PARSE base name "bn" */
|
2021-12-20 12:08:53 +01:00
|
|
|
if (!json_next_token(&msg->in, &fd)) {
|
|
|
|
return -ENODATA;
|
|
|
|
}
|
2021-07-22 16:20:22 +02:00
|
|
|
|
|
|
|
if (fd.value_len >= sizeof(base_name)) {
|
|
|
|
LOG_ERR("Base name too long");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
/* TODO: validate name == "bn" */
|
|
|
|
if (buf_read(base_name, fd.value_len,
|
|
|
|
CPKT_BUF_READ(msg->in.in_cpkt),
|
|
|
|
&fd.value_offset) < 0) {
|
|
|
|
LOG_ERR("Error parsing base name!");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
2021-07-22 16:20:22 +02:00
|
|
|
base_name[fd.value_len] = '\0';
|
|
|
|
|
|
|
|
/* Relative name is optional - preinitialize full name with base name */
|
|
|
|
snprintk(full_name, sizeof(full_name), "%s", base_name);
|
|
|
|
|
|
|
|
/* skip to elements ("e")*/
|
2019-01-26 00:56:23 +01:00
|
|
|
json_next_token(&msg->in, &fd);
|
|
|
|
|
|
|
|
while (json_next_token(&msg->in, &fd)) {
|
|
|
|
|
|
|
|
if (!(fd.json_flags & T_VALUE)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-07-22 16:20:22 +02:00
|
|
|
if (fd.name_len > sizeof(value)) {
|
|
|
|
LOG_ERR("Token value too long");
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
if (buf_read(value, fd.name_len,
|
|
|
|
CPKT_BUF_READ(msg->in.in_cpkt),
|
|
|
|
&fd.name_offset) < 0) {
|
|
|
|
LOG_ERR("Error parsing name!");
|
2021-07-22 16:20:22 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
if (value[0] == 'n') {
|
2021-07-22 16:20:22 +02:00
|
|
|
/* handle resource name */
|
|
|
|
if (fd.value_len >= sizeof(value)) {
|
|
|
|
LOG_ERR("Relative name too long");
|
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* get value for relative path */
|
|
|
|
if (buf_read(value, fd.value_len,
|
|
|
|
CPKT_BUF_READ(msg->in.in_cpkt),
|
|
|
|
&fd.value_offset) < 0) {
|
|
|
|
LOG_ERR("Error parsing relative path!");
|
2021-07-22 16:20:22 +02:00
|
|
|
ret = -EINVAL;
|
|
|
|
break;
|
2019-01-26 00:56:23 +01:00
|
|
|
}
|
|
|
|
|
2021-07-22 16:20:22 +02:00
|
|
|
value[fd.value_len] = '\0';
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
/* combine base_name + name */
|
2020-05-07 12:08:02 +02:00
|
|
|
snprintk(full_name, sizeof(full_name), "%s%s",
|
2019-01-26 00:56:23 +01:00
|
|
|
base_name, value);
|
2021-07-22 16:20:22 +02:00
|
|
|
} else {
|
|
|
|
/* handle resource value */
|
|
|
|
/* reset values */
|
|
|
|
created = 0U;
|
2019-01-26 00:56:23 +01:00
|
|
|
|
|
|
|
/* parse full_name into path */
|
2022-03-10 15:48:23 +01:00
|
|
|
ret = lwm2m_string_to_path(full_name, &msg->path, '/');
|
2019-01-26 00:56:23 +01:00
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst,
|
|
|
|
&created);
|
|
|
|
if (ret < 0) {
|
|
|
|
break;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
|
2022-02-14 08:49:31 +01:00
|
|
|
ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field);
|
|
|
|
if (ret < 0) {
|
|
|
|
return ret;
|
2019-07-29 19:09:00 +02:00
|
|
|
}
|
|
|
|
|
2022-02-14 08:49:31 +01:00
|
|
|
ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst);
|
|
|
|
if (ret < 0) {
|
|
|
|
return -ENOENT;
|
2019-07-29 19:09:00 +02:00
|
|
|
}
|
2021-07-22 16:20:22 +02:00
|
|
|
|
|
|
|
/* Write the resource value */
|
2019-07-29 19:09:00 +02:00
|
|
|
ret = lwm2m_write_handler(obj_inst, res, res_inst,
|
|
|
|
obj_field, msg);
|
|
|
|
if (orig_path.level >= 3U && ret < 0) {
|
2019-01-26 00:56:23 +01:00
|
|
|
/* return errors on a single write */
|
|
|
|
break;
|
|
|
|
}
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-26 00:56:23 +01:00
|
|
|
engine_clear_in_user_data(&msg->in);
|
|
|
|
|
|
|
|
return ret;
|
2017-07-07 20:04:03 +02:00
|
|
|
}
|