parser json UPDATE support for opaque nodes with invalid-encoded value

Fixes #2033
diff --git a/src/parser_json.c b/src/parser_json.c
index 9cbd5d8..40eb568 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -338,6 +338,55 @@
 }
 
 /**
+ * @brief Get the hint for the data type parsers according to the current JSON parser context.
+ *
+ * @param[in] jsonctx JSON parser context. The context is supposed to be on a value.
+ * @param[in,out] status Pointer to the current context status,
+ * in some circumstances the function manipulates with the context so the status is updated.
+ * @param[out] type_hint_p Pointer to the variable to store the result.
+ * @return LY_SUCCESS in case of success.
+ * @return LY_EINVAL in case of invalid context status not referring to a value.
+ */
+static LY_ERR
+lydjson_value_type_hint(struct lyjson_ctx *jsonctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
+{
+    *type_hint_p = 0;
+
+    if (*status_p == LYJSON_ARRAY) {
+        /* only [null] */
+        LY_CHECK_RET(lyjson_ctx_next(jsonctx, status_p));
+        if (*status_p != LYJSON_NULL) {
+            LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON,
+                    "Expected JSON name/value or special name/[null], but input data contains name/[%s].",
+                    lyjson_token2str(*status_p));
+            return LY_EINVAL;
+        }
+
+        LY_CHECK_RET(lyjson_ctx_next(jsonctx, NULL));
+        if (lyjson_ctx_status(jsonctx) != LYJSON_ARRAY_CLOSED) {
+            LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON, "Expected array end, but input data contains %s.",
+                    lyjson_token2str(*status_p));
+            return LY_EINVAL;
+        }
+
+        *type_hint_p = LYD_VALHINT_EMPTY;
+    } else if (*status_p == LYJSON_STRING) {
+        *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
+    } else if (*status_p == LYJSON_NUMBER) {
+        *type_hint_p = LYD_VALHINT_DECNUM;
+    } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
+        *type_hint_p = LYD_VALHINT_BOOLEAN;
+    } else if (*status_p == LYJSON_NULL) {
+        *type_hint_p = 0;
+    } else {
+        LOGVAL(jsonctx->ctx, LYVE_SYNTAX_JSON, "Unexpected input data %s.", lyjson_token2str(*status_p));
+        return LY_EINVAL;
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
  * @brief Check that the input data are parseable as the @p list.
  *
  * Checks for all the list's keys. Function does not revert the context state.
@@ -354,7 +403,7 @@
     enum LYJSON_PARSER_STATUS status = lyjson_ctx_status(jsonctx);
     struct ly_set key_set = {0};
     const struct lysc_node *snode;
-    uint32_t i;
+    uint32_t i, hints;
 
     assert(list && (list->nodetype == LYS_LIST));
 
@@ -402,7 +451,9 @@
                         goto cleanup;
                     }
 
-                    rc = lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL);
+                    rc = lydjson_value_type_hint(jsonctx, &status, &hints);
+                    LY_CHECK_GOTO(rc, cleanup);
+                    rc = ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, hints);
                     LY_CHECK_GOTO(rc, cleanup);
 
                     /* key with a valid value, remove from the set */
