439641f772
If JSON structure is not known it is hard to use it with current API. To address this gap lets add API that will give more flexibility the user. This patch also adds proper unit tests. Change-Id: I82eb8c8d4a562ee4c9eb5b72c69fe36004dc576e Signed-off-by: Pawel Wodkowski <pawelx.wodkowski@intel.com> Reviewed-on: https://review.gerrithub.io/424009 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Jim Harris <james.r.harris@intel.com>
338 lines
13 KiB
C
338 lines
13 KiB
C
/*-
|
|
* BSD LICENSE
|
|
*
|
|
* Copyright (c) Intel Corporation.
|
|
* All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* * Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* * Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* * Neither the name of Intel Corporation nor the names of its
|
|
* contributors may be used to endorse or promote products derived
|
|
* from this software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
/**
|
|
* \file
|
|
* JSON parsing and encoding
|
|
*/
|
|
|
|
#ifndef SPDK_JSON_H_
|
|
#define SPDK_JSON_H_
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
enum spdk_json_val_type {
|
|
SPDK_JSON_VAL_INVALID = 0,
|
|
#define SPDK_JSON_VAL_ANY SPDK_JSON_VAL_INVALID
|
|
SPDK_JSON_VAL_NULL = 1U << 1,
|
|
SPDK_JSON_VAL_TRUE = 1U << 2,
|
|
SPDK_JSON_VAL_FALSE = 1U << 3,
|
|
SPDK_JSON_VAL_NUMBER = 1U << 4,
|
|
SPDK_JSON_VAL_STRING = 1U << 5,
|
|
SPDK_JSON_VAL_ARRAY_BEGIN = 1U << 6,
|
|
SPDK_JSON_VAL_ARRAY_END = 1U << 7,
|
|
SPDK_JSON_VAL_OBJECT_BEGIN = 1U << 8,
|
|
SPDK_JSON_VAL_OBJECT_END = 1U << 9,
|
|
SPDK_JSON_VAL_NAME = 1U << 10,
|
|
};
|
|
|
|
struct spdk_json_val {
|
|
/**
|
|
* Pointer to the location of the value within the parsed JSON input.
|
|
*
|
|
* For SPDK_JSON_VAL_STRING and SPDK_JSON_VAL_NAME,
|
|
* this points to the beginning of the decoded UTF-8 string without quotes.
|
|
*
|
|
* For SPDK_JSON_VAL_NUMBER, this points to the beginning of the number as represented in
|
|
* the original JSON (text representation, not converted to a numeric value).
|
|
*/
|
|
void *start;
|
|
|
|
/**
|
|
* Length of value.
|
|
*
|
|
* For SPDK_JSON_VAL_STRING, SPDK_JSON_VAL_NUMBER, and SPDK_JSON_VAL_NAME,
|
|
* this is the length in bytes of the value starting at \ref start.
|
|
*
|
|
* For SPDK_JSON_VAL_ARRAY_BEGIN and SPDK_JSON_VAL_OBJECT_BEGIN,
|
|
* this is the number of values contained within the array or object (including
|
|
* nested objects and arrays, but not including the _END value). The array or object _END
|
|
* value can be found by advancing len values from the _BEGIN value.
|
|
*/
|
|
uint32_t len;
|
|
|
|
/**
|
|
* Type of value.
|
|
*/
|
|
enum spdk_json_val_type type;
|
|
};
|
|
|
|
/**
|
|
* Invalid JSON syntax.
|
|
*/
|
|
#define SPDK_JSON_PARSE_INVALID -1
|
|
|
|
/**
|
|
* JSON was valid up to the end of the current buffer, but did not represent a complete JSON value.
|
|
*/
|
|
#define SPDK_JSON_PARSE_INCOMPLETE -2
|
|
|
|
#define SPDK_JSON_PARSE_MAX_DEPTH_EXCEEDED -3
|
|
|
|
/**
|
|
* Decode JSON strings and names in place (modify the input buffer).
|
|
*/
|
|
#define SPDK_JSON_PARSE_FLAG_DECODE_IN_PLACE 0x000000001
|
|
|
|
/**
|
|
* Allow parsing of comments.
|
|
*
|
|
* Comments are not allowed by the JSON RFC, so this is not enabled by default.
|
|
*/
|
|
#define SPDK_JSON_PARSE_FLAG_ALLOW_COMMENTS 0x000000002
|
|
|
|
/*
|
|
* Parse JSON data.
|
|
*
|
|
* \param data Raw JSON data; must be encoded in UTF-8.
|
|
* Note that the data may be modified to perform in-place string decoding.
|
|
*
|
|
* \param size Size of data in bytes.
|
|
*
|
|
* \param end If non-NULL, this will be filled a pointer to the byte just beyond the end
|
|
* of the valid JSON.
|
|
*
|
|
* \return Number of values parsed, or negative on failure:
|
|
* SPDK_JSON_PARSE_INVALID if the provided data was not valid JSON, or
|
|
* SPDK_JSON_PARSE_INCOMPLETE if the provided data was not a complete JSON value.
|
|
*/
|
|
ssize_t spdk_json_parse(void *json, size_t size, struct spdk_json_val *values, size_t num_values,
|
|
void **end, uint32_t flags);
|
|
|
|
typedef int (*spdk_json_decode_fn)(const struct spdk_json_val *val, void *out);
|
|
|
|
struct spdk_json_object_decoder {
|
|
const char *name;
|
|
size_t offset;
|
|
spdk_json_decode_fn decode_func;
|
|
bool optional;
|
|
};
|
|
|
|
int spdk_json_decode_object(const struct spdk_json_val *values,
|
|
const struct spdk_json_object_decoder *decoders, size_t num_decoders, void *out);
|
|
int spdk_json_decode_array(const struct spdk_json_val *values, spdk_json_decode_fn decode_func,
|
|
void *out, size_t max_size, size_t *out_size, size_t stride);
|
|
|
|
int spdk_json_decode_bool(const struct spdk_json_val *val, void *out);
|
|
int spdk_json_decode_uint16(const struct spdk_json_val *val, void *out);
|
|
int spdk_json_decode_int32(const struct spdk_json_val *val, void *out);
|
|
int spdk_json_decode_uint32(const struct spdk_json_val *val, void *out);
|
|
int spdk_json_decode_uint64(const struct spdk_json_val *val, void *out);
|
|
int spdk_json_decode_string(const struct spdk_json_val *val, void *out);
|
|
|
|
/**
|
|
* Get length of a value in number of values.
|
|
*
|
|
* This can be used to skip over a value while interpreting parse results.
|
|
*
|
|
* For SPDK_JSON_VAL_ARRAY_BEGIN and SPDK_JSON_VAL_OBJECT_BEGIN,
|
|
* this returns the number of values contained within this value, plus the _BEGIN and _END values.
|
|
*
|
|
* For all other values, this returns 1.
|
|
*/
|
|
size_t spdk_json_val_len(const struct spdk_json_val *val);
|
|
|
|
/**
|
|
* Compare JSON string with null terminated C string.
|
|
*
|
|
* \return true if strings are equal or false if not
|
|
*/
|
|
bool spdk_json_strequal(const struct spdk_json_val *val, const char *str);
|
|
|
|
/**
|
|
* Equivalent of strdup() for JSON string values.
|
|
*
|
|
* If val is not representable as a C string (contains embedded '\0' characters),
|
|
* returns NULL.
|
|
*
|
|
* Caller is responsible for passing the result to free() when it is no longer needed.
|
|
*/
|
|
char *spdk_json_strdup(const struct spdk_json_val *val);
|
|
|
|
int spdk_json_number_to_uint16(const struct spdk_json_val *val, uint16_t *num);
|
|
int spdk_json_number_to_int32(const struct spdk_json_val *val, int32_t *num);
|
|
int spdk_json_number_to_uint32(const struct spdk_json_val *val, uint32_t *num);
|
|
int spdk_json_number_to_uint64(const struct spdk_json_val *val, uint64_t *num);
|
|
|
|
struct spdk_json_write_ctx;
|
|
|
|
#define SPDK_JSON_WRITE_FLAG_FORMATTED 0x00000001
|
|
|
|
typedef int (*spdk_json_write_cb)(void *cb_ctx, const void *data, size_t size);
|
|
|
|
struct spdk_json_write_ctx *spdk_json_write_begin(spdk_json_write_cb write_cb, void *cb_ctx,
|
|
uint32_t flags);
|
|
int spdk_json_write_end(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_null(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_bool(struct spdk_json_write_ctx *w, bool val);
|
|
int spdk_json_write_int32(struct spdk_json_write_ctx *w, int32_t val);
|
|
int spdk_json_write_uint32(struct spdk_json_write_ctx *w, uint32_t val);
|
|
int spdk_json_write_int64(struct spdk_json_write_ctx *w, int64_t val);
|
|
int spdk_json_write_uint64(struct spdk_json_write_ctx *w, uint64_t val);
|
|
int spdk_json_write_string(struct spdk_json_write_ctx *w, const char *val);
|
|
int spdk_json_write_string_raw(struct spdk_json_write_ctx *w, const char *val, size_t len);
|
|
|
|
/**
|
|
* Write null-terminated UTF-16LE string.
|
|
*
|
|
* \param w JSON write context.
|
|
* \param val UTF-16LE string; must be null terminated.
|
|
* \return 0 on success or negative on failure.
|
|
*/
|
|
int spdk_json_write_string_utf16le(struct spdk_json_write_ctx *w, const uint16_t *val);
|
|
|
|
/**
|
|
* Write UTF-16LE string.
|
|
*
|
|
* \param w JSON write context.
|
|
* \param val UTF-16LE string; may contain embedded null characters.
|
|
* \param len Length of val in 16-bit code units (i.e. size of string in bytes divided by 2).
|
|
* \return 0 on success or negative on failure.
|
|
*/
|
|
int spdk_json_write_string_utf16le_raw(struct spdk_json_write_ctx *w, const uint16_t *val,
|
|
size_t len);
|
|
|
|
int spdk_json_write_string_fmt(struct spdk_json_write_ctx *w, const char *fmt,
|
|
...) __attribute__((__format__(__printf__, 2, 3)));
|
|
int spdk_json_write_string_fmt_v(struct spdk_json_write_ctx *w, const char *fmt, va_list args);
|
|
|
|
int spdk_json_write_array_begin(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_array_end(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_object_begin(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_object_end(struct spdk_json_write_ctx *w);
|
|
int spdk_json_write_name(struct spdk_json_write_ctx *w, const char *name);
|
|
int spdk_json_write_name_raw(struct spdk_json_write_ctx *w, const char *name, size_t len);
|
|
|
|
int spdk_json_write_val(struct spdk_json_write_ctx *w, const struct spdk_json_val *val);
|
|
|
|
/*
|
|
* Append bytes directly to the output stream without validation.
|
|
*
|
|
* Can be used to write values with specific encodings that differ from the JSON writer output.
|
|
*/
|
|
int spdk_json_write_val_raw(struct spdk_json_write_ctx *w, const void *data, size_t len);
|
|
|
|
/* Utility functions */
|
|
int spdk_json_write_named_null(struct spdk_json_write_ctx *w, const char *name);
|
|
int spdk_json_write_named_bool(struct spdk_json_write_ctx *w, const char *name, bool val);
|
|
int spdk_json_write_named_int32(struct spdk_json_write_ctx *w, const char *name, int32_t val);
|
|
int spdk_json_write_named_uint32(struct spdk_json_write_ctx *w, const char *name, uint32_t val);
|
|
int spdk_json_write_named_uint64(struct spdk_json_write_ctx *w, const char *name, uint64_t val);
|
|
int spdk_json_write_named_int64(struct spdk_json_write_ctx *w, const char *name, int64_t val);
|
|
int spdk_json_write_named_string(struct spdk_json_write_ctx *w, const char *name, const char *val);
|
|
int spdk_json_write_named_string_fmt(struct spdk_json_write_ctx *w, const char *name,
|
|
const char *fmt, ...) __attribute__((__format__(__printf__, 3, 4)));
|
|
int spdk_json_write_named_string_fmt_v(struct spdk_json_write_ctx *w, const char *name,
|
|
const char *fmt, va_list args);
|
|
|
|
int spdk_json_write_named_array_begin(struct spdk_json_write_ctx *w, const char *name);
|
|
int spdk_json_write_named_object_begin(struct spdk_json_write_ctx *w, const char *name);
|
|
|
|
/**
|
|
* Return JSON value asociated with key \c key_name. Subobjects won't be searched.
|
|
*
|
|
* \param object JSON object to be examined
|
|
* \param key_name name of the key
|
|
* \param key optional, will be set with found key
|
|
* \param val optional, will be set with value of the key
|
|
* \param type search for specific value type. Pass SPDK_JSON_VAL_ANY to match any type.
|
|
* \return 0 if found or negative error code:
|
|
* -EINVAL - json object is invalid
|
|
* -ENOENT - key not found
|
|
* -EDOM - key exists but value type mismatch.
|
|
*/
|
|
int spdk_json_find(struct spdk_json_val *object, const char *key_name, struct spdk_json_val **key,
|
|
struct spdk_json_val **val, enum spdk_json_val_type type);
|
|
|
|
/**
|
|
* The same as calling \c spdk_json_find() function with \c type set to \c SPDK_JSON_VAL_STRING
|
|
*
|
|
* \param object JSON object to be examined
|
|
* \param key_name name of the key
|
|
* \param key optional, will be set with found key
|
|
* \param val optional, will be set with value of the key
|
|
* \return See \c spdk_json_find
|
|
*/
|
|
|
|
int spdk_json_find_string(struct spdk_json_val *object, const char *key_name,
|
|
struct spdk_json_val **key, struct spdk_json_val **val);
|
|
|
|
/**
|
|
* The same as calling \c spdk_json_key() function with \c type set to \c SPDK_JSON_VAL_ARRAY_BEGIN
|
|
*
|
|
* \param object JSON object to be examined
|
|
* \param key_name name of the key
|
|
* \param key optional, will be set with found key
|
|
* \param value optional, will be set with key value
|
|
* \return See \c spdk_json_find
|
|
*/
|
|
int spdk_json_find_array(struct spdk_json_val *object, const char *key_name,
|
|
struct spdk_json_val **key, struct spdk_json_val **value);
|
|
|
|
/**
|
|
* Return first JSON value in given JSON object.
|
|
*
|
|
* \param object pointer to JSON object begin
|
|
* \return Pointer to first object or NULL if object is empty or is not an JSON object
|
|
*/
|
|
struct spdk_json_val *spdk_json_object_first(struct spdk_json_val *object);
|
|
|
|
/**
|
|
* Return first JSON value in array.
|
|
*
|
|
* \param array_begin pointer to JSON array begin
|
|
* \return Pointer to first JSON value or NULL if array is empty or is not an JSON array.
|
|
*/
|
|
|
|
struct spdk_json_val *spdk_json_array_first(struct spdk_json_val *array_begin);
|
|
|
|
/**
|
|
* Advance to the next JSON value in JSON object or array.
|
|
*
|
|
* \warning if \c pos is not JSON key or JSON array element behaviour is undefined.
|
|
*
|
|
* \param pos pointer to JSON key if iterating over JSON object or array element
|
|
* \return next JSON value or NULL if there is no more objects or array elements
|
|
*/
|
|
struct spdk_json_val *spdk_json_next(struct spdk_json_val *pos);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif
|