lyb UPDATE support for nested ext data

Needed LYB format change.
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 43eafc1..25295ef 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -30,6 +30,7 @@
 #include "log.h"
 #include "parser_data.h"
 #include "parser_internal.h"
+#include "plugins_exts.h"
 #include "set.h"
 #include "tree.h"
 #include "tree_data.h"
@@ -331,67 +332,86 @@
 }
 
 /**
- * @brief Parse YANG model info.
+ * @brief Read YANG model info.
  *
  * @param[in] lybctx LYB context.
- * @param[in] parse_options Flag with options for parsing.
- * @param[out] model Parsed module.
+ * @param[out] mod_name Module name, if any.
+ * @param[out] mod_rev Module revision, "" if none.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_parse_model(struct lylyb_ctx *lybctx, uint32_t parse_options, const struct lys_module **model)
+lyb_read_model(struct lylyb_ctx *lybctx, char **mod_name, char mod_rev[])
 {
-    LY_ERR ret = LY_SUCCESS;
-    const struct lys_module *mod = NULL;
-    char *mod_name = NULL, mod_rev[LY_REV_SIZE];
     uint16_t rev, length;
 
-    lyb_read_number(&length, 2, 2, lybctx);
+    *mod_name = NULL;
+    mod_rev[0] = '\0';
 
-    if (length) {
-        mod_name = malloc((length + 1) * sizeof *mod_name);
-        LY_CHECK_ERR_RET(!mod_name, LOGMEM(lybctx->ctx), LY_EMEM);
-        lyb_read(((uint8_t *)mod_name), length, lybctx);
-        mod_name[length] = '\0';
-    } else {
-        goto cleanup;
+    lyb_read_number(&length, 2, 2, lybctx);
+    if (!length) {
+        return LY_SUCCESS;
     }
 
-    /* revision */
+    /* module name */
+    *mod_name = malloc((length + 1) * sizeof *mod_name);
+    LY_CHECK_ERR_RET(!*mod_name, LOGMEM(lybctx->ctx), LY_EMEM);
+    lyb_read(((uint8_t *)*mod_name), length, lybctx);
+    (*mod_name)[length] = '\0';
+
+    /* module revision */
     lyb_read_number(&rev, sizeof rev, 2, lybctx);
 
     if (rev) {
         sprintf(mod_rev, "%04u-%02u-%02u", ((rev & LYB_REV_YEAR_MASK) >> LYB_REV_YEAR_SHIFT) + LYB_REV_YEAR_OFFSET,
                 (rev & LYB_REV_MONTH_MASK) >> LYB_REV_MONTH_SHIFT, rev & LYB_REV_DAY_MASK);
-        mod = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
-        if ((parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !mod) {
+    }
+
+    return LY_SUCCESS;
+}
+
+/**
+ * @brief Parse YANG model info.
+ *
+ * @param[in] lybctx LYB context.
+ * @param[in] parse_options Flag with options for parsing.
+ * @param[out] mod Parsed module.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyb_parse_model(struct lylyb_ctx *lybctx, uint32_t parse_options, const struct lys_module **mod)
+{
+    LY_ERR ret = LY_SUCCESS;
+    const struct lys_module *m = NULL;
+    char *mod_name = NULL, mod_rev[LY_REV_SIZE];
+
+    /* read module info */
+    if ((ret = lyb_read_model(lybctx, &mod_name, mod_rev))) {
+        goto cleanup;
+    }
+
+    /* get the module */
+    if (mod_rev[0]) {
+        m = ly_ctx_get_module(lybctx->ctx, mod_name, mod_rev);
+        if ((parse_options & LYD_PARSE_LYB_MOD_UPDATE) && !m) {
             /* try to use an updated module */
-            mod = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
-            if (mod && (!mod->revision || (strcmp(mod->revision, mod_rev) < 0))) {
+            m = ly_ctx_get_module_implemented(lybctx->ctx, mod_name);
+            if (m && (!m->revision || (strcmp(m->revision, mod_rev) < 0))) {
                 /* not an implemented module in a newer revision */
-                mod = NULL;
+                m = NULL;
             }
         }
     } else {
-        mod = ly_ctx_get_module_latest(lybctx->ctx, mod_name);
+        m = ly_ctx_get_module_latest(lybctx->ctx, mod_name);
     }
-    /* TODO data_clb supported?
-    if (lybctx->ctx->data_clb) {
-        if (!*mod) {
-            *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, NULL, 0, lybctx->ctx->data_clb_data);
-        } else if (!(*mod)->implemented) {
-            *mod = lybctx->ctx->data_clb(lybctx->ctx, mod_name, (*mod)->ns, LY_MODCLB_NOT_IMPLEMENTED, lybctx->ctx->data_clb_data);
-        }
-    }*/
 
-    if (!mod || !mod->implemented) {
+    if (!m || !m->implemented) {
         if (parse_options & LYD_PARSE_STRICT) {
-            if (!mod) {
+            if (!m) {
                 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, missing module \"%s%s%s\".",
-                        mod_name, rev ? "@" : "", rev ? mod_rev : "");
-            } else if (!mod->implemented) {
+                        mod_name, mod_rev[0] ? "@" : "", mod_rev[0] ? mod_rev : "");
+            } else if (!m->implemented) {
                 LOGERR(lybctx->ctx, LY_EINVAL, "Invalid context for LYB data parsing, module \"%s%s%s\" not implemented.",
-                        mod_name, rev ? "@" : "", rev ? mod_rev : "");
+                        mod_name, mod_rev[0] ? "@" : "", mod_rev[0] ? mod_rev : "");
             }
             ret = LY_EINVAL;
             goto cleanup;
@@ -399,13 +419,13 @@
 
     }
 
-    if (mod) {
+    if (m) {
         /* fill cached hashes, if not already */
-        lyb_cache_module_hash(mod);
+        lyb_cache_module_hash(m);
     }
 
 cleanup:
-    *model = mod;
+    *mod = m;
     free(mod_name);
     return ret;
 }
@@ -748,7 +768,7 @@
             break;
         }
         /* skip schema nodes from models not present during printing */
-        if (lyb_has_schema_model(sibling, lybctx->lybctx->models) &&
+        if (((sibling->module->ctx != lybctx->lybctx->ctx) || lyb_has_schema_model(sibling, lybctx->lybctx->models)) &&
                 lyb_is_schema_hash_match((struct lysc_node *)sibling, hash, hash_count)) {
             /* match found */
             break;
@@ -776,6 +796,50 @@
 }
 
 /**
+ * @brief Parse schema node name of a nested extension data node.
+ *
+ * @param[in] lybctx LYB context.
+ * @param[in] parent Data parent.
+ * @param[in] mod_name Module name of the node.
+ * @param[out] snode Parsed found schema node of a nested extension.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+lyb_parse_schema_nested_ext(struct lyd_lyb_ctx *lybctx, const struct lyd_node *parent, const char *mod_name,
+        const struct lysc_node **snode)
+{
+    LY_ERR rc = LY_SUCCESS, r;
+    char *name = NULL;
+    struct lysc_ext_instance *ext;
+
+    assert(parent);
+
+    /* read schema node name */
+    LY_CHECK_GOTO(rc = lyb_read_string(&name, sizeof(uint16_t), lybctx->lybctx), cleanup);
+
+    /* check for extension data */
+    r = ly_nested_ext_schema(parent, NULL, mod_name, mod_name ? strlen(mod_name) : 0, LY_VALUE_JSON, NULL, name,
+            strlen(name), snode, &ext);
+    if (r == LY_ENOT) {
+        /* failed to parse */
+        LOGERR(lybctx->lybctx->ctx, LY_EINVAL, "Failed to parse node \"%s\" as nested extension instance data.", name);
+        rc = LY_EINVAL;
+        goto cleanup;
+    } else if (r) {
+        /* error */
+        rc = r;
+        goto cleanup;
+    }
+
+    /* fill cached hashes in the module, it may be from a different context */
+    lyb_cache_module_hash((*snode)->module);
+
+cleanup:
+    free(name);
+    return rc;
+}
+
+/**
  * @brief Read until the end of the current siblings.
  *
  * @param[in] lybctx LYB context.
@@ -849,7 +913,11 @@
         struct ly_set *parsed)
 {
     /* insert, keep first pointer correct */
-    lyd_insert_node(parent, first_p, node, lybctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+    if (parent && (LYD_CTX(parent) != LYD_CTX(node))) {
+        lyd_insert_ext(parent, node);
+    } else {
+        lyd_insert_node(parent, first_p, node, lybctx->parse_opts & LYD_PARSE_ORDERED ? 1 : 0);
+    }
     while (!parent && (*first_p)->prev->next) {
         *first_p = (*first_p)->prev;
     }
@@ -1363,12 +1431,12 @@
 }
 
 /**
- * @brief Parse node.
+ * @brief Parse a node.
  *
- * @param[in] out Out structure.
- * @param[in,out] printed_node Current data node to print. Sets to the last printed node.
- * @param[in,out] sibling_ht Cached hash table for these siblings, created if NULL.
  * @param[in] lybctx LYB context.
+ * @param[in] parent Data parent of the sibling, must be set if @p first_p is not.
+ * @param[in,out] first_p First top-level sibling, must be set if @p parent is not.
+ * @param[in,out] parsed Set of all successfully parsed nodes to add to.
  * @return LY_ERR value.
  */
 static LY_ERR
@@ -1378,19 +1446,33 @@
     LY_ERR ret;
     const struct lysc_node *snode;
     const struct lys_module *mod;
+    enum lylyb_node_type lyb_type;
+    char *mod_name = NULL, mod_rev[LY_REV_SIZE];
 
-    if (!parent || !parent->schema) {
-        /* top-level or opaque, read module name */
-        ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
-        LY_CHECK_RET(ret);
+    /* read node type */
+    lyb_read_number(&lyb_type, sizeof lyb_type, 1, lybctx->lybctx);
+
+    switch (lyb_type) {
+    case LYB_NODE_TOP:
+        /* top-level, read module name */
+        LY_CHECK_GOTO(ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod), cleanup);
 
         /* read hash, find the schema node starting from mod */
-        ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode);
-    } else {
-        /* read hash, find the schema node starting from parent schema */
-        ret = lyb_parse_schema_hash(lybctx, parent->schema, NULL, &snode);
+        LY_CHECK_GOTO(ret = lyb_parse_schema_hash(lybctx, NULL, mod, &snode), cleanup);
+        break;
+    case LYB_NODE_CHILD:
+    case LYB_NODE_OPAQ:
+        /* read hash, find the schema node starting from parent schema, if any */
+        LY_CHECK_GOTO(ret = lyb_parse_schema_hash(lybctx, parent ? parent->schema : NULL, NULL, &snode), cleanup);
+        break;
+    case LYB_NODE_EXT:
+        /* ext, read module name */
+        LY_CHECK_GOTO(ret = lyb_read_model(lybctx->lybctx, &mod_name, mod_rev), cleanup);
+
+        /* read schema node name, find the nexted ext schema node */
+        LY_CHECK_GOTO(ret = lyb_parse_schema_nested_ext(lybctx, parent, mod_name, &snode), cleanup);
+        break;
     }
