Contiki-NG
Loading...
Searching...
No Matches
lwm2m-json.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2016, Eistec AB.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the copyright holder nor the names of its
14 * contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
20 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
21 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
28 * OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/**
32 * \addtogroup lwm2m
33 * @{
34 */
35
36/**
37 * \file
38 * Implementation of the Contiki OMA LWM2M JSON writer
39 * \author
40 * Joakim NohlgÄrd <joakim.nohlgard@eistec.se>
41 * Joakim Eriksson <joakime@sics.se> added JSON reader parts
42 */
43
44#include "lwm2m-object.h"
45#include "lwm2m-json.h"
46#include "lwm2m-plain-text.h"
47#include <stdio.h>
48#include <stddef.h>
49#include <stdint.h>
50#include <inttypes.h>
51
52/* Log configuration */
53#include "coap-log.h"
54#define LOG_MODULE "lwm2m-json"
55#define LOG_LEVEL LOG_LEVEL_NONE
56/*---------------------------------------------------------------------------*/
57
58/* {"e":[{"n":"111/1","v":123},{"n":"111/2","v":42}]} */
59
60/* Begin String */
61#define T_NONE 0
62#define T_STRING_B 1
63#define T_STRING 2
64#define T_NAME 4
65#define T_VNUM 5
66#define T_OBJ 6
67#define T_VAL 7
68
69/* Simlified JSON style reader for reading in values from a LWM2M JSON
70 string */
71int
72lwm2m_json_next_token(lwm2m_context_t *ctx, struct json_data *json)
73{
74 int pos = ctx->inbuf->pos;
75 uint8_t type = T_NONE;
76 /* Positions index into the input buffer, which can be larger than 255
77 bytes, so these must be as wide as pos rather than uint8_t. */
78 unsigned int vpos_start = 0;
79 unsigned int vpos_end = 0;
80 uint8_t cont;
81 unsigned int wscount = 0;
82
83 json->name = NULL;
84 json->value = NULL;
85 json->name_len = 0;
86 json->value_len = 0;
87
88 cont = 1;
89 /* We will be either at start, or at a specific position */
90 while(pos < ctx->inbuf->size && cont) {
91 uint8_t c = ctx->inbuf->buffer[pos++];
92 switch(c) {
93 case '{': type = T_OBJ; break;
94 case '}':
95 case ',':
96 if(type == T_VAL || type == T_STRING) {
97 json->value = &ctx->inbuf->buffer[vpos_start];
98 /* Guard against the trailing-whitespace count exceeding the token
99 span, which would otherwise underflow value_len. */
100 json->value_len = (vpos_end > vpos_start + wscount) ?
101 (vpos_end - vpos_start - wscount) : 0;
102 type = T_NONE;
103 cont = 0;
104 }
105 wscount = 0;
106 break;
107 case '\\':
108 /* stuffing */
109 if(pos < ctx->inbuf->size) {
110 pos++;
111 vpos_end = pos;
112 }
113 break;
114 case '"':
115 if(type == T_STRING_B) {
116 type = T_STRING;
117 vpos_end = pos - 1;
118 wscount = 0;
119 } else {
120 type = T_STRING_B;
121 vpos_start = pos;
122 }
123 break;
124 case ':':
125 if(type == T_STRING) {
126 json->name = &ctx->inbuf->buffer[vpos_start];
127 json->name_len = (vpos_end > vpos_start) ? (vpos_end - vpos_start) : 0;
128 vpos_start = vpos_end = pos;
129 type = T_VAL;
130 } else {
131 /* Could be in string or at illegal pos */
132 if(type != T_STRING_B) {
133 LOG_DBG("ERROR - illegal ':'\n");
134 }
135 }
136 break;
137 /* ignore whitespace */
138 case ' ':
139 case '\n':
140 case '\t':
141 if(type != T_STRING_B) {
142 if(vpos_start == pos - 1) {
143 vpos_start = pos;
144 } else {
145 wscount++;
146 }
147 }
148 default:
149 vpos_end = pos;
150 }
151 }
152
153 if(cont == 0 && pos < ctx->inbuf->size) {
154 ctx->inbuf->pos = pos;
155 }
156 /* OK if cont == 0 othewise we failed */
157 return cont == 0 && pos < ctx->inbuf->size;
158}
159/*---------------------------------------------------------------------------*/
160static size_t
161init_write(lwm2m_context_t *ctx)
162{
163 int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
164 ctx->outbuf->size - ctx->outbuf->len, "{\"bn\":\"/%u/%u/\",\"e\":[",
165 ctx->object_id, ctx->object_instance_id);
166 ctx->writer_flags = 0; /* set flags to zero */
167 if((len < 0) || (len >= ctx->outbuf->size)) {
168 return 0;
169 }
170 return len;
171}
172/*---------------------------------------------------------------------------*/
173static size_t
174end_write(lwm2m_context_t *ctx)
175{
176 int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
177 ctx->outbuf->size - ctx->outbuf->len, "]}");
178 if((len < 0) || (len >= ctx->outbuf->size - ctx->outbuf->len)) {
179 return 0;
180 }
181 return len;
182}
183/*---------------------------------------------------------------------------*/
184static size_t
185enter_sub(lwm2m_context_t *ctx)
186{
187 /* set some flags in state */
188 LOG_DBG("Enter sub-resource rsc=%d\n", ctx->resource_id);
189 ctx->writer_flags |= WRITER_RESOURCE_INSTANCE;
190 return 0;
191}
192/*---------------------------------------------------------------------------*/
193static size_t
194exit_sub(lwm2m_context_t *ctx)
195{
196 /* clear out state info */
197 LOG_DBG("Exit sub-resource rsc=%d\n", ctx->resource_id);
198 ctx->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
199 return 0;
200}
201/*---------------------------------------------------------------------------*/
202static size_t
203write_boolean(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
204 int value)
205{
206 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
207 int len;
208 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
209 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"bv\":%s}", sep, ctx->resource_id, ctx->resource_instance_id, value ? "true" : "false");
210 } else {
211 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"bv\":%s}", sep, ctx->resource_id, value ? "true" : "false");
212 }
213 if((len < 0) || (len >= outlen)) {
214 return 0;
215 }
216 LOG_DBG("JSON: Write bool:%s\n", outbuf);
217
218 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
219 return len;
220}
221/*---------------------------------------------------------------------------*/
222static size_t
223write_int(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
224 int32_t value)
225{
226 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
227 int len;
228 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
229 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, ctx->resource_instance_id, value);
230 } else {
231 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, value);
232 }
233 if((len < 0) || (len >= outlen)) {
234 return 0;
235 }
236 LOG_DBG("Write int:%s\n", outbuf);
237
238 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
239 return len;
240}
241/*---------------------------------------------------------------------------*/
242static size_t
243write_float32fix(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
244 int32_t value, int bits)
245{
246 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
247 size_t len = 0;
248 int res;
249 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
250 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":", sep, ctx->resource_id, ctx->resource_instance_id);
251 } else {
252 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":", sep, ctx->resource_id);
253 }
254 if(res <= 0 || res >= outlen) {
255 return 0;
256 }
257 len += res;
258 outlen -= res;
259 res = lwm2m_plain_text_write_float32fix(&outbuf[len], outlen, value, bits);
260 if((res <= 0) || (res >= outlen)) {
261 return 0;
262 }
263 len += res;
264 outlen -= res;
265 res = snprintf((char *)&outbuf[len], outlen, "}");
266 if((res <= 0) || (res >= outlen)) {
267 return 0;
268 }
269 len += res;
270 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
271 return len;
272}
273/*---------------------------------------------------------------------------*/
274static size_t
275write_string(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
276 const char *value, size_t stringlen)
277{
278 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
279 size_t i;
280 size_t len = 0;
281 int res;
282 LOG_DBG("{\"n\":\"%u\",\"sv\":\"", ctx->resource_id);
283 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
284 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"sv\":\"", sep,
285 ctx->resource_id, ctx->resource_instance_id);
286 } else {
287 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"sv\":\"", sep,
288 ctx->resource_id);
289 }
290 if(res < 0 || res >= outlen) {
291 return 0;
292 }
293 len += res;
294 for (i = 0; i < stringlen && len < outlen; ++i) {
295 /* Escape special characters */
296 /* TODO: Handle UTF-8 strings */
297 if(value[i] < '\x20') {
298 LOG_DBG_("\\x%x", value[i]);
299 res = snprintf((char *)&outbuf[len], outlen - len, "\\x%x", value[i]);
300 if((res < 0) || (res >= (outlen - len))) {
301 return 0;
302 }
303 len += res;
304 continue;
305 } else if(value[i] == '"' || value[i] == '\\') {
306 LOG_DBG_("\\");
307 outbuf[len] = '\\';
308 ++len;
309 if(len >= outlen) {
310 return 0;
311 }
312 }
313 LOG_DBG_("%c", value[i]);
314 outbuf[len] = value[i];
315 ++len;
316 if(len >= outlen) {
317 return 0;
318 }
319 }
320 LOG_DBG_("\"}\n");
321 res = snprintf((char *)&outbuf[len], outlen - len, "\"}");
322 if((res < 0) || (res >= (outlen - len))) {
323 return 0;
324 }
325
326 LOG_DBG("JSON: Write string:%s\n", outbuf);
327
328 len += res;
329 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
330 return len;
331}
332/*---------------------------------------------------------------------------*/
333const lwm2m_writer_t lwm2m_json_writer = {
334 init_write,
335 end_write,
336 enter_sub,
337 exit_sub,
338 write_int,
339 write_string,
340 write_float32fix,
341 write_boolean
342};
343/*---------------------------------------------------------------------------*/
344
345/*---------------------------------------------------------------------------*/
346/** @} */
Log support for CoAP.
static int value(int type)
Header file for the Contiki OMA LWM2M JSON writer.
Header file for the LWM2M object API.
Header file for the Contiki OMA LWM2M plain text reader / writer.