plugins types FEATURE instance-identifier LYB value support
diff --git a/src/plugins_types.h b/src/plugins_types.h
index 5a67905..b8981af 100644
--- a/src/plugins_types.h
+++ b/src/plugins_types.h
@@ -770,42 +770,36 @@
  */
 
 /**
- * @brief Validate and store value of the YANG built-in instance-identifier type.
- * Implementation of the ::lyplg_type_store_clb.
+ * @brief Implementation of ::lyplg_type_store_clb for the built-in instance-identifier type.
  */
 LY_ERR lyplg_type_store_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const void *value, size_t value_len,
         uint32_t options, LY_VALUE_FORMAT format, void *prefix_data, uint32_t hints, const struct lysc_node *ctx_node,
         struct lyd_value *storage, struct lys_glob_unres *unres, struct ly_err_item **err);
 
 /**
- * @brief Comparison callback checking the instance-identifier value.
- * Implementation of the ::lyplg_type_compare_clb.
- */
-LY_ERR lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2);
-
-/**
- * @brief Printer callback printing the instance-identifier value.
- * Implementation of the ::lyplg_type_print_clb.
- */
-const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len);
-
-/**
- * @brief Duplication callback of the instance-identifier values.
- * Implementation of the ::lyplg_type_dup_clb.
- */
-LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
-
-/**
- * @brief Validate value of the YANG built-in instance-identifier type.
- * Implementation of the ::lyplg_type_validate_clb.
+ * @brief Implementation of ::lyplg_type_validate_clb for the built-in instance-identifier type.
  */
 LY_ERR lyplg_type_validate_instanceid(const struct ly_ctx *ctx, const struct lysc_type *type, const struct lyd_node *ctx_node,
         const struct lyd_node *tree, struct lyd_value *storage, struct ly_err_item **err);
 
 /**
- * @brief Free value of the YANG built-in instance-identifier types.
- * Implementation of the ::lyplg_type_free_clb.
+ * @brief Implementation of ::lyplg_type_compare_clb for the built-in instance-identifier type.
+ */
+LY_ERR lyplg_type_compare_instanceid(const struct lyd_value *val1, const struct lyd_value *val2);
+
+/**
+ * @brief Implementation of ::lyplg_type_print_clb for the built-in instance-identifier type.
+ */
+const void *lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
+        void *prefix_data, ly_bool *dynamic, size_t *value_len);
+
+/**
+ * @brief Implementation of ::lyplg_type_dup_clb for the built-in instance-identifier type.
+ */
+LY_ERR lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup);
+
+/**
+ * @brief Implementation of ::lyplg_type_free_clb for the built-in instance-identifier type.
  */
 void lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value);
 
diff --git a/src/plugins_types/instanceid.c b/src/plugins_types/instanceid.c
index ced2bac..c7aa720 100644
--- a/src/plugins_types/instanceid.c
+++ b/src/plugins_types/instanceid.c
@@ -12,8 +12,6 @@
  *     https://opensource.org/licenses/BSD-3-Clause
  */
 
-#define _GNU_SOURCE
-
 #include "plugins_types.h"
 
 #include <assert.h>
@@ -31,137 +29,119 @@
 #include "path.h"
 #include "plugins_internal.h" /* LY_TYPE_*_STR */
 
