JSON parser BUGFIX check for the top-level object

YANG data JSON encoding expects JSON object at the data top-level. So
far we were checking for it just with asserts, so change it and check
that the document is empty or an starts with an object.
diff --git a/src/parser_json.c b/src/parser_json.c
index 776379a..d2794ad 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1377,16 +1377,20 @@
  * @param[in] parse_options Options for parser, see @ref dataparseroptions.
  * @param[in] validate_options Options for the validation phase, see @ref datavalidationoptions.
  * @param[out] lydctx_p Data parser context to finish validation.
+ * @param[out] status Storage for the current context's status
  * @return LY_ERR value.
  */
 static LY_ERR
 lyd_parse_json_init(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_options, uint32_t validate_options,
-        struct lyd_json_ctx **lydctx_p)
+        struct lyd_json_ctx **lydctx_p, enum LYJSON_PARSER_STATUS *status)
 {
     LY_ERR ret = LY_SUCCESS;
     struct lyd_json_ctx *lydctx;
     size_t i, line = 1;
 
+    assert(lydctx_p);
+    assert(status);
+
     /* init context */
     lydctx = calloc(1, sizeof *lydctx);
     LY_CHECK_ERR_RET(!lydctx, LOGMEM(ctx), LY_EMEM);
@@ -1402,13 +1406,17 @@
     }
 
     LY_CHECK_ERR_RET(ret = lyjson_ctx_new(ctx, in, &lydctx->jsonctx), free(lydctx), ret);
-    if (lyjson_ctx_status(lydctx->jsonctx, 0) == LYJSON_END) {
-        /* empty data input */
+    *status = lyjson_ctx_status(lydctx->jsonctx, 0);
+    if (*status == LYJSON_END || *status == LYJSON_OBJECT_EMPTY || *status == LYJSON_OBJECT) {
         *lydctx_p = lydctx;
         return LY_SUCCESS;
+    } else {
+        /* expecting top-level object */
+        LOGVAL(ctx, LY_VLOG_LINE, &line, LYVE_SYNTAX_JSON, "Expected top-level JSON object, but %s found.",
+                lyjson_token2str(*status));
+        *lydctx_p = NULL;
+        return LY_EVALID;
     }
-    *lydctx_p = lydctx;
-    return LY_SUCCESS;
 }
 
 LY_ERR
@@ -1422,12 +1430,10 @@
     assert(tree_p);
     *tree_p = NULL;
 
-    ret = lyd_parse_json_init(ctx, in, parse_options, validate_options, &lydctx);
-    LY_CHECK_GOTO(ret, cleanup);
+    ret = lyd_parse_json_init(ctx, in, parse_options, validate_options, &lydctx, &status);
+    LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
 
