Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2013-2017 MsgPuck Authors
3 : : * All rights reserved.
4 : : *
5 : : * Redistribution and use in source and binary forms, with or
6 : : * without modification, are permitted provided that the following
7 : : * conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above
10 : : * copyright notice, this list of conditions and the
11 : : * following disclaimer.
12 : : *
13 : : * 2. Redistributions in binary form must reproduce the above
14 : : * copyright notice, this list of conditions and the following
15 : : * disclaimer in the documentation and/or other materials
16 : : * provided with the distribution.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
19 : : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20 : : * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22 : : * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
23 : : * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 : : * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
26 : : * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
27 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 : : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
29 : : * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 : : * SUCH DAMAGE.
31 : : */
32 : :
33 : : #define MP_LIBRARY 1
34 : : #include "msgpuck.h"
35 : :
36 : : size_t
37 : 0 : mp_vformat(char *data, size_t data_size, const char *format, va_list vl)
38 : : {
39 : 0 : size_t result = 0;
40 : 0 : const char *f = NULL;
41 : :
42 [ # # ]: 0 : for (f = format; *f; f++) {
43 [ # # ]: 0 : if (f[0] == '[') {
44 : 0 : uint32_t size = 0;
45 : 0 : int level = 1;
46 : 0 : const char *e = NULL;
47 : :
48 [ # # # # ]: 0 : for (e = f + 1; level && *e; e++) {
49 [ # # # # ]: 0 : if (*e == '[' || *e == '{') {
50 [ # # ]: 0 : if (level == 1)
51 : 0 : size++;
52 : 0 : level++;
53 [ # # # # ]: 0 : } else if (*e == ']' || *e == '}') {
54 : 0 : level--;
55 : : /* opened '[' must be closed by ']' */
56 [ # # # # ]: 0 : assert(level || *e == ']');
57 [ # # ]: 0 : } else if (*e == '%') {
58 [ # # ]: 0 : if (e[1] == '%')
59 : 0 : e++;
60 [ # # ]: 0 : else if (level == 1)
61 : 0 : size++;
62 [ # # # # ]: 0 : } else if (*e == 'N' && e[1] == 'I'
63 [ # # # # ]: 0 : && e[2] == 'L' && level == 1) {
64 : 0 : size++;
65 : 0 : }
66 : 0 : }
67 : : /* opened '[' must be closed */
68 [ # # ]: 0 : assert(level == 0);
69 : 0 : result += mp_sizeof_array(size);
70 [ # # ]: 0 : if (result <= data_size)
71 : 0 : data = mp_encode_array(data, size);
72 [ # # ]: 0 : } else if (f[0] == '{') {
73 : 0 : uint32_t count = 0;
74 : 0 : int level = 1;
75 : 0 : const char *e = NULL;
76 : :
77 [ # # # # ]: 0 : for (e = f + 1; level && *e; e++) {
78 [ # # # # ]: 0 : if (*e == '[' || *e == '{') {
79 [ # # ]: 0 : if (level == 1)
80 : 0 : count++;
81 : 0 : level++;
82 [ # # # # ]: 0 : } else if (*e == ']' || *e == '}') {
83 : 0 : level--;
84 : : /* opened '{' must be closed by '}' */
85 [ # # # # ]: 0 : assert(level || *e == '}');
86 [ # # ]: 0 : } else if (*e == '%') {
87 [ # # ]: 0 : if (e[1] == '%')
88 : 0 : e++;
89 [ # # ]: 0 : else if (level == 1)
90 : 0 : count++;
91 [ # # # # ]: 0 : } else if (*e == 'N' && e[1] == 'I'
92 [ # # # # ]: 0 : && e[2] == 'L' && level == 1) {
93 : 0 : count++;
94 : 0 : }
95 : 0 : }
96 : : /* opened '{' must be closed */
97 [ # # ]: 0 : assert(level == 0);
98 : : /* since map is a pair list, count must be even */
99 [ # # ]: 0 : assert(count % 2 == 0);
100 : 0 : uint32_t size = count / 2;
101 : 0 : result += mp_sizeof_map(size);
102 [ # # ]: 0 : if (result <= data_size)
103 : 0 : data = mp_encode_map(data, size);
104 [ # # ]: 0 : } else if (f[0] == '%') {
105 : 0 : f++;
106 [ # # ]: 0 : assert(f[0]);
107 : 0 : int64_t int_value = 0;
108 : 0 : int int_status = 0; /* 1 - signed, 2 - unsigned */
109 : :
110 [ # # # # ]: 0 : if (f[0] == 'd' || f[0] == 'i') {
111 [ # # ]: 0 : int_value = va_arg(vl, int);
112 : 0 : int_status = 1;
113 [ # # ]: 0 : } else if (f[0] == 'u') {
114 [ # # ]: 0 : int_value = va_arg(vl, unsigned int);
115 : 0 : int_status = 2;
116 [ # # ]: 0 : } else if (f[0] == 's') {
117 [ # # ]: 0 : const char *str = va_arg(vl, const char *);
118 : 0 : uint32_t len = (uint32_t)strlen(str);
119 : 0 : result += mp_sizeof_str(len);
120 [ # # ]: 0 : if (result <= data_size)
121 : 0 : data = mp_encode_str(data, str, len);
122 [ # # # # : 0 : } else if (f[0] == '.' && f[1] == '*' && f[2] == 's') {
# # ]
123 [ # # ]: 0 : uint32_t len = va_arg(vl, uint32_t);
124 [ # # ]: 0 : const char *str = va_arg(vl, const char *);
125 : 0 : result += mp_sizeof_str(len);
126 [ # # ]: 0 : if (result <= data_size)
127 : 0 : data = mp_encode_str(data, str, len);
128 : 0 : f += 2;
129 [ # # ]: 0 : } else if (f[0] == 'p') {
130 [ # # ]: 0 : const char *p = va_arg(vl, const char *);
131 : 0 : const char *end = p;
132 : 0 : mp_next(&end);
133 : 0 : uint32_t len = end - p;
134 : 0 : result += len;
135 [ # # ]: 0 : if (result <= data_size) {
136 : 0 : memcpy(data, p, len);
137 : 0 : data += len;
138 : 0 : }
139 [ # # # # : 0 : } else if (f[0] == '.' && f[1] == '*' && f[2] == 'p') {
# # ]
140 [ # # ]: 0 : uint32_t len = va_arg(vl, uint32_t);
141 [ # # ]: 0 : const char *p = va_arg(vl, const char *);
142 [ # # ]: 0 : assert(len > 0);
143 : 0 : result += len;
144 [ # # ]: 0 : if (result <= data_size) {
145 : 0 : memcpy(data, p, len);
146 : 0 : data += len;
147 : 0 : }
148 : 0 : f += 2;
149 [ # # ]: 0 : } else if(f[0] == 'f') {
150 [ # # ]: 0 : float v = (float)va_arg(vl, double);
151 : 0 : result += mp_sizeof_float(v);
152 [ # # ]: 0 : if (result <= data_size)
153 : 0 : data = mp_encode_float(data, v);
154 [ # # # # ]: 0 : } else if(f[0] == 'l' && f[1] == 'f') {
155 [ # # ]: 0 : double v = va_arg(vl, double);
156 : 0 : result += mp_sizeof_double(v);
157 [ # # ]: 0 : if (result <= data_size)
158 : 0 : data = mp_encode_double(data, v);
159 : 0 : f++;
160 [ # # ]: 0 : } else if(f[0] == 'b') {
161 [ # # ]: 0 : bool v = (bool)va_arg(vl, int);
162 : 0 : result += mp_sizeof_bool(v);
163 [ # # ]: 0 : if (result <= data_size)
164 : 0 : data = mp_encode_bool(data, v);
165 [ # # ]: 0 : } else if (f[0] == 'l'
166 [ # # # # ]: 0 : && (f[1] == 'd' || f[1] == 'i')) {
167 [ # # ]: 0 : int_value = va_arg(vl, long);
168 : 0 : int_status = 1;
169 : 0 : f++;
170 [ # # # # ]: 0 : } else if (f[0] == 'l' && f[1] == 'u') {
171 [ # # ]: 0 : int_value = va_arg(vl, unsigned long);
172 : 0 : int_status = 2;
173 : 0 : f++;
174 [ # # # # ]: 0 : } else if (f[0] == 'l' && f[1] == 'l'
175 [ # # # # ]: 0 : && (f[2] == 'd' || f[2] == 'i')) {
176 [ # # ]: 0 : int_value = va_arg(vl, long long);
177 : 0 : int_status = 1;
178 : 0 : f += 2;
179 [ # # # # : 0 : } else if (f[0] == 'l' && f[1] == 'l' && f[2] == 'u') {
# # ]
180 [ # # ]: 0 : int_value = va_arg(vl, unsigned long long);
181 : 0 : int_status = 2;
182 : 0 : f += 2;
183 [ # # ]: 0 : } else if (f[0] == 'h'
184 [ # # # # ]: 0 : && (f[1] == 'd' || f[1] == 'i')) {
185 [ # # ]: 0 : int_value = va_arg(vl, int);
186 : 0 : int_status = 1;
187 : 0 : f++;
188 [ # # # # ]: 0 : } else if (f[0] == 'h' && f[1] == 'u') {
189 [ # # ]: 0 : int_value = va_arg(vl, unsigned int);
190 : 0 : int_status = 2;
191 : 0 : f++;
192 [ # # # # ]: 0 : } else if (f[0] == 'h' && f[1] == 'h'
193 [ # # # # ]: 0 : && (f[2] == 'd' || f[2] == 'i')) {
194 [ # # ]: 0 : int_value = va_arg(vl, int);
195 : 0 : int_status = 1;
196 : 0 : f += 2;
197 [ # # # # : 0 : } else if (f[0] == 'h' && f[1] == 'h' && f[2] == 'u') {
# # ]
198 [ # # ]: 0 : int_value = va_arg(vl, unsigned int);
199 : 0 : int_status = 2;
200 : 0 : f += 2;
201 [ # # ]: 0 : } else if (f[0] != '%') {
202 : : /* unexpected format specifier */
203 : 0 : assert(false);
204 : : }
205 : :
206 [ # # # # ]: 0 : if (int_status == 1 && int_value < 0) {
207 : 0 : result += mp_sizeof_int(int_value);
208 [ # # ]: 0 : if (result <= data_size)
209 : 0 : data = mp_encode_int(data, int_value);
210 [ # # ]: 0 : } else if(int_status) {
211 : 0 : result += mp_sizeof_uint(int_value);
212 [ # # ]: 0 : if (result <= data_size)
213 : 0 : data = mp_encode_uint(data, int_value);
214 : 0 : }
215 [ # # # # : 0 : } else if (f[0] == 'N' && f[1] == 'I' && f[2] == 'L') {
# # ]
216 : 0 : result += mp_sizeof_nil();
217 [ # # ]: 0 : if (result <= data_size)
218 : 0 : data = mp_encode_nil(data);
219 : 0 : f += 2;
220 : 0 : }
221 : 0 : }
222 : 0 : return result;
223 : : }
224 : :
225 : : size_t
226 : 0 : mp_format(char *data, size_t data_size, const char *format, ...)
227 : : {
228 : : va_list args;
229 : 0 : va_start(args, format);
230 : 0 : size_t res = mp_vformat(data, data_size, format, args);
231 : 0 : va_end(args);
232 : 0 : return res;
233 : : }
234 : :
235 : : #define MP_PRINT(SELF, PRINTF) \
236 : : { \
237 : : switch (mp_typeof(**data)) { \
238 : : case MP_NIL: \
239 : : mp_decode_nil(data); \
240 : : PRINTF("null"); \
241 : : break; \
242 : : case MP_UINT: \
243 : : PRINTF("%llu", (unsigned long long) mp_decode_uint(data)); \
244 : : break; \
245 : : case MP_INT: \
246 : : PRINTF("%lld", (long long) mp_decode_int(data)); \
247 : : break; \
248 : : case MP_STR: \
249 : : case MP_BIN: \
250 : : { \
251 : : uint32_t len = mp_typeof(**data) == MP_STR ? \
252 : : mp_decode_strl(data) : mp_decode_binl(data); \
253 : : PRINTF("\""); \
254 : : const char *s; \
255 : : for (s = *data; s < *data + len; s++) { \
256 : : unsigned char c = (unsigned char ) *s; \
257 : : if (c < 128 && mp_char2escape[c] != NULL) { \
258 : : /* Escape character */ \
259 : : PRINTF("%s", mp_char2escape[c]); \
260 : : } else { \
261 : : PRINTF("%c", c); \
262 : : } \
263 : : } \
264 : : PRINTF("\""); \
265 : : *data += len; \
266 : : break; \
267 : : } \
268 : : case MP_ARRAY: \
269 : : { \
270 : : uint32_t count = mp_decode_array(data); \
271 : : PRINTF("["); \
272 : : uint32_t i; \
273 : : for (i = 0; i < count; i++) { \
274 : : if (i) \
275 : : PRINTF(", "); \
276 : : SELF(data); \
277 : : } \
278 : : PRINTF("]"); \
279 : : break; \
280 : : } \
281 : : case MP_MAP: \
282 : : { \
283 : : uint32_t count = mp_decode_map(data); \
284 : : PRINTF("{"); \
285 : : uint32_t i; \
286 : : for (i = 0; i < count; i++) { \
287 : : if (i) \
288 : : PRINTF(", "); \
289 : : SELF(data); \
290 : : PRINTF(": "); \
291 : : SELF(data); \
292 : : } \
293 : : PRINTF("}"); \
294 : : break; \
295 : : } \
296 : : case MP_BOOL: \
297 : : PRINTF(mp_decode_bool(data) ? "true" : "false"); \
298 : : break; \
299 : : case MP_FLOAT: \
300 : : PRINTF("%g", mp_decode_float(data)); \
301 : : break; \
302 : : case MP_DOUBLE: \
303 : : PRINTF("%lg", mp_decode_double(data)); \
304 : : break; \
305 : : case MP_EXT: \
306 : : mp_next(data); \
307 : : PRINTF("undefined"); \
308 : : break; \
309 : : default: \
310 : : mp_unreachable(); \
311 : : return -1; \
312 : : } \
313 : : }
314 : :
315 : : static inline int
316 : 0 : mp_fprint_internal(FILE *file, const char **data)
317 : : {
318 : 0 : int total_bytes = 0;
319 : : #define HANDLE(FUN, ...) do { \
320 : : int bytes = FUN(file, __VA_ARGS__); \
321 : : if (mp_unlikely(bytes < 0)) \
322 : : return -1; \
323 : : total_bytes += bytes; \
324 : : } while (0)
325 : : #define PRINT(...) HANDLE(fprintf, __VA_ARGS__)
326 : : #define SELF(...) HANDLE(mp_fprint_internal, __VA_ARGS__)
327 [ # # # # : 0 : MP_PRINT(SELF, PRINT)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # #
# ]
328 : : #undef HANDLE
329 : : #undef SELF
330 : : #undef PRINT
331 : 0 : return total_bytes;
332 : 0 : }
333 : :
334 : : int
335 : 0 : mp_fprint(FILE *file, const char *data)
336 : : {
337 [ # # ]: 0 : if (!file)
338 : 0 : file = stdout;
339 : 0 : int res = mp_fprint_internal(file, &data);
340 : 0 : return res;
341 : : }
342 : :
343 : : static inline int
344 : 0 : mp_snprint_internal(char *buf, int size, const char **data)
345 : : {
346 : 0 : int total_bytes = 0;
347 : : #define HANDLE(FUN, ...) do { \
348 : : int bytes = FUN(buf, size, __VA_ARGS__); \
349 : : if (mp_unlikely(bytes < 0)) \
350 : : return -1; \
351 : : total_bytes += bytes; \
352 : : if (bytes < size) { \
353 : : buf += bytes; \
354 : : size -= bytes; \
355 : : } else { \
356 : : /* Calculate the number of bytes needed */ \
357 : : buf = NULL; \
358 : : size = 0; \
359 : : } \
360 : : } while (0)
361 : : #define PRINT(...) HANDLE(snprintf, __VA_ARGS__)
362 : : #define SELF(...) HANDLE(mp_snprint_internal, __VA_ARGS__)
363 [ # # # # : 0 : MP_PRINT(SELF, PRINT)
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # # # #
# # ]
364 : : #undef HANDLE
365 : : #undef SELF
366 : : #undef PRINT
367 : 0 : return total_bytes;
368 : 0 : }
369 : : #undef MP_PRINT
370 : :
371 : : int
372 : 0 : mp_snprint(char *buf, int size, const char *data)
373 : : {
374 : 0 : return mp_snprint_internal(buf, size, &data);
375 : : }
|