-API const void *
-lyplg_type_print_instanceid(const struct ly_ctx *ctx, const struct lyd_value *value, LY_VALUE_FORMAT format,
-        void *prefix_data, ly_bool *dynamic, size_t *value_len)
+/**
+ * @page howtoDataLYB LYB Binary Format
+ * @subsection howtoDataLYBTypesInstanceIdentifier instance-identifier (built-in)
+ *
+ * | Size (B) | Mandatory | Type | Meaning |
+ * | :------  | :-------: | :--: | :-----: |
+ * | string length | yes | `char *` | string JSON format of the instance-identifier |
+ */
+
+/**
+ * @brief Convert compiled path (instance-identifier) into string.
+ *
+ * @param[in] path Compiled path.
+ * @param[in] format Value format.
+ * @param[in] prefix_data Format-specific data for resolving prefixes.
+ * @param[out] str Printed instance-identifier.
+ * @return LY_ERR value.
+ */
+static LY_ERR
+instanceid_path2str(const struct ly_path *path, LY_VALUE_FORMAT format, void *prefix_data, char **str)
 {
+    LY_ERR ret = LY_SUCCESS;
     LY_ARRAY_COUNT_TYPE u, v;
-    char *result = NULL;
+    char *result = NULL, quot;
+    const struct lys_module *mod = NULL;
+    ly_bool inherit_prefix, d;
+    const char *strval;
 
-    if (!value->target) {
-        /* value was not fully processed */
-        return NULL;
-    }
-
-    if ((format == LY_VALUE_XML) || (format == LY_VALUE_SCHEMA)) {
+    switch (format) {
+    case LY_VALUE_XML:
+    case LY_VALUE_SCHEMA:
+    case LY_VALUE_SCHEMA_RESOLVED:
         /* everything is prefixed */
-        LY_ARRAY_FOR(value->target, u) {
-            ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(value->target[u].node->module, format, prefix_data),
-                    value->target[u].node->name);
-            LY_ARRAY_FOR(value->target[u].predicates, v) {
-                struct ly_path_predicate *pred = &value->target[u].predicates[v];
+        inherit_prefix = 0;
+        break;
+    case LY_VALUE_CANON:
+    case LY_VALUE_JSON:
+    case LY_VALUE_LYB:
+        /* the same prefix is inherited and skipped */
+        inherit_prefix = 1;
+        break;
+    }
 
-                switch (value->target[u].pred_type) {
-                case LY_PATH_PREDTYPE_NONE:
-                    break;
-                case LY_PATH_PREDTYPE_POSITION:
-                    /* position predicate */
-                    ly_strcat(&result, "[%" PRIu64 "]", pred->position);
-                    break;
-                case LY_PATH_PREDTYPE_LIST: {
-                    /* key-predicate */
-                    ly_bool d = 0;
-                    const char *str = pred->value.realtype->plugin->print(ctx, &pred->value, format, prefix_data, &d, NULL);
-                    char quot = '\'';
-                    if (strchr(str, quot)) {
-                        quot = '"';
-                    }
-                    ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
-                            pred->key->name, quot, str, quot);
-                    if (d) {
-                        free((char *)str);
-                    }
-                    break;
-                }
-                case LY_PATH_PREDTYPE_LEAFLIST: {
-                    /* leaf-list-predicate */
-                    ly_bool d = 0;
-                    const char *str = pred->value.realtype->plugin->print(ctx, &pred->value, format, prefix_data, &d, NULL);
-                    char quot = '\'';
-                    if (strchr(str, quot)) {
-                        quot = '"';
-                    }
-                    ly_strcat(&result, "[.=%c%s%c]", quot, str, quot);
-                    if (d) {
-                        free((char *)str);
-                    }
-                    break;
-                }
-                }
-            }
+    LY_ARRAY_FOR(path, u) {
+        /* new node */
+        if (!inherit_prefix || (mod != path[u].node->module)) {
+            mod = path[u].node->module;
+            ret = ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), path[u].node->name);
+        } else {
+            ret = ly_strcat(&result, "/%s", path[u].node->name);
         }
+        LY_CHECK_GOTO(ret, cleanup);
 
