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.
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.