@@ -430,55 +481,6 @@
 }
 
 /**
- * @brief Get the hint for the data type parsers according to the current JSON parser context.
- *
- * @param[in] lydctx JSON data parser context. The context is supposed to be on a value.
- * @param[in,out] status Pointer to the current context status,
- * in some circumstances the function manipulates with the context so the status is updated.
- * @param[out] type_hint_p Pointer to the variable to store the result.
- * @return LY_SUCCESS in case of success.
- * @return LY_EINVAL in case of invalid context status not referring to a value.
- */
-static LY_ERR
-lydjson_value_type_hint(struct lyd_json_ctx *lydctx, enum LYJSON_PARSER_STATUS *status_p, uint32_t *type_hint_p)
-{
-    *type_hint_p = 0;
-
-    if (*status_p == LYJSON_ARRAY) {
-        /* only [null] */
-        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, status_p));
-        if (*status_p != LYJSON_NULL) {
-            LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON,
-                    "Expected JSON name/value or special name/[null], but input data contains name/[%s].",
-                    lyjson_token2str(*status_p));
-            return LY_EINVAL;
-        }
-
-        LY_CHECK_RET(lyjson_ctx_next(lydctx->jsonctx, NULL));
-        if (lyjson_ctx_status(lydctx->jsonctx) != LYJSON_ARRAY_CLOSED) {
-            LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Expected array end, but input data contains %s.",
-                    lyjson_token2str(*status_p));
-            return LY_EINVAL;
-        }
-
-        *type_hint_p = LYD_VALHINT_EMPTY;
-    } else if (*status_p == LYJSON_STRING) {
-        *type_hint_p = LYD_VALHINT_STRING | LYD_VALHINT_NUM64;
-    } else if (*status_p == LYJSON_NUMBER) {
-        *type_hint_p = LYD_VALHINT_DECNUM;
-    } else if ((*status_p == LYJSON_FALSE) || (*status_p == LYJSON_TRUE)) {
-        *type_hint_p = LYD_VALHINT_BOOLEAN;
-    } else if (*status_p == LYJSON_NULL) {
-        *type_hint_p = 0;
-    } else {
-        LOGVAL(lydctx->jsonctx->ctx, LYVE_SYNTAX_JSON, "Unexpected input data %s.", lyjson_token2str(*status_p));
-        return LY_EINVAL;
-    }
-
-    return LY_SUCCESS;
-}
-
-/**
  * @brief Check in advance if the input data are parsable according to the provided @p snode.
  *
  * Note that the checks are done only in case the LYD_PARSE_OPAQ is allowed. Otherwise the same checking
@@ -518,12 +520,10 @@
         case LYS_LEAFLIST:
         case LYS_LEAF:
             /* value may not be valid in which case we parse it as an opaque node */
-            ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
-            if (ret) {
+            if ((ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p))) {
                 break;
             }
-
-            if (lys_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL)) {
+            if (ly_value_validate(NULL, snode, jsonctx->value, jsonctx->value_len, LY_VALUE_JSON, NULL, *type_hint_p)) {
                 ret = LY_ENOT;
             }
             break;
@@ -536,7 +536,7 @@
             break;
         }
     } else if (snode->nodetype & LYD_NODE_TERM) {
-        ret = lydjson_value_type_hint(lydctx, &status, type_hint_p);
+        ret = lydjson_value_type_hint(jsonctx, &status, type_hint_p);
     }
 
     /* restore parser */
@@ -846,7 +846,7 @@
         LY_CHECK_GOTO(rc = lyjson_ctx_next(lydctx->jsonctx, &status), cleanup);
 
         /* get value hints */
-        LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx, &status, &val_hints), cleanup);
+        LY_CHECK_GOTO(rc = lydjson_value_type_hint(lydctx->jsonctx, &status, &val_hints), cleanup);
 
         if (node->schema) {
             /* create metadata */
@@ -969,7 +969,7 @@
         dynamic = lydctx->jsonctx->dynamic;
         lydctx->jsonctx->dynamic = 0;
 
-        LY_CHECK_RET(lydjson_value_type_hint(lydctx, status_inner_p, &type_hint));
+        LY_CHECK_RET(lydjson_value_type_hint(lydctx->jsonctx, status_inner_p, &type_hint));
     }
 
     /* get the module name */
diff --git a/src/parser_xml.c b/src/parser_xml.c
index 54e6c8b..054e01a 100644
--- a/src/parser_xml.c
+++ b/src/parser_xml.c
@@ -286,7 +286,7 @@
         assert(xmlctx->status == LYXML_ELEM_CONTENT);
         if (i < key_set.count) {
             /* validate the value */
-            r = lys_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns);
+            r = ly_value_validate(NULL, snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA);
             if (!r) {
                 /* key with a valid value, remove from the set */
                 ly_set_rm_index(&key_set, i, NULL);
@@ -392,7 +392,7 @@
 
     if ((*snode)->nodetype & LYD_NODE_TERM) {
         /* value may not be valid in which case we parse it as an opaque node */
-        if (lys_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns)) {
+        if (ly_value_validate(NULL, *snode, xmlctx->value, xmlctx->value_len, LY_VALUE_XML, &xmlctx->ns, LYD_HINT_DATA)) {
             LOGVRB("Parsing opaque term node \"%s\" with invalid value \"%.*s\".", (*snode)->name, xmlctx->value_len,
                     xmlctx->value);
             *snode = NULL;
diff --git a/src/tree_data_common.c b/src/tree_data_common.c
index 69c3851..65784ae 100644
--- a/src/tree_data_common.c
+++ b/src/tree_data_common.c
@@ -499,8 +499,8 @@
 }
 
 LY_ERR
-lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
-        LY_VALUE_FORMAT format, void *prefix_data)
+ly_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
+        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints)
 {
     LY_ERR rc = LY_SUCCESS;
     struct ly_err_item *err = NULL;
@@ -515,8 +515,8 @@
     }
 
     type = ((struct lysc_node_leaf *)node)->type;