-        *dynamic = 1;
-    } else if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
-        /* generate canonical, only the first node or the node changing module is prefixed */
-        if (!value->_canonical) {
-            struct lys_module *mod = NULL;
-            LY_ARRAY_FOR(value->target, u) {
-                if (mod != value->target[u].node->module) {
-                    mod = value->target[u].node->module;
-                    ly_strcat(&result, "/%s:%s", lyplg_type_get_prefix(mod, format, prefix_data), value->target[u].node->name);
+        /* node predicates */
+        LY_ARRAY_FOR(path[u].predicates, v) {
+            struct ly_path_predicate *pred = &path[u].predicates[v];
+
+            switch (path[u].pred_type) {
+            case LY_PATH_PREDTYPE_NONE:
+                break;
+            case LY_PATH_PREDTYPE_POSITION:
+                /* position predicate */
+                ret = ly_strcat(&result, "[%" PRIu64 "]", pred->position);
+                break;
+            case LY_PATH_PREDTYPE_LIST:
+                /* key-predicate */
+                strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
+                        &d, NULL);
+
+                /* default quote */
+                quot = '\'';
+                if (strchr(strval, quot)) {
+                    quot = '"';
+                }
+                if (inherit_prefix) {
+                    /* always the same prefix as the parent */
+                    ret = ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, strval, quot);
                 } else {
-                    ly_strcat(&result, "/%s", value->target[u].node->name);
+                    ret = ly_strcat(&result, "[%s:%s=%c%s%c]", lyplg_type_get_prefix(pred->key->module, format, prefix_data),
+                            pred->key->name, quot, strval, quot);
                 }
-                LY_ARRAY_FOR(value->target[u].predicates, v) {
-                    struct ly_path_predicate *pred = &value->target[u].predicates[v];
+                if (d) {
+                    free((char *)strval);
+                }
+                break;
+            case LY_PATH_PREDTYPE_LEAFLIST:
+                /* leaf-list-predicate */
+                strval = pred->value.realtype->plugin->print(path[u].node->module->ctx, &pred->value, format, prefix_data,
+                        &d, NULL);
 
-                    switch (value->target[u].pred_type) {
-                    case LY_PATH_PREDTYPE_NONE:
-                        break;
-                    case LY_PATH_PREDTYPE_POSITION:
-                        /* position predicate */
-                        ly_strcat(&result, "[%" PRIu64 "]", pred->position);
-                        break;
-                    case LY_PATH_PREDTYPE_LIST: {
-                        /* key-predicate */
-                        ly_bool d = 0;
-                        const char *str = pred->value.realtype->plugin->print(ctx, &pred->value, format, prefix_data, &d, NULL);
-                        char quot = '\'';
-                        if (strchr(str, quot)) {
-                            quot = '"';
-                        }
-                        ly_strcat(&result, "[%s=%c%s%c]", pred->key->name, quot, str, quot);
-                        if (d) {
-                            free((char *)str);
-                        }
-                        break;
-                    }
-                    case LY_PATH_PREDTYPE_LEAFLIST: {
-                        /* leaf-list-predicate */
-                        ly_bool d = 0;
-                        const char *str = pred->value.realtype->plugin->print(ctx, &pred->value, format, prefix_data, &d, NULL);
-                        char quot = '\'';
-                        if (strchr(str, quot)) {
-                            quot = '"';
-                        }
-                        ly_strcat(&result, "[.=%c%s%c]", quot, str, quot);
-                        if (d) {
-                            free((char *)str);
-                        }
-                        break;
-                    }
-                    }
+                /* default quote */
+                quot = '\'';
+                if (strchr(strval, quot)) {
+                    quot = '"';
                 }
+                ret = ly_strcat(&result, "[.=%c%s%c]", quot, strval, quot);
+                if (d) {
+                    free((char *)strval);
+                }
+                break;
             }
 
-            lydict_insert_zc(ctx, result, (const char **)&value->_canonical);
+            LY_CHECK_GOTO(ret, cleanup);
         }
+    }
 
-        /* use canonical */
-        result = (char *)value->_canonical;
-        if (dynamic) {
-            *dynamic = 0;
-        }
+cleanup:
+    if (ret) {
+        free(result);
     } else {
-        /* not supported format */
-        return NULL;
+        *str = result;
     }
-
-    if (value_len) {
-        *value_len = strlen(result);
-    }
-    return result;
+    return ret;
 }
 
 API LY_ERR