-    LY_CHECK_RET(ret);
 
     if (!snode) {
         ret = lyb_parse_node_opaq(lybctx, parent, first_p, parsed);
@@ -1405,8 +1487,10 @@
     } else {
         ret = lyb_parse_node_leaf(lybctx, parent, snode, first_p, parsed);
     }
-    LY_CHECK_RET(ret);
+    LY_CHECK_GOTO(ret, cleanup);
 
+cleanup:
+    free(mod_name);
     return ret;
 }
 
@@ -1423,18 +1507,15 @@
 lyb_parse_siblings(struct lyd_lyb_ctx *lybctx, struct lyd_node *parent, struct lyd_node **first_p,
         struct ly_set *parsed)
 {
-    LY_ERR ret;
     ly_bool top_level;
 
     top_level = !LY_ARRAY_COUNT(lybctx->lybctx->siblings);
 
     /* register a new siblings */
-    ret = lyb_read_start_siblings(lybctx->lybctx);
-    LY_CHECK_RET(ret);
+    LY_CHECK_RET(lyb_read_start_siblings(lybctx->lybctx));
 
     while (LYB_LAST_SIBLING(lybctx->lybctx).written) {
-        ret = lyb_parse_node(lybctx, parent, first_p, parsed);
-        LY_CHECK_RET(ret);
+        LY_CHECK_RET(lyb_parse_node(lybctx, parent, first_p, parsed));
 
         if (top_level && !(lybctx->int_opts & LYD_INTOPT_WITH_SIBLINGS)) {
             break;
@@ -1442,10 +1523,9 @@
     }
 
     /* end the siblings */
-    ret = lyb_read_stop_siblings(lybctx->lybctx);
-    LY_CHECK_RET(ret);
+    LY_CHECK_RET(lyb_read_stop_siblings(lybctx->lybctx));
 
-    return ret;
+    return LY_SUCCESS;
 }
 
 /**