-    status = lyjson_ctx_status(lydctx->jsonctx, 0);
-    LY_CHECK_GOTO(status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
-    assert((status == LYJSON_OBJECT));
+    assert(status == LYJSON_OBJECT);
 
     /* read subtree(s) */
     while (lydctx->jsonctx->in->current[0] && status != LYJSON_OBJECT_CLOSED) {
@@ -1462,12 +1468,13 @@
  *
  * @param[in] jsonctx JSON parser context
  * @param[out] envp_p Pointer to the created envelope opaq container.
+ * @param[out] status Storage for the current context's status
  * @return LY_SUCCESS if the envelope present and successfully parsed.
  * @return LY_ENOT in case there is not the expected envelope.
  * @return LY_ERR in case of parsing failure.
  */
 static LY_ERR
-lydjson_notif_envelope(struct lyjson_ctx *jsonctx, struct lyd_node **envp_p)
+lydjson_notif_envelope(struct lyjson_ctx *jsonctx, struct lyd_node **envp_p, enum LYJSON_PARSER_STATUS *status_p)
 {
     LY_ERR ret = LY_ENOT, r;
     const char *name, *prefix, *value = NULL;
@@ -1523,6 +1530,7 @@
     lyd_insert_node(*envp_p, NULL, et);
 
     ret = LY_SUCCESS;
+    *status_p = status;
 cleanup:
     if (ret) {
         /* restore the context */
@@ -1544,21 +1552,21 @@
     enum LYJSON_PARSER_STATUS status;
 
     /* init */
-    ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
-    LY_CHECK_GOTO(ret || !lydctx, cleanup);
+    ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
+    LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
+
     lydctx->int_opts = LYD_INTOPT_NOTIF;
 
-    status = lyjson_ctx_status(lydctx->jsonctx, 0);
-    assert(status == LYJSON_OBJECT);
-
     /* parse "notification" and "eventTime", if present */
-    ret = lydjson_notif_envelope(lydctx->jsonctx, &ntf_e);
+    ret = lydjson_notif_envelope(lydctx->jsonctx, &ntf_e, &status);
     if (ret == LY_ENOT) {
         ret = LY_SUCCESS;
     } else if (ret) {
         goto cleanup;
     }
 
+    assert(status == LYJSON_OBJECT);
+
     /* read subtree */
     ret = lydjson_subtree_r(lydctx, NULL, &tree);
     LY_CHECK_GOTO(ret, cleanup);
@@ -1628,19 +1636,19 @@
  * @param[in] module_key Name of the module where the envelope element is expected.
  * @param[in] object_id Name of the envelope object.
  * @param[out] envp_p Pointer to the created envelope opaq container.
+ * @param[out] status Storage for the current context's status
  * @return LY_SUCCESS if the envelope present and successfully parsed.
  * @return LY_ENOT in case there is not the expected envelope.
  * @return LY_ERR in case of parsing failure.
  */
 static LY_ERR
 lydjson_object_envelope(struct lyjson_ctx *jsonctx, struct lyd_node *parent, const char *module_key,
-        const char *object_id, struct lyd_node **envp_p)
+        const char *object_id, struct lyd_node **envp_p, enum LYJSON_PARSER_STATUS *status)
 {
     LY_ERR ret = LY_ENOT, r;
     const char *name, *prefix;
     size_t name_len, prefix_len;
     ly_bool is_attr;
-    enum LYJSON_PARSER_STATUS status;
 
     *envp_p = NULL;
 
@@ -1651,9 +1659,9 @@
     LY_CHECK_GOTO(prefix_len != strlen(module_key) || strncmp(prefix, module_key, prefix_len), cleanup);
     LY_CHECK_GOTO(name_len != strlen(object_id) || strncmp(name, object_id, name_len), cleanup);
 
-    r = lyjson_ctx_next(jsonctx, &status);
+    r = lyjson_ctx_next(jsonctx, status);
     LY_CHECK_ERR_GOTO(r, ret = r, cleanup);
-    LY_CHECK_GOTO(status != LYJSON_OBJECT, cleanup);
+    LY_CHECK_GOTO(*status != LYJSON_OBJECT, cleanup);
 
     /* create the object envelope */
     ret = lyd_create_opaq(jsonctx->ctx, object_id, strlen(object_id), "", 0, NULL, LYD_JSON, LYD_NODEHINT_ENVELOPE,
@@ -1670,15 +1678,13 @@
 }
 
 static LY_ERR
-lydjson_object_envelope_close(struct lyjson_ctx *jsonctx, const char *object_id)
+lydjson_object_envelope_close(struct lyjson_ctx *jsonctx, const char *object_id, enum LYJSON_PARSER_STATUS *status)
 {
-    enum LYJSON_PARSER_STATUS status;
-
-    LY_CHECK_RET(lyjson_ctx_next(jsonctx, &status));
-    if (status == LYJSON_END) {
+    LY_CHECK_RET(lyjson_ctx_next(jsonctx, status));
+    if (*status == LYJSON_END) {
         LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LY_VCODE_EOF);
         return LY_EVALID;
-    } else if (status != LYJSON_OBJECT_CLOSED) {
+    } else if (*status != LYJSON_OBJECT_CLOSED) {
         LOGVAL(jsonctx->ctx, LY_VLOG_LINE, &jsonctx->line, LYVE_SYNTAX, "Unexpected sibling member \"%.*s\" of \"%s\".",
                 jsonctx->value_len, jsonctx->value, object_id);
         return LY_EVALID;
@@ -1693,16 +1699,18 @@
     struct lyd_json_ctx *lydctx = NULL;
     struct lyd_node *rpc_e = NULL, *act_e = NULL;
     struct lyd_node *tree = NULL;
+    enum LYJSON_PARSER_STATUS status;
 
     /* init */
-    ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
-    LY_CHECK_GOTO(ret || !lydctx, cleanup);
+    ret = lyd_parse_json_init(ctx, in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
+    LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
+
     lydctx->int_opts = LYD_INTOPT_RPC;
 
     /* process envelope(s), if present */
 
     /* process rpc */
-    ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc", &rpc_e);
+    ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc", &rpc_e, &status);
     if (ret == LY_ENOT) {
         ret = LY_SUCCESS;
         goto parse_content;
@@ -1710,7 +1718,7 @@
         goto cleanup;
     }
     /* process action */
-    ret = lydjson_object_envelope(lydctx->jsonctx, rpc_e, "yang", "action", &act_e);
+    ret = lydjson_object_envelope(lydctx->jsonctx, rpc_e, "yang", "action", &act_e, &status);
     if (ret == LY_ENOT) {
         ret = LY_SUCCESS;
         goto parse_content;
@@ -1719,7 +1727,7 @@
     }
 
 parse_content:
-    assert(lyjson_ctx_status(lydctx->jsonctx, 0) == LYJSON_OBJECT);
+    assert(status == LYJSON_OBJECT);
 
     /* read subtree(s) */
     ret = lydjson_subtree_r(lydctx, act_e ? (struct lyd_node_inner *)act_e : (struct lyd_node_inner *)rpc_e, &tree);
@@ -1744,7 +1752,7 @@
 
     if (act_e) {
         /* finish action envelope */
-        ret = lydjson_object_envelope_close(lydctx->jsonctx, "action");
+        ret = lydjson_object_envelope_close(lydctx->jsonctx, "action", &status);
         LY_CHECK_GOTO(ret, cleanup);
         if (lydctx->op_node->schema->nodetype != LYS_ACTION) {
             LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"action\" expected.",
@@ -1755,7 +1763,7 @@
     }
     if (rpc_e) {
         /* finish rpc envelope */
-        ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc");
+        ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc", &status);
         LY_CHECK_GOTO(ret, cleanup);
         if (!act_e && (lydctx->op_node->schema->nodetype != LYS_RPC)) {
             LOGVAL(ctx, LY_VLOG_LYD, lydctx->op_node, LYVE_DATA, "Unexpected %s element, an \"rpc\" expected.",
@@ -1801,8 +1809,9 @@
     enum LYJSON_PARSER_STATUS status;
 
     /* init */
-    ret = lyd_parse_json_init(LYD_CTX(request), in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx);
-    LY_CHECK_GOTO(ret || !lydctx, cleanup);
+    ret = lyd_parse_json_init(LYD_CTX(request), in, LYD_PARSE_ONLY | LYD_PARSE_STRICT, 0, &lydctx, &status);
+    LY_CHECK_GOTO(ret || status == LYJSON_END || status == LYJSON_OBJECT_EMPTY, cleanup);
+
     lydctx->int_opts = LYD_INTOPT_REPLY;
 
     /* find request OP */
@@ -1822,14 +1831,13 @@
     LY_CHECK_GOTO(ret = lyd_dup_single(req_op, NULL, LYD_DUP_WITH_PARENTS, &rep_op), cleanup);
 
     /* parse "rpc-reply", if any */
-    ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc-reply", &rpcr_e);
+    ret = lydjson_object_envelope(lydctx->jsonctx, NULL, "ietf-netconf", "rpc-reply", &rpcr_e, &status);
     if (ret == LY_ENOT) {
         ret = LY_SUCCESS;
     } else if (ret) {
         goto cleanup;
     }
 
-    status = lyjson_ctx_status(lydctx->jsonctx, 0);
     assert(status == LYJSON_OBJECT);
 
     /* read subtree(s) */
@@ -1846,7 +1854,7 @@
 
     if (rpcr_e) {
         /* finish rpc-reply envelope */
-        ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc-reply");
+        ret = lydjson_object_envelope_close(lydctx->jsonctx, "rpc-reply", &status);
         LY_CHECK_GOTO(ret, cleanup);
     }