1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/*
*******************************************************************************
\file json.h
\brief JSON (JavaScript Object Notation, https://json.org)
\project bee2 [cryptographic library]
\created 2025.05.07
\version 2025.05.13
\copyright The Bee2 authors
\license Licensed under the Apache License, Version 2.0 (see LICENSE.txt).
*******************************************************************************
*/
/*!
*******************************************************************************
\file json.h
\brief JSON
*******************************************************************************
*/
#ifndef __BEE2_JSON_H
#define __BEE2_JSON_H
#include "bee2/defs.h"
#ifdef __cplusplus
extern "C" {
#endif
/*
*******************************************************************************
\file json.h
Элементы JSON -- это текстовые строки следующих типов.
1. Объект. Начинается открывающей фигурной скобкой (`{`) и заканчивается
закрывающей (`}`). Состоит из пар (имя, элемент). Имя представляет собой
строку. Имя и элемент внутри пары разделяются двоеточием (`:`). Пары
разделяются запятыми. Запятая перед закрывающей скобкой не допускается.
2. Массив. Начинается открывающей квадратной скобкой (`[`) и заканчивается
закрывающей (`]`). Состоит из элементов, разделенных запятыми. Запятая
перед закрывающей скобкой не допускается.
3. Строка. Начинается и заканчивается кавычками (`"`). Может содержать escape-
последовательности. Escape-последовательность начинается символом `\`и
продолжается одним из символов строки `"\/bfnrtu`. Escape-последовательность
`\u` дополнительно продолжается четырьмя шестнадцатеричными символами --
кодом символа Unicode.
4. Число. Состоит из десятичных символов `0` -- `9`. Незначащие нули не
допускаются.
5. Лексема `true`.
6. Лексема `false`.
7. Лексема `null`.
\warning Сужение реализации: отрицательные числа и числа с плавающей точкой
не поддерживаются. Число должно укладываться в size_t.
Объект и массив являются составными элементами, строка, число и лексемы ---
примитивными.
Тип элемента можно определить по его первому символу:
`{`, `[`, `"`, `0`..`9`, `t`, `f` или `n`.
Между элементами и разделителями (запятыми, двоеточиями, скобками) может
размещаться любое число пробелов. Пробелом является как собственно пробел, так
и символы `\n`, `\r`, `\t`.
JSON-код представляет собой элемент с любым числом предваряющих и завершающих
пробелов. Обычно подразумевается составной элемент -- объект или массив.
Элемент описываются типом json_elem_t. При декодировании составного элемента
возвращается массив вложенных элементов этого типа. В каждом подэлементе
поле json ссылается на фрагмент в родительском элементе, а поле count задает
длину этого фрагмента. Таким образом, для вложенных элемента можно не выделять
дополнительную память.
\remark Похожий подход реализован в https://github.com/zserge/jsmn.
\remark Элемент типа json_elem_t может быть и результатом декодирования,
и объектом декодирования. В последнем случае в функцию декодирования
передается не указатель на объект, а его поля по отдельности:
\code
json_elem_t elem;
size_t c;
size_t size;
...
c = jsonArrDec(&elem, 1, json, count);
...
c = jsonSizeDec(&size, elem.json, elem.count);
\endcode
*******************************************************************************
*/
/*! \brief Элемент JSON
Описывается элемент JSON -- фрагмент [count]json JSON-кода.
*/
typedef struct
{
const char* json; /*!< начало элемента */
size_t count; /*!< длина элемента */
} json_elem_t;
/*! \brief Корректный код?
Проверяется корректность кода [count]json.
\return Признак корректности.
*/
bool_t jsonIsValid(
const char json[], /*!< [in] код */
size_t count /*!< [in] длина кода */
);
/*! \brief Декодирование строки
Декодируется строка JSON, заданная кодом [count]json. В результате
декодирования определяется подстрока [len]str.
\pre Указатель json корректен.
\pre Любой из указателей str и len может быть нулевым.
\return Обработанная при декодировании длина JSON-кода (включая
предваряющие и завершающие пробелы) или SIZE_MAX в случае ошибки.
\remark Декодирование состоит в исключении пробелов и окаймляющих
кавычек.
*/
size_t jsonStrDec(
const char** str, /*!< [out] подстрока */
size_t* len, /*!< [out] длина подстроки */
const char json[], /*!< [in] код */
size_t count /*!< [in] длина кода */
);
/*! \brief Декодирование строки
Декодируется число size, заданное кодом [count]json.
\pre Указатель json корректен.
\pre Указатель size может быть нулевым и тогда декодированное
число не возвращается.
\return Обработанная при декодировании длина JSON-кода (включая
предваряющие и завершающие пробелы) или SIZE_MAX в случае ошибки.
\remark Код SIZE_MAX будет вовзращен, если число не укладывается
в size_t.
*/
size_t jsonSizeDec(
size_t* size, /*!< [out] число */
const char json[], /*!< [in] код */
size_t count /*!< [in] длина кода */
);
/*! \brief Декодирование объекта
Декодируется объект JSON, заданный кодом [count]json. В результате
декодирования определяются вложенные в объект элементы [names_count]elems
с именами [names_count]names: elems[i] -- это элемент с именем names[i].
\pre Указатели json, names и elems корректны.
\return Обработанная при декодировании длина JSON-кода (включая
предваряющие и завершающие пробелы) или SIZE_MAX в случае ошибки.
\remark При повторе имен в names, при отсутствии нужного элемента и при
наличии лишних элементов будет возвращена ошибка.
*/
size_t jsonObjDec(
json_elem_t elems[], /*!< [out] элементы */
const char json[], /*!< [in] код */
size_t count, /*!< [in] длина кода */
const char* const names[], /*!< [in] имена элементов */
size_t names_count /*!< [in] число элементов */
);
/*! \brief Декодирование массива
Декодируется массив JSON, заданный кодом [count]json. В результате
декодирования определяются вложенные в массив элементы [elems_count?]elems.
\pre Указатель json корректен.
\pre Любой из указателей elems и count может быть нулевым.
\return Обработанная при декодировании длина JSON-кода (включая
предваряющие и завершающие пробелы) или SIZE_MAX в случае ошибки.
*/
size_t jsonArrDec(
json_elem_t elems[], /*!< [out] элементы */
size_t* elems_count, /*!< [out] число элементов */
const char json[], /*!< [in] код */
size_t count /*!< [in] длина кода */
);
/*! \brief Кодирование по форматной строке
По форматной строке fmt и аргументам ... в буфере [size]json формируется
JSON-код и возвращается его длина. Код размещается с начала буфера и
завершается символом '\0'. Завершающий '\0' не учитывается в возвращеемой
длине кода, но должен учитываться во входном размере буфера size.
При передаче нулевого json и (или) нулевого size код не формируется, но
его длина все равно возвращается.
\pre Строка fmt корректна.
\expect Строка fmt и аргументы дают корректный код.
\return Длина кода или SIZE_MAX в случае ошибки.
\remark Ошибкой считается ситуация, когда код не умещается в буфере,
т.е. его длина count >= size.
\remark Корректность кода можно проверить с помощью jsonIsValid().
*/
size_t jsonFmtEnc(
char json[], /*!< [out] буфер для кода */
size_t size, /*!< [out] объем буфера */
const char* fmt, /*!< [in] форматная строка */
... /*!< [in] аргументы */
);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* __BEE2_JSON_H */