1 /*
2  * Copyright (c) 2017 Linaro Limited
3  * Copyright (c) 2018-2019 Foundries.io
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 /*
9  * Copyright (c) 2016, Eistec AB.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the copyright holder nor the names of its
21  *    contributors may be used to endorse or promote products derived
22  *    from this software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS
25  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
33  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
35  * OF THE POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39  * Original Authors:
40  *         Joakim Nohlgård <joakim.nohlgard@eistec.se>
41  *         Joakim Eriksson <joakime@sics.se> added JSON reader parts
42  */
43 
44 /*
45  * Zephyr Contribution by Michael Scott <michael.scott@linaro.org>
46  * - Zephyr code style changes / code cleanup
47  * - Move to Zephyr APIs where possible
48  * - Convert to Zephyr int/uint types
49  * - Remove engine dependency (replace with writer/reader context)
50  * - Add write / read int64 functions
51  */
52 
53 /*
54  * TODO:
55  * - Debug formatting errors in Leshan
56  * - Replace magic #'s with defines
57  */
58 
59 #define LOG_MODULE_NAME net_lwm2m_json
60 #define LOG_LEVEL CONFIG_LWM2M_LOG_LEVEL
61 
62 #include <zephyr/logging/log.h>
63 LOG_MODULE_REGISTER(LOG_MODULE_NAME);
64 
65 #include <stdio.h>
66 #include <stddef.h>
67 #include <stdint.h>
68 #include <inttypes.h>
69 #include <ctype.h>
70 #include <zephyr/data/json.h>
71 
72 #include "lwm2m_object.h"
73 #include "lwm2m_rw_json.h"
74 #include "lwm2m_engine.h"
75 #include "lwm2m_util.h"
76 
77 struct json_string_payload {
78 	const char *name;
79 	const char *val_string;
80 };
81 
82 struct json_boolean_payload {
83 	const char *name;
84 	bool val_bool;
85 };
86 
87 struct json_float_payload {
88 	const char *name;
89 	struct json_obj_token val_float;
90 };
91 
92 struct json_array_object {
93 	union {
94 		struct json_float_payload  float_obj;
95 		struct json_boolean_payload boolean_obj;
96 		struct json_string_payload string_obj;
97 	} obj;
98 };
99 
100 /* Decode payload structure */
101 struct json_context {
102 	const char *base_name;
103 	struct json_obj_token obj_array;
104 };
105 
106 /* Decode description structure for parsing LwM2m JSON main object*/
107 static const struct json_obj_descr json_descr[] = {
108 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_context, "bn",
109 				  base_name, JSON_TOK_STRING),
110 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_context, "e",
111 				  obj_array, JSON_TOK_OBJ_ARRAY),
112 };
113 
114 #define	JSON_BN_TYPE	1
115 #define	JSON_E_TYPE		2
116 
117 /* Decode payload structure */
118 struct json_obj_struct {
119 	const char *name;
120 	char *val_object_link;
121 	const char *val_string;
122 	struct json_obj_token val_float;
123 	bool val_bool;
124 };
125 
126 /* Decode description structure for parsing LwM2m JSON Arrary object*/
127 static const struct json_obj_descr json_obj_descr[] = {
128 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "n",
129 				  name, JSON_TOK_STRING),
130 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "v",
131 				  val_float, JSON_TOK_FLOAT),
132 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "bv",
133 				  val_bool, JSON_TOK_TRUE),
134 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "ov",
135 				  val_object_link, JSON_TOK_STRING),
136 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_obj_struct, "sv",
137 				  val_string, JSON_TOK_STRING),
138 };
139 
140 #define	JSON_N_TYPE	1
141 #define	JSON_V_TYPE	2
142 #define	JSON_BV_TYPE	4
143 #define	JSON_OV_TYPE	8
144 #define	JSON_SV_TYPE	16
145 
146 #define JSON_NAME_MASK (JSON_N_TYPE)
147 #define JSON_VAL_MASK (JSON_V_TYPE + JSON_BV_TYPE + JSON_OV_TYPE + JSON_SV_TYPE)
148 
149 static const struct json_obj_descr json_float_descr[] = {
150 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_float_payload, "n",
151 				  name, JSON_TOK_STRING),
152 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_float_payload, "v",
153 				  val_float, JSON_TOK_FLOAT),
154 };
155 
156 static const struct json_obj_descr json_boolean_descr[] = {
157 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_boolean_payload, "n",
158 				  name, JSON_TOK_STRING),
159 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_boolean_payload, "bv",
160 				  val_bool, JSON_TOK_TRUE),
161 };
162 
163 static const struct json_obj_descr json_obj_lnk_descr[] = {
164 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "n",
165 				  name, JSON_TOK_STRING),
166 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "ov",
167 				  val_string, JSON_TOK_STRING),
168 };
169 
170 static const struct json_obj_descr json_string_descr[] = {
171 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "n",
172 				  name, JSON_TOK_STRING),
173 	JSON_OBJ_DESCR_PRIM_NAMED(struct json_string_payload, "sv",
174 				  val_string, JSON_TOK_STRING),
175 };
176 
177 struct json_out_formatter_data {
178 	uint8_t writer_flags;
179 	char name_string[sizeof("/65535/65535/") + 1];
180 	struct json_array_object json;
181 	struct lwm2m_output_context *out;
182 };
183 
184 struct json_in_formatter_data {
185 	uint8_t json_flags;
186 	int object_bit_field;
187 	struct json_obj_struct array_object;
188 };
189 
190 /* some temporary buffer space for format conversions */
191 static char pt_buffer[42];
192 
init_object_name_parameters(struct json_out_formatter_data * fd,struct lwm2m_obj_path * path)193 static int init_object_name_parameters(struct json_out_formatter_data *fd,
194 				       struct lwm2m_obj_path *path)
195 {
196 	int ret;
197 
198 	/* Init Name string */
199 	if (fd->writer_flags & WRITER_RESOURCE_INSTANCE) {
200 		ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u/%u", path->res_id,
201 			       path->res_inst_id);
202 	} else {
203 		ret = snprintk(fd->name_string, sizeof(fd->name_string), "%u", path->res_id);
204 	}
205 
206 	if (ret < 0) {
207 		return ret;
208 	}
209 
210 	return 0;
211 }
212 
number_to_string(const char * format,...)213 static int number_to_string(const char *format, ...)
214 {
215 	va_list vargs;
216 	int n;
217 
218 	va_start(vargs, format);
219 	n = vsnprintk(pt_buffer, sizeof(pt_buffer), format, vargs);
220 	va_end(vargs);
221 	if (n < 0 || n >= sizeof(pt_buffer)) {
222 		return -EINVAL;
223 	}
224 
225 	return n;
226 }
227 
float_to_string(double * value)228 static int float_to_string(double *value)
229 {
230 	int len;
231 
232 	len = lwm2m_ftoa(value, pt_buffer, sizeof(pt_buffer), 15);
233 	if (len < 0 || len >= sizeof(pt_buffer)) {
234 		LOG_ERR("Failed to encode float value");
235 		return -EINVAL;
236 	}
237 
238 	return len;
239 }
240 
objlnk_to_string(struct lwm2m_objlnk * value)241 static int objlnk_to_string(struct lwm2m_objlnk *value)
242 {
243 	return snprintk(pt_buffer, sizeof(pt_buffer), "%u:%u", value->obj_id, value->obj_inst);
244 }
245 
json_add_separator(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)246 static int json_add_separator(struct lwm2m_output_context *out, struct json_out_formatter_data *fd)
247 {
248 	int len = 0;
249 
250 	if (fd->writer_flags & WRITER_OUTPUT_VALUE) {
251 		/* Add separator */
252 		char separator = ',';
253 
254 		len = buf_append(CPKT_BUF_WRITE(out->out_cpkt), &separator, sizeof(separator));
255 		if (len < 0) {
256 			return -ENOMEM;
257 		}
258 	}
259 
260 	return len;
261 }
262 
json_postprefix(struct json_out_formatter_data * fd)263 static void json_postprefix(struct json_out_formatter_data *fd)
264 {
265 	fd->writer_flags |= WRITER_OUTPUT_VALUE;
266 }
267 
json_float_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,int float_string_length)268 static int json_float_object_write(struct lwm2m_output_context *out,
269 				   struct json_out_formatter_data *fd, int float_string_length)
270 {
271 	int res, len;
272 	ssize_t o_len;
273 	const struct json_obj_descr *descr;
274 	size_t descr_len;
275 	void *obj_payload;
276 
277 	len = json_add_separator(out, fd);
278 	if (len < 0) {
279 		return len;
280 	}
281 
282 	descr = json_float_descr;
283 	descr_len = ARRAY_SIZE(json_float_descr);
284 	obj_payload = &fd->json.obj.float_obj;
285 	fd->json.obj.float_obj.name = fd->name_string;
286 	fd->json.obj.float_obj.val_float.start = pt_buffer;
287 	fd->json.obj.float_obj.val_float.length = float_string_length;
288 
289 	/* Calculate length */
290 	o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
291 	if (o_len < 0) {
292 		return -EINVAL;
293 	}
294 
295 	/* Encode */
296 	res = json_obj_encode_buf(descr, descr_len, obj_payload,
297 				  CPKT_BUF_W_REGION(out->out_cpkt));
298 	if (res < 0) {
299 		return -ENOMEM;
300 	}
301 
302 	len += o_len;
303 	out->out_cpkt->offset += len;
304 	json_postprefix(fd);
305 	return len;
306 }
307 
json_string_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,char * buf)308 static int json_string_object_write(struct lwm2m_output_context *out,
309 				    struct json_out_formatter_data *fd, char *buf)
310 {
311 	int res, len;
312 	ssize_t o_len;
313 	const struct json_obj_descr *descr;
314 	size_t descr_len;
315 	void *obj_payload;
316 
317 	len = json_add_separator(out, fd);
318 	if (len < 0) {
319 		return len;
320 	}
321 
322 	descr = json_string_descr;
323 	descr_len = ARRAY_SIZE(json_string_descr);
324 	obj_payload = &fd->json.obj.string_obj;
325 	fd->json.obj.string_obj.name = fd->name_string;
326 	fd->json.obj.string_obj.val_string = buf;
327 
328 	/* Calculate length */
329 	o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
330 	if (o_len < 0) {
331 		return -EINVAL;
332 	}
333 
334 	/* Encode */
335 	res = json_obj_encode_buf(descr, descr_len, obj_payload,
336 				  CPKT_BUF_W_REGION(out->out_cpkt));
337 	if (res < 0) {
338 		return -ENOMEM;
339 	}
340 
341 	len += o_len;
342 	out->out_cpkt->offset += len;
343 	json_postprefix(fd);
344 	return len;
345 }
346 
json_boolean_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd,bool value)347 static int json_boolean_object_write(struct lwm2m_output_context *out,
348 				     struct json_out_formatter_data *fd, bool value)
349 {
350 	int res, len;
351 	ssize_t o_len;
352 	const struct json_obj_descr *descr;
353 	size_t descr_len;
354 	void *obj_payload;
355 
356 	len = json_add_separator(out, fd);
357 	if (len < 0) {
358 		return len;
359 	}
360 
361 	descr = json_boolean_descr;
362 	descr_len = ARRAY_SIZE(json_boolean_descr);
363 	obj_payload = &fd->json.obj.boolean_obj;
364 	fd->json.obj.boolean_obj.name = fd->name_string;
365 	fd->json.obj.boolean_obj.val_bool = value;
366 
367 	/* Calculate length */
368 	o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
369 	if (o_len < 0) {
370 		return -EINVAL;
371 	}
372 
373 	/* Encode */
374 	res = json_obj_encode_buf(descr, descr_len, obj_payload,
375 				  CPKT_BUF_W_REGION(out->out_cpkt));
376 	if (res < 0) {
377 		return -ENOMEM;
378 	}
379 
380 	len += o_len;
381 	out->out_cpkt->offset += len;
382 	json_postprefix(fd);
383 	return len;
384 }
385 
json_objlnk_object_write(struct lwm2m_output_context * out,struct json_out_formatter_data * fd)386 static int json_objlnk_object_write(struct lwm2m_output_context *out,
387 				    struct json_out_formatter_data *fd)
388 {
389 	int res, len;
390 	ssize_t o_len;
391 	const struct json_obj_descr *descr;
392 	size_t descr_len;
393 	void *obj_payload;
394 
395 	len = json_add_separator(out, fd);
396 	if (len < 0) {
397 		return len;
398 	}
399 
400 	descr = json_obj_lnk_descr;
401 	descr_len = ARRAY_SIZE(json_obj_lnk_descr);
402 	obj_payload = &fd->json.obj.string_obj;
403 	fd->json.obj.string_obj.name = fd->name_string;
404 	fd->json.obj.string_obj.val_string = pt_buffer;
405 
406 	/* Calculate length */
407 	o_len = json_calc_encoded_len(descr, descr_len, obj_payload);
408 	if (o_len < 0) {
409 		return -EINVAL;
410 	}
411 
412 	/* Encode */
413 	res = json_obj_encode_buf(descr, descr_len, obj_payload,
414 				  CPKT_BUF_W_REGION(out->out_cpkt));
415 	if (res < 0) {
416 		return -ENOMEM;
417 	}
418 
419 	len += o_len;
420 	out->out_cpkt->offset += len;
421 	json_postprefix(fd);
422 	return len;
423 }
424 
put_begin(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)425 static int put_begin(struct lwm2m_output_context *out,
426 		     struct lwm2m_obj_path *path)
427 {
428 	int len = -1, res;
429 
430 	if (path->level >= 2U) {
431 		len = snprintk(pt_buffer, sizeof(pt_buffer),
432 			       "{\"bn\":\"/%u/%u/\",\"e\":[",
433 			       path->obj_id, path->obj_inst_id);
434 	} else {
435 		len = snprintk(pt_buffer, sizeof(pt_buffer),
436 			       "{\"bn\":\"/%u/\",\"e\":[",
437 			       path->obj_id);
438 	}
439 
440 	if (len < 0) {
441 		return len;
442 	}
443 
444 	res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), pt_buffer, len);
445 	if (res < 0) {
446 		return res;
447 	}
448 
449 	return len;
450 }
451 
put_end(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)452 static int put_end(struct lwm2m_output_context *out,
453 		   struct lwm2m_obj_path *path)
454 {
455 	int res;
456 
457 	res = buf_append(CPKT_BUF_WRITE(out->out_cpkt), "]}", 2);
458 	if (res < 0) {
459 		return res;
460 	}
461 
462 	return 2;
463 }
464 
put_begin_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)465 static int put_begin_ri(struct lwm2m_output_context *out,
466 			struct lwm2m_obj_path *path)
467 {
468 	struct json_out_formatter_data *fd;
469 
470 	fd = engine_get_out_user_data(out);
471 	if (!fd) {
472 		return -EINVAL;
473 	}
474 
475 	fd->writer_flags |= WRITER_RESOURCE_INSTANCE;
476 	return 0;
477 }
478 
put_end_ri(struct lwm2m_output_context * out,struct lwm2m_obj_path * path)479 static int put_end_ri(struct lwm2m_output_context *out,
480 		      struct lwm2m_obj_path *path)
481 {
482 	struct json_out_formatter_data *fd;
483 
484 	fd = engine_get_out_user_data(out);
485 	if (!fd) {
486 		return -EINVAL;
487 	}
488 
489 	fd->writer_flags &= ~WRITER_RESOURCE_INSTANCE;
490 	return 0;
491 }
492 
put_s32(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int32_t value)493 static int put_s32(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, int32_t value)
494 {
495 	struct json_out_formatter_data *fd;
496 	int len = 0;
497 
498 	fd = engine_get_out_user_data(out);
499 
500 	if (!out->out_cpkt || !fd) {
501 		return -EINVAL;
502 	}
503 
504 	if (init_object_name_parameters(fd, path)) {
505 		return -EINVAL;
506 	}
507 
508 	len = number_to_string("%d", value);
509 	if (len < 0) {
510 		return len;
511 	}
512 
513 	return json_float_object_write(out, fd, len);
514 }
515 
put_s16(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int16_t value)516 static int put_s16(struct lwm2m_output_context *out,
517 		   struct lwm2m_obj_path *path, int16_t value)
518 {
519 	return put_s32(out, path, (int32_t)value);
520 }
521 
put_s8(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int8_t value)522 static int put_s8(struct lwm2m_output_context *out, struct lwm2m_obj_path *path,
523 		  int8_t value)
524 {
525 	return put_s32(out, path, (int32_t)value);
526 }
527 
put_s64(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,int64_t value)528 static int put_s64(struct lwm2m_output_context *out,
529 		   struct lwm2m_obj_path *path, int64_t value)
530 {
531 	struct json_out_formatter_data *fd;
532 	int len;
533 
534 	fd = engine_get_out_user_data(out);
535 
536 	if (!out->out_cpkt || !fd) {
537 		return -EINVAL;
538 	}
539 
540 	if (init_object_name_parameters(fd, path)) {
541 		return -EINVAL;
542 	}
543 
544 	len = number_to_string("%lld", value);
545 	if (len < 0) {
546 		return len;
547 	}
548 
549 	return json_float_object_write(out, fd, len);
550 }
551 
put_time(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,time_t value)552 static int put_time(struct lwm2m_output_context *out, struct lwm2m_obj_path *path, time_t value)
553 {
554 	return put_s64(out, path, (int64_t) value);
555 }
556 
put_string(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,char * buf,size_t buflen)557 static int put_string(struct lwm2m_output_context *out,
558 		      struct lwm2m_obj_path *path, char *buf, size_t buflen)
559 {
560 	struct json_out_formatter_data *fd;
561 
562 	fd = engine_get_out_user_data(out);
563 
564 	if (!out->out_cpkt || !fd) {
565 		return -EINVAL;
566 	}
567 
568 	if (init_object_name_parameters(fd, path)) {
569 		return -EINVAL;
570 	}
571 
572 	return json_string_object_write(out, fd, buf);
573 }
574 
put_float(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,double * value)575 static int put_float(struct lwm2m_output_context *out,
576 		     struct lwm2m_obj_path *path, double *value)
577 {
578 	struct json_out_formatter_data *fd;
579 	int len;
580 
581 	fd = engine_get_out_user_data(out);
582 
583 	if (!out->out_cpkt || !fd) {
584 		return -EINVAL;
585 	}
586 
587 	if (init_object_name_parameters(fd, path)) {
588 		return -EINVAL;
589 	}
590 
591 	len = float_to_string(value);
592 	if (len < 0) {
593 		return len;
594 	}
595 
596 	return json_float_object_write(out, fd, len);
597 }
598 
put_bool(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,bool value)599 static int put_bool(struct lwm2m_output_context *out,
600 		    struct lwm2m_obj_path *path, bool value)
601 {
602 	struct json_out_formatter_data *fd;
603 
604 	fd = engine_get_out_user_data(out);
605 
606 	if (!out->out_cpkt || !fd) {
607 		return -EINVAL;
608 	}
609 
610 	if (init_object_name_parameters(fd, path)) {
611 		return -EINVAL;
612 	}
613 
614 	return json_boolean_object_write(out, fd, value);
615 }
616 
put_objlnk(struct lwm2m_output_context * out,struct lwm2m_obj_path * path,struct lwm2m_objlnk * value)617 static int put_objlnk(struct lwm2m_output_context *out,
618 		      struct lwm2m_obj_path *path, struct lwm2m_objlnk *value)
619 {
620 	struct json_out_formatter_data *fd;
621 
622 	fd = engine_get_out_user_data(out);
623 
624 	if (!out->out_cpkt || !fd) {
625 		return -EINVAL;
626 	}
627 
628 	if (init_object_name_parameters(fd, path)) {
629 		return -EINVAL;
630 	}
631 
632 	if (objlnk_to_string(value) < 0) {
633 		return -EINVAL;
634 	}
635 
636 	return json_objlnk_object_write(out, fd);
637 }
638 
read_int(struct lwm2m_input_context * in,int64_t * value,bool accept_sign)639 static int read_int(struct lwm2m_input_context *in, int64_t *value,
640 		    bool accept_sign)
641 {
642 	struct json_in_formatter_data *fd;
643 	uint8_t *buf;
644 	int i = 0;
645 	bool neg = false;
646 	char c;
647 
648 	/* initialize values to 0 */
649 	*value = 0;
650 
651 	fd = engine_get_in_user_data(in);
652 	if (!fd || (fd->object_bit_field & JSON_V_TYPE) == 0) {
653 		return -EINVAL;
654 	}
655 
656 	if (fd->array_object.val_float.length == 0) {
657 		return -ENODATA;
658 	}
659 
660 	buf = fd->array_object.val_float.start;
661 	while (*(buf + i) && i < fd->array_object.val_float.length) {
662 		c = *(buf + i);
663 		if (c == '-' && accept_sign && i == 0) {
664 			neg = true;
665 		} else if (isdigit(c) != 0) {
666 			*value = *value * 10 + (c - '0');
667 		} else {
668 			/* anything else stop reading */
669 			break;
670 		}
671 		i++;
672 	}
673 
674 	if (neg) {
675 		*value = -*value;
676 	}
677 
678 	return i;
679 }
680 
get_s64(struct lwm2m_input_context * in,int64_t * value)681 static int get_s64(struct lwm2m_input_context *in, int64_t *value)
682 {
683 	return read_int(in, value, true);
684 }
685 
get_time(struct lwm2m_input_context * in,time_t * value)686 static int get_time(struct lwm2m_input_context *in, time_t *value)
687 {
688 	int64_t temp64;
689 	int ret;
690 
691 	ret = read_int(in, &temp64, true);
692 	*value = (time_t)temp64;
693 
694 	return ret;
695 }
696 
get_s32(struct lwm2m_input_context * in,int32_t * value)697 static int get_s32(struct lwm2m_input_context *in, int32_t *value)
698 {
699 	int64_t tmp = 0;
700 	int len = 0;
701 
702 	len = read_int(in, &tmp, true);
703 	if (len > 0) {
704 		*value = (int32_t)tmp;
705 	}
706 
707 	return len;
708 }
709 
get_string(struct lwm2m_input_context * in,uint8_t * buf,size_t buflen)710 static int get_string(struct lwm2m_input_context *in, uint8_t *buf,
711 		      size_t buflen)
712 {
713 	struct json_in_formatter_data *fd;
714 	size_t string_length;
715 
716 	fd = engine_get_in_user_data(in);
717 	if (!fd || (fd->object_bit_field & JSON_SV_TYPE) == 0) {
718 		return -EINVAL;
719 	}
720 
721 	string_length = strlen(fd->array_object.val_string);
722 
723 	if (string_length > buflen) {
724 		LOG_WRN("Buffer too small to accommodate string, truncating");
725 		string_length = buflen - 1;
726 	}
727 	memcpy(buf, fd->array_object.val_string, string_length);
728 
729 	/* add NULL */
730 	buf[string_length] = '\0';
731 
732 	return string_length;
733 }
734 
get_float(struct lwm2m_input_context * in,double * value)735 static int get_float(struct lwm2m_input_context *in, double *value)
736 {
737 	struct json_in_formatter_data *fd;
738 
739 	int i = 0, len = 0;
740 	bool has_dot = false;
741 	uint8_t tmp, buf[24];
742 	uint8_t *json_buf;
743 
744 	fd = engine_get_in_user_data(in);
745 	if (!fd || (fd->object_bit_field & JSON_V_TYPE) == 0) {
746 		return -EINVAL;
747 	}
748 
749 	size_t value_length = fd->array_object.val_float.length;
750 
751 	if (value_length == 0) {
752 		return -ENODATA;
753 	}
754 
755 	json_buf = fd->array_object.val_float.start;
756 	while (*(json_buf + len) && len < value_length) {
757 		tmp = *(json_buf + len);
758 
759 		if ((tmp == '-' && i == 0) || (tmp == '.' && !has_dot) ||
760 		    isdigit(tmp) != 0) {
761 			len++;
762 
763 			/* Copy only if it fits into provided buffer - we won't
764 			 * get better precision anyway.
765 			 */
766 			if (i < sizeof(buf) - 1) {
767 				buf[i++] = tmp;
768 			}
769 
770 			if (tmp == '.') {
771 				has_dot = true;
772 			}
773 		} else {
774 			break;
775 		}
776 	}
777 
778 	buf[i] = '\0';
779 
780 	if (lwm2m_atof(buf, value) != 0) {
781 		LOG_ERR("Failed to parse float value");
782 		return -EBADMSG;
783 	}
784 
785 	return len;
786 }
787 
get_bool(struct lwm2m_input_context * in,bool * value)788 static int get_bool(struct lwm2m_input_context *in, bool *value)
789 {
790 	struct json_in_formatter_data *fd;
791 
792 	fd = engine_get_in_user_data(in);
793 	if (!fd || (fd->object_bit_field & JSON_BV_TYPE) == 0) {
794 		return -EINVAL;
795 	}
796 
797 	*value = fd->array_object.val_bool;
798 
799 	return 1;
800 }
801 
get_opaque(struct lwm2m_input_context * in,uint8_t * value,size_t buflen,struct lwm2m_opaque_context * opaque,bool * last_block)802 static int get_opaque(struct lwm2m_input_context *in, uint8_t *value,
803 		      size_t buflen, struct lwm2m_opaque_context *opaque,
804 		      bool *last_block)
805 {
806 	/* TODO */
807 	return -EOPNOTSUPP;
808 }
809 
get_objlnk(struct lwm2m_input_context * in,struct lwm2m_objlnk * value)810 static int get_objlnk(struct lwm2m_input_context *in,
811 		      struct lwm2m_objlnk *value)
812 {
813 	int64_t tmp;
814 	int len, total_len;
815 	struct json_in_formatter_data *fd;
816 	char *demiliter_pos;
817 
818 	fd = engine_get_in_user_data(in);
819 	if (!fd || (fd->object_bit_field & JSON_OV_TYPE) == 0) {
820 		return -EINVAL;
821 	}
822 
823 	demiliter_pos = strchr(fd->array_object.val_object_link, ':');
824 	if (!demiliter_pos) {
825 		return -ENODATA;
826 	}
827 
828 	fd->object_bit_field |= JSON_V_TYPE;
829 	fd->array_object.val_float.start = fd->array_object.val_object_link;
830 	fd->array_object.val_float.length = strlen(fd->array_object.val_object_link);
831 
832 	/* Set String end for first item  */
833 	*demiliter_pos = '\0';
834 
835 	len = read_int(in, &tmp, false);
836 	if (len <= 0) {
837 		return -ENODATA;
838 	}
839 
840 	total_len = len;
841 	value->obj_id = (uint16_t)tmp;
842 
843 	len++;  /* +1 for ':' delimiter. */
844 	demiliter_pos++;
845 	fd->array_object.val_float.start = demiliter_pos;
846 	fd->array_object.val_float.length = strlen(demiliter_pos);
847 
848 	len = read_int(in, &tmp, false);
849 	if (len <= 0) {
850 		return -ENODATA;
851 	}
852 
853 	total_len += len;
854 	value->obj_inst = (uint16_t)tmp;
855 
856 	return total_len;
857 }
858 
859 const struct lwm2m_writer json_writer = {
860 	.put_begin = put_begin,
861 	.put_end = put_end,
862 	.put_begin_ri = put_begin_ri,
863 	.put_end_ri = put_end_ri,
864 	.put_s8 = put_s8,
865 	.put_s16 = put_s16,
866 	.put_s32 = put_s32,
867 	.put_s64 = put_s64,
868 	.put_string = put_string,
869 	.put_float = put_float,
870 	.put_time = put_time,
871 	.put_bool = put_bool,
872 	.put_objlnk = put_objlnk,
873 };
874 
875 const struct lwm2m_reader json_reader = {
876 	.get_s32 = get_s32,
877 	.get_s64 = get_s64,
878 	.get_string = get_string,
879 	.get_time = get_time,
880 	.get_float = get_float,
881 	.get_bool = get_bool,
882 	.get_opaque = get_opaque,
883 	.get_objlnk = get_objlnk,
884 };
885 
do_read_op_json(struct lwm2m_message * msg,int content_format)886 int do_read_op_json(struct lwm2m_message *msg, int content_format)
887 {
888 	struct json_out_formatter_data fd;
889 	int ret;
890 
891 	(void)memset(&fd, 0, sizeof(fd));
892 	engine_set_out_user_data(&msg->out, &fd);
893 	ret = lwm2m_perform_read_op(msg, content_format);
894 	engine_clear_out_user_data(&msg->out);
895 
896 	return ret;
897 }
898 
do_write_op_json(struct lwm2m_message * msg)899 int do_write_op_json(struct lwm2m_message *msg)
900 {
901 	struct lwm2m_engine_obj_field *obj_field = NULL;
902 	struct lwm2m_engine_obj_inst *obj_inst = NULL;
903 	struct lwm2m_engine_res *res = NULL;
904 	struct lwm2m_engine_res_inst *res_inst = NULL;
905 	struct lwm2m_obj_path orig_path;
906 	struct json_in_formatter_data fd;
907 	struct json_obj json_object;
908 	struct json_context main_object;
909 
910 	char *data_ptr;
911 	const char *base_name_ptr = NULL;
912 	uint16_t in_len;
913 	int ret = 0, obj_bit_field;
914 
915 	uint8_t full_name[MAX_RESOURCE_LEN + 1] = {0};
916 	uint8_t created;
917 
918 	(void)memset(&fd, 0, sizeof(fd));
919 	(void)memset(&main_object, 0, sizeof(main_object));
920 	engine_set_in_user_data(&msg->in, &fd);
921 
922 	data_ptr = (char *)coap_packet_get_payload(msg->in.in_cpkt, &in_len);
923 
924 	obj_bit_field =
925 		json_obj_parse(data_ptr, in_len, json_descr, ARRAY_SIZE(json_descr), &main_object);
926 
927 	if (obj_bit_field < 0 || (obj_bit_field & 2) == 0 || main_object.obj_array.length == 0) {
928 		LOG_ERR("JSON object bits not valid %d", obj_bit_field);
929 		ret = -EINVAL;
930 		goto end_of_operation;
931 	}
932 
933 	if (obj_bit_field & 1) {
934 		base_name_ptr = main_object.base_name;
935 	}
936 
937 	/* store a copy of the original path */
938 	memcpy(&orig_path, &msg->path, sizeof(msg->path));
939 
940 	/* When No blockwise do Normal Init */
941 	if (json_arr_separate_object_parse_init(&json_object, main_object.obj_array.start,
942 						main_object.obj_array.length)) {
943 		ret = -EINVAL;
944 		goto end_of_operation;
945 	}
946 
947 	while (1) {
948 		(void)memset(&fd.array_object, 0, sizeof(fd.array_object));
949 		fd.object_bit_field = json_arr_separate_parse_object(
950 			&json_object, json_obj_descr, ARRAY_SIZE(json_obj_descr), &fd.array_object);
951 		if (fd.object_bit_field == 0) {
952 			/* End of  */
953 			break;
954 		} else if (fd.object_bit_field < 0 ||
955 			   ((fd.object_bit_field & JSON_VAL_MASK) == 0)) {
956 			LOG_ERR("Json Write Parse object fail %d", fd.object_bit_field);
957 			ret = -EINVAL;
958 			goto end_of_operation;
959 		}
960 
961 		/* Create object resource path */
962 		if (base_name_ptr) {
963 			if (fd.object_bit_field & JSON_N_TYPE) {
964 				ret = snprintk(full_name, sizeof(full_name), "%s%s", base_name_ptr,
965 					       fd.array_object.name);
966 			} else {
967 				ret = snprintk(full_name, sizeof(full_name), "%s", base_name_ptr);
968 			}
969 		} else {
970 			if ((fd.object_bit_field & JSON_N_TYPE) == 0) {
971 				ret = -EINVAL;
972 				goto end_of_operation;
973 			}
974 			ret = snprintk(full_name, sizeof(full_name), "%s", fd.array_object.name);
975 		}
976 
977 		if (ret >= MAX_RESOURCE_LEN) {
978 			ret = -EINVAL;
979 			goto end_of_operation;
980 		}
981 
982 		/* handle resource value */
983 		/* reset values */
984 		created = 0U;
985 
986 		/* parse full_name into path */
987 		ret = lwm2m_string_to_path(full_name, &msg->path, '/');
988 		if (ret < 0) {
989 			LOG_ERR("Relative name too long");
990 			ret = -EINVAL;
991 			goto end_of_operation;
992 		}
993 
994 		ret = lwm2m_get_or_create_engine_obj(msg, &obj_inst, &created);
995 		if (ret < 0) {
996 			break;
997 		}
998 
999 		ret = lwm2m_engine_validate_write_access(msg, obj_inst, &obj_field);
1000 		if (ret < 0) {
1001 			return ret;
1002 		}
1003 
1004 		ret = lwm2m_engine_get_create_res_inst(&msg->path, &res, &res_inst);
1005 		if (ret < 0) {
1006 			return -ENOENT;
1007 		}
1008 
1009 		/* Write the resource value */
1010 		ret = lwm2m_write_handler(obj_inst, res, res_inst, obj_field, msg);
1011 		if (orig_path.level >= 3U && ret < 0) {
1012 			/* return errors on a single write */
1013 			break;
1014 		}
1015 	}
1016 
1017 end_of_operation:
1018 	engine_clear_in_user_data(&msg->in);
1019 
1020 	return ret;
1021 }
1022