-    rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data,
-            LYD_HINT_SCHEMA, node, &storage, NULL, &err);
+    rc = type->plugin->store(ctx ? ctx : node->module->ctx, type, value, value_len, 0, format, prefix_data, hints, node,
+            &storage, NULL, &err);
     if (rc == LY_EINCOMPLETE) {
         /* actually success since we do not provide the context tree and call validation with
          * LY_TYPE_OPTS_INCOMPLETE_DATA */
@@ -778,8 +778,8 @@
         ly_set_rm_index(&key_set, i, NULL);
 
         /* check value */
-        ret = lys_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
-                opaq_k->val_prefix_data);
+        ret = ly_value_validate(LYD_CTX(node), key, opaq_k->value, strlen(opaq_k->value), opaq_k->format,
+                opaq_k->val_prefix_data, opaq_k->hints);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -889,7 +889,7 @@
 
     if (snode->nodetype & LYD_NODE_TERM) {
         /* leaf / leaf-list */
-        rc = lys_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data);
+        rc = ly_value_validate(ctx, snode, opaq->value, strlen(opaq->value), opaq->format, opaq->val_prefix_data, opaq->hints);
         LY_CHECK_GOTO(rc, cleanup);
     } else if (snode->nodetype == LYS_LIST) {
         /* list */
diff --git a/src/tree_data_internal.h b/src/tree_data_internal.h
index e87723b..c7449ce 100644
--- a/src/tree_data_internal.h
+++ b/src/tree_data_internal.h
@@ -506,8 +506,7 @@
         const struct lyd_node *ctx_node, const struct lyd_node *tree);
 
 /**
- * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value coming
- * from a schema.
+ * @brief Check type restrictions applicable to the particular leaf/leaf-list with the given string @p value.
  *
  * This function check just the type's restriction, if you want to check also the data tree context (e.g. in case of
  * require-instance restriction), use ::lyd_value_validate().
@@ -518,11 +517,12 @@
  * @param[in] value_len Length of the given @p value (mandatory).
  * @param[in] format Value prefix format.
  * @param[in] prefix_data Format-specific data for resolving any prefixes (see ::ly_resolve_prefix).
+ * @param[in] hints Value encoding hints.
  * @return LY_SUCCESS on success
  * @return LY_ERR value if an error occurred.
  */
-LY_ERR lys_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
-        LY_VALUE_FORMAT format, void *prefix_data);
+LY_ERR ly_value_validate(const struct ly_ctx *ctx, const struct lysc_node *node, const char *value, size_t value_len,
+        LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints);
 
 /**
  * @defgroup datahash Data nodes hash manipulation
diff --git a/tests/utests/data/test_parser_json.c b/tests/utests/data/test_parser_json.c
index 9e99e34..e5513da 100644
--- a/tests/utests/data/test_parser_json.c
+++ b/tests/utests/data/test_parser_json.c
@@ -45,6 +45,7 @@
             "leaf-list ll1 { type uint8; }"
             "leaf foo2 { type string; default \"default-val\"; }"
             "leaf foo3 { type uint32; }"
+            "leaf foo4 { type uint64; }"
             "notification n2;}";
 
     UTEST_SETUP;
@@ -526,6 +527,19 @@
     CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
     lyd_free_all(tree);
 
+    /* wrong encoding */
+    data = "{\"a:foo3\":\"25\"}";
+    CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo3", 0, 0, NULL,  0,  "25");
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
+    data = "{\"a:foo4\":25}";
+    CHECK_PARSE_LYD(data, LYD_PARSE_OPAQ | LYD_PARSE_ONLY, 0, tree);
+    CHECK_LYD_NODE_OPAQ((struct lyd_node_opaq *)tree, 0, 0, LY_VALUE_JSON, "foo4", 0, 0, NULL,  0,  "25");
+    CHECK_LYD_STRING(tree, LYD_PRINT_SHRINK | LYD_PRINT_WITHSIBLINGS, data);
+    lyd_free_all(tree);
+
     /* missing key, no flags */
     data = "{\"a:l1\":[{\"a\":\"val_a\",\"b\":\"val_b\",\"d\":\"val_d\"}]}";
     PARSER_CHECK_ERROR(data, 0, LYD_VALIDATE_PRESENT, tree, LY_EVALID,