From f7ea709a0e78f155255a9bef67b58e520617a895 Mon Sep 17 00:00:00 2001 From: haozi007 Date: Thu, 2 Jul 2020 11:37:01 +0800 Subject: [PATCH] backport libocispec ommit 1ae9059360dad8c0614b1bbce5f16dd0f8c0898c Author: duguhaotian Date: Sun May 24 16:54:55 2020 +0800 support keep all keys and values even unkonwn Signed-off-by: haozi007 --- third_party/libocispec/common_c.py | 111 ++++++++++++++++++++++++++++- third_party/libocispec/common_h.py | 6 +- third_party/libocispec/headers.py | 2 + third_party/libocispec/sources.py | 71 ++++++++++++++++-- 4 files changed, 181 insertions(+), 9 deletions(-) diff --git a/third_party/libocispec/common_c.py b/third_party/libocispec/common_c.py index aec856b..78224c7 100644 --- a/third_party/libocispec/common_c.py +++ b/third_party/libocispec/common_c.py @@ -43,6 +43,116 @@ CODE = '''// Auto generated file. Do not edit! # define MAX_NUM_STR_LEN 21 +static yajl_gen_status gen_yajl_val (yajl_val obj, yajl_gen g, parser_error *err); + +static yajl_gen_status gen_yajl_val_obj (yajl_val obj, yajl_gen g, parser_error *err) +{ + size_t i; + yajl_gen_status stat = yajl_gen_status_ok; + + stat = yajl_gen_map_open (g); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + + for (i = 0; i < obj->u.object.len; i++) + { + stat = yajl_gen_string (g, (const unsigned char *) obj->u.object.keys[i], strlen (obj->u.object.keys[i])); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + stat = gen_yajl_val (obj->u.object.values[i], g, err); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + } + + stat = yajl_gen_map_close (g); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + return yajl_gen_status_ok; +} + +static yajl_gen_status gen_yajl_val_array (yajl_val arr, yajl_gen g, parser_error *err) +{ + size_t i; + yajl_gen_status stat = yajl_gen_status_ok; + + stat = yajl_gen_array_open (g); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + + for (i = 0; i < arr->u.array.len; i++) + { + stat = gen_yajl_val (arr->u.array.values[i], g, err); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + } + + stat = yajl_gen_array_close (g); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + return yajl_gen_status_ok; +} + +static yajl_gen_status gen_yajl_val (yajl_val obj, yajl_gen g, parser_error *err) +{ + yajl_gen_status __stat = yajl_gen_status_ok; + char *__tstr; + + switch(obj->type) + { + case yajl_t_string: + __tstr = YAJL_GET_STRING (obj); + if (__tstr == NULL) { + return __stat; + } + __stat = yajl_gen_string (g, (const unsigned char *) __tstr, strlen (__tstr)); + if (yajl_gen_status_ok != __stat) + GEN_SET_ERROR_AND_RETURN (__stat, err); + return yajl_gen_status_ok; + case yajl_t_number: + __tstr = YAJL_GET_NUMBER (obj); + if (__tstr == NULL) { + return __stat; + } + __stat = yajl_gen_number (g, __tstr, strlen (__tstr)); + if (yajl_gen_status_ok != __stat) + GEN_SET_ERROR_AND_RETURN (__stat, err); + return yajl_gen_status_ok; + case yajl_t_object: + return gen_yajl_val_obj (obj, g, err); + case yajl_t_array: + return gen_yajl_val_array (obj, g, err); + case yajl_t_true: + return yajl_gen_bool (g, true); + case yajl_t_false: + return yajl_gen_bool (g, false); + case yajl_t_null: + case yajl_t_any: + return __stat; + } + return __stat; +} + +yajl_gen_status gen_yajl_object_residual (yajl_val obj, yajl_gen g, parser_error *err) +{ + size_t i; + yajl_gen_status stat = yajl_gen_status_ok; + + for (i = 0; i < obj->u.object.len; i++) + { + if (obj->u.object.keys[i] == NULL) + { + continue; + } + stat = yajl_gen_string (g, (const unsigned char *) obj->u.object.keys[i], strlen (obj->u.object.keys[i])); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + stat = gen_yajl_val (obj->u.object.values[i], g, err); + if (yajl_gen_status_ok != stat) + GEN_SET_ERROR_AND_RETURN (stat, err); + } + + return yajl_gen_status_ok; +} yajl_gen_status map_uint(void *ctx, long long unsigned int num) { char numstr[MAX_NUM_STR_LEN]; @@ -66,7 +176,6 @@ yajl_gen_status map_int(void *ctx, long long int num) { return yajl_gen_number((yajl_gen)ctx, (const char *)numstr, strlen(numstr)); } - bool json_gen_init(yajl_gen *g, const struct parser_context *ctx) { *g = yajl_gen_alloc(NULL); if (NULL == *g) { diff --git a/third_party/libocispec/common_h.py b/third_party/libocispec/common_h.py index 3918662..4ce7bda 100644 --- a/third_party/libocispec/common_h.py +++ b/third_party/libocispec/common_h.py @@ -66,8 +66,10 @@ extern "C" { # define OPT_GEN_KAY_VALUE 0x02 // options to generate simplify(no indent) json string # define OPT_GEN_SIMPLIFY 0x04 +// options to keep all keys and values, even do not known +# define OPT_PARSE_FULLKEY 0x08 // options not to validate utf8 data -# define OPT_GEN_NO_VALIDATE_UTF8 0x08 +# define OPT_GEN_NO_VALIDATE_UTF8 0x10 # define GEN_SET_ERROR_AND_RETURN(stat, err) { \\ if (*(err) == NULL) {\\ @@ -85,6 +87,8 @@ struct parser_context { FILE *stderr; }; +yajl_gen_status gen_yajl_object_residual (yajl_val obj, yajl_gen g, parser_error *err); + yajl_gen_status map_uint(void *ctx, long long unsigned int num); yajl_gen_status map_int(void *ctx, long long int num); diff --git a/third_party/libocispec/headers.py b/third_party/libocispec/headers.py index e35d24c..8e0dd3b 100644 --- a/third_party/libocispec/headers.py +++ b/third_party/libocispec/headers.py @@ -159,6 +159,8 @@ def append_type_c_header(obj, header, prefix): append_header_child_arr(i, header, prefix) else: append_header_child_others(i, header, prefix) + if obj.children is not None: + header.write(" yajl_val _residual;\n") typename = helpers.get_prefixe_name(obj.name, prefix) header.write("}\n%s;\n\n" % typename) diff --git a/third_party/libocispec/sources.py b/third_party/libocispec/sources.py index 3b5d9a1..88f83d5 100644 --- a/third_party/libocispec/sources.py +++ b/third_party/libocispec/sources.py @@ -224,16 +224,61 @@ def parse_obj_arr_obj(obj, c_file, prefix, obj_typename): condition = " &&\n ".join( \ ['strcmp(tree->u.object.keys[i], "%s")' % i.origname for i in obj.children]) c_file.write(""" - if (tree->type == yajl_t_object && (ctx->options & OPT_PARSE_STRICT)) { + if (tree->type == yajl_t_object) + { size_t i; - for (i = 0; i < tree->u.object.len; i++) - if (%s) { - if (ctx->stderr > 0) - (void)fprintf(ctx->stderr, "WARNING: unknown key found: %%s\\n", - tree->u.object.keys[i]); + size_t j = 0; + size_t cnt = tree->u.object.len; + yajl_val resi = NULL; + + if (ctx->options & OPT_PARSE_FULLKEY) + { + resi = calloc (1, sizeof(*tree)); + if (resi == NULL) + { + free_%s(ret); + return NULL; + } + resi->type = yajl_t_object; + resi->u.object.keys = calloc (cnt, sizeof (const char *)); + if (resi->u.object.keys == NULL) + { + free_%s(ret); + yajl_tree_free(resi); + return NULL; + } + resi->u.object.values = calloc (cnt, sizeof (yajl_val)); + if (resi->u.object.values == NULL) + { + free_%s(ret); + yajl_tree_free(resi); + return NULL; } } -""" % condition) + for (i = 0; i < tree->u.object.len; i++) + { + if (%s) + { + if (ctx->options & OPT_PARSE_FULLKEY) + { + resi->u.object.keys[j] = tree->u.object.keys[i]; + tree->u.object.keys[i] = NULL; + resi->u.object.values[j] = tree->u.object.values[i]; + tree->u.object.values[i] = NULL; + resi->u.object.len++; + } + j++; + } + } + if (ctx->options & OPT_PARSE_STRICT) + { + if (j > 0 && ctx->stderr > 0) + fprintf (ctx->stderr, "WARNING: unknown key found\\n"); + } + if (ctx->options & OPT_PARSE_FULLKEY) + ret->_residual = resi; + } +""" % (obj_typename, obj_typename, obj_typename, condition)) def parse_json_to_c(obj, c_file, prefix): @@ -518,6 +563,14 @@ def get_c_json(obj, c_file, prefix): c_file.write(" GEN_SET_ERROR_AND_RETURN(stat, err);\n") for i in nodes or []: get_obj_arr_obj(i, c_file, prefix) + if obj.typ == 'object': + if obj.children is not None: + c_file.write(" if (ptr != NULL && ptr->_residual != NULL)\n") + c_file.write(" {\n") + c_file.write(" stat = gen_yajl_object_residual (ptr->_residual, g, err);\n") + c_file.write(" if (yajl_gen_status_ok != stat)\n") + c_file.write(" GEN_SET_ERROR_AND_RETURN (stat, err);\n") + c_file.write(" }\n") c_file.write(" stat = yajl_gen_map_close((yajl_gen)g);\n") c_file.write(" if (yajl_gen_status_ok != stat)\n") c_file.write(" GEN_SET_ERROR_AND_RETURN(stat, err);\n") @@ -752,6 +805,10 @@ def make_c_free(obj, c_file, prefix): c_file.write(" free_%s(ptr->%s);\n" % (typename, i.fixname)) c_file.write(" ptr->%s = NULL;\n" % (i.fixname)) c_file.write(" }\n") + if obj.typ == 'object': + if obj.children is not None: + c_file.write(" yajl_tree_free (ptr->_residual);\n") + c_file.write(" ptr->_residual = NULL;\n") c_file.write(" free(ptr);\n") c_file.write("}\n\n") -- GitLab