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/**
23 * @file
24 *
25 * Defines types and functions shared by the MPack reader and writer.
26 */
27
28#ifndef MPACK_COMMON_H
29#define MPACK_COMMON_H 1
30
31#include "mpack-platform.h"
32
33#ifndef MPACK_PRINT_BYTE_COUNT
34#define MPACK_PRINT_BYTE_COUNT 12
35#endif
36
37MPACK_SILENCE_WARNINGS_BEGIN
38MPACK_EXTERN_C_BEGIN
39
40
41
42/**
43 * @defgroup common Tags and Common Elements
44 *
45 * Contains types, constants and functions shared by both the encoding
46 * and decoding portions of MPack.
47 *
48 * @{
49 */
50
51/* Version information */
52
53#define MPACK_VERSION_MAJOR 1 /**< The major version number of MPack. */
54#define MPACK_VERSION_MINOR 1 /**< The minor version number of MPack. */
55#define MPACK_VERSION_PATCH 1 /**< The patch version number of MPack. */
56
57/** A number containing the version number of MPack for comparison purposes. */
58#define MPACK_VERSION ((MPACK_VERSION_MAJOR * 10000) + \
59 (MPACK_VERSION_MINOR * 100) + MPACK_VERSION_PATCH)
60
61/** A macro to test for a minimum version of MPack. */
62#define MPACK_VERSION_AT_LEAST(major, minor, patch) \
63 (MPACK_VERSION >= (((major) * 10000) + ((minor) * 100) + (patch)))
64
65/** @cond */
66#if (MPACK_VERSION_PATCH > 0)
67#define MPACK_VERSION_STRING_BASE \
68 MPACK_STRINGIFY(MPACK_VERSION_MAJOR) "." \
69 MPACK_STRINGIFY(MPACK_VERSION_MINOR) "." \
70 MPACK_STRINGIFY(MPACK_VERSION_PATCH)
71#else
72#define MPACK_VERSION_STRING_BASE \
73 MPACK_STRINGIFY(MPACK_VERSION_MAJOR) "." \
74 MPACK_STRINGIFY(MPACK_VERSION_MINOR)
75#endif
76/** @endcond */
77
78/**
79 * @def MPACK_VERSION_STRING
80 * @hideinitializer
81 *
82 * A string containing the MPack version.
83 */
84#if MPACK_RELEASE_VERSION
85#define MPACK_VERSION_STRING MPACK_VERSION_STRING_BASE
86#else
87#define MPACK_VERSION_STRING MPACK_VERSION_STRING_BASE "dev"
88#endif
89
90/**
91 * @def MPACK_LIBRARY_STRING
92 * @hideinitializer
93 *
94 * A string describing MPack, containing the library name, version and debug mode.
95 */
96#if MPACK_DEBUG
97#define MPACK_LIBRARY_STRING "MPack " MPACK_VERSION_STRING "-debug"
98#else
99#define MPACK_LIBRARY_STRING "MPack " MPACK_VERSION_STRING
100#endif
101
102/** @cond */
103/**
104 * @def MPACK_MAXIMUM_TAG_SIZE
105 *
106 * The maximum encoded size of a tag in bytes.
107 */
108#define MPACK_MAXIMUM_TAG_SIZE 9
109/** @endcond */
110
111#if MPACK_EXTENSIONS
112/**
113 * @def MPACK_TIMESTAMP_NANOSECONDS_MAX
114 *
115 * The maximum value of nanoseconds for a timestamp.
116 *
117 * @note This requires @ref MPACK_EXTENSIONS.
118 */
119#define MPACK_TIMESTAMP_NANOSECONDS_MAX 999999999
120#endif
121
122
123
124#if MPACK_COMPATIBILITY
125/**
126 * Versions of the MessagePack format.
127 *
128 * A reader, writer, or tree can be configured to serialize in an older
129 * version of the MessagePack spec. This is necessary to interface with
130 * older MessagePack libraries that do not support new MessagePack features.
131 *
132 * @note This requires @ref MPACK_COMPATIBILITY.
133 */
134typedef enum mpack_version_t {
135
136 /**
137 * Version 1.0/v4, supporting only the @c raw type without @c str8.
138 */
139 mpack_version_v4 = 4,
140
141 /**
142 * Version 2.0/v5, supporting the @c str8, @c bin and @c ext types.
143 */
144 mpack_version_v5 = 5,
145
146 /**
147 * The most recent supported version of MessagePack. This is the default.
148 */
149 mpack_version_current = mpack_version_v5,
150
151} mpack_version_t;
152#endif
153
154/**
155 * Error states for MPack objects.
156 *
157 * When a reader, writer, or tree is in an error state, all subsequent calls
158 * are ignored and their return values are nil/zero. You should check whether
159 * the source is in an error state before using such values.
160 */
161typedef enum mpack_error_t {
162 mpack_ok = 0, /**< No error. */
163 mpack_error_io = 2, /**< The reader or writer failed to fill or flush, or some other file or socket error occurred. */
164 mpack_error_invalid, /**< The data read is not valid MessagePack. */
165 mpack_error_unsupported, /**< The data read is not supported by this configuration of MPack. (See @ref MPACK_EXTENSIONS.) */
166 mpack_error_type, /**< The type or value range did not match what was expected by the caller. */
167 mpack_error_too_big, /**< A read or write was bigger than the maximum size allowed for that operation. */
168 mpack_error_memory, /**< An allocation failure occurred. */
169 mpack_error_bug, /**< The MPack API was used incorrectly. (This will always assert in debug mode.) */
170 mpack_error_data, /**< The contained data is not valid. */
171 mpack_error_eof, /**< The reader failed to read because of file or socket EOF */
172} mpack_error_t;
173
174/**
175 * Converts an MPack error to a string. This function returns an empty
176 * string when MPACK_DEBUG is not set.
177 */
178const char* mpack_error_to_string(mpack_error_t error);
179
180/**
181 * Defines the type of a MessagePack tag.
182 *
183 * Note that extension types, both user defined and built-in, are represented
184 * in tags as @ref mpack_type_ext. The value for an extension type is stored
185 * separately.
186 */
187typedef enum mpack_type_t {
188 mpack_type_missing = 0, /**< Special type indicating a missing optional value. */
189 mpack_type_nil, /**< A null value. */
190 mpack_type_bool, /**< A boolean (true or false.) */
191 mpack_type_int, /**< A 64-bit signed integer. */
192 mpack_type_uint, /**< A 64-bit unsigned integer. */
193 mpack_type_float, /**< A 32-bit IEEE 754 floating point number. */
194 mpack_type_double, /**< A 64-bit IEEE 754 floating point number. */
195 mpack_type_str, /**< A string. */
196 mpack_type_bin, /**< A chunk of binary data. */
197 mpack_type_array, /**< An array of MessagePack objects. */
198 mpack_type_map, /**< An ordered map of key/value pairs of MessagePack objects. */
199
200 #if MPACK_EXTENSIONS
201 /**
202 * A typed MessagePack extension object containing a chunk of binary data.
203 *
204 * @note This requires @ref MPACK_EXTENSIONS.
205 */
206 mpack_type_ext,
207 #endif
208} mpack_type_t;
209
210/**
211 * Converts an MPack type to a string. This function returns an empty
212 * string when MPACK_DEBUG is not set.
213 */
214const char* mpack_type_to_string(mpack_type_t type);
215
216#if MPACK_EXTENSIONS
217/**
218 * A timestamp.
219 *
220 * @note This requires @ref MPACK_EXTENSIONS.
221 */
222typedef struct mpack_timestamp_t {
223 int64_t seconds; /*< The number of seconds (signed) since 1970-01-01T00:00:00Z. */
224 uint32_t nanoseconds; /*< The number of additional nanoseconds, between 0 and 999,999,999. */
225} mpack_timestamp_t;
226#endif
227
228/**
229 * An MPack tag is a MessagePack object header. It is a variant type
230 * representing any kind of object, and includes the length of compound types
231 * (e.g. map, array, string) or the value of non-compound types (e.g. boolean,
232 * integer, float.)
233 *
234 * If the type is compound (str, bin, ext, array or map), the contained
235 * elements or bytes are stored separately.
236 *
237 * This structure is opaque; its fields should not be accessed outside
238 * of MPack.
239 */
240typedef struct mpack_tag_t mpack_tag_t;
241
242/* Hide internals from documentation */
243/** @cond */
244struct mpack_tag_t {
245 mpack_type_t type; /*< The type of value. */
246
247 #if MPACK_EXTENSIONS
248 int8_t exttype; /*< The extension type if the type is @ref mpack_type_ext. */
249 #endif
250
251 /* The value for non-compound types. */
252 union {
253 uint64_t u; /*< The value if the type is unsigned int. */
254 int64_t i; /*< The value if the type is signed int. */
255 bool b; /*< The value if the type is bool. */
256
257 #if MPACK_FLOAT
258 float f; /*< The value if the type is float. */
259 #else
260 uint32_t f; /*< The raw value if the type is float. */
261 #endif
262
263 #if MPACK_DOUBLE
264 double d; /*< The value if the type is double. */
265 #else
266 uint64_t d; /*< The raw value if the type is double. */
267 #endif
268
269 /* The number of bytes if the type is str, bin or ext. */
270 uint32_t l;
271
272 /* The element count if the type is an array, or the number of
273 key/value pairs if the type is map. */
274 uint32_t n;
275 } v;
276};
277/** @endcond */
278
279/**
280 * @name Tag Generators
281 * @{
282 */
283
284/**
285 * @def MPACK_TAG_ZERO
286 *
287 * An @ref mpack_tag_t initializer that zeroes the given tag.
288 *
289 * @warning This does not make the tag nil! The tag's type is invalid when
290 * initialized this way. Use @ref mpack_tag_make_nil() to generate a nil tag.
291 */
292#if MPACK_EXTENSIONS
293#define MPACK_TAG_ZERO {(mpack_type_t)0, 0, {0}}
294#else
295#define MPACK_TAG_ZERO {(mpack_type_t)0, {0}}
296#endif
297
298/** Generates a nil tag. */
299MPACK_INLINE mpack_tag_t mpack_tag_make_nil(void) {
300 mpack_tag_t ret = MPACK_TAG_ZERO;
301 ret.type = mpack_type_nil;
302 return ret;
303}
304
305/** Generates a bool tag. */
306MPACK_INLINE mpack_tag_t mpack_tag_make_bool(bool value) {
307 mpack_tag_t ret = MPACK_TAG_ZERO;
308 ret.type = mpack_type_bool;
309 ret.v.b = value;
310 return ret;
311}
312
313/** Generates a bool tag with value true. */
314MPACK_INLINE mpack_tag_t mpack_tag_make_true(void) {
315 mpack_tag_t ret = MPACK_TAG_ZERO;
316 ret.type = mpack_type_bool;
317 ret.v.b = true;
318 return ret;
319}
320
321/** Generates a bool tag with value false. */
322MPACK_INLINE mpack_tag_t mpack_tag_make_false(void) {
323 mpack_tag_t ret = MPACK_TAG_ZERO;
324 ret.type = mpack_type_bool;
325 ret.v.b = false;
326 return ret;
327}
328
329/** Generates a signed int tag. */
330MPACK_INLINE mpack_tag_t mpack_tag_make_int(int64_t value) {
331 mpack_tag_t ret = MPACK_TAG_ZERO;
332 ret.type = mpack_type_int;
333 ret.v.i = value;
334 return ret;
335}
336
337/** Generates an unsigned int tag. */
338MPACK_INLINE mpack_tag_t mpack_tag_make_uint(uint64_t value) {
339 mpack_tag_t ret = MPACK_TAG_ZERO;
340 ret.type = mpack_type_uint;
341 ret.v.u = value;
342 return ret;
343}
344
345#if MPACK_FLOAT
346/** Generates a float tag. */
347MPACK_INLINE mpack_tag_t mpack_tag_make_float(float value)
348#else
349/** Generates a float tag from a raw uint32_t. */
350MPACK_INLINE mpack_tag_t mpack_tag_make_raw_float(uint32_t value)
351#endif
352{
353 mpack_tag_t ret = MPACK_TAG_ZERO;
354 ret.type = mpack_type_float;
355 ret.v.f = value;
356 return ret;
357}
358
359#if MPACK_DOUBLE
360/** Generates a double tag. */
361MPACK_INLINE mpack_tag_t mpack_tag_make_double(double value)
362#else
363/** Generates a double tag from a raw uint64_t. */
364MPACK_INLINE mpack_tag_t mpack_tag_make_raw_double(uint64_t value)
365#endif
366{
367 mpack_tag_t ret = MPACK_TAG_ZERO;
368 ret.type = mpack_type_double;
369 ret.v.d = value;
370 return ret;
371}
372
373/** Generates an array tag. */
374MPACK_INLINE mpack_tag_t mpack_tag_make_array(uint32_t count) {
375 mpack_tag_t ret = MPACK_TAG_ZERO;
376 ret.type = mpack_type_array;
377 ret.v.n = count;
378 return ret;
379}
380
381/** Generates a map tag. */
382MPACK_INLINE mpack_tag_t mpack_tag_make_map(uint32_t count) {
383 mpack_tag_t ret = MPACK_TAG_ZERO;
384 ret.type = mpack_type_map;
385 ret.v.n = count;
386 return ret;
387}
388
389/** Generates a str tag. */
390MPACK_INLINE mpack_tag_t mpack_tag_make_str(uint32_t length) {
391 mpack_tag_t ret = MPACK_TAG_ZERO;
392 ret.type = mpack_type_str;
393 ret.v.l = length;
394 return ret;
395}
396
397/** Generates a bin tag. */
398MPACK_INLINE mpack_tag_t mpack_tag_make_bin(uint32_t length) {
399 mpack_tag_t ret = MPACK_TAG_ZERO;
400 ret.type = mpack_type_bin;
401 ret.v.l = length;
402 return ret;
403}
404
405#if MPACK_EXTENSIONS
406/**
407 * Generates an ext tag.
408 *
409 * @note This requires @ref MPACK_EXTENSIONS.
410 */
411MPACK_INLINE mpack_tag_t mpack_tag_make_ext(int8_t exttype, uint32_t length) {
412 mpack_tag_t ret = MPACK_TAG_ZERO;
413 ret.type = mpack_type_ext;
414 ret.exttype = exttype;
415 ret.v.l = length;
416 return ret;
417}
418#endif
419
420/**
421 * @}
422 */
423
424/**
425 * @name Tag Querying Functions
426 * @{
427 */
428
429/**
430 * Gets the type of a tag.
431 */
432MPACK_INLINE mpack_type_t mpack_tag_type(mpack_tag_t* tag) {
433 return tag->type;
434}
435
436/**
437 * Gets the boolean value of a bool-type tag. The tag must be of type @ref
438 * mpack_type_bool.
439 *
440 * This asserts that the type in the tag is @ref mpack_type_bool. (No check is
441 * performed if MPACK_DEBUG is not set.)
442 */
443MPACK_INLINE bool mpack_tag_bool_value(mpack_tag_t* tag) {
444 mpack_assert(tag->type == mpack_type_bool, "tag is not a bool!");
445 return tag->v.b;
446}
447
448/**
449 * Gets the signed integer value of an int-type tag.
450 *
451 * This asserts that the type in the tag is @ref mpack_type_int. (No check is
452 * performed if MPACK_DEBUG is not set.)
453 *
454 * @warning This does not convert between signed and unsigned tags! A positive
455 * integer may be stored in a tag as either @ref mpack_type_int or @ref
456 * mpack_type_uint. You must check the type first; this can only be used if the
457 * type is @ref mpack_type_int.
458 *
459 * @see mpack_type_int
460 */
461MPACK_INLINE int64_t mpack_tag_int_value(mpack_tag_t* tag) {
462 mpack_assert(tag->type == mpack_type_int, "tag is not an int!");
463 return tag->v.i;
464}
465
466/**
467 * Gets the unsigned integer value of a uint-type tag.
468 *
469 * This asserts that the type in the tag is @ref mpack_type_uint. (No check is
470 * performed if MPACK_DEBUG is not set.)
471 *
472 * @warning This does not convert between signed and unsigned tags! A positive
473 * integer may be stored in a tag as either @ref mpack_type_int or @ref
474 * mpack_type_uint. You must check the type first; this can only be used if the
475 * type is @ref mpack_type_uint.
476 *
477 * @see mpack_type_uint
478 */
479MPACK_INLINE uint64_t mpack_tag_uint_value(mpack_tag_t* tag) {
480 mpack_assert(tag->type == mpack_type_uint, "tag is not a uint!");
481 return tag->v.u;
482}
483
484/**
485 * Gets the float value of a float-type tag.
486 *
487 * This asserts that the type in the tag is @ref mpack_type_float. (No check is
488 * performed if MPACK_DEBUG is not set.)
489 *
490 * @warning This does not convert between float and double tags! This can only
491 * be used if the type is @ref mpack_type_float.
492 *
493 * @see mpack_type_float
494 */
495MPACK_INLINE
496#if MPACK_FLOAT
497float mpack_tag_float_value(mpack_tag_t* tag)
498#else
499uint32_t mpack_tag_raw_float_value(mpack_tag_t* tag)
500#endif
501{
502 mpack_assert(tag->type == mpack_type_float, "tag is not a float!");
503 return tag->v.f;
504}
505
506/**
507 * Gets the double value of a double-type tag.
508 *
509 * This asserts that the type in the tag is @ref mpack_type_double. (No check
510 * is performed if MPACK_DEBUG is not set.)
511 *
512 * @warning This does not convert between float and double tags! This can only
513 * be used if the type is @ref mpack_type_double.
514 *
515 * @see mpack_type_double
516 */
517MPACK_INLINE
518#if MPACK_DOUBLE
519double mpack_tag_double_value(mpack_tag_t* tag)
520#else
521uint64_t mpack_tag_raw_double_value(mpack_tag_t* tag)
522#endif
523{
524 mpack_assert(tag->type == mpack_type_double, "tag is not a double!");
525 return tag->v.d;
526}
527
528/**
529 * Gets the number of elements in an array tag.
530 *
531 * This asserts that the type in the tag is @ref mpack_type_array. (No check is
532 * performed if MPACK_DEBUG is not set.)
533 *
534 * @see mpack_type_array
535 */
536MPACK_INLINE uint32_t mpack_tag_array_count(mpack_tag_t* tag) {
537 mpack_assert(tag->type == mpack_type_array, "tag is not an array!");
538 return tag->v.n;
539}
540
541/**
542 * Gets the number of key-value pairs in a map tag.
543 *
544 * This asserts that the type in the tag is @ref mpack_type_map. (No check is
545 * performed if MPACK_DEBUG is not set.)
546 *
547 * @see mpack_type_map
548 */
549MPACK_INLINE uint32_t mpack_tag_map_count(mpack_tag_t* tag) {
550 mpack_assert(tag->type == mpack_type_map, "tag is not a map!");
551 return tag->v.n;
552}
553
554/**
555 * Gets the length in bytes of a str-type tag.
556 *
557 * This asserts that the type in the tag is @ref mpack_type_str. (No check is
558 * performed if MPACK_DEBUG is not set.)
559 *
560 * @see mpack_type_str
561 */
562MPACK_INLINE uint32_t mpack_tag_str_length(mpack_tag_t* tag) {
563 mpack_assert(tag->type == mpack_type_str, "tag is not a str!");
564 return tag->v.l;
565}
566
567/**
568 * Gets the length in bytes of a bin-type tag.
569 *
570 * This asserts that the type in the tag is @ref mpack_type_bin. (No check is
571 * performed if MPACK_DEBUG is not set.)
572 *
573 * @see mpack_type_bin
574 */
575MPACK_INLINE uint32_t mpack_tag_bin_length(mpack_tag_t* tag) {
576 mpack_assert(tag->type == mpack_type_bin, "tag is not a bin!");
577 return tag->v.l;
578}
579
580#if MPACK_EXTENSIONS
581/**
582 * Gets the length in bytes of an ext-type tag.
583 *
584 * This asserts that the type in the tag is @ref mpack_type_ext. (No check is
585 * performed if MPACK_DEBUG is not set.)
586 *
587 * @note This requires @ref MPACK_EXTENSIONS.
588 *
589 * @see mpack_type_ext
590 */
591MPACK_INLINE uint32_t mpack_tag_ext_length(mpack_tag_t* tag) {
592 mpack_assert(tag->type == mpack_type_ext, "tag is not an ext!");
593 return tag->v.l;
594}
595
596/**
597 * Gets the extension type (exttype) of an ext-type tag.
598 *
599 * This asserts that the type in the tag is @ref mpack_type_ext. (No check is
600 * performed if MPACK_DEBUG is not set.)
601 *
602 * @note This requires @ref MPACK_EXTENSIONS.
603 *
604 * @see mpack_type_ext
605 */
606MPACK_INLINE int8_t mpack_tag_ext_exttype(mpack_tag_t* tag) {
607 mpack_assert(tag->type == mpack_type_ext, "tag is not an ext!");
608 return tag->exttype;
609}
610#endif
611
612/**
613 * Gets the length in bytes of a str-, bin- or ext-type tag.
614 *
615 * This asserts that the type in the tag is @ref mpack_type_str, @ref
616 * mpack_type_bin or @ref mpack_type_ext. (No check is performed if MPACK_DEBUG
617 * is not set.)
618 *
619 * @see mpack_type_str
620 * @see mpack_type_bin
621 * @see mpack_type_ext
622 */
623MPACK_INLINE uint32_t mpack_tag_bytes(mpack_tag_t* tag) {
624 #if MPACK_EXTENSIONS
625 mpack_assert(tag->type == mpack_type_str || tag->type == mpack_type_bin
626 || tag->type == mpack_type_ext, "tag is not a str, bin or ext!");
627 #else
628 mpack_assert(tag->type == mpack_type_str || tag->type == mpack_type_bin,
629 "tag is not a str or bin!");
630 #endif
631 return tag->v.l;
632}
633
634/**
635 * @}
636 */
637
638/**
639 * @name Other tag functions
640 * @{
641 */
642
643#if MPACK_EXTENSIONS
644/**
645 * The extension type for a timestamp.
646 *
647 * @note This requires @ref MPACK_EXTENSIONS.
648 */
649#define MPACK_EXTTYPE_TIMESTAMP ((int8_t)(-1))
650#endif
651
652/**
653 * Compares two tags with an arbitrary fixed ordering. Returns 0 if the tags are
654 * equal, a negative integer if left comes before right, or a positive integer
655 * otherwise.
656 *
657 * \warning The ordering is not guaranteed to be preserved across MPack versions; do
658 * not rely on it in persistent data.
659 *
660 * \warning Floating point numbers are compared bit-for-bit, not using the language's
661 * operator==. This means that NaNs with matching representation will compare equal.
662 * This behaviour is up for debate; see comments in the definition of mpack_tag_cmp().
663 *
664 * See mpack_tag_equal() for more information on when tags are considered equal.
665 */
666int mpack_tag_cmp(mpack_tag_t left, mpack_tag_t right);
667
668/**
669 * Compares two tags for equality. Tags are considered equal if the types are compatible
670 * and the values (for non-compound types) are equal.
671 *
672 * The field width of variable-width fields is ignored (and in fact is not stored
673 * in a tag), and positive numbers in signed integers are considered equal to their
674 * unsigned counterparts. So for example the value 1 stored as a positive fixint
675 * is equal to the value 1 stored in a 64-bit unsigned integer field.
676 *
677 * The "extension type" of an extension object is considered part of the value
678 * and must match exactly.
679 *
680 * \warning Floating point numbers are compared bit-for-bit, not using the language's
681 * operator==. This means that NaNs with matching representation will compare equal.
682 * This behaviour is up for debate; see comments in the definition of mpack_tag_cmp().
683 */
684MPACK_INLINE bool mpack_tag_equal(mpack_tag_t left, mpack_tag_t right) {
685 return mpack_tag_cmp(left, right) == 0;
686}
687
688#if MPACK_DEBUG && MPACK_STDIO
689/**
690 * Generates a json-like debug description of the given tag into the given buffer.
691 *
692 * This is only available in debug mode, and only if stdio is available (since
693 * it uses snprintf().) It's strictly for debugging purposes.
694 *
695 * The prefix is used to print the first few hexadecimal bytes of a bin or ext
696 * type. Pass NULL if not a bin or ext.
697 */
698void mpack_tag_debug_pseudo_json(mpack_tag_t tag, char* buffer, size_t buffer_size,
699 const char* prefix, size_t prefix_size);
700
701/**
702 * Generates a debug string description of the given tag into the given buffer.
703 *
704 * This is only available in debug mode, and only if stdio is available (since
705 * it uses snprintf().) It's strictly for debugging purposes.
706 */
707void mpack_tag_debug_describe(mpack_tag_t tag, char* buffer, size_t buffer_size);
708
709/** @cond */
710
711/*
712 * A callback function for printing pseudo-JSON for debugging purposes.
713 *
714 * @see mpack_node_print_callback
715 */
716typedef void (*mpack_print_callback_t)(void* context, const char* data, size_t count);
717
718// helpers for printing debug output
719// i feel a bit like i'm re-implementing a buffered writer again...
720typedef struct mpack_print_t {
721 char* buffer;
722 size_t size;
723 size_t count;
724 mpack_print_callback_t callback;
725 void* context;
726} mpack_print_t;
727
728void mpack_print_append(mpack_print_t* print, const char* data, size_t count);
729
730MPACK_INLINE void mpack_print_append_cstr(mpack_print_t* print, const char* cstr) {
731 mpack_print_append(print, cstr, mpack_strlen(cstr));
732}
733
734void mpack_print_flush(mpack_print_t* print);
735
736void mpack_print_file_callback(void* context, const char* data, size_t count);
737
738/** @endcond */
739
740#endif
741
742/**
743 * @}
744 */
745
746/**
747 * @name Deprecated Tag Generators
748 * @{
749 */
750
751/*
752 * "make" has been added to their names to disambiguate them from the
753 * value-fetching functions (e.g. mpack_tag_make_bool() vs
754 * mpack_tag_bool_value().)
755 *
756 * The length and count for all compound types was the wrong sign (int32_t
757 * instead of uint32_t.) These preserve the old behaviour; the new "make"
758 * functions have the correct sign.
759 */
760
761/** \deprecated Renamed to mpack_tag_make_nil(). */
762MPACK_INLINE mpack_tag_t mpack_tag_nil(void) {
763 return mpack_tag_make_nil();
764}
765
766/** \deprecated Renamed to mpack_tag_make_bool(). */
767MPACK_INLINE mpack_tag_t mpack_tag_bool(bool value) {
768 return mpack_tag_make_bool(value);
769}
770
771/** \deprecated Renamed to mpack_tag_make_true(). */
772MPACK_INLINE mpack_tag_t mpack_tag_true(void) {
773 return mpack_tag_make_true();
774}
775
776/** \deprecated Renamed to mpack_tag_make_false(). */
777MPACK_INLINE mpack_tag_t mpack_tag_false(void) {
778 return mpack_tag_make_false();
779}
780
781/** \deprecated Renamed to mpack_tag_make_int(). */
782MPACK_INLINE mpack_tag_t mpack_tag_int(int64_t value) {
783 return mpack_tag_make_int(value);
784}
785
786/** \deprecated Renamed to mpack_tag_make_uint(). */
787MPACK_INLINE mpack_tag_t mpack_tag_uint(uint64_t value) {
788 return mpack_tag_make_uint(value);
789}
790
791#if MPACK_FLOAT
792/** \deprecated Renamed to mpack_tag_make_float(). */
793MPACK_INLINE mpack_tag_t mpack_tag_float(float value) {
794 return mpack_tag_make_float(value);
795}
796#endif
797
798#if MPACK_DOUBLE
799/** \deprecated Renamed to mpack_tag_make_double(). */
800MPACK_INLINE mpack_tag_t mpack_tag_double(double value) {
801 return mpack_tag_make_double(value);
802}
803#endif
804
805/** \deprecated Renamed to mpack_tag_make_array(). */
806MPACK_INLINE mpack_tag_t mpack_tag_array(int32_t count) {
807 return mpack_tag_make_array((uint32_t)count);
808}
809
810/** \deprecated Renamed to mpack_tag_make_map(). */
811MPACK_INLINE mpack_tag_t mpack_tag_map(int32_t count) {
812 return mpack_tag_make_map((uint32_t)count);
813}
814
815/** \deprecated Renamed to mpack_tag_make_str(). */
816MPACK_INLINE mpack_tag_t mpack_tag_str(int32_t length) {
817 return mpack_tag_make_str((uint32_t)length);
818}
819
820/** \deprecated Renamed to mpack_tag_make_bin(). */
821MPACK_INLINE mpack_tag_t mpack_tag_bin(int32_t length) {
822 return mpack_tag_make_bin((uint32_t)length);
823}
824
825#if MPACK_EXTENSIONS
826/** \deprecated Renamed to mpack_tag_make_ext(). */
827MPACK_INLINE mpack_tag_t mpack_tag_ext(int8_t exttype, int32_t length) {
828 return mpack_tag_make_ext(exttype, (uint32_t)length);
829}
830#endif
831
832/**
833 * @}
834 */
835
836/** @cond */
837
838/*
839 * Helpers to perform unaligned network-endian loads and stores
840 * at arbitrary addresses. Byte-swapping builtins are used if they
841 * are available and if they improve performance.
842 *
843 * These will remain available in the public API so feel free to
844 * use them for other purposes, but they are undocumented.
845 */
846
847MPACK_INLINE uint8_t mpack_load_u8(const char* p) {
848 return (uint8_t)p[0];
849}
850
851MPACK_INLINE uint16_t mpack_load_u16(const char* p) {
852 #ifdef MPACK_NHSWAP16
853 uint16_t val;
854 mpack_memcpy(&val, p, sizeof(val));
855 return MPACK_NHSWAP16(val);
856 #else
857 return (uint16_t)((((uint16_t)(uint8_t)p[0]) << 8) |
858 ((uint16_t)(uint8_t)p[1]));
859 #endif
860}
861
862MPACK_INLINE uint32_t mpack_load_u32(const char* p) {
863 #ifdef MPACK_NHSWAP32
864 uint32_t val;
865 mpack_memcpy(&val, p, sizeof(val));
866 return MPACK_NHSWAP32(val);
867 #else
868 return (((uint32_t)(uint8_t)p[0]) << 24) |
869 (((uint32_t)(uint8_t)p[1]) << 16) |
870 (((uint32_t)(uint8_t)p[2]) << 8) |
871 ((uint32_t)(uint8_t)p[3]);
872 #endif
873}
874
875MPACK_INLINE uint64_t mpack_load_u64(const char* p) {
876 #ifdef MPACK_NHSWAP64
877 uint64_t val;
878 mpack_memcpy(&val, p, sizeof(val));
879 return MPACK_NHSWAP64(val);
880 #else
881 return (((uint64_t)(uint8_t)p[0]) << 56) |
882 (((uint64_t)(uint8_t)p[1]) << 48) |
883 (((uint64_t)(uint8_t)p[2]) << 40) |
884 (((uint64_t)(uint8_t)p[3]) << 32) |
885 (((uint64_t)(uint8_t)p[4]) << 24) |
886 (((uint64_t)(uint8_t)p[5]) << 16) |
887 (((uint64_t)(uint8_t)p[6]) << 8) |
888 ((uint64_t)(uint8_t)p[7]);
889 #endif
890}
891
892MPACK_INLINE void mpack_store_u8(char* p, uint8_t val) {
893 uint8_t* u = (uint8_t*)p;
894 u[0] = val;
895}
896
897MPACK_INLINE void mpack_store_u16(char* p, uint16_t val) {
898 #ifdef MPACK_NHSWAP16
899 val = MPACK_NHSWAP16(val);
900 mpack_memcpy(p, &val, sizeof(val));
901 #else
902 uint8_t* u = (uint8_t*)p;
903 u[0] = (uint8_t)((val >> 8) & 0xFF);
904 u[1] = (uint8_t)( val & 0xFF);
905 #endif
906}
907
908MPACK_INLINE void mpack_store_u32(char* p, uint32_t val) {
909 #ifdef MPACK_NHSWAP32
910 val = MPACK_NHSWAP32(val);
911 mpack_memcpy(p, &val, sizeof(val));
912 #else
913 uint8_t* u = (uint8_t*)p;
914 u[0] = (uint8_t)((val >> 24) & 0xFF);
915 u[1] = (uint8_t)((val >> 16) & 0xFF);
916 u[2] = (uint8_t)((val >> 8) & 0xFF);
917 u[3] = (uint8_t)( val & 0xFF);
918 #endif
919}
920
921MPACK_INLINE void mpack_store_u64(char* p, uint64_t val) {
922 #ifdef MPACK_NHSWAP64
923 val = MPACK_NHSWAP64(val);
924 mpack_memcpy(p, &val, sizeof(val));
925 #else
926 uint8_t* u = (uint8_t*)p;
927 u[0] = (uint8_t)((val >> 56) & 0xFF);
928 u[1] = (uint8_t)((val >> 48) & 0xFF);
929 u[2] = (uint8_t)((val >> 40) & 0xFF);
930 u[3] = (uint8_t)((val >> 32) & 0xFF);
931 u[4] = (uint8_t)((val >> 24) & 0xFF);
932 u[5] = (uint8_t)((val >> 16) & 0xFF);
933 u[6] = (uint8_t)((val >> 8) & 0xFF);
934 u[7] = (uint8_t)( val & 0xFF);
935 #endif
936}
937
938MPACK_INLINE int8_t mpack_load_i8 (const char* p) {return (int8_t) mpack_load_u8 (p);}
939MPACK_INLINE int16_t mpack_load_i16(const char* p) {return (int16_t)mpack_load_u16(p);}
940MPACK_INLINE int32_t mpack_load_i32(const char* p) {return (int32_t)mpack_load_u32(p);}
941MPACK_INLINE int64_t mpack_load_i64(const char* p) {return (int64_t)mpack_load_u64(p);}
942MPACK_INLINE void mpack_store_i8 (char* p, int8_t val) {mpack_store_u8 (p, (uint8_t) val);}
943MPACK_INLINE void mpack_store_i16(char* p, int16_t val) {mpack_store_u16(p, (uint16_t)val);}
944MPACK_INLINE void mpack_store_i32(char* p, int32_t val) {mpack_store_u32(p, (uint32_t)val);}
945MPACK_INLINE void mpack_store_i64(char* p, int64_t val) {mpack_store_u64(p, (uint64_t)val);}
946
947#if MPACK_FLOAT
948MPACK_INLINE float mpack_load_float(const char* p) {
949 MPACK_CHECK_FLOAT_ORDER();
950 MPACK_STATIC_ASSERT(sizeof(float) == sizeof(uint32_t), "float is wrong size??");
951 union {
952 float f;
953 uint32_t u;
954 } v;
955 v.u = mpack_load_u32(p);
956 return v.f;
957}
958#endif
959
960#if MPACK_DOUBLE
961MPACK_INLINE double mpack_load_double(const char* p) {
962 MPACK_CHECK_FLOAT_ORDER();
963 MPACK_STATIC_ASSERT(sizeof(double) == sizeof(uint64_t), "double is wrong size??");
964 union {
965 double d;
966 uint64_t u;
967 } v;
968 v.u = mpack_load_u64(p);
969 return v.d;
970}
971#endif
972
973#if MPACK_FLOAT
974MPACK_INLINE void mpack_store_float(char* p, float value) {
975 MPACK_CHECK_FLOAT_ORDER();
976 union {
977 float f;
978 uint32_t u;
979 } v;
980 v.f = value;
981 mpack_store_u32(p, v.u);
982}
983#endif
984
985#if MPACK_DOUBLE
986MPACK_INLINE void mpack_store_double(char* p, double value) {
987 MPACK_CHECK_FLOAT_ORDER();
988 union {
989 double d;
990 uint64_t u;
991 } v;
992 v.d = value;
993 mpack_store_u64(p, v.u);
994}
995#endif
996
997#if MPACK_FLOAT && !MPACK_DOUBLE
998/**
999 * Performs a manual shortening conversion on the raw 64-bit representation of
1000 * a double. This is useful for parsing doubles on platforms that only support
1001 * floats (such as AVR.)
1002 *
1003 * The significand is truncated rather than rounded and subnormal numbers are
1004 * set to 0 so this may not be quite as accurate as a real double-to-float
1005 * conversion.
1006 */
1007MPACK_INLINE float mpack_shorten_raw_double_to_float(uint64_t d) {
1008 MPACK_CHECK_FLOAT_ORDER();
1009 union {
1010 float f;
1011 uint32_t u;
1012 } v;
1013
1014 // float has 1 bit sign, 8 bits exponent, 23 bits significand
1015 // double has 1 bit sign, 11 bits exponent, 52 bits significand
1016
1017 uint64_t d_sign = (uint64_t)(d >> 63);
1018 uint64_t d_exponent = (uint32_t)(d >> 52) & ((1 << 11) - 1);
1019 uint64_t d_significand = d & (((uint64_t)1 << 52) - 1);
1020
1021 uint32_t f_sign = (uint32_t)d_sign;
1022 uint32_t f_exponent;
1023 uint32_t f_significand;
1024
1025 if (MPACK_UNLIKELY(d_exponent == ((1 << 11) - 1))) {
1026 // infinity or NAN. shift down to preserve the top bit since it
1027 // indicates signaling NAN, but also set the low bit if any bits were
1028 // set (that way we can't shift NAN to infinity.)
1029 f_exponent = ((1 << 8) - 1);
1030 f_significand = (uint32_t)(d_significand >> 29) | (d_significand ? 1 : 0);
1031
1032 } else {
1033 int fix_bias = (int)d_exponent - ((1 << 10) - 1) + ((1 << 7) - 1);
1034 if (MPACK_UNLIKELY(fix_bias <= 0)) {
1035 // we don't currently handle subnormal numbers. just set it to zero.
1036 f_exponent = 0;
1037 f_significand = 0;
1038 } else if (MPACK_UNLIKELY(fix_bias > 0xff)) {
1039 // exponent is too large; saturate to infinity
1040 f_exponent = 0xff;
1041 f_significand = 0;
1042 } else {
1043 // a normal number that fits in a float. this is the usual case.
1044 f_exponent = (uint32_t)fix_bias;
1045 f_significand = (uint32_t)(d_significand >> 29);
1046 }
1047 }
1048
1049 #if 0
1050 printf("\n===============\n");
1051 for (size_t i = 0; i < 64; ++i)
1052 printf("%i%s",(int)((d>>(63-i))&1),((i%8)==7)?" ":"");
1053 printf("\n%lu %lu %lu\n", d_sign, d_exponent, d_significand);
1054 printf("%u %u %u\n", f_sign, f_exponent, f_significand);
1055 #endif
1056
1057 v.u = (f_sign << 31) | (f_exponent << 23) | f_significand;
1058 return v.f;
1059}
1060#endif
1061
1062/** @endcond */
1063
1064
1065
1066/** @cond */
1067
1068// Sizes in bytes for the various possible tags
1069#define MPACK_TAG_SIZE_FIXUINT 1
1070#define MPACK_TAG_SIZE_U8 2
1071#define MPACK_TAG_SIZE_U16 3
1072#define MPACK_TAG_SIZE_U32 5
1073#define MPACK_TAG_SIZE_U64 9
1074#define MPACK_TAG_SIZE_FIXINT 1
1075#define MPACK_TAG_SIZE_I8 2
1076#define MPACK_TAG_SIZE_I16 3
1077#define MPACK_TAG_SIZE_I32 5
1078#define MPACK_TAG_SIZE_I64 9
1079#define MPACK_TAG_SIZE_FLOAT 5
1080#define MPACK_TAG_SIZE_DOUBLE 9
1081#define MPACK_TAG_SIZE_FIXARRAY 1
1082#define MPACK_TAG_SIZE_ARRAY16 3
1083#define MPACK_TAG_SIZE_ARRAY32 5
1084#define MPACK_TAG_SIZE_FIXMAP 1
1085#define MPACK_TAG_SIZE_MAP16 3
1086#define MPACK_TAG_SIZE_MAP32 5
1087#define MPACK_TAG_SIZE_FIXSTR 1
1088#define MPACK_TAG_SIZE_STR8 2
1089#define MPACK_TAG_SIZE_STR16 3
1090#define MPACK_TAG_SIZE_STR32 5
1091#define MPACK_TAG_SIZE_BIN8 2
1092#define MPACK_TAG_SIZE_BIN16 3
1093#define MPACK_TAG_SIZE_BIN32 5
1094#define MPACK_TAG_SIZE_FIXEXT1 2
1095#define MPACK_TAG_SIZE_FIXEXT2 2
1096#define MPACK_TAG_SIZE_FIXEXT4 2
1097#define MPACK_TAG_SIZE_FIXEXT8 2
1098#define MPACK_TAG_SIZE_FIXEXT16 2
1099#define MPACK_TAG_SIZE_EXT8 3
1100#define MPACK_TAG_SIZE_EXT16 4
1101#define MPACK_TAG_SIZE_EXT32 6
1102
1103// size in bytes for complete ext types
1104#define MPACK_EXT_SIZE_TIMESTAMP4 (MPACK_TAG_SIZE_FIXEXT4 + 4)
1105#define MPACK_EXT_SIZE_TIMESTAMP8 (MPACK_TAG_SIZE_FIXEXT8 + 8)
1106#define MPACK_EXT_SIZE_TIMESTAMP12 (MPACK_TAG_SIZE_EXT8 + 12)
1107
1108/** @endcond */
1109
1110
1111
1112#if MPACK_READ_TRACKING || MPACK_WRITE_TRACKING
1113/* Tracks the write state of compound elements (maps, arrays, */
1114/* strings, binary blobs and extension types) */
1115/** @cond */
1116
1117typedef struct mpack_track_element_t {
1118 mpack_type_t type;
1119 uint32_t left;
1120
1121 // indicates that a value still needs to be read/written for an already
1122 // read/written key. left is not decremented until both key and value are
1123 // read/written.
1124 bool key_needs_value;
1125
1126 // tracks whether the map/array being written is using a builder. if true,
1127 // the number of elements is automatic, and left is 0.
1128 bool builder;
1129} mpack_track_element_t;
1130
1131typedef struct mpack_track_t {
1132 size_t count;
1133 size_t capacity;
1134 mpack_track_element_t* elements;
1135} mpack_track_t;
1136
1137#if MPACK_INTERNAL
1138mpack_error_t mpack_track_init(mpack_track_t* track);
1139mpack_error_t mpack_track_grow(mpack_track_t* track);
1140mpack_error_t mpack_track_push(mpack_track_t* track, mpack_type_t type, uint32_t count);
1141mpack_error_t mpack_track_push_builder(mpack_track_t* track, mpack_type_t type);
1142mpack_error_t mpack_track_pop(mpack_track_t* track, mpack_type_t type);
1143mpack_error_t mpack_track_pop_builder(mpack_track_t* track, mpack_type_t type);
1144mpack_error_t mpack_track_element(mpack_track_t* track, bool read);
1145mpack_error_t mpack_track_peek_element(mpack_track_t* track, bool read);
1146mpack_error_t mpack_track_bytes(mpack_track_t* track, bool read, size_t count);
1147mpack_error_t mpack_track_str_bytes_all(mpack_track_t* track, bool read, size_t count);
1148mpack_error_t mpack_track_check_empty(mpack_track_t* track);
1149mpack_error_t mpack_track_destroy(mpack_track_t* track, bool cancel);
1150#endif
1151
1152/** @endcond */
1153#endif
1154
1155
1156
1157#if MPACK_INTERNAL
1158/** @cond */
1159
1160
1161
1162/* Miscellaneous string functions */
1163
1164/**
1165 * Returns true if the given UTF-8 string is valid.
1166 */
1167bool mpack_utf8_check(const char* str, size_t bytes);
1168
1169/**
1170 * Returns true if the given UTF-8 string is valid and contains no null characters.
1171 */
1172bool mpack_utf8_check_no_null(const char* str, size_t bytes);
1173
1174/**
1175 * Returns true if the given string has no null bytes.
1176 */
1177bool mpack_str_check_no_null(const char* str, size_t bytes);
1178
1179
1180
1181/** @endcond */
1182#endif
1183
1184
1185
1186/**
1187 * @}
1188 */
1189
1190MPACK_EXTERN_C_END
1191MPACK_SILENCE_WARNINGS_END
1192
1193#endif
1194
1195