1/*
2 * Copyright (c) 2015-2021 Nicholas Fraser and the MPack authors
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy of
5 * this software and associated documentation files (the "Software"), to deal in
6 * the Software without restriction, including without limitation the rights to
7 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
8 * the Software, and to permit persons to whom the Software is furnished to do so,
9 * subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in all
12 * copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
16 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
17 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
18 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22#define MPACK_INTERNAL 1
23
24#include "mpack-reader.h"
25
26MPACK_SILENCE_WARNINGS_BEGIN
27
28#if MPACK_READER
29
30static void mpack_reader_skip_using_fill(mpack_reader_t* reader, size_t count);
31
32void mpack_reader_init(mpack_reader_t* reader, char* buffer, size_t size, size_t count) {
33 mpack_assert(buffer != NULL, "buffer is NULL");
34
35 mpack_memset(reader, 0, sizeof(*reader));
36 reader->buffer = buffer;
37 reader->size = size;
38 reader->data = buffer;
39 reader->end = buffer + count;
40
41 #if MPACK_READ_TRACKING
42 mpack_reader_flag_if_error(reader, mpack_track_init(&reader->track));
43 #endif
44
45 mpack_log("===========================\n");
46 mpack_log("initializing reader with buffer size %i\n", (int)size);
47}
48
49void mpack_reader_init_error(mpack_reader_t* reader, mpack_error_t error) {
50 mpack_memset(reader, 0, sizeof(*reader));
51 reader->error = error;
52
53 mpack_log("===========================\n");
54 mpack_log("initializing reader error state %i\n", (int)error);
55}
56
57void mpack_reader_init_data(mpack_reader_t* reader, const char* data, size_t count) {
58 mpack_assert(data != NULL, "data is NULL");
59
60 mpack_memset(reader, 0, sizeof(*reader));
61 reader->data = data;
62 reader->end = data + count;
63
64 #if MPACK_READ_TRACKING
65 mpack_reader_flag_if_error(reader, mpack_track_init(&reader->track));
66 #endif
67
68 mpack_log("===========================\n");
69 mpack_log("initializing reader with data size %i\n", (int)count);
70}
71
72void mpack_reader_set_fill(mpack_reader_t* reader, mpack_reader_fill_t fill) {
73 MPACK_STATIC_ASSERT(MPACK_READER_MINIMUM_BUFFER_SIZE >= MPACK_MAXIMUM_TAG_SIZE,
74 "minimum buffer size must fit any tag!");
75
76 if (reader->size == 0) {
77 mpack_break("cannot use fill function without a writeable buffer!");
78 mpack_reader_flag_error(reader, mpack_error_bug);
79 return;
80 }
81
82 if (reader->size < MPACK_READER_MINIMUM_BUFFER_SIZE) {
83 mpack_break("buffer size is %i, but minimum buffer size for fill is %i",
84 (int)reader->size, MPACK_READER_MINIMUM_BUFFER_SIZE);
85 mpack_reader_flag_error(reader, mpack_error_bug);
86 return;
87 }
88
89 reader->fill = fill;
90}
91
92void mpack_reader_set_skip(mpack_reader_t* reader, mpack_reader_skip_t skip) {
93 mpack_assert(reader->size != 0, "cannot use skip function without a writeable buffer!");
94 reader->skip = skip;
95}
96
97#if MPACK_STDIO
98static size_t mpack_file_reader_fill(mpack_reader_t* reader, char* buffer, size_t count) {
99 if (feof((FILE *)reader->context)) {
100 mpack_reader_flag_error(reader, mpack_error_eof);
101 return 0;
102 }
103 return fread((void*)buffer, 1, count, (FILE*)reader->context);
104}
105
106static void mpack_file_reader_skip(mpack_reader_t* reader, size_t count) {
107 if (mpack_reader_error(reader) != mpack_ok)
108 return;
109 FILE* file = (FILE*)reader->context;
110
111 // We call ftell() to test whether the stream is seekable
112 // without causing a file error.
113 if (ftell(file) >= 0) {
114 mpack_log("seeking forward %i bytes\n", (int)count);
115 if (fseek(file, (long int)count, SEEK_CUR) == 0)
116 return;
117 mpack_log("fseek() didn't return zero!\n");
118 if (ferror(file)) {
119 mpack_reader_flag_error(reader, mpack_error_io);
120 return;
121 }
122 }
123
124 // If the stream is not seekable, fall back to the fill function.
125 mpack_reader_skip_using_fill(reader, count);
126}
127
128static void mpack_file_reader_teardown(mpack_reader_t* reader) {
129 MPACK_FREE(reader->buffer);
130 reader->buffer = NULL;
131 reader->context = NULL;
132 reader->size = 0;
133 reader->fill = NULL;
134 reader->skip = NULL;
135 reader->teardown = NULL;
136}
137
138static void mpack_file_reader_teardown_close(mpack_reader_t* reader) {
139 FILE* file = (FILE*)reader->context;
140
141 if (file) {
142 int ret = fclose(file);
143 if (ret != 0)
144 mpack_reader_flag_error(reader, mpack_error_io);
145 }
146
147 mpack_file_reader_teardown(reader);
148}
149
150void mpack_reader_init_stdfile(mpack_reader_t* reader, FILE* file, bool close_when_done) {
151 mpack_assert(file != NULL, "file is NULL");
152
153 size_t capacity = MPACK_BUFFER_SIZE;
154 char* buffer = (char*)MPACK_MALLOC(capacity);
155 if (buffer == NULL) {
156 mpack_reader_init_error(reader, mpack_error_memory);
157 if (close_when_done) {
158 fclose(file);
159 }
160 return;
161 }
162
163 mpack_reader_init(reader, buffer, capacity, 0);
164 mpack_reader_set_context(reader, file);
165 mpack_reader_set_fill(reader, mpack_file_reader_fill);
166 mpack_reader_set_skip(reader, mpack_file_reader_skip);
167 mpack_reader_set_teardown(reader, close_when_done ?
168 mpack_file_reader_teardown_close :
169 mpack_file_reader_teardown);
170}
171
172void mpack_reader_init_filename(mpack_reader_t* reader, const char* filename) {
173 mpack_assert(filename != NULL, "filename is NULL");
174
175 FILE* file = fopen(filename, "rb");
176 if (file == NULL) {
177 mpack_reader_init_error(reader, mpack_error_io);
178 return;
179 }
180
181 mpack_reader_init_stdfile(reader, file, true);
182}
183#endif
184
185mpack_error_t mpack_reader_destroy(mpack_reader_t* reader) {
186
187 // clean up tracking, asserting if we're not already in an error state
188 #if MPACK_READ_TRACKING
189 mpack_reader_flag_if_error(reader, mpack_track_destroy(&reader->track, mpack_reader_error(reader) != mpack_ok));
190 #endif
191
192 if (reader->teardown)
193 reader->teardown(reader);
194 reader->teardown = NULL;
195
196 return reader->error;
197}
198
199size_t mpack_reader_remaining(mpack_reader_t* reader, const char** data) {
200 if (mpack_reader_error(reader) != mpack_ok)
201 return 0;
202
203 #if MPACK_READ_TRACKING
204 if (mpack_reader_flag_if_error(reader, mpack_track_check_empty(&reader->track)) != mpack_ok)
205 return 0;
206 #endif
207
208 if (data)
209 *data = reader->data;
210 return (size_t)(reader->end - reader->data);
211}
212
213void mpack_reader_flag_error(mpack_reader_t* reader, mpack_error_t error) {
214 mpack_log("reader %p setting error %i: %s\n", (void*)reader, (int)error, mpack_error_to_string(error));
215
216 if (reader->error == mpack_ok) {
217 reader->error = error;
218 reader->end = reader->data;
219 if (reader->error_fn)
220 reader->error_fn(reader, error);
221 }
222}
223
224// Loops on the fill function, reading between the minimum and
225// maximum number of bytes and flagging an error if it fails.
226MPACK_NOINLINE static size_t mpack_fill_range(mpack_reader_t* reader, char* p, size_t min_bytes, size_t max_bytes) {
227 mpack_assert(reader->fill != NULL, "mpack_fill_range() called with no fill function?");
228 mpack_assert(min_bytes > 0, "cannot fill zero bytes!");
229 mpack_assert(max_bytes >= min_bytes, "min_bytes %i cannot be larger than max_bytes %i!",
230 (int)min_bytes, (int)max_bytes);
231
232 size_t count = 0;
233 while (count < min_bytes) {
234 size_t read = reader->fill(reader, p + count, max_bytes - count);
235
236 // Reader fill functions can flag an error or return 0 on failure. We
237 // also guard against functions that return -1 just in case.
238 if (mpack_reader_error(reader) != mpack_ok)
239 return 0;
240 if (read == 0 || read == ((size_t)(-1))) {
241 mpack_reader_flag_error(reader, mpack_error_io);
242 return 0;
243 }
244
245 count += read;
246 }
247 return count;
248}
249
250MPACK_NOINLINE bool mpack_reader_ensure_straddle(mpack_reader_t* reader, size_t count) {
251 mpack_assert(count != 0, "cannot ensure zero bytes!");
252 mpack_assert(reader->error == mpack_ok, "reader cannot be in an error state!");
253
254 mpack_assert(count > (size_t)(reader->end - reader->data),
255 "straddling ensure requested for %i bytes, but there are %i bytes "
256 "left in buffer. call mpack_reader_ensure() instead",
257 (int)count, (int)(reader->end - reader->data));
258
259 // we'll need a fill function to get more data. if there's no
260 // fill function, the buffer should contain an entire MessagePack
261 // object, so we raise mpack_error_invalid instead of mpack_error_io
262 // on truncated data.
263 if (reader->fill == NULL) {
264 mpack_reader_flag_error(reader, mpack_error_invalid);
265 return false;
266 }
267
268 // we need enough space in the buffer. if the buffer is not
269 // big enough, we return mpack_error_too_big (since this is
270 // for an in-place read larger than the buffer size.)
271 if (count > reader->size) {
272 mpack_reader_flag_error(reader, mpack_error_too_big);
273 return false;
274 }
275
276 // move the existing data to the start of the buffer
277 size_t left = (size_t)(reader->end - reader->data);
278 mpack_memmove(reader->buffer, reader->data, left);
279 reader->end -= reader->data - reader->buffer;
280 reader->data = reader->buffer;
281
282 // read at least the necessary number of bytes, accepting up to the
283 // buffer size
284 size_t read = mpack_fill_range(reader, reader->buffer + left,
285 count - left, reader->size - left);
286 if (mpack_reader_error(reader) != mpack_ok)
287 return false;
288 reader->end += read;
289 return true;
290}
291
292// Reads count bytes into p. Used when there are not enough bytes
293// left in the buffer to satisfy a read.
294MPACK_NOINLINE void mpack_read_native_straddle(mpack_reader_t* reader, char* p, size_t count) {
295 mpack_assert(count == 0 || p != NULL, "data pointer for %i bytes is NULL", (int)count);
296
297 if (mpack_reader_error(reader) != mpack_ok) {
298 mpack_memset(p, 0, count);
299 return;
300 }
301
302 size_t left = (size_t)(reader->end - reader->data);
303 mpack_log("big read for %i bytes into %p, %i left in buffer, buffer size %i\n",
304 (int)count, p, (int)left, (int)reader->size);
305
306 if (count <= left) {
307 mpack_assert(0,
308 "big read requested for %i bytes, but there are %i bytes "
309 "left in buffer. call mpack_read_native() instead",
310 (int)count, (int)left);
311 mpack_reader_flag_error(reader, mpack_error_bug);
312 mpack_memset(p, 0, count);
313 return;
314 }
315
316 // we'll need a fill function to get more data. if there's no
317 // fill function, the buffer should contain an entire MessagePack
318 // object, so we raise mpack_error_invalid instead of mpack_error_io
319 // on truncated data.
320 if (reader->fill == NULL) {
321 mpack_reader_flag_error(reader, mpack_error_invalid);
322 mpack_memset(p, 0, count);
323 return;
324 }
325
326 if (reader->size == 0) {
327 // somewhat debatable what error should be returned here. when
328 // initializing a reader with an in-memory buffer it's not
329 // necessarily a bug if the data is blank; it might just have
330 // been truncated to zero. for this reason we return the same
331 // error as if the data was truncated.
332 mpack_reader_flag_error(reader, mpack_error_io);
333 mpack_memset(p, 0, count);
334 return;
335 }
336
337 // flush what's left of the buffer
338 if (left > 0) {
339 mpack_log("flushing %i bytes remaining in buffer\n", (int)left);
340 mpack_memcpy(p, reader->data, left);
341 count -= left;
342 p += left;
343 reader->data += left;
344 }
345
346 // if the remaining data needed is some small fraction of the
347 // buffer size, we'll try to fill the buffer as much as possible
348 // and copy the needed data out.
349 if (count <= reader->size / MPACK_READER_SMALL_FRACTION_DENOMINATOR) {
350 size_t read = mpack_fill_range(reader, reader->buffer, count, reader->size);
351 if (mpack_reader_error(reader) != mpack_ok)
352 return;
353 mpack_memcpy(p, reader->buffer, count);
354 reader->data = reader->buffer + count;
355 reader->end = reader->buffer + read;
356
357 // otherwise we read the remaining data directly into the target.
358 } else {
359 mpack_log("reading %i additional bytes\n", (int)count);
360 mpack_fill_range(reader, p, count, count);
361 }
362}
363
364MPACK_NOINLINE static void mpack_skip_bytes_straddle(mpack_reader_t* reader, size_t count) {
365
366 // we'll need at least a fill function to skip more data. if there's
367 // no fill function, the buffer should contain an entire MessagePack
368 // object, so we raise mpack_error_invalid instead of mpack_error_io
369 // on truncated data. (see mpack_read_native_straddle())
370 if (reader->fill == NULL) {
371 mpack_log("reader has no fill function!\n");
372 mpack_reader_flag_error(reader, mpack_error_invalid);
373 return;
374 }
375
376 // discard whatever's left in the buffer
377 size_t left = (size_t)(reader->end - reader->data);
378 mpack_log("discarding %i bytes still in buffer\n", (int)left);
379 count -= left;
380 reader->data = reader->end;
381
382 // use the skip function if we've got one, and if we're trying
383 // to skip a lot of data. if we only need to skip some tiny
384 // fraction of the buffer size, it's probably better to just
385 // fill the buffer and skip from it instead of trying to seek.
386 if (reader->skip && count > reader->size / 16) {
387 mpack_log("calling skip function for %i bytes\n", (int)count);
388 reader->skip(reader, count);
389 return;
390 }
391
392 mpack_reader_skip_using_fill(reader, count);
393}
394
395void mpack_skip_bytes(mpack_reader_t* reader, size_t count) {
396 if (mpack_reader_error(reader) != mpack_ok)
397 return;
398 mpack_log("skip requested for %i bytes\n", (int)count);
399
400 mpack_reader_track_bytes(reader, count);
401
402 // check if we have enough in the buffer already
403 size_t left = (size_t)(reader->end - reader->data);
404 if (left >= count) {
405 mpack_log("skipping %" PRIu32 " bytes still in buffer\n", (uint32_t)count);
406 reader->data += count;
407 return;
408 }
409
410 mpack_skip_bytes_straddle(reader, count);
411}
412
413MPACK_NOINLINE static void mpack_reader_skip_using_fill(mpack_reader_t* reader, size_t count) {
414 mpack_assert(reader->fill != NULL, "missing fill function!");
415 mpack_assert(reader->data == reader->end, "there are bytes left in the buffer!");
416 mpack_assert(reader->error == mpack_ok, "should not have called this in an error state (%i)", reader->error);
417 mpack_log("skip using fill for %i bytes\n", (int)count);
418
419 // fill and discard multiples of the buffer size
420 while (count > reader->size) {
421 mpack_log("filling and discarding buffer of %i bytes\n", (int)reader->size);
422 if (mpack_fill_range(reader, reader->buffer, reader->size, reader->size) < reader->size) {
423 mpack_reader_flag_error(reader, mpack_error_io);
424 return;
425 }
426 count -= reader->size;
427 }
428
429 // fill the buffer as much as possible
430 reader->data = reader->buffer;
431 size_t read = mpack_fill_range(reader, reader->buffer, count, reader->size);
432 if (read < count) {
433 mpack_reader_flag_error(reader, mpack_error_io);
434 return;
435 }
436 reader->end = reader->data + read;
437 mpack_log("filled %i bytes into buffer; discarding %i bytes\n", (int)read, (int)count);
438 reader->data += count;
439}
440
441void mpack_read_bytes(mpack_reader_t* reader, char* p, size_t count) {
442 mpack_assert(p != NULL, "destination for read of %i bytes is NULL", (int)count);
443 mpack_reader_track_bytes(reader, count);
444 mpack_read_native(reader, p, count);
445}
446
447void mpack_read_utf8(mpack_reader_t* reader, char* p, size_t byte_count) {
448 mpack_assert(p != NULL, "destination for read of %i bytes is NULL", (int)byte_count);
449 mpack_reader_track_str_bytes_all(reader, byte_count);
450 mpack_read_native(reader, p, byte_count);
451
452 if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(p, byte_count))
453 mpack_reader_flag_error(reader, mpack_error_type);
454}
455
456static void mpack_read_cstr_unchecked(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
457 mpack_assert(buf != NULL, "destination for read of %i bytes is NULL", (int)byte_count);
458 mpack_assert(buffer_size >= 1, "buffer size is zero; you must have room for at least a null-terminator");
459
460 if (mpack_reader_error(reader)) {
461 buf[0] = 0;
462 return;
463 }
464
465 if (byte_count > buffer_size - 1) {
466 mpack_reader_flag_error(reader, mpack_error_too_big);
467 buf[0] = 0;
468 return;
469 }
470
471 mpack_reader_track_str_bytes_all(reader, byte_count);
472 mpack_read_native(reader, buf, byte_count);
473 buf[byte_count] = 0;
474}
475
476void mpack_read_cstr(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
477 mpack_read_cstr_unchecked(reader, buf, buffer_size, byte_count);
478
479 // check for null bytes
480 if (mpack_reader_error(reader) == mpack_ok && !mpack_str_check_no_null(buf, byte_count)) {
481 buf[0] = 0;
482 mpack_reader_flag_error(reader, mpack_error_type);
483 }
484}
485
486void mpack_read_utf8_cstr(mpack_reader_t* reader, char* buf, size_t buffer_size, size_t byte_count) {
487 mpack_read_cstr_unchecked(reader, buf, buffer_size, byte_count);
488
489 // check encoding
490 if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check_no_null(buf, byte_count)) {
491 buf[0] = 0;
492 mpack_reader_flag_error(reader, mpack_error_type);
493 }
494}
495
496#ifdef MPACK_MALLOC
497// Reads native bytes with error callback disabled. This allows MPack reader functions
498// to hold an allocated buffer and read native data into it without leaking it in
499// case of a non-local jump (longjmp, throw) out of an error handler.
500static void mpack_read_native_noerrorfn(mpack_reader_t* reader, char* p, size_t count) {
501 mpack_assert(reader->error == mpack_ok, "cannot call if an error is already flagged!");
502 mpack_reader_error_t error_fn = reader->error_fn;
503 reader->error_fn = NULL;
504 mpack_read_native(reader, p, count);
505 reader->error_fn = error_fn;
506}
507
508char* mpack_read_bytes_alloc_impl(mpack_reader_t* reader, size_t count, bool null_terminated) {
509
510 // track the bytes first in case it jumps
511 mpack_reader_track_bytes(reader, count);
512 if (mpack_reader_error(reader) != mpack_ok)
513 return NULL;
514
515 // cannot allocate zero bytes. this is not an error.
516 if (count == 0 && null_terminated == false)
517 return NULL;
518
519 // allocate data
520 char* data = (char*)MPACK_MALLOC(count + (null_terminated ? 1 : 0)); // TODO: can this overflow?
521 if (data == NULL) {
522 mpack_reader_flag_error(reader, mpack_error_memory);
523 return NULL;
524 }
525
526 // read with error callback disabled so we don't leak our buffer
527 mpack_read_native_noerrorfn(reader, data, count);
528
529 // report flagged errors
530 if (mpack_reader_error(reader) != mpack_ok) {
531 MPACK_FREE(data);
532 if (reader->error_fn)
533 reader->error_fn(reader, mpack_reader_error(reader));
534 return NULL;
535 }
536
537 if (null_terminated)
538 data[count] = '\0';
539 return data;
540}
541#endif
542
543// read inplace without tracking (since there are different
544// tracking modes for different inplace readers)
545static const char* mpack_read_bytes_inplace_notrack(mpack_reader_t* reader, size_t count) {
546 if (mpack_reader_error(reader) != mpack_ok)
547 return NULL;
548
549 // if we have enough bytes already in the buffer, we can return it directly.
550 if ((size_t)(reader->end - reader->data) >= count) {
551 const char* bytes = reader->data;
552 reader->data += count;
553 return bytes;
554 }
555
556 if (!mpack_reader_ensure(reader, count))
557 return NULL;
558
559 const char* bytes = reader->data;
560 reader->data += count;
561 return bytes;
562}
563
564const char* mpack_read_bytes_inplace(mpack_reader_t* reader, size_t count) {
565 mpack_reader_track_bytes(reader, count);
566 return mpack_read_bytes_inplace_notrack(reader, count);
567}
568
569const char* mpack_read_utf8_inplace(mpack_reader_t* reader, size_t count) {
570 mpack_reader_track_str_bytes_all(reader, count);
571 const char* str = mpack_read_bytes_inplace_notrack(reader, count);
572
573 if (mpack_reader_error(reader) == mpack_ok && !mpack_utf8_check(str, count)) {
574 mpack_reader_flag_error(reader, mpack_error_type);
575 return NULL;
576 }
577
578 return str;
579}
580
581static size_t mpack_parse_tag(mpack_reader_t* reader, mpack_tag_t* tag) {
582 mpack_assert(reader->error == mpack_ok, "reader cannot be in an error state!");
583
584 if (!mpack_reader_ensure(reader, 1))
585 return 0;
586 uint8_t type = mpack_load_u8(reader->data);
587
588 // unfortunately, by far the fastest way to parse a tag is to switch
589 // on the first byte, and to explicitly list every possible byte. so for
590 // infix types, the list of cases is quite large.
591 //
592 // in size-optimized builds, we switch on the top four bits first to
593 // handle most infix types with a smaller jump table to save space.
594
595 #if MPACK_OPTIMIZE_FOR_SIZE
596 switch (type >> 4) {
597
598 // positive fixnum
599 case 0x0: case 0x1: case 0x2: case 0x3:
600 case 0x4: case 0x5: case 0x6: case 0x7:
601 *tag = mpack_tag_make_uint(type);
602 return 1;
603
604 // negative fixnum
605 case 0xe: case 0xf:
606 *tag = mpack_tag_make_int((int8_t)type);
607 return 1;
608
609 // fixmap
610 case 0x8:
611 *tag = mpack_tag_make_map(type & ~0xf0u);
612 return 1;
613
614 // fixarray
615 case 0x9:
616 *tag = mpack_tag_make_array(type & ~0xf0u);
617 return 1;
618
619 // fixstr
620 case 0xa: case 0xb:
621 *tag = mpack_tag_make_str(type & ~0xe0u);
622 return 1;
623
624 // not one of the common infix types
625 default:
626 break;
627
628 }
629 #endif
630
631 // handle individual type tags
632 switch (type) {
633
634 #if !MPACK_OPTIMIZE_FOR_SIZE
635 // positive fixnum
636 case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
637 case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: case 0x0e: case 0x0f:
638 case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
639 case 0x18: case 0x19: case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: case 0x1f:
640 case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
641 case 0x28: case 0x29: case 0x2a: case 0x2b: case 0x2c: case 0x2d: case 0x2e: case 0x2f:
642 case 0x30: case 0x31: case 0x32: case 0x33: case 0x34: case 0x35: case 0x36: case 0x37:
643 case 0x38: case 0x39: case 0x3a: case 0x3b: case 0x3c: case 0x3d: case 0x3e: case 0x3f:
644 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
645 case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
646 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57:
647 case 0x58: case 0x59: case 0x5a: case 0x5b: case 0x5c: case 0x5d: case 0x5e: case 0x5f:
648 case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
649 case 0x68: case 0x69: case 0x6a: case 0x6b: case 0x6c: case 0x6d: case 0x6e: case 0x6f:
650 case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
651 case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f:
652 *tag = mpack_tag_make_uint(type);
653 return 1;
654
655 // negative fixnum
656 case 0xe0: case 0xe1: case 0xe2: case 0xe3: case 0xe4: case 0xe5: case 0xe6: case 0xe7:
657 case 0xe8: case 0xe9: case 0xea: case 0xeb: case 0xec: case 0xed: case 0xee: case 0xef:
658 case 0xf0: case 0xf1: case 0xf2: case 0xf3: case 0xf4: case 0xf5: case 0xf6: case 0xf7:
659 case 0xf8: case 0xf9: case 0xfa: case 0xfb: case 0xfc: case 0xfd: case 0xfe: case 0xff:
660 *tag = mpack_tag_make_int((int8_t)type);
661 return 1;
662
663 // fixmap
664 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
665 case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f:
666 *tag = mpack_tag_make_map(type & ~0xf0u);
667 return 1;
668
669 // fixarray
670 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
671 case 0x98: case 0x99: case 0x9a: case 0x9b: case 0x9c: case 0x9d: case 0x9e: case 0x9f:
672 *tag = mpack_tag_make_array(type & ~0xf0u);
673 return 1;
674
675 // fixstr
676 case 0xa0: case 0xa1: case 0xa2: case 0xa3: case 0xa4: case 0xa5: case 0xa6: case 0xa7:
677 case 0xa8: case 0xa9: case 0xaa: case 0xab: case 0xac: case 0xad: case 0xae: case 0xaf:
678 case 0xb0: case 0xb1: case 0xb2: case 0xb3: case 0xb4: case 0xb5: case 0xb6: case 0xb7:
679 case 0xb8: case 0xb9: case 0xba: case 0xbb: case 0xbc: case 0xbd: case 0xbe: case 0xbf:
680 *tag = mpack_tag_make_str(type & ~0xe0u);
681 return 1;
682 #endif
683
684 // nil
685 case 0xc0:
686 *tag = mpack_tag_make_nil();
687 return 1;
688
689 // bool
690 case 0xc2: case 0xc3:
691 *tag = mpack_tag_make_bool((bool)(type & 1));
692 return 1;
693
694 // bin8
695 case 0xc4:
696 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN8))
697 return 0;
698 *tag = mpack_tag_make_bin(mpack_load_u8(reader->data + 1));
699 return MPACK_TAG_SIZE_BIN8;
700
701 // bin16
702 case 0xc5:
703 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN16))
704 return 0;
705 *tag = mpack_tag_make_bin(mpack_load_u16(reader->data + 1));
706 return MPACK_TAG_SIZE_BIN16;
707
708 // bin32
709 case 0xc6:
710 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_BIN32))
711 return 0;
712 *tag = mpack_tag_make_bin(mpack_load_u32(reader->data + 1));
713 return MPACK_TAG_SIZE_BIN32;
714
715 #if MPACK_EXTENSIONS
716 // ext8
717 case 0xc7:
718 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT8))
719 return 0;
720 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 2), mpack_load_u8(reader->data + 1));
721 return MPACK_TAG_SIZE_EXT8;
722
723 // ext16
724 case 0xc8:
725 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT16))
726 return 0;
727 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 3), mpack_load_u16(reader->data + 1));
728 return MPACK_TAG_SIZE_EXT16;
729
730 // ext32
731 case 0xc9:
732 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_EXT32))
733 return 0;
734 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 5), mpack_load_u32(reader->data + 1));
735 return MPACK_TAG_SIZE_EXT32;
736 #endif
737
738 // float
739 case 0xca:
740 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FLOAT))
741 return 0;
742 #if MPACK_FLOAT
743 *tag = mpack_tag_make_float(mpack_load_float(reader->data + 1));
744 #else
745 *tag = mpack_tag_make_raw_float(mpack_load_u32(reader->data + 1));
746 #endif
747 return MPACK_TAG_SIZE_FLOAT;
748
749 // double
750 case 0xcb:
751 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_DOUBLE))
752 return 0;
753 #if MPACK_DOUBLE
754 *tag = mpack_tag_make_double(mpack_load_double(reader->data + 1));
755 #else
756 *tag = mpack_tag_make_raw_double(mpack_load_u64(reader->data + 1));
757 #endif
758 return MPACK_TAG_SIZE_DOUBLE;
759
760 // uint8
761 case 0xcc:
762 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U8))
763 return 0;
764 *tag = mpack_tag_make_uint(mpack_load_u8(reader->data + 1));
765 return MPACK_TAG_SIZE_U8;
766
767 // uint16
768 case 0xcd:
769 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U16))
770 return 0;
771 *tag = mpack_tag_make_uint(mpack_load_u16(reader->data + 1));
772 return MPACK_TAG_SIZE_U16;
773
774 // uint32
775 case 0xce:
776 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U32))
777 return 0;
778 *tag = mpack_tag_make_uint(mpack_load_u32(reader->data + 1));
779 return MPACK_TAG_SIZE_U32;
780
781 // uint64
782 case 0xcf:
783 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_U64))
784 return 0;
785 *tag = mpack_tag_make_uint(mpack_load_u64(reader->data + 1));
786 return MPACK_TAG_SIZE_U64;
787
788 // int8
789 case 0xd0:
790 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I8))
791 return 0;
792 *tag = mpack_tag_make_int(mpack_load_i8(reader->data + 1));
793 return MPACK_TAG_SIZE_I8;
794
795 // int16
796 case 0xd1:
797 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I16))
798 return 0;
799 *tag = mpack_tag_make_int(mpack_load_i16(reader->data + 1));
800 return MPACK_TAG_SIZE_I16;
801
802 // int32
803 case 0xd2:
804 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I32))
805 return 0;
806 *tag = mpack_tag_make_int(mpack_load_i32(reader->data + 1));
807 return MPACK_TAG_SIZE_I32;
808
809 // int64
810 case 0xd3:
811 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_I64))
812 return 0;
813 *tag = mpack_tag_make_int(mpack_load_i64(reader->data + 1));
814 return MPACK_TAG_SIZE_I64;
815
816 #if MPACK_EXTENSIONS
817 // fixext1
818 case 0xd4:
819 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT1))
820 return 0;
821 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 1);
822 return MPACK_TAG_SIZE_FIXEXT1;
823
824 // fixext2
825 case 0xd5:
826 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT2))
827 return 0;
828 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 2);
829 return MPACK_TAG_SIZE_FIXEXT2;
830
831 // fixext4
832 case 0xd6:
833 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT4))
834 return 0;
835 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 4);
836 return 2;
837
838 // fixext8
839 case 0xd7:
840 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT8))
841 return 0;
842 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 8);
843 return MPACK_TAG_SIZE_FIXEXT8;
844
845 // fixext16
846 case 0xd8:
847 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_FIXEXT16))
848 return 0;
849 *tag = mpack_tag_make_ext(mpack_load_i8(reader->data + 1), 16);
850 return MPACK_TAG_SIZE_FIXEXT16;
851 #endif
852
853 // str8
854 case 0xd9:
855 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR8))
856 return 0;
857 *tag = mpack_tag_make_str(mpack_load_u8(reader->data + 1));
858 return MPACK_TAG_SIZE_STR8;
859
860 // str16
861 case 0xda:
862 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR16))
863 return 0;
864 *tag = mpack_tag_make_str(mpack_load_u16(reader->data + 1));
865 return MPACK_TAG_SIZE_STR16;
866
867 // str32
868 case 0xdb:
869 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_STR32))
870 return 0;
871 *tag = mpack_tag_make_str(mpack_load_u32(reader->data + 1));
872 return MPACK_TAG_SIZE_STR32;
873
874 // array16
875 case 0xdc:
876 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_ARRAY16))
877 return 0;
878 *tag = mpack_tag_make_array(mpack_load_u16(reader->data + 1));
879 return MPACK_TAG_SIZE_ARRAY16;
880
881 // array32
882 case 0xdd:
883 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_ARRAY32))
884 return 0;
885 *tag = mpack_tag_make_array(mpack_load_u32(reader->data + 1));
886 return MPACK_TAG_SIZE_ARRAY32;
887
888 // map16
889 case 0xde:
890 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_MAP16))
891 return 0;
892 *tag = mpack_tag_make_map(mpack_load_u16(reader->data + 1));
893 return MPACK_TAG_SIZE_MAP16;
894
895 // map32
896 case 0xdf:
897 if (!mpack_reader_ensure(reader, MPACK_TAG_SIZE_MAP32))
898 return 0;
899 *tag = mpack_tag_make_map(mpack_load_u32(reader->data + 1));
900 return MPACK_TAG_SIZE_MAP32;
901
902 // reserved
903 case 0xc1:
904 mpack_reader_flag_error(reader, mpack_error_invalid);
905 return 0;
906
907 #if !MPACK_EXTENSIONS
908 // ext
909 case 0xc7: // fallthrough
910 case 0xc8: // fallthrough
911 case 0xc9: // fallthrough
912 // fixext
913 case 0xd4: // fallthrough
914 case 0xd5: // fallthrough
915 case 0xd6: // fallthrough
916 case 0xd7: // fallthrough
917 case 0xd8:
918 mpack_reader_flag_error(reader, mpack_error_unsupported);
919 return 0;
920 #endif
921
922 #if MPACK_OPTIMIZE_FOR_SIZE
923 // any other bytes should have been handled by the infix switch
924 default:
925 break;
926 #endif
927 }
928
929 mpack_assert(0, "unreachable");
930 return 0;
931}
932
933mpack_tag_t mpack_read_tag(mpack_reader_t* reader) {
934 mpack_log("reading tag\n");
935
936 // make sure we can read a tag
937 if (mpack_reader_error(reader) != mpack_ok)
938 return mpack_tag_nil();
939 if (mpack_reader_track_element(reader) != mpack_ok)
940 return mpack_tag_nil();
941
942 mpack_tag_t tag = MPACK_TAG_ZERO;
943 size_t count = mpack_parse_tag(reader, &tag);
944 if (count == 0)
945 return mpack_tag_nil();
946
947 #if MPACK_READ_TRACKING
948 mpack_error_t track_error = mpack_ok;
949
950 switch (tag.type) {
951 case mpack_type_map:
952 case mpack_type_array:
953 track_error = mpack_track_push(&reader->track, tag.type, tag.v.n);
954 break;
955 #if MPACK_EXTENSIONS
956 case mpack_type_ext:
957 #endif
958 case mpack_type_str:
959 case mpack_type_bin:
960 track_error = mpack_track_push(&reader->track, tag.type, tag.v.l);
961 break;
962 default:
963 break;
964 }
965
966 if (track_error != mpack_ok) {
967 mpack_reader_flag_error(reader, track_error);
968 return mpack_tag_nil();
969 }
970 #endif
971
972 reader->data += count;
973 return tag;
974}
975
976mpack_tag_t mpack_peek_tag(mpack_reader_t* reader) {
977 mpack_log("peeking tag\n");
978
979 // make sure we can peek a tag
980 if (mpack_reader_error(reader) != mpack_ok)
981 return mpack_tag_nil();
982 if (mpack_reader_track_peek_element(reader) != mpack_ok)
983 return mpack_tag_nil();
984
985 mpack_tag_t tag = MPACK_TAG_ZERO;
986 if (mpack_parse_tag(reader, &tag) == 0)
987 return mpack_tag_nil();
988 return tag;
989}
990
991void mpack_discard(mpack_reader_t* reader) {
992 mpack_tag_t var = mpack_read_tag(reader);
993 if (mpack_reader_error(reader))
994 return;
995 switch (var.type) {
996 case mpack_type_str:
997 mpack_skip_bytes(reader, var.v.l);
998 mpack_done_str(reader);
999 break;
1000 case mpack_type_bin:
1001 mpack_skip_bytes(reader, var.v.l);
1002 mpack_done_bin(reader);
1003 break;
1004 #if MPACK_EXTENSIONS
1005 case mpack_type_ext:
1006 mpack_skip_bytes(reader, var.v.l);
1007 mpack_done_ext(reader);
1008 break;
1009 #endif
1010 case mpack_type_array: {
1011 for (; var.v.n > 0; --var.v.n) {
1012 mpack_discard(reader);
1013 if (mpack_reader_error(reader))
1014 break;
1015 }
1016 mpack_done_array(reader);
1017 break;
1018 }
1019 case mpack_type_map: {
1020 for (; var.v.n > 0; --var.v.n) {
1021 mpack_discard(reader);
1022 mpack_discard(reader);
1023 if (mpack_reader_error(reader))
1024 break;
1025 }
1026 mpack_done_map(reader);
1027 break;
1028 }
1029 default:
1030 break;
1031 }
1032}
1033
1034#if MPACK_EXTENSIONS
1035mpack_timestamp_t mpack_read_timestamp(mpack_reader_t* reader, size_t size) {
1036 mpack_timestamp_t timestamp = {0, 0};
1037
1038 if (size != 4 && size != 8 && size != 12) {
1039 mpack_reader_flag_error(reader, mpack_error_invalid);
1040 return timestamp;
1041 }
1042
1043 char buf[12];
1044 mpack_read_bytes(reader, buf, size);
1045 mpack_done_ext(reader);
1046 if (mpack_reader_error(reader) != mpack_ok)
1047 return timestamp;
1048
1049 switch (size) {
1050 case 4:
1051 timestamp.seconds = (int64_t)(uint64_t)mpack_load_u32(buf);
1052 break;
1053
1054 case 8: {
1055 uint64_t packed = mpack_load_u64(buf);
1056 timestamp.seconds = (int64_t)(packed & ((MPACK_UINT64_C(1) << 34) - 1));
1057 timestamp.nanoseconds = (uint32_t)(packed >> 34);
1058 break;
1059 }
1060
1061 case 12:
1062 timestamp.nanoseconds = mpack_load_u32(buf);
1063 timestamp.seconds = mpack_load_i64(buf + 4);
1064 break;
1065
1066 default:
1067 mpack_assert(false, "unreachable");
1068 break;
1069 }
1070
1071 if (timestamp.nanoseconds > MPACK_TIMESTAMP_NANOSECONDS_MAX) {
1072 mpack_reader_flag_error(reader, mpack_error_invalid);
1073 mpack_timestamp_t zero = {0, 0};
1074 return zero;
1075 }
1076
1077 return timestamp;
1078}
1079#endif
1080
1081#if MPACK_READ_TRACKING
1082void mpack_done_type(mpack_reader_t* reader, mpack_type_t type) {
1083 if (mpack_reader_error(reader) == mpack_ok)
1084 mpack_reader_flag_if_error(reader, mpack_track_pop(&reader->track, type));
1085}
1086#endif
1087
1088#if MPACK_DEBUG && MPACK_STDIO
1089static size_t mpack_print_read_prefix(mpack_reader_t* reader, size_t length, char* buffer, size_t buffer_size) {
1090 if (length == 0)
1091 return 0;
1092
1093 size_t read = (length < buffer_size) ? length : buffer_size;
1094 mpack_read_bytes(reader, buffer, read);
1095 if (mpack_reader_error(reader) != mpack_ok)
1096 return 0;
1097
1098 mpack_skip_bytes(reader, length - read);
1099 return read;
1100}
1101
1102static void mpack_print_element(mpack_reader_t* reader, mpack_print_t* print, size_t depth) {
1103 mpack_tag_t val = mpack_read_tag(reader);
1104 if (mpack_reader_error(reader) != mpack_ok)
1105 return;
1106
1107 // We read some bytes from bin and ext so we can print its prefix in hex.
1108 char buffer[MPACK_PRINT_BYTE_COUNT];
1109 size_t count = 0;
1110 size_t i, j;
1111
1112 switch (val.type) {
1113 case mpack_type_str:
1114 mpack_print_append_cstr(print, "\"");
1115 for (i = 0; i < val.v.l; ++i) {
1116 char c;
1117 mpack_read_bytes(reader, &c, 1);
1118 if (mpack_reader_error(reader) != mpack_ok)
1119 return;
1120 switch (c) {
1121 case '\n': mpack_print_append_cstr(print, "\\n"); break;
1122 case '\\': mpack_print_append_cstr(print, "\\\\"); break;
1123 case '"': mpack_print_append_cstr(print, "\\\""); break;
1124 default: mpack_print_append(print, &c, 1); break;
1125 }
1126 }
1127 mpack_print_append_cstr(print, "\"");
1128 mpack_done_str(reader);
1129 return;
1130
1131 case mpack_type_array:
1132 mpack_print_append_cstr(print, "[\n");
1133 for (i = 0; i < val.v.n; ++i) {
1134 for (j = 0; j < depth + 1; ++j)
1135 mpack_print_append_cstr(print, " ");
1136 mpack_print_element(reader, print, depth + 1);
1137 if (mpack_reader_error(reader) != mpack_ok)
1138 return;
1139 if (i != val.v.n - 1)
1140 mpack_print_append_cstr(print, ",");
1141 mpack_print_append_cstr(print, "\n");
1142 }
1143 for (i = 0; i < depth; ++i)
1144 mpack_print_append_cstr(print, " ");
1145 mpack_print_append_cstr(print, "]");
1146 mpack_done_array(reader);
1147 return;
1148
1149 case mpack_type_map:
1150 mpack_print_append_cstr(print, "{\n");
1151 for (i = 0; i < val.v.n; ++i) {
1152 for (j = 0; j < depth + 1; ++j)
1153 mpack_print_append_cstr(print, " ");
1154 mpack_print_element(reader, print, depth + 1);
1155 if (mpack_reader_error(reader) != mpack_ok)
1156 return;
1157 mpack_print_append_cstr(print, ": ");
1158 mpack_print_element(reader, print, depth + 1);
1159 if (mpack_reader_error(reader) != mpack_ok)
1160 return;
1161 if (i != val.v.n - 1)
1162 mpack_print_append_cstr(print, ",");
1163 mpack_print_append_cstr(print, "\n");
1164 }
1165 for (i = 0; i < depth; ++i)
1166 mpack_print_append_cstr(print, " ");
1167 mpack_print_append_cstr(print, "}");
1168 mpack_done_map(reader);
1169 return;
1170
1171 // The above cases return so as not to print a pseudo-json value. The
1172 // below cases break and print pseudo-json.
1173
1174 case mpack_type_bin:
1175 count = mpack_print_read_prefix(reader, mpack_tag_bin_length(&val), buffer, sizeof(buffer));
1176 mpack_done_bin(reader);
1177 break;
1178
1179 #if MPACK_EXTENSIONS
1180 case mpack_type_ext:
1181 count = mpack_print_read_prefix(reader, mpack_tag_ext_length(&val), buffer, sizeof(buffer));
1182 mpack_done_ext(reader);
1183 break;
1184 #endif
1185
1186 default:
1187 break;
1188 }
1189
1190 char buf[256];
1191 mpack_tag_debug_pseudo_json(val, buf, sizeof(buf), buffer, count);
1192 mpack_print_append_cstr(print, buf);
1193}
1194
1195static void mpack_print_and_destroy(mpack_reader_t* reader, mpack_print_t* print, size_t depth) {
1196 size_t i;
1197 for (i = 0; i < depth; ++i)
1198 mpack_print_append_cstr(print, " ");
1199 mpack_print_element(reader, print, depth);
1200
1201 size_t remaining = mpack_reader_remaining(reader, NULL);
1202
1203 char buf[256];
1204 if (mpack_reader_destroy(reader) != mpack_ok) {
1205 mpack_snprintf(buf, sizeof(buf), "\n<mpack parsing error %s>", mpack_error_to_string(mpack_reader_error(reader)));
1206 buf[sizeof(buf) - 1] = '\0';
1207 mpack_print_append_cstr(print, buf);
1208 } else if (remaining > 0) {
1209 mpack_snprintf(buf, sizeof(buf), "\n<%i extra bytes at end of message>", (int)remaining);
1210 buf[sizeof(buf) - 1] = '\0';
1211 mpack_print_append_cstr(print, buf);
1212 }
1213}
1214
1215static void mpack_print_data(const char* data, size_t len, mpack_print_t* print, size_t depth) {
1216 mpack_reader_t reader;
1217 mpack_reader_init_data(&reader, data, len);
1218 mpack_print_and_destroy(&reader, print, depth);
1219}
1220
1221void mpack_print_data_to_buffer(const char* data, size_t data_size, char* buffer, size_t buffer_size) {
1222 if (buffer_size == 0) {
1223 mpack_assert(false, "buffer size is zero!");
1224 return;
1225 }
1226
1227 mpack_print_t print;
1228 mpack_memset(&print, 0, sizeof(print));
1229 print.buffer = buffer;
1230 print.size = buffer_size;
1231 mpack_print_data(data, data_size, &print, 0);
1232 mpack_print_append(&print, "", 1); // null-terminator
1233 mpack_print_flush(&print);
1234
1235 // we always make sure there's a null-terminator at the end of the buffer
1236 // in case we ran out of space.
1237 print.buffer[print.size - 1] = '\0';
1238}
1239
1240void mpack_print_data_to_callback(const char* data, size_t size, mpack_print_callback_t callback, void* context) {
1241 char buffer[1024];
1242 mpack_print_t print;
1243 mpack_memset(&print, 0, sizeof(print));
1244 print.buffer = buffer;
1245 print.size = sizeof(buffer);
1246 print.callback = callback;
1247 print.context = context;
1248 mpack_print_data(data, size, &print, 0);
1249 mpack_print_flush(&print);
1250}
1251
1252void mpack_print_data_to_file(const char* data, size_t len, FILE* file) {
1253 mpack_assert(data != NULL, "data is NULL");
1254 mpack_assert(file != NULL, "file is NULL");
1255
1256 char buffer[1024];
1257 mpack_print_t print;
1258 mpack_memset(&print, 0, sizeof(print));
1259 print.buffer = buffer;
1260 print.size = sizeof(buffer);
1261 print.callback = &mpack_print_file_callback;
1262 print.context = file;
1263
1264 mpack_print_data(data, len, &print, 2);
1265 mpack_print_append_cstr(&print, "\n");
1266 mpack_print_flush(&print);
1267}
1268
1269void mpack_print_stdfile_to_callback(FILE* file, mpack_print_callback_t callback, void* context) {
1270 char buffer[1024];
1271 mpack_print_t print;
1272 mpack_memset(&print, 0, sizeof(print));
1273 print.buffer = buffer;
1274 print.size = sizeof(buffer);
1275 print.callback = callback;
1276 print.context = context;
1277
1278 mpack_reader_t reader;
1279 mpack_reader_init_stdfile(&reader, file, false);
1280 mpack_print_and_destroy(&reader, &print, 0);
1281 mpack_print_flush(&print);
1282}
1283#endif
1284
1285#endif
1286
1287MPACK_SILENCE_WARNINGS_END
1288