JSON-YY

 view release on metacpan or  search on metacpan

yyjson.h  view on Meta::CPAN

 @param line A pointer to receive the line number, starting from 1.
 @param col  A pointer to receive the column number, starting from 1.
 @param chr  A pointer to receive the character index, starting from 0.
 @return true on success, false if `str` is NULL or `pos` is out of bounds.
 @note Line/column/character are calculated based on Unicode characters for
    compatibility with text editors. For multi-byte UTF-8 characters,
    the returned value may not directly correspond to the byte position.
 */
yyjson_api bool yyjson_locate_pos(const char *str, size_t len, size_t pos,
                                  size_t *line, size_t *col, size_t *chr);



/*==============================================================================
 * MARK: - JSON Structure
 *============================================================================*/

/**
 An immutable document for reading JSON.
 This document holds memory for all its JSON values and strings. When it is no
 longer used, the user should call `yyjson_doc_free()` to free its memory.
 */
typedef struct yyjson_doc yyjson_doc;

/**
 An immutable value for reading JSON.
 A JSON Value has the same lifetime as its document. The memory is held by its
 document and and cannot be freed alone.
 */
typedef struct yyjson_val yyjson_val;

/**
 A mutable document for building JSON.
 This document holds memory for all its JSON values and strings. When it is no
 longer used, the user should call `yyjson_mut_doc_free()` to free its memory.
 */
typedef struct yyjson_mut_doc yyjson_mut_doc;

/**
 A mutable value for building JSON.
 A JSON Value has the same lifetime as its document. The memory is held by its
 document and and cannot be freed alone.
 */
typedef struct yyjson_mut_val yyjson_mut_val;



/*==============================================================================
 * MARK: - JSON Reader API
 *============================================================================*/

/** Run-time options for JSON reader. */
typedef uint32_t yyjson_read_flag;

/** Default option (RFC 8259 compliant):
    - Read positive integer as uint64_t.
    - Read negative integer as int64_t.
    - Read floating-point number as double with round-to-nearest mode.
    - Read integer which cannot fit in uint64_t or int64_t as double.
    - Report error if double number is infinity.
    - Report error if string contains invalid UTF-8 character or BOM.
    - Report error on trailing commas, comments, inf and nan literals. */
static const yyjson_read_flag YYJSON_READ_NOFLAG                    = 0;

/** Read the input data in-situ.
    This option allows the reader to modify and use input data to store string
    values, which can increase reading speed slightly.
    The caller should hold the input data before free the document.
    The input data must be padded by at least `YYJSON_PADDING_SIZE` bytes.
    For example: `[1,2]` should be `[1,2]\0\0\0\0`, input length should be 5. */
static const yyjson_read_flag YYJSON_READ_INSITU                    = 1 << 0;

/** Stop when done instead of issuing an error if there's additional content
    after a JSON document. This option may be used to parse small pieces of JSON
    in larger data, such as `NDJSON`. */
static const yyjson_read_flag YYJSON_READ_STOP_WHEN_DONE            = 1 << 1;

/** Allow single trailing comma at the end of an object or array,
    such as `[1,2,3,]`, `{"a":1,"b":2,}` (non-standard). */
static const yyjson_read_flag YYJSON_READ_ALLOW_TRAILING_COMMAS     = 1 << 2;

/** Allow C-style single-line and mult-line comments (non-standard). */
static const yyjson_read_flag YYJSON_READ_ALLOW_COMMENTS            = 1 << 3;

/** Allow inf/nan number and literal, case-insensitive,
    such as 1e999, NaN, inf, -Infinity (non-standard). */
static const yyjson_read_flag YYJSON_READ_ALLOW_INF_AND_NAN         = 1 << 4;

/** Read all numbers as raw strings (value with `YYJSON_TYPE_RAW` type),
    inf/nan literal is also read as raw with `ALLOW_INF_AND_NAN` flag. */
static const yyjson_read_flag YYJSON_READ_NUMBER_AS_RAW             = 1 << 5;

/** Allow reading invalid unicode when parsing string values (non-standard).
    Invalid characters will be allowed to appear in the string values, but
    invalid escape sequences will still be reported as errors.
    This flag does not affect the performance of correctly encoded strings.

    @warning Strings in JSON values may contain incorrect encoding when this
    option is used, you need to handle these strings carefully to avoid security
    risks. */