@@ -171,37 +151,54 @@
 {
     LY_ERR ret = LY_SUCCESS;
     struct lysc_type_instanceid *type_inst = (struct lysc_type_instanceid *)type;
-    struct ly_path *path = NULL;
+    struct ly_path *path;
+    char *canon;
 
-    /* init */
-    *err = NULL;
+    /* clear storage */
+    memset(storage, 0, sizeof *storage);
 
     /* check hints */
     ret = lyplg_type_check_hints(hints, value, value_len, type->basetype, NULL, err);
-    LY_CHECK_GOTO(ret != LY_SUCCESS,  cleanup_value);
+    LY_CHECK_GOTO(ret, cleanup);
 
-    LY_CHECK_GOTO(ret = lyplg_type_lypath_new(ctx, value, value_len, options, format, prefix_data, ctx_node,
-            unres, &path, err), cleanup);
+    /* compile instance-identifier into path */
+    ret = lyplg_type_lypath_new(ctx, value, value_len, options, format, prefix_data, ctx_node,
+            unres, &path, err);
+    LY_CHECK_GOTO(ret, cleanup);
 
-    /* store resolved schema path and init storage */
+    /* init storage */
     storage->_canonical = NULL;
     storage->target = path;
-    path = NULL;
     storage->realtype = type;
 
-    /* generate canonical value */
-    lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
+    /* store canonical value */
+    if (format == LY_VALUE_CANON) {
+        if (options & LYPLG_TYPE_STORE_DYNAMIC) {
+            ret = lydict_insert_zc(ctx, (char *)value, &storage->_canonical);
+            options &= ~LYPLG_TYPE_STORE_DYNAMIC;
+            LY_CHECK_GOTO(ret, cleanup);
+        } else {
+            ret = lydict_insert(ctx, value, value_len, &storage->_canonical);
+            LY_CHECK_GOTO(ret, cleanup);
+        }
+    } else {
+        /* JSON format with prefix is the canonical one */
+        ret = instanceid_path2str(path, LY_VALUE_JSON, NULL, &canon);
+        LY_CHECK_GOTO(ret, cleanup);
 
-    /* cleanup */
-cleanup:
-    lyplg_type_lypath_free(ctx, path);
-
-cleanup_value:
-    if (options & LYPLG_TYPE_STORE_DYNAMIC) {
-        free((char *)value);
+        ret = lydict_insert_zc(ctx, canon, &storage->_canonical);
+        LY_CHECK_GOTO(ret, cleanup);
     }
 
-    if ((ret == LY_SUCCESS) && type_inst->require_instance) {
+cleanup:
+    if (options & LYPLG_TYPE_STORE_DYNAMIC) {
+        free((void *)value);
+    }
+
+    if (ret) {
+        lyplg_type_free_instanceid(ctx, storage);
+    }
+    if (!ret && type_inst->require_instance) {
         /* needs to be resolved */
         return LY_EINCOMPLETE;
     } else {
@@ -225,14 +222,12 @@
     }
 
     /* find the target in data */
-    if (!(ret = ly_path_eval(storage->target, tree, NULL))) {
-        return LY_SUCCESS;
+    if ((ret = ly_path_eval(storage->target, tree, NULL))) {
+        const char *value = lyplg_type_print_instanceid(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
+        return ly_err_new(err, ret, LYVE_DATA, NULL, NULL, LY_ERRMSG_NOINST, value);
     }
 
-    /* error */
-    const char *value = storage->realtype->plugin->print(ctx, storage, LY_VALUE_CANON, NULL, NULL, NULL);
-
-    return ly_err_new(err, ret, LYVE_DATA, NULL, NULL, LY_ERRMSG_NOINST, value);
+    return LY_SUCCESS;
 }
 
 API LY_ERR
@@ -246,7 +241,7 @@
 
     if (val1 == val2) {
         return LY_SUCCESS;
-    } else if (!val1->target || !val2->target || (LY_ARRAY_COUNT(val1->target) != LY_ARRAY_COUNT(val2->target))) {
+    } else if (LY_ARRAY_COUNT(val1->target) != LY_ARRAY_COUNT(val2->target)) {
         return LY_ENOT;
     }
 
@@ -274,7 +269,8 @@
                     break;
                 case LY_PATH_PREDTYPE_LIST:
                     /* key-predicate */
-                    if ((pred1->key != pred2->key) || ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
+                    if ((pred1->key != pred2->key) ||
+                            ((struct lysc_node_leaf *)pred1->key)->type->plugin->compare(&pred1->value, &pred2->value)) {
                         return LY_ENOT;
                     }
                     break;
@@ -291,20 +287,61 @@
     return LY_SUCCESS;
 }
 
+API const void *
+lyplg_type_print_instanceid(const struct ly_ctx *UNUSED(ctx), const struct lyd_value *value, LY_VALUE_FORMAT format,
+        void *prefix_data, ly_bool *dynamic, size_t *value_len)
+{
+    char *ret;
+
+    if ((format == LY_VALUE_CANON) || (format == LY_VALUE_JSON) || (format == LY_VALUE_LYB)) {
+        if (dynamic) {
+            *dynamic = 0;
+        }
+        if (value_len) {
+            *value_len = strlen(value->_canonical);
+        }
+        return value->_canonical;
+    }
+
+    /* print the value in the specific format */
+    if (instanceid_path2str(value->target, format, prefix_data, &ret)) {
+        return NULL;
+    }
+    *dynamic = 1;
+    if (value_len) {
+        *value_len = strlen(ret);
+    }
+    return ret;
+}
+
 API LY_ERR
 lyplg_type_dup_instanceid(const struct ly_ctx *ctx, const struct lyd_value *original, struct lyd_value *dup)
 {
-    LY_CHECK_RET(lydict_insert(ctx, original->_canonical, strlen(original->_canonical), &dup->_canonical));
+    LY_ERR ret;
+
+    memset(dup, 0, sizeof *dup);
+
+    /* canonical value */
+    ret = lydict_insert(ctx, original->_canonical, ly_strlen(original->_canonical), &dup->_canonical);
+    LY_CHECK_GOTO(ret, error);
+
+    /* copy path */
+    ret = ly_path_dup(ctx, original->target, &dup->target);
+    LY_CHECK_GOTO(ret, error);
+
     dup->realtype = original->realtype;
-    return ly_path_dup(ctx, original->target, &dup->target);
+    return LY_SUCCESS;
+
+error:
+    lyplg_type_free_instanceid(ctx, dup);
+    return ret;
 }
 
 API void
 lyplg_type_free_instanceid(const struct ly_ctx *ctx, struct lyd_value *value)
 {
+    lydict_remove(ctx, value->_canonical);
     ly_path_free(ctx, value->target);
-    value->target = NULL;
-    lyplg_type_free_simple(ctx, value);
 }
 
 /**