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 uint8_t vpos_start = 0;
77 uint8_t vpos_end = 0;
78 uint8_t cont;
79 uint8_t wscount = 0;
80
81 json->name_len = 0;
82 json->value_len = 0;
83
84 cont = 1;
85 /* We will be either at start, or at a specific position */
86 while(pos < ctx->inbuf->size && cont) {
87 uint8_t c = ctx->inbuf->buffer[pos++];
88 switch(c) {
89 case '{': type = T_OBJ; break;
90 case '}':
91 case ',':
92 if(type == T_VAL || type == T_STRING) {
93 json->value = &ctx->inbuf->buffer[vpos_start];
94 json->value_len = vpos_end - vpos_start - wscount;
95 type = T_NONE;
96 cont = 0;
97 }
98 wscount = 0;
99 break;
100 case '\\':
101 /* stuffing */
102 if(pos < ctx->inbuf->size) {
103 pos++;
104 vpos_end = pos;
105 }
106 break;
107 case '"':
108 if(type == T_STRING_B) {
109 type = T_STRING;
110 vpos_end = pos - 1;
111 wscount = 0;
112 } else {
113 type = T_STRING_B;
114 vpos_start = pos;
115 }
116 break;
117 case ':':
118 if(type == T_STRING) {
119 json->name = &ctx->inbuf->buffer[vpos_start];
120 json->name_len = vpos_end - vpos_start;
121 vpos_start = vpos_end = pos;
122 type = T_VAL;
123 } else {
124 /* Could be in string or at illegal pos */
125 if(type != T_STRING_B) {
126 LOG_DBG("ERROR - illegal ':'\n");
127 }
128 }
129 break;
130 /* ignore whitespace */
131 case ' ':
132 case '\n':
133 case '\t':
134 if(type != T_STRING_B) {
135 if(vpos_start == pos - 1) {
136 vpos_start = pos;
137 } else {
138 wscount++;
139 }
140 }
141 default:
142 vpos_end = pos;
143 }
144 }
145
146 if(cont == 0 && pos < ctx->inbuf->size) {
147 ctx->inbuf->pos = pos;
148 }
149 /* OK if cont == 0 othewise we failed */
150 return cont == 0 && pos < ctx->inbuf->size;
151}
152/*---------------------------------------------------------------------------*/
153static size_t
154init_write(lwm2m_context_t *ctx)
155{
156 int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
157 ctx->outbuf->size - ctx->outbuf->len, "{\"bn\":\"/%u/%u/\",\"e\":[",
158 ctx->object_id, ctx->object_instance_id);
159 ctx->writer_flags = 0; /* set flags to zero */
160 if((len < 0) || (len >= ctx->outbuf->size)) {
161 return 0;
162 }
163 return len;
164}
165/*---------------------------------------------------------------------------*/
166static size_t
167end_write(lwm2m_context_t *ctx)
168{
169 int len = snprintf((char *)&ctx->outbuf->buffer[ctx->outbuf->len],
170 ctx->outbuf->size - ctx->outbuf->len, "]}");
171 if((len < 0) || (len >= ctx->outbuf->size - ctx->outbuf->len)) {
172 return 0;
173 }
174 return len;
175}
176/*---------------------------------------------------------------------------*/
177static size_t
178enter_sub(lwm2m_context_t *ctx)
179{
180 /* set some flags in state */
181 LOG_DBG("Enter sub-resource rsc=%d\n", ctx->resource_id);
182 ctx->writer_flags |= WRITER_RESOURCE_INSTANCE;
183 return 0;
184}
185/*---------------------------------------------------------------------------*/
186static size_t
187exit_sub(lwm2m_context_t *ctx)
188{
189 /* clear out state info */
190 LOG_DBG("Exit sub-resource rsc=%d\n", ctx->resource_id);
191 ctx->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
192 return 0;
193}
194/*---------------------------------------------------------------------------*/
195static size_t
196write_boolean(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
197 int value)
198{
199 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
200 int len;
201 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
202 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"bv\":%s}", sep, ctx->resource_id, ctx->resource_instance_id, value ? "true" : "false");
203 } else {
204 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"bv\":%s}", sep, ctx->resource_id, value ? "true" : "false");
205 }
206 if((len < 0) || (len >= outlen)) {
207 return 0;
208 }
209 LOG_DBG("JSON: Write bool:%s\n", outbuf);
210
211 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
212 return len;
213}
214/*---------------------------------------------------------------------------*/
215static size_t
216write_int(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
217 int32_t value)
218{
219 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
220 int len;
221 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
222 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, ctx->resource_instance_id, value);
223 } else {
224 len = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":%"PRId32"}", sep, ctx->resource_id, value);
225 }
226 if((len < 0) || (len >= outlen)) {
227 return 0;
228 }
229 LOG_DBG("Write int:%s\n", outbuf);
230
231 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
232 return len;
233}
234/*---------------------------------------------------------------------------*/
235static size_t
236write_float32fix(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
237 int32_t value, int bits)
238{
239 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
240 size_t len = 0;
241 int res;
242 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
243 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"v\":", sep, ctx->resource_id, ctx->resource_instance_id);
244 } else {
245 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"v\":", sep, ctx->resource_id);
246 }
247 if(res <= 0 || res >= outlen) {
248 return 0;
249 }
250 len += res;
251 outlen -= res;
252 res = lwm2m_plain_text_write_float32fix(&outbuf[len], outlen, value, bits);
253 if((res <= 0) || (res >= outlen)) {
254 return 0;
255 }
256 len += res;
257 outlen -= res;
258 res = snprintf((char *)&outbuf[len], outlen, "}");
259 if((res <= 0) || (res >= outlen)) {
260 return 0;
261 }
262 len += res;
263 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
264 return len;
265}
266/*---------------------------------------------------------------------------*/
267static size_t
268write_string(lwm2m_context_t *ctx, uint8_t *outbuf, size_t outlen,
269 const char *value, size_t stringlen)
270{
271 char *sep = (ctx->writer_flags & WRITER_OUTPUT_VALUE) ? "," : "";
272 size_t i;
273 size_t len = 0;
274 int res;
275 LOG_DBG("{\"n\":\"%u\",\"sv\":\"", ctx->resource_id);
276 if(ctx->writer_flags & WRITER_RESOURCE_INSTANCE) {
277 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u/%u\",\"sv\":\"", sep,
278 ctx->resource_id, ctx->resource_instance_id);
279 } else {
280 res = snprintf((char *)outbuf, outlen, "%s{\"n\":\"%u\",\"sv\":\"", sep,
281 ctx->resource_id);
282 }
283 if(res < 0 || res >= outlen) {
284 return 0;
285 }
286 len += res;
287 for (i = 0; i < stringlen && len < outlen; ++i) {
288 /* Escape special characters */
289 /* TODO: Handle UTF-8 strings */
290 if(value[i] < '\x20') {
291 LOG_DBG_("\\x%x", value[i]);
292 res = snprintf((char *)&outbuf[len], outlen - len, "\\x%x", value[i]);
293 if((res < 0) || (res >= (outlen - len))) {
294 return 0;
295 }
296 len += res;
297 continue;
298 } else if(value[i] == '"' || value[i] == '\\') {
299 LOG_DBG_("\\");
300 outbuf[len] = '\\';
301 ++len;
302 if(len >= outlen) {
303 return 0;
304 }
305 }
306 LOG_DBG_("%c", value[i]);
307 outbuf[len] = value[i];
308 ++len;
309 if(len >= outlen) {
310 return 0;
311 }
312 }
313 LOG_DBG_("\"}\n");
314 res = snprintf((char *)&outbuf[len], outlen - len, "\"}");
315 if((res < 0) || (res >= (outlen - len))) {
316 return 0;
317 }
318
319 LOG_DBG("JSON: Write string:%s\n", outbuf);
320
321 len += res;
322 ctx->writer_flags |= WRITER_OUTPUT_VALUE;
323 return len;
324}
325/*---------------------------------------------------------------------------*/
326const lwm2m_writer_t lwm2m_json_writer = {
327 init_write,
328 end_write,
329 enter_sub,
330 exit_sub,
331 write_int,
332 write_string,
333 write_float32fix,
334 write_boolean
335};
336/*---------------------------------------------------------------------------*/
337
338/*---------------------------------------------------------------------------*/
339/** @} */
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.