static const yyjson_read_flag YYJSON_READ_ALLOW_INVALID_UNICODE     = 1 << 6;

/** Read big numbers as raw strings. These big numbers include integers that
    cannot be represented by `int64_t` and `uint64_t`, and floating-point
    numbers that cannot be represented by finite `double`.
    The flag will be overridden by `YYJSON_READ_NUMBER_AS_RAW` flag. */
static const yyjson_read_flag YYJSON_READ_BIGNUM_AS_RAW             = 1 << 7;

/** Allow UTF-8 BOM and skip it before parsing if any (non-standard). */
static const yyjson_read_flag YYJSON_READ_ALLOW_BOM                 = 1 << 8;

/** Allow extended number formats (non-standard):
    - Hexadecimal numbers, such as `0x7B`.
    - Numbers with leading or trailing decimal point, such as `.123`, `123.`.
    - Numbers with a leading plus sign, such as `+123`. */
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_NUMBER          = 1 << 9;

/** Allow extended escape sequences in strings (non-standard):
    - Additional escapes: `\a`, `\e`, `\v`, ``\'``, `\?`, `\0`.
    - Hex escapes: `\xNN`, such as `\x7B`.
    - Line continuation: backslash followed by line terminator sequences.
    - Unknown escape: if backslash is followed by an unsupported character,
        the backslash will be removed and the character will be kept as-is.
        However, `\1`-`\9` will still trigger an error. */
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_ESCAPE          = 1 << 10;

/** Allow extended whitespace characters (non-standard):
    - Vertical tab `\v` and form feed `\f`.
    - Line separator `\u2028` and paragraph separator `\u2029`.
    - Non-breaking space `\xA0`.
    - Byte order mark: `\uFEFF`.
    - Other Unicode characters in the Zs (Separator, space) category. */
static const yyjson_read_flag YYJSON_READ_ALLOW_EXT_WHITESPACE      = 1 << 11;

/** Allow strings enclosed in single quotes (non-standard), such as ``'ab'``. */
static const yyjson_read_flag YYJSON_READ_ALLOW_SINGLE_QUOTED_STR   = 1 << 12;

/** Allow object keys without quotes (non-standard), such as `{a:1,b:2}`.
    This extends the ECMAScript IdentifierName rule by allowing any
    non-whitespace character with code point above `U+007F`. */
static const yyjson_read_flag YYJSON_READ_ALLOW_UNQUOTED_KEY        = 1 << 13;

/** Allow JSON5 format, see: [https://json5.org].
    This flag supports all JSON5 features with some additional extensions:
    - Accepts more escape sequences than JSON5 (e.g. `\a`, `\e`).
    - Unquoted keys are not limited to ECMAScript IdentifierName.
    - Allow case-insensitive `NaN`, `Inf` and `Infinity` literals. */
static const yyjson_read_flag YYJSON_READ_JSON5 =
    (1 << 2)  | /* YYJSON_READ_ALLOW_TRAILING_COMMAS */
    (1 << 3)  | /* YYJSON_READ_ALLOW_COMMENTS */
    (1 << 4)  | /* YYJSON_READ_ALLOW_INF_AND_NAN */
    (1 << 9)  | /* YYJSON_READ_ALLOW_EXT_NUMBER */
    (1 << 10) | /* YYJSON_READ_ALLOW_EXT_ESCAPE */
    (1 << 11) | /* YYJSON_READ_ALLOW_EXT_WHITESPACE */
    (1 << 12) | /* YYJSON_READ_ALLOW_SINGLE_QUOTED_STR */
    (1 << 13);  /* YYJSON_READ_ALLOW_UNQUOTED_KEY */



/** Result code for JSON reader. */
typedef uint32_t yyjson_read_code;

/** Success, no error. */
static const yyjson_read_code YYJSON_READ_SUCCESS                       = 0;

/** Invalid parameter, such as NULL input string or 0 input length. */
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_PARAMETER       = 1;

/** Memory allocation failed. */
static const yyjson_read_code YYJSON_READ_ERROR_MEMORY_ALLOCATION       = 2;

