1// This is an open source non-commercial project. Dear PVS-Studio, please check
2// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
3
4#include <stddef.h>
5
6#include <msgpack.h>
7
8#include "nvim/eval/typval.h"
9#include "nvim/eval.h"
10#include "nvim/eval/decode.h"
11#include "nvim/eval/encode.h"
12#include "nvim/ascii.h"
13#include "nvim/macros.h"
14#include "nvim/message.h"
15#include "nvim/globals.h"
16#include "nvim/charset.h" // vim_str2nr
17#include "nvim/lib/kvec.h"
18#include "nvim/vim.h" // OK, FAIL
19
20/// Helper structure for container_struct
21typedef struct {
22 size_t stack_index; ///< Index of current container in stack.
23 list_T *special_val; ///< _VAL key contents for special maps.
24 ///< When container is not a special dictionary it is
25 ///< NULL.
26 const char *s; ///< Location where container starts.
27 typval_T container; ///< Container. Either VAR_LIST, VAR_DICT or VAR_LIST
28 ///< which is _VAL from special dictionary.
29} ContainerStackItem;
30
31/// Helper structure for values struct
32typedef struct {
33 bool is_special_string; ///< Indicates that current value is a special
34 ///< dictionary with string.
35 bool didcomma; ///< True if previous token was comma.
36 bool didcolon; ///< True if previous token was colon.
37 typval_T val; ///< Actual value.
38} ValuesStackItem;
39
40/// Vector containing values not yet saved in any container
41typedef kvec_t(ValuesStackItem) ValuesStack;
42
43/// Vector containing containers, each next container is located inside previous
44typedef kvec_t(ContainerStackItem) ContainerStack;
45
46#ifdef INCLUDE_GENERATED_DECLARATIONS
47# include "eval/decode.c.generated.h"
48#endif
49
50/// Create special dictionary
51///
52/// @param[out] rettv Location where created dictionary will be saved.
53/// @param[in] type Type of the dictionary.
54/// @param[in] val Value associated with the _VAL key.
55static inline void create_special_dict(typval_T *const rettv,
56 const MessagePackType type,
57 typval_T val)
58 FUNC_ATTR_NONNULL_ALL
59{
60 dict_T *const dict = tv_dict_alloc();
61 dictitem_T *const type_di = tv_dict_item_alloc_len(S_LEN("_TYPE"));
62 type_di->di_tv.v_type = VAR_LIST;
63 type_di->di_tv.v_lock = VAR_UNLOCKED;
64 type_di->di_tv.vval.v_list = (list_T *)eval_msgpack_type_lists[type];
65 tv_list_ref(type_di->di_tv.vval.v_list);
66 tv_dict_add(dict, type_di);
67 dictitem_T *const val_di = tv_dict_item_alloc_len(S_LEN("_VAL"));
68 val_di->di_tv = val;
69 tv_dict_add(dict, val_di);
70 dict->dv_refcount++;
71 *rettv = (typval_T) {
72 .v_type = VAR_DICT,
73 .v_lock = VAR_UNLOCKED,
74 .vval = { .v_dict = dict },
75 };
76}
77
78#define DICT_LEN(dict) (dict)->dv_hashtab.ht_used
79
80/// Helper function used for working with stack vectors used by JSON decoder
81///
82/// @param[in,out] obj New object. Will either be put into the stack (and,
83/// probably, also inside container) or freed.
84/// @param[out] stack Object stack.
85/// @param[out] container_stack Container objects stack.
86/// @param[in,out] pp Position in string which is currently being parsed. Used
87/// for error reporting and is also set when decoding is
88/// restarted due to the necessity of converting regular
89/// dictionary to a special map.
90/// @param[out] next_map_special Is set to true when dictionary needs to be
91/// converted to a special map, otherwise not
92/// touched. Indicates that decoding has been
93/// restarted.
94/// @param[out] didcomma True if previous token was comma. Is set to recorded
95/// value when decoder is restarted, otherwise unused.
96/// @param[out] didcolon True if previous token was colon. Is set to recorded
97/// value when decoder is restarted, otherwise unused.
98///
99/// @return OK in case of success, FAIL in case of error.
100static inline int json_decoder_pop(ValuesStackItem obj,
101 ValuesStack *const stack,
102 ContainerStack *const container_stack,
103 const char **const pp,
104 bool *const next_map_special,
105 bool *const didcomma,
106 bool *const didcolon)
107 FUNC_ATTR_NONNULL_ALL
108{
109 if (kv_size(*container_stack) == 0) {
110 kv_push(*stack, obj);
111 return OK;
112 }
113 ContainerStackItem last_container = kv_last(*container_stack);
114 const char *val_location = *pp;
115 if (obj.val.v_type == last_container.container.v_type
116 // vval.v_list and vval.v_dict should have the same size and offset
117 && ((void *) obj.val.vval.v_list
118 == (void *) last_container.container.vval.v_list)) {
119 (void) kv_pop(*container_stack);
120 val_location = last_container.s;
121 last_container = kv_last(*container_stack);
122 }
123 if (last_container.container.v_type == VAR_LIST) {
124 if (tv_list_len(last_container.container.vval.v_list) != 0
125 && !obj.didcomma) {
126 EMSG2(_("E474: Expected comma before list item: %s"), val_location);
127 tv_clear(&obj.val);
128 return FAIL;
129 }
130 assert(last_container.special_val == NULL);
131 tv_list_append_owned_tv(last_container.container.vval.v_list, obj.val);
132 } else if (last_container.stack_index == kv_size(*stack) - 2) {
133 if (!obj.didcolon) {
134 EMSG2(_("E474: Expected colon before dictionary value: %s"),
135 val_location);
136 tv_clear(&obj.val);
137 return FAIL;
138 }
139 ValuesStackItem key = kv_pop(*stack);
140 if (last_container.special_val == NULL) {
141 // These cases should have already been handled.
142 assert(!(key.is_special_string
143 || key.val.vval.v_string == NULL
144 || *key.val.vval.v_string == NUL));
145 dictitem_T *const obj_di = tv_dict_item_alloc(
146 (const char *)key.val.vval.v_string);
147 tv_clear(&key.val);
148 if (tv_dict_add(last_container.container.vval.v_dict, obj_di)
149 == FAIL) {
150 assert(false);
151 }
152 obj_di->di_tv = obj.val;
153 } else {
154 list_T *const kv_pair = tv_list_alloc(2);
155 tv_list_append_list(last_container.special_val, kv_pair);
156 tv_list_append_owned_tv(kv_pair, key.val);
157 tv_list_append_owned_tv(kv_pair, obj.val);
158 }
159 } else {
160 // Object with key only
161 if (!obj.is_special_string && obj.val.v_type != VAR_STRING) {
162 EMSG2(_("E474: Expected string key: %s"), *pp);
163 tv_clear(&obj.val);
164 return FAIL;
165 } else if (!obj.didcomma
166 && (last_container.special_val == NULL
167 && (DICT_LEN(last_container.container.vval.v_dict) != 0))) {
168 EMSG2(_("E474: Expected comma before dictionary key: %s"), val_location);
169 tv_clear(&obj.val);
170 return FAIL;
171 }
172 // Handle empty key and key represented as special dictionary
173 if (last_container.special_val == NULL
174 && (obj.is_special_string
175 || obj.val.vval.v_string == NULL
176 || *obj.val.vval.v_string == NUL
177 || tv_dict_find(last_container.container.vval.v_dict,
178 (const char *)obj.val.vval.v_string, -1))) {
179 tv_clear(&obj.val);
180
181 // Restart
182 (void) kv_pop(*container_stack);
183 ValuesStackItem last_container_val =
184 kv_A(*stack, last_container.stack_index);
185 while (kv_size(*stack) > last_container.stack_index) {
186 tv_clear(&(kv_pop(*stack).val));
187 }
188 *pp = last_container.s;
189 *didcomma = last_container_val.didcomma;
190 *didcolon = last_container_val.didcolon;
191 *next_map_special = true;
192 return OK;
193 }
194 kv_push(*stack, obj);
195 }
196 return OK;
197}
198
199#define LENP(p, e) \
200 ((int) ((e) - (p))), (p)
201#define OBJ(obj_tv, is_sp_string, didcomma_, didcolon_) \
202 ((ValuesStackItem) { \
203 .is_special_string = (is_sp_string), \
204 .val = (obj_tv), \
205 .didcomma = (didcomma_), \
206 .didcolon = (didcolon_), \
207 })
208
209#define POP(obj_tv, is_sp_string) \
210 do { \
211 if (json_decoder_pop(OBJ(obj_tv, is_sp_string, *didcomma, *didcolon), \
212 stack, container_stack, \
213 &p, next_map_special, didcomma, didcolon) \
214 == FAIL) { \
215 goto parse_json_string_fail; \
216 } \
217 if (*next_map_special) { \
218 goto parse_json_string_ret; \
219 } \
220 } while (0)
221
222/// Create a new special dictionary that ought to represent a MAP
223///
224/// @param[out] ret_tv Address where new special dictionary is saved.
225/// @param[in] len Expected number of items to be populated before list
226/// becomes accessible from VimL. It is still valid to
227/// underpopulate a list, value only controls how many elements
228/// will be allocated in advance. @see ListLenSpecials.
229///
230/// @return [allocated] list which should contain key-value pairs. Return value
231/// may be safely ignored.
232list_T *decode_create_map_special_dict(typval_T *const ret_tv,
233 const ptrdiff_t len)
234 FUNC_ATTR_NONNULL_ALL
235{
236 list_T *const list = tv_list_alloc(len);
237 tv_list_ref(list);
238 create_special_dict(ret_tv, kMPMap, ((typval_T) {
239 .v_type = VAR_LIST,
240 .v_lock = VAR_UNLOCKED,
241 .vval = { .v_list = list },
242 }));
243 return list;
244}
245
246/// Convert char* string to typval_T
247///
248/// Depending on whether string has (no) NUL bytes, it may use a special
249/// dictionary or decode string to VAR_STRING.
250///
251/// @param[in] s String to decode.
252/// @param[in] len String length.
253/// @param[in] hasnul Whether string has NUL byte, not or it was not yet
254/// determined.
255/// @param[in] binary If true, save special string type as kMPBinary,
256/// otherwise kMPString.
257/// @param[in] s_allocated If true, then `s` was allocated and can be saved in
258/// a returned structure. If it is not saved there, it
259/// will be freed.
260///
261/// @return Decoded string.
262typval_T decode_string(const char *const s, const size_t len,
263 const TriState hasnul, const bool binary,
264 const bool s_allocated)
265 FUNC_ATTR_WARN_UNUSED_RESULT
266{
267 assert(s != NULL || len == 0);
268 const bool really_hasnul = (hasnul == kNone
269 ? ((s != NULL) && (memchr(s, NUL, len) != NULL))
270 : (bool)hasnul);
271 if (really_hasnul) {
272 list_T *const list = tv_list_alloc(kListLenMayKnow);
273 tv_list_ref(list);
274 typval_T tv;
275 create_special_dict(&tv, binary ? kMPBinary : kMPString, ((typval_T) {
276 .v_type = VAR_LIST,
277 .v_lock = VAR_UNLOCKED,
278 .vval = { .v_list = list },
279 }));
280 const int elw_ret = encode_list_write((void *)list, s, len);
281 if (s_allocated) {
282 xfree((void *)s);
283 }
284 if (elw_ret == -1) {
285 tv_clear(&tv);
286 return (typval_T) { .v_type = VAR_UNKNOWN, .v_lock = VAR_UNLOCKED };
287 }
288 return tv;
289 } else {
290 return (typval_T) {
291 .v_type = VAR_STRING,
292 .v_lock = VAR_UNLOCKED,
293 .vval = { .v_string = (char_u *)(
294 (s == NULL || s_allocated) ? (char *)s : xmemdupz(s, len)) },
295 };
296 }
297}
298
299/// Parse JSON double-quoted string
300///
301/// @param[in] buf Buffer being converted.
302/// @param[in] buf_len Length of the buffer.
303/// @param[in,out] pp Pointer to the start of the string. Must point to '"'.
304/// Is advanced to the closing '"'. Also see
305/// json_decoder_pop(), it may set pp to another location
306/// and alter next_map_special, didcomma and didcolon.
307/// @param[out] stack Object stack.
308/// @param[out] container_stack Container objects stack.
309/// @param[out] next_map_special Is set to true when dictionary is converted
310/// to a special map, otherwise not touched.
311/// @param[out] didcomma True if previous token was comma. Is set to recorded
312/// value when decoder is restarted, otherwise unused.
313/// @param[out] didcolon True if previous token was colon. Is set to recorded
314/// value when decoder is restarted, otherwise unused.
315///
316/// @return OK in case of success, FAIL in case of error.
317static inline int parse_json_string(const char *const buf, const size_t buf_len,
318 const char **const pp,
319 ValuesStack *const stack,
320 ContainerStack *const container_stack,
321 bool *const next_map_special,
322 bool *const didcomma,
323 bool *const didcolon)
324 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
325{
326 const char *const e = buf + buf_len;
327 const char *p = *pp;
328 size_t len = 0;
329 const char *const s = ++p;
330 int ret = OK;
331 while (p < e && *p != '"') {
332 if (*p == '\\') {
333 p++;
334 if (p == e) {
335 emsgf(_("E474: Unfinished escape sequence: %.*s"),
336 (int) buf_len, buf);
337 goto parse_json_string_fail;
338 }
339 switch (*p) {
340 case 'u': {
341 if (p + 4 >= e) {
342 emsgf(_("E474: Unfinished unicode escape sequence: %.*s"),
343 (int) buf_len, buf);
344 goto parse_json_string_fail;
345 } else if (!ascii_isxdigit(p[1])
346 || !ascii_isxdigit(p[2])
347 || !ascii_isxdigit(p[3])
348 || !ascii_isxdigit(p[4])) {
349 emsgf(_("E474: Expected four hex digits after \\u: %.*s"),
350 LENP(p - 1, e));
351 goto parse_json_string_fail;
352 }
353 // One UTF-8 character below U+10000 can take up to 3 bytes,
354 // above up to 6, but they are encoded using two \u escapes.
355 len += 3;
356 p += 5;
357 break;
358 }
359 case '\\':
360 case '/':
361 case '"':
362 case 't':
363 case 'b':
364 case 'n':
365 case 'r':
366 case 'f': {
367 len++;
368 p++;
369 break;
370 }
371 default: {
372 emsgf(_("E474: Unknown escape sequence: %.*s"), LENP(p - 1, e));
373 goto parse_json_string_fail;
374 }
375 }
376 } else {
377 uint8_t p_byte = (uint8_t) *p;
378 // unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
379 if (p_byte < 0x20) {
380 emsgf(_("E474: ASCII control characters cannot be present "
381 "inside string: %.*s"), LENP(p, e));
382 goto parse_json_string_fail;
383 }
384 const int ch = utf_ptr2char((char_u *) p);
385 // All characters above U+007F are encoded using two or more bytes
386 // and thus cannot possibly be equal to *p. But utf_ptr2char({0xFF,
387 // 0}) will return 0xFF, even though 0xFF cannot start any UTF-8
388 // code point at all.
389 //
390 // The only exception is U+00C3 which is represented as 0xC3 0x83.
391 if (ch >= 0x80 && p_byte == ch
392 && !(ch == 0xC3 && p + 1 < e && (uint8_t) p[1] == 0x83)) {
393 emsgf(_("E474: Only UTF-8 strings allowed: %.*s"), LENP(p, e));
394 goto parse_json_string_fail;
395 } else if (ch > 0x10FFFF) {
396 emsgf(_("E474: Only UTF-8 code points up to U+10FFFF "
397 "are allowed to appear unescaped: %.*s"), LENP(p, e));
398 goto parse_json_string_fail;
399 }
400 const size_t ch_len = (size_t) utf_char2len(ch);
401 assert(ch_len == (size_t) (ch ? utf_ptr2len((char_u *) p) : 1));
402 len += ch_len;
403 p += ch_len;
404 }
405 }
406 if (p == e || *p != '"') {
407 emsgf(_("E474: Expected string end: %.*s"), (int) buf_len, buf);
408 goto parse_json_string_fail;
409 }
410 if (len == 0) {
411 POP(((typval_T) {
412 .v_type = VAR_STRING,
413 .vval = { .v_string = NULL },
414 }), false);
415 goto parse_json_string_ret;
416 }
417 char *str = xmalloc(len + 1);
418 int fst_in_pair = 0;
419 char *str_end = str;
420 bool hasnul = false;
421#define PUT_FST_IN_PAIR(fst_in_pair, str_end) \
422 do { \
423 if (fst_in_pair != 0) { \
424 str_end += utf_char2bytes(fst_in_pair, (char_u *) str_end); \
425 fst_in_pair = 0; \
426 } \
427 } while (0)
428 for (const char *t = s; t < p; t++) {
429 if (t[0] != '\\' || t[1] != 'u') {
430 PUT_FST_IN_PAIR(fst_in_pair, str_end);
431 }
432 if (*t == '\\') {
433 t++;
434 switch (*t) {
435 case 'u': {
436 const char ubuf[] = { t[1], t[2], t[3], t[4] };
437 t += 4;
438 uvarnumber_T ch;
439 vim_str2nr((char_u *)ubuf, NULL, NULL,
440 STR2NR_HEX | STR2NR_FORCE, NULL, &ch, 4);
441 if (ch == 0) {
442 hasnul = true;
443 }
444 if (SURROGATE_HI_START <= ch && ch <= SURROGATE_HI_END) {
445 PUT_FST_IN_PAIR(fst_in_pair, str_end);
446 fst_in_pair = (int) ch;
447 } else if (SURROGATE_LO_START <= ch && ch <= SURROGATE_LO_END
448 && fst_in_pair != 0) {
449 const int full_char = (
450 (int) (ch - SURROGATE_LO_START)
451 + ((fst_in_pair - SURROGATE_HI_START) << 10)
452 + SURROGATE_FIRST_CHAR);
453 str_end += utf_char2bytes(full_char, (char_u *) str_end);
454 fst_in_pair = 0;
455 } else {
456 PUT_FST_IN_PAIR(fst_in_pair, str_end);
457 str_end += utf_char2bytes((int) ch, (char_u *) str_end);
458 }
459 break;
460 }
461 case '\\':
462 case '/':
463 case '"':
464 case 't':
465 case 'b':
466 case 'n':
467 case 'r':
468 case 'f': {
469 static const char escapes[] = {
470 ['\\'] = '\\',
471 ['/'] = '/',
472 ['"'] = '"',
473 ['t'] = TAB,
474 ['b'] = BS,
475 ['n'] = NL,
476 ['r'] = CAR,
477 ['f'] = FF,
478 };
479 *str_end++ = escapes[(int) *t];
480 break;
481 }
482 default: {
483 assert(false);
484 }
485 }
486 } else {
487 *str_end++ = *t;
488 }
489 }
490 PUT_FST_IN_PAIR(fst_in_pair, str_end);
491#undef PUT_FST_IN_PAIR
492 *str_end = NUL;
493 typval_T obj = decode_string(
494 str, (size_t)(str_end - str), hasnul ? kTrue : kFalse, false, true);
495 if (obj.v_type == VAR_UNKNOWN) {
496 goto parse_json_string_fail;
497 }
498 POP(obj, obj.v_type != VAR_STRING);
499 goto parse_json_string_ret;
500parse_json_string_fail:
501 ret = FAIL;
502parse_json_string_ret:
503 *pp = p;
504 return ret;
505}
506
507#undef POP
508
509/// Parse JSON number: both floating-point and integer
510///
511/// Number format: `-?\d+(?:.\d+)?(?:[eE][+-]?\d+)?`.
512///
513/// @param[in] buf Buffer being converted.
514/// @param[in] buf_len Length of the buffer.
515/// @param[in,out] pp Pointer to the start of the number. Must point to
516/// a digit or a minus sign. Is advanced to the last
517/// character of the number. Also see json_decoder_pop(), it
518/// may set pp to another location and alter
519/// next_map_special, didcomma and didcolon.
520/// @param[out] stack Object stack.
521/// @param[out] container_stack Container objects stack.
522/// @param[out] next_map_special Is set to true when dictionary is converted
523/// to a special map, otherwise not touched.
524/// @param[out] didcomma True if previous token was comma. Is set to recorded
525/// value when decoder is restarted, otherwise unused.
526/// @param[out] didcolon True if previous token was colon. Is set to recorded
527/// value when decoder is restarted, otherwise unused.
528///
529/// @return OK in case of success, FAIL in case of error.
530static inline int parse_json_number(const char *const buf, const size_t buf_len,
531 const char **const pp,
532 ValuesStack *const stack,
533 ContainerStack *const container_stack,
534 bool *const next_map_special,
535 bool *const didcomma,
536 bool *const didcolon)
537 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE
538{
539 const char *const e = buf + buf_len;
540 const char *p = *pp;
541 int ret = OK;
542 const char *const s = p;
543 const char *ints = NULL;
544 const char *fracs = NULL;
545 const char *exps = NULL;
546 const char *exps_s = NULL;
547 if (*p == '-') {
548 p++;
549 }
550 ints = p;
551 if (p >= e) {
552 goto parse_json_number_check;
553 }
554 while (p < e && ascii_isdigit(*p)) {
555 p++;
556 }
557 if (p != ints + 1 && *ints == '0') {
558 emsgf(_("E474: Leading zeroes are not allowed: %.*s"), LENP(s, e));
559 goto parse_json_number_fail;
560 }
561 if (p >= e || p == ints) {
562 goto parse_json_number_check;
563 }
564 if (*p == '.') {
565 p++;
566 fracs = p;
567 while (p < e && ascii_isdigit(*p)) {
568 p++;
569 }
570 if (p >= e || p == fracs) {
571 goto parse_json_number_check;
572 }
573 }
574 if (*p == 'e' || *p == 'E') {
575 p++;
576 exps_s = p;
577 if (p < e && (*p == '-' || *p == '+')) {
578 p++;
579 }
580 exps = p;
581 while (p < e && ascii_isdigit(*p)) {
582 p++;
583 }
584 }
585parse_json_number_check:
586 if (p == ints) {
587 emsgf(_("E474: Missing number after minus sign: %.*s"), LENP(s, e));
588 goto parse_json_number_fail;
589 } else if (p == fracs || exps_s == fracs + 1) {
590 emsgf(_("E474: Missing number after decimal dot: %.*s"), LENP(s, e));
591 goto parse_json_number_fail;
592 } else if (p == exps) {
593 emsgf(_("E474: Missing exponent: %.*s"), LENP(s, e));
594 goto parse_json_number_fail;
595 }
596 typval_T tv = {
597 .v_type = VAR_NUMBER,
598 .v_lock = VAR_UNLOCKED,
599 };
600 const size_t exp_num_len = (size_t) (p - s);
601 if (fracs || exps) {
602 // Convert floating-point number
603 const size_t num_len = string2float(s, &tv.vval.v_float);
604 if (exp_num_len != num_len) {
605 emsgf(_("E685: internal error: while converting number \"%.*s\" "
606 "to float string2float consumed %zu bytes in place of %zu"),
607 (int) exp_num_len, s, num_len, exp_num_len);
608 }
609 tv.v_type = VAR_FLOAT;
610 } else {
611 // Convert integer
612 varnumber_T nr;
613 int num_len;
614 vim_str2nr((char_u *) s, NULL, &num_len, 0, &nr, NULL, (int) (p - s));
615 if ((int) exp_num_len != num_len) {
616 emsgf(_("E685: internal error: while converting number \"%.*s\" "
617 "to integer vim_str2nr consumed %i bytes in place of %zu"),
618 (int) exp_num_len, s, num_len, exp_num_len);
619 }
620 tv.vval.v_number = nr;
621 }
622 if (json_decoder_pop(OBJ(tv, false, *didcomma, *didcolon),
623 stack, container_stack,
624 &p, next_map_special, didcomma, didcolon) == FAIL) {
625 goto parse_json_number_fail;
626 }
627 if (*next_map_special) {
628 goto parse_json_number_ret;
629 }
630 p--;
631 goto parse_json_number_ret;
632parse_json_number_fail:
633 ret = FAIL;
634parse_json_number_ret:
635 *pp = p;
636 return ret;
637}
638
639#define POP(obj_tv, is_sp_string) \
640 do { \
641 if (json_decoder_pop(OBJ(obj_tv, is_sp_string, didcomma, didcolon), \
642 &stack, &container_stack, \
643 &p, &next_map_special, &didcomma, &didcolon) \
644 == FAIL) { \
645 goto json_decode_string_fail; \
646 } \
647 if (next_map_special) { \
648 goto json_decode_string_cycle_start; \
649 } \
650 } while (0)
651
652/// Convert JSON string into VimL object
653///
654/// @param[in] buf String to convert. UTF-8 encoding is assumed.
655/// @param[in] buf_len Length of the string.
656/// @param[out] rettv Location where to save results.
657///
658/// @return OK in case of success, FAIL otherwise.
659int json_decode_string(const char *const buf, const size_t buf_len,
660 typval_T *const rettv)
661 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
662{
663 const char *p = buf;
664 const char *const e = buf + buf_len;
665 while (p < e && (*p == ' ' || *p == TAB || *p == NL || *p == CAR)) {
666 p++;
667 }
668 if (p == e) {
669 EMSG(_("E474: Attempt to decode a blank string"));
670 return FAIL;
671 }
672 int ret = OK;
673 ValuesStack stack = KV_INITIAL_VALUE;
674 ContainerStack container_stack = KV_INITIAL_VALUE;
675 rettv->v_type = VAR_UNKNOWN;
676 bool didcomma = false;
677 bool didcolon = false;
678 bool next_map_special = false;
679 for (; p < e; p++) {
680json_decode_string_cycle_start:
681 assert(*p == '{' || next_map_special == false);
682 switch (*p) {
683 case '}':
684 case ']': {
685 if (kv_size(container_stack) == 0) {
686 emsgf(_("E474: No container to close: %.*s"), LENP(p, e));
687 goto json_decode_string_fail;
688 }
689 ContainerStackItem last_container = kv_last(container_stack);
690 if (*p == '}' && last_container.container.v_type != VAR_DICT) {
691 emsgf(_("E474: Closing list with curly bracket: %.*s"), LENP(p, e));
692 goto json_decode_string_fail;
693 } else if (*p == ']' && last_container.container.v_type != VAR_LIST) {
694 emsgf(_("E474: Closing dictionary with square bracket: %.*s"),
695 LENP(p, e));
696 goto json_decode_string_fail;
697 } else if (didcomma) {
698 emsgf(_("E474: Trailing comma: %.*s"), LENP(p, e));
699 goto json_decode_string_fail;
700 } else if (didcolon) {
701 emsgf(_("E474: Expected value after colon: %.*s"), LENP(p, e));
702 goto json_decode_string_fail;
703 } else if (last_container.stack_index != kv_size(stack) - 1) {
704 assert(last_container.stack_index < kv_size(stack) - 1);
705 emsgf(_("E474: Expected value: %.*s"), LENP(p, e));
706 goto json_decode_string_fail;
707 }
708 if (kv_size(stack) == 1) {
709 p++;
710 (void) kv_pop(container_stack);
711 goto json_decode_string_after_cycle;
712 } else {
713 if (json_decoder_pop(kv_pop(stack), &stack, &container_stack, &p,
714 &next_map_special, &didcomma, &didcolon)
715 == FAIL) {
716 goto json_decode_string_fail;
717 }
718 assert(!next_map_special);
719 break;
720 }
721 }
722 case ',': {
723 if (kv_size(container_stack) == 0) {
724 emsgf(_("E474: Comma not inside container: %.*s"), LENP(p, e));
725 goto json_decode_string_fail;
726 }
727 ContainerStackItem last_container = kv_last(container_stack);
728 if (didcomma) {
729 emsgf(_("E474: Duplicate comma: %.*s"), LENP(p, e));
730 goto json_decode_string_fail;
731 } else if (didcolon) {
732 emsgf(_("E474: Comma after colon: %.*s"), LENP(p, e));
733 goto json_decode_string_fail;
734 } else if (last_container.container.v_type == VAR_DICT
735 && last_container.stack_index != kv_size(stack) - 1) {
736 emsgf(_("E474: Using comma in place of colon: %.*s"), LENP(p, e));
737 goto json_decode_string_fail;
738 } else if (last_container.special_val == NULL
739 ? (last_container.container.v_type == VAR_DICT
740 ? (DICT_LEN(last_container.container.vval.v_dict) == 0)
741 : (tv_list_len(last_container.container.vval.v_list)
742 == 0))
743 : (tv_list_len(last_container.special_val) == 0)) {
744 emsgf(_("E474: Leading comma: %.*s"), LENP(p, e));
745 goto json_decode_string_fail;
746 }
747 didcomma = true;
748 continue;
749 }
750 case ':': {
751 if (kv_size(container_stack) == 0) {
752 emsgf(_("E474: Colon not inside container: %.*s"), LENP(p, e));
753 goto json_decode_string_fail;
754 }
755 ContainerStackItem last_container = kv_last(container_stack);
756 if (last_container.container.v_type != VAR_DICT) {
757 emsgf(_("E474: Using colon not in dictionary: %.*s"), LENP(p, e));
758 goto json_decode_string_fail;
759 } else if (last_container.stack_index != kv_size(stack) - 2) {
760 emsgf(_("E474: Unexpected colon: %.*s"), LENP(p, e));
761 goto json_decode_string_fail;
762 } else if (didcomma) {
763 emsgf(_("E474: Colon after comma: %.*s"), LENP(p, e));
764 goto json_decode_string_fail;
765 } else if (didcolon) {
766 emsgf(_("E474: Duplicate colon: %.*s"), LENP(p, e));
767 goto json_decode_string_fail;
768 }
769 didcolon = true;
770 continue;
771 }
772 case ' ':
773 case TAB:
774 case NL:
775 case CAR: {
776 continue;
777 }
778 case 'n': {
779 if ((p + 3) >= e || strncmp(p + 1, "ull", 3) != 0) {
780 emsgf(_("E474: Expected null: %.*s"), LENP(p, e));
781 goto json_decode_string_fail;
782 }
783 p += 3;
784 POP(((typval_T) {
785 .v_type = VAR_SPECIAL,
786 .v_lock = VAR_UNLOCKED,
787 .vval = { .v_special = kSpecialVarNull },
788 }), false);
789 break;
790 }
791 case 't': {
792 if ((p + 3) >= e || strncmp(p + 1, "rue", 3) != 0) {
793 emsgf(_("E474: Expected true: %.*s"), LENP(p, e));
794 goto json_decode_string_fail;
795 }
796 p += 3;
797 POP(((typval_T) {
798 .v_type = VAR_SPECIAL,
799 .v_lock = VAR_UNLOCKED,
800 .vval = { .v_special = kSpecialVarTrue },
801 }), false);
802 break;
803 }
804 case 'f': {
805 if ((p + 4) >= e || strncmp(p + 1, "alse", 4) != 0) {
806 emsgf(_("E474: Expected false: %.*s"), LENP(p, e));
807 goto json_decode_string_fail;
808 }
809 p += 4;
810 POP(((typval_T) {
811 .v_type = VAR_SPECIAL,
812 .v_lock = VAR_UNLOCKED,
813 .vval = { .v_special = kSpecialVarFalse },
814 }), false);
815 break;
816 }
817 case '"': {
818 if (parse_json_string(buf, buf_len, &p, &stack, &container_stack,
819 &next_map_special, &didcomma, &didcolon)
820 == FAIL) {
821 // Error message was already given
822 goto json_decode_string_fail;
823 }
824 if (next_map_special) {
825 goto json_decode_string_cycle_start;
826 }
827 break;
828 }
829 case '-':
830 case '0':
831 case '1':
832 case '2':
833 case '3':
834 case '4':
835 case '5':
836 case '6':
837 case '7':
838 case '8':
839 case '9': {
840 if (parse_json_number(buf, buf_len, &p, &stack, &container_stack,
841 &next_map_special, &didcomma, &didcolon)
842 == FAIL) {
843 // Error message was already given
844 goto json_decode_string_fail;
845 }
846 if (next_map_special) {
847 goto json_decode_string_cycle_start;
848 }
849 break;
850 }
851 case '[': {
852 list_T *list = tv_list_alloc(kListLenMayKnow);
853 tv_list_ref(list);
854 typval_T tv = {
855 .v_type = VAR_LIST,
856 .v_lock = VAR_UNLOCKED,
857 .vval = { .v_list = list },
858 };
859 kv_push(container_stack, ((ContainerStackItem) {
860 .stack_index = kv_size(stack),
861 .s = p,
862 .container = tv,
863 .special_val = NULL,
864 }));
865 kv_push(stack, OBJ(tv, false, didcomma, didcolon));
866 break;
867 }
868 case '{': {
869 typval_T tv;
870 list_T *val_list = NULL;
871 if (next_map_special) {
872 next_map_special = false;
873 val_list = decode_create_map_special_dict(&tv, kListLenMayKnow);
874 } else {
875 dict_T *dict = tv_dict_alloc();
876 dict->dv_refcount++;
877 tv = (typval_T) {
878 .v_type = VAR_DICT,
879 .v_lock = VAR_UNLOCKED,
880 .vval = { .v_dict = dict },
881 };
882 }
883 kv_push(container_stack, ((ContainerStackItem) {
884 .stack_index = kv_size(stack),
885 .s = p,
886 .container = tv,
887 .special_val = val_list,
888 }));
889 kv_push(stack, OBJ(tv, false, didcomma, didcolon));
890 break;
891 }
892 default: {
893 emsgf(_("E474: Unidentified byte: %.*s"), LENP(p, e));
894 goto json_decode_string_fail;
895 }
896 }
897 didcomma = false;
898 didcolon = false;
899 if (kv_size(container_stack) == 0) {
900 p++;
901 break;
902 }
903 }
904json_decode_string_after_cycle:
905 for (; p < e; p++) {
906 switch (*p) {
907 case NL:
908 case ' ':
909 case TAB:
910 case CAR: {
911 break;
912 }
913 default: {
914 emsgf(_("E474: Trailing characters: %.*s"), LENP(p, e));
915 goto json_decode_string_fail;
916 }
917 }
918 }
919 if (kv_size(stack) == 1 && kv_size(container_stack) == 0) {
920 *rettv = kv_pop(stack).val;
921 goto json_decode_string_ret;
922 }
923 emsgf(_("E474: Unexpected end of input: %.*s"), (int) buf_len, buf);
924json_decode_string_fail:
925 ret = FAIL;
926 while (kv_size(stack)) {
927 tv_clear(&(kv_pop(stack).val));
928 }
929json_decode_string_ret:
930 kv_destroy(stack);
931 kv_destroy(container_stack);
932 return ret;
933}
934
935#undef LENP
936#undef POP
937
938#undef OBJ
939
940#undef DICT_LEN
941
942/// Convert msgpack object to a VimL one
943int msgpack_to_vim(const msgpack_object mobj, typval_T *const rettv)
944 FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
945{
946 switch (mobj.type) {
947 case MSGPACK_OBJECT_NIL: {
948 *rettv = (typval_T) {
949 .v_type = VAR_SPECIAL,
950 .v_lock = VAR_UNLOCKED,
951 .vval = { .v_special = kSpecialVarNull },
952 };
953 break;
954 }
955 case MSGPACK_OBJECT_BOOLEAN: {
956 *rettv = (typval_T) {
957 .v_type = VAR_SPECIAL,
958 .v_lock = VAR_UNLOCKED,
959 .vval = {
960 .v_special = mobj.via.boolean ? kSpecialVarTrue : kSpecialVarFalse
961 },
962 };
963 break;
964 }
965 case MSGPACK_OBJECT_POSITIVE_INTEGER: {
966 if (mobj.via.u64 <= VARNUMBER_MAX) {
967 *rettv = (typval_T) {
968 .v_type = VAR_NUMBER,
969 .v_lock = VAR_UNLOCKED,
970 .vval = { .v_number = (varnumber_T) mobj.via.u64 },
971 };
972 } else {
973 list_T *const list = tv_list_alloc(4);
974 tv_list_ref(list);
975 create_special_dict(rettv, kMPInteger, ((typval_T) {
976 .v_type = VAR_LIST,
977 .v_lock = VAR_UNLOCKED,
978 .vval = { .v_list = list },
979 }));
980 uint64_t n = mobj.via.u64;
981 tv_list_append_number(list, 1);
982 tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
983 tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
984 tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
985 }
986 break;
987 }
988 case MSGPACK_OBJECT_NEGATIVE_INTEGER: {
989 if (mobj.via.i64 >= VARNUMBER_MIN) { // -V547
990 *rettv = (typval_T) {
991 .v_type = VAR_NUMBER,
992 .v_lock = VAR_UNLOCKED,
993 .vval = { .v_number = (varnumber_T) mobj.via.i64 },
994 };
995 } else {
996 list_T *const list = tv_list_alloc(4);
997 tv_list_ref(list);
998 create_special_dict(rettv, kMPInteger, ((typval_T) {
999 .v_type = VAR_LIST,
1000 .v_lock = VAR_UNLOCKED,
1001 .vval = { .v_list = list },
1002 }));
1003 uint64_t n = -((uint64_t)mobj.via.i64);
1004 tv_list_append_number(list, -1);
1005 tv_list_append_number(list, (varnumber_T)((n >> 62) & 0x3));
1006 tv_list_append_number(list, (varnumber_T)((n >> 31) & 0x7FFFFFFF));
1007 tv_list_append_number(list, (varnumber_T)(n & 0x7FFFFFFF));
1008 }
1009 break;
1010 }
1011#ifdef NVIM_MSGPACK_HAS_FLOAT32
1012 case MSGPACK_OBJECT_FLOAT32:
1013 case MSGPACK_OBJECT_FLOAT64:
1014#else
1015 case MSGPACK_OBJECT_FLOAT:
1016#endif
1017 {
1018 *rettv = (typval_T) {
1019 .v_type = VAR_FLOAT,
1020 .v_lock = VAR_UNLOCKED,
1021 .vval = { .v_float = mobj.via.f64 },
1022 };
1023 break;
1024 }
1025 case MSGPACK_OBJECT_STR: {
1026 *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kTrue, false,
1027 false);
1028 if (rettv->v_type == VAR_UNKNOWN) {
1029 return FAIL;
1030 }
1031 break;
1032 }
1033 case MSGPACK_OBJECT_BIN: {
1034 *rettv = decode_string(mobj.via.bin.ptr, mobj.via.bin.size, kNone, true,
1035 false);
1036 if (rettv->v_type == VAR_UNKNOWN) {
1037 return FAIL;
1038 }
1039 break;
1040 }
1041 case MSGPACK_OBJECT_ARRAY: {
1042 list_T *const list = tv_list_alloc((ptrdiff_t)mobj.via.array.size);
1043 tv_list_ref(list);
1044 *rettv = (typval_T) {
1045 .v_type = VAR_LIST,
1046 .v_lock = VAR_UNLOCKED,
1047 .vval = { .v_list = list },
1048 };
1049 for (size_t i = 0; i < mobj.via.array.size; i++) {
1050 // Not populated yet, need to create list item to push.
1051 tv_list_append_owned_tv(list, (typval_T) { .v_type = VAR_UNKNOWN });
1052 if (msgpack_to_vim(mobj.via.array.ptr[i],
1053 TV_LIST_ITEM_TV(tv_list_last(list)))
1054 == FAIL) {
1055 return FAIL;
1056 }
1057 }
1058 break;
1059 }
1060 case MSGPACK_OBJECT_MAP: {
1061 for (size_t i = 0; i < mobj.via.map.size; i++) {
1062 if (mobj.via.map.ptr[i].key.type != MSGPACK_OBJECT_STR
1063 || mobj.via.map.ptr[i].key.via.str.size == 0
1064 || memchr(mobj.via.map.ptr[i].key.via.str.ptr, NUL,
1065 mobj.via.map.ptr[i].key.via.str.size) != NULL) {
1066 goto msgpack_to_vim_generic_map;
1067 }
1068 }
1069 dict_T *const dict = tv_dict_alloc();
1070 dict->dv_refcount++;
1071 *rettv = (typval_T) {
1072 .v_type = VAR_DICT,
1073 .v_lock = VAR_UNLOCKED,
1074 .vval = { .v_dict = dict },
1075 };
1076 for (size_t i = 0; i < mobj.via.map.size; i++) {
1077 dictitem_T *const di = xmallocz(offsetof(dictitem_T, di_key)
1078 + mobj.via.map.ptr[i].key.via.str.size);
1079 memcpy(&di->di_key[0], mobj.via.map.ptr[i].key.via.str.ptr,
1080 mobj.via.map.ptr[i].key.via.str.size);
1081 di->di_tv.v_type = VAR_UNKNOWN;
1082 if (tv_dict_add(dict, di) == FAIL) {
1083 // Duplicate key: fallback to generic map
1084 tv_clear(rettv);
1085 xfree(di);
1086 goto msgpack_to_vim_generic_map;
1087 }
1088 if (msgpack_to_vim(mobj.via.map.ptr[i].val, &di->di_tv) == FAIL) {
1089 return FAIL;
1090 }
1091 }
1092 break;
1093msgpack_to_vim_generic_map: {}
1094 list_T *const list = decode_create_map_special_dict(
1095 rettv, (ptrdiff_t)mobj.via.map.size);
1096 for (size_t i = 0; i < mobj.via.map.size; i++) {
1097 list_T *const kv_pair = tv_list_alloc(2);
1098 tv_list_append_list(list, kv_pair);
1099
1100 typval_T key_tv = { .v_type = VAR_UNKNOWN };
1101 if (msgpack_to_vim(mobj.via.map.ptr[i].key, &key_tv) == FAIL) {
1102 tv_clear(&key_tv);
1103 return FAIL;
1104 }
1105 tv_list_append_owned_tv(kv_pair, key_tv);
1106
1107 typval_T val_tv = { .v_type = VAR_UNKNOWN };
1108 if (msgpack_to_vim(mobj.via.map.ptr[i].val, &val_tv) == FAIL) {
1109 tv_clear(&val_tv);
1110 return FAIL;
1111 }
1112 tv_list_append_owned_tv(kv_pair, val_tv);
1113 }
1114 break;
1115 }
1116 case MSGPACK_OBJECT_EXT: {
1117 list_T *const list = tv_list_alloc(2);
1118 tv_list_ref(list);
1119 tv_list_append_number(list, mobj.via.ext.type);
1120 list_T *const ext_val_list = tv_list_alloc(kListLenMayKnow);
1121 tv_list_append_list(list, ext_val_list);
1122 create_special_dict(rettv, kMPExt, ((typval_T) {
1123 .v_type = VAR_LIST,
1124 .v_lock = VAR_UNLOCKED,
1125 .vval = { .v_list = list },
1126 }));
1127 if (encode_list_write((void *) ext_val_list, mobj.via.ext.ptr,
1128 mobj.via.ext.size) == -1) {
1129 return FAIL;
1130 }
1131 break;
1132 }
1133 }
1134 return OK;
1135}
1136