/** Input JSON string is empty. */
static const yyjson_read_code YYJSON_READ_ERROR_EMPTY_CONTENT           = 3;

/** Unexpected content after document, such as `[123]abc`. */
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CONTENT      = 4;

/** Unexpected end of input, the parsed part is valid, such as `[123`. */
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_END          = 5;

/** Unexpected character inside the document, such as `[abc]`. */
static const yyjson_read_code YYJSON_READ_ERROR_UNEXPECTED_CHARACTER    = 6;

/** Invalid JSON structure, such as `[1,]`. */
static const yyjson_read_code YYJSON_READ_ERROR_JSON_STRUCTURE          = 7;

/** Invalid comment, deprecated, use `UNEXPECTED_END` for unclosed comment. */
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_COMMENT         = 8;

/** Invalid number, such as `123.e12`, `000`. */
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_NUMBER          = 9;

/** Invalid string, such as invalid escaped character inside a string. */
static const yyjson_read_code YYJSON_READ_ERROR_INVALID_STRING          = 10;

/** Invalid JSON literal, such as `truu`. */
static const yyjson_read_code YYJSON_READ_ERROR_LITERAL                 = 11;

/** Failed to open a file. */
static const yyjson_read_code YYJSON_READ_ERROR_FILE_OPEN               = 12;

/** Failed to read a file. */
static const yyjson_read_code YYJSON_READ_ERROR_FILE_READ               = 13;

/** Incomplete input during incremental parsing; parsing state is preserved. */
static const yyjson_read_code YYJSON_READ_ERROR_MORE                    = 14;

/** Error information for JSON reader. */
typedef struct yyjson_read_err {
    /** Error code, see `yyjson_read_code` for all possible values. */
    yyjson_read_code code;
    /** Error message, constant, no need to free (NULL if success). */
    const char *msg;
    /** Error byte position for input data (0 if success). */
    size_t pos;
} yyjson_read_err;



#if !defined(YYJSON_DISABLE_READER) || !YYJSON_DISABLE_READER

/**
 Read JSON with options.

 This function is thread-safe when:
 1. The `dat` is not modified by other threads.
 2. The `alc` is thread-safe or NULL.

 @param dat The JSON data (UTF-8 without BOM), null-terminator is not required.
    If this parameter is NULL, the function will fail and return NULL.
    The `dat` will not be modified without the flag `YYJSON_READ_INSITU`, so you
    can pass a `const char *` string and case it to `char *` if you don't use
    the `YYJSON_READ_INSITU` flag.
 @param len The length of JSON data in bytes.
    If this parameter is 0, the function will fail and return NULL.
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator. 0 means no options.
 @param alc The memory allocator used by JSON reader.
    Pass NULL to use the libc's default allocator.
 @param err A pointer to receive error information.
    Pass NULL if you don't need error information.
 @return A new JSON document, or NULL if an error occurs.
    When it's no longer needed, it should be freed with `yyjson_doc_free()`.
 */
yyjson_api yyjson_doc *yyjson_read_opts(char *dat,
                                        size_t len,
                                        yyjson_read_flag flg,
                                        const yyjson_alc *alc,
                                        yyjson_read_err *err);

/**
 Read a JSON file.

 This function is thread-safe when:
 1. The file is not modified by other threads.
 2. The `alc` is thread-safe or NULL.

 @param path The JSON file's path.
    This should be a null-terminated string using the system's native encoding.
    If this path is NULL or invalid, the function will fail and return NULL.
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator. 0 means no options.
 @param alc The memory allocator used by JSON reader.
    Pass NULL to use the libc's default allocator.
 @param err A pointer to receive error information.
    Pass NULL if you don't need error information.
 @return A new JSON document, or NULL if an error occurs.
    When it's no longer needed, it should be freed with `yyjson_doc_free()`.

 @warning On 32-bit operating system, files larger than 2GB may fail to read.
 */
yyjson_api yyjson_doc *yyjson_read_file(const char *path,
                                        yyjson_read_flag flg,
                                        const yyjson_alc *alc,
                                        yyjson_read_err *err);

/**
 Read JSON from a file pointer.

 @param fp The file pointer.
    The data will be read from the current position of the FILE to the end.
    If this fp is NULL or invalid, the function will fail and return NULL.
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator. 0 means no options.
 @param alc The memory allocator used by JSON reader.
    Pass NULL to use the libc's default allocator.
 @param err A pointer to receive error information.
    Pass NULL if you don't need error information.
 @return A new JSON document, or NULL if an error occurs.
    When it's no longer needed, it should be freed with `yyjson_doc_free()`.

 @warning On 32-bit operating system, files larger than 2GB may fail to read.
 */
yyjson_api yyjson_doc *yyjson_read_fp(FILE *fp,
                                      yyjson_read_flag flg,
                                      const yyjson_alc *alc,
                                      yyjson_read_err *err);

/**
 Read a JSON string.

 This function is thread-safe.

 @param dat The JSON data (UTF-8 without BOM), null-terminator is not required.
    If this parameter is NULL, the function will fail and return NULL.
 @param len The length of JSON data in bytes.
    If this parameter is 0, the function will fail and return NULL.
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator. 0 means no options.
 @return A new JSON document, or NULL if an error occurs.
    When it's no longer needed, it should be freed with `yyjson_doc_free()`.
 */
yyjson_api_inline yyjson_doc *yyjson_read(const char *dat,
                                          size_t len,
                                          yyjson_read_flag flg) {
    flg &= ~YYJSON_READ_INSITU; /* const string cannot be modified */
    return yyjson_read_opts((char *)(void *)(size_t)(const void *)dat,
                            len, flg, NULL, NULL);
}



#if !defined(YYJSON_DISABLE_INCR_READER) || !YYJSON_DISABLE_INCR_READER

/** Opaque state for incremental JSON reader. */
typedef struct yyjson_incr_state yyjson_incr_state;

/**
 Initialize state for incremental read.

 To read a large JSON document incrementally:
 1. Call `yyjson_incr_new()` to create the state for incremental reading.
 2. Call `yyjson_incr_read()` repeatedly.
 3. Call `yyjson_incr_free()` to free the state.

 Note: The incremental JSON reader only supports standard JSON.
 Flags for non-standard features (e.g. comments, trailing commas) are ignored.

 @param buf The JSON data, null-terminator is not required.
    If this parameter is NULL, the function will fail and return NULL.
 @param buf_len The length of the JSON data in `buf`.
    If use `YYJSON_READ_INSITU`, `buf_len` should not include the padding size.
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator.
 @param alc The memory allocator used by JSON reader.
    Pass NULL to use the libc's default allocator.
 @return A state for incremental reading.
    It should be freed with `yyjson_incr_free()`.
    NULL is returned if memory allocation fails.
*/
yyjson_api yyjson_incr_state *yyjson_incr_new(char *buf, size_t buf_len,
                                              yyjson_read_flag flg,
                                              const yyjson_alc *alc);

/**
 Performs incremental read of up to `len` bytes.

 If NULL is returned and `err->code` is set to `YYJSON_READ_ERROR_MORE`, it
 indicates that more data is required to continue parsing. Then, call this
 function again with incremented `len`. Continue until a document is returned or
 an error other than `YYJSON_READ_ERROR_MORE` is returned.

 Note: Parsing in very small increments is not efficient. An increment of
 several kilobytes or megabytes is recommended.

yyjson.h  view on Meta::CPAN


 You may use this value to avoid malloc() or calloc() call inside the reader
 to get better performance, or read multiple JSON with one piece of memory.

 @param len The length of JSON data in bytes.
 @param flg The JSON read options.
 @return The maximum memory size to read this JSON, or 0 if overflow.

 @b Example
 @code
    // read multiple JSON with same pre-allocated memory

    char *dat1, *dat2, *dat3; // JSON data
    size_t len1, len2, len3; // JSON length
    size_t max_len = MAX(len1, MAX(len2, len3));
    yyjson_doc *doc;

    // use one allocator for multiple JSON
    size_t size = yyjson_read_max_memory_usage(max_len, 0);
    void *buf = malloc(size);
    yyjson_alc alc;
    yyjson_alc_pool_init(&alc, buf, size);

    // no more alloc() or realloc() call during reading
    doc = yyjson_read_opts(dat1, len1, 0, &alc, NULL);
    yyjson_doc_free(doc);
    doc = yyjson_read_opts(dat2, len2, 0, &alc, NULL);
    yyjson_doc_free(doc);
    doc = yyjson_read_opts(dat3, len3, 0, &alc, NULL);
    yyjson_doc_free(doc);

    free(buf);
 @endcode
 @see yyjson_alc_pool_init()
 */
yyjson_api_inline size_t yyjson_read_max_memory_usage(size_t len,
                                                      yyjson_read_flag flg) {
    /*
     1. The max value count is (json_size / 2 + 1),
        for example: "[1,2,3,4]" size is 9, value count is 5.
     2. Some broken JSON may cost more memory during reading, but fail at end,
        for example: "[[[[[[[[".
     3. yyjson use 16 bytes per value, see struct yyjson_val.
     4. yyjson use dynamic memory with a growth factor of 1.5.

     The max memory size is (json_size / 2 * 16 * 1.5 + padding).
     */
    size_t mul = (size_t)12 + !(flg & YYJSON_READ_INSITU);
    size_t pad = 256;
    size_t max = (size_t)(~(size_t)0);
    if (flg & YYJSON_READ_STOP_WHEN_DONE) len = len < 256 ? 256 : len;
    if (len >= (max - pad - mul) / mul) return 0;
    return len * mul + pad;
}

/**
 Read a JSON number.

 This function is thread-safe when data is not modified by other threads.

 @param dat The JSON data (UTF-8 without BOM), null-terminator is required.
    If this parameter is NULL, the function will fail and return NULL.
 @param val The output value where result is stored.
    If this parameter is NULL, the function will fail and return NULL.
    The value will hold either UINT or SINT or REAL number;
 @param flg The JSON read options.
    Multiple options can be combined with `|` operator. 0 means no options.
    Supports `YYJSON_READ_NUMBER_AS_RAW` and `YYJSON_READ_ALLOW_INF_AND_NAN`.
 @param alc The memory allocator used for long number.
    It is only used when the built-in floating point reader is disabled.
    Pass NULL to use the libc's default allocator.
 @param err A pointer to receive error information.
    Pass NULL if you don't need error information.
 @return If successful, a pointer to the character after the last character
    used in the conversion, NULL if an error occurs.
 */
yyjson_api const char *yyjson_read_number(const char *dat,
                                          yyjson_val *val,
                                          yyjson_read_flag flg,
                                          const yyjson_alc *alc,
                                          yyjson_read_err *err);

/** Same as `yyjson_read_number()`. */
yyjson_api_inline const char *yyjson_mut_read_number(const char *dat,
                                                     yyjson_mut_val *val,
                                                     yyjson_read_flag flg,
                                                     const yyjson_alc *alc,
                                                     yyjson_read_err *err) {
    return yyjson_read_number(dat, (yyjson_val *)val, flg, alc, err);
}

#endif /* YYJSON_DISABLE_READER) */



/*==============================================================================
 * MARK: - JSON Writer API
 *============================================================================*/

/** Run-time options for JSON writer. */
typedef uint32_t yyjson_write_flag;

/** Default option:
    - Write JSON minify.
    - Report error on inf or nan number.
    - Report error on invalid UTF-8 string.
    - Do not escape unicode or slash. */
static const yyjson_write_flag YYJSON_WRITE_NOFLAG                  = 0;

/** Write JSON pretty with 4 space indent. */
static const yyjson_write_flag YYJSON_WRITE_PRETTY                  = 1 << 0;

/** Escape unicode as `uXXXX`, make the output ASCII only. */
static const yyjson_write_flag YYJSON_WRITE_ESCAPE_UNICODE          = 1 << 1;

/** Escape '/' as '\/'. */
static const yyjson_write_flag YYJSON_WRITE_ESCAPE_SLASHES          = 1 << 2;

/** Write inf and nan number as 'Infinity' and 'NaN' literal (non-standard). */
static const yyjson_write_flag YYJSON_WRITE_ALLOW_INF_AND_NAN       = 1 << 3;



( run in 4.118 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )