Merge branch 'master' into devel
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c3693af..ea1758d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -62,12 +62,12 @@
 # set version of the project
 set(LIBYANG_MAJOR_VERSION 2)
 set(LIBYANG_MINOR_VERSION 0)
-set(LIBYANG_MICRO_VERSION 88)
+set(LIBYANG_MICRO_VERSION 92)
 set(LIBYANG_VERSION ${LIBYANG_MAJOR_VERSION}.${LIBYANG_MINOR_VERSION}.${LIBYANG_MICRO_VERSION})
 # set version of the library
 set(LIBYANG_MAJOR_SOVERSION 2)
 set(LIBYANG_MINOR_SOVERSION 8)
-set(LIBYANG_MICRO_SOVERSION 18)
+set(LIBYANG_MICRO_SOVERSION 21)
 set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
 set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})
 
diff --git a/src/lyb.h b/src/lyb.h
index 687e760..165dfe5 100644
--- a/src/lyb.h
+++ b/src/lyb.h
@@ -23,6 +23,48 @@
 struct ly_ctx;
 struct lysc_node;
 
+/*
+ * LYB format
+ *
+ * Unlike XML or JSON, it is binary format so most data are represented in similar way but in binary.
+ * Some notable differences:
+ *
+ * - schema nodes are identified based on their hash instead of their string name. In case of collisions
+ * an array of hashes is created with each next hash one bit shorter until a unique sequence of all these
+ * hashes is found and then all of them are stored.
+ *
+ * - tree structure is represented as individual strictly bounded "siblings". Each "siblings" begins
+ * with its metadata, which consist of 1) the whole "sibling" length in bytes and 2) number
+ * of included metadata chunks of nested "siblings".
+ *
+ * - since length of a "sibling" is not known before it is printed, holes are first written and
+ * after the "sibling" is printed, they are filled with actual valid metadata. As a consequence,
+ * LYB data cannot be directly printed into streams!
+ *
+ * - data are preceded with information about all the used modules. It is needed because of
+ * possible augments and deviations which must be known beforehand, otherwise schema hashes
+ * could be matched to the wrong nodes.
+ *
+ * This is a short summary of the format:
+ * @verbatim
+
+ sb          = siblings_start
+ se          = siblings_end
+ siblings    = zero-LYB_SIZE_BYTES | (sb instance+ se)
+ instance    = model hash node
+ model       = 16bit_zero | (model_name_length model_name revision)
+ node        = opaq | leaflist | list | any | inner | leaf
+ opaq        = opaq_data siblings
+ leaflist    = sb leaf+ se
+ list        = sb (node_header siblings)+ se
+ any         = node_header anydata_data
+ inner       = node_header siblings
+ leaf        = node_header term_value
+ node_header = metadata node_flags
+
+ @endverbatim
+ */
+
 /**
  * @brief LYB format parser context
  */
@@ -52,29 +94,6 @@
  */
 void lyd_lyb_ctx_free(struct lyd_ctx *lydctx);
 
-/**
- * LYB format
- *
- * Unlike XML or JSON, it is binary format so most data are represented in similar way but in binary.
- * Some notable differences:
- *
- * - schema nodes are identified based on their hash instead of their string name. In case of collisions
- * an array of hashes is created with each next hash one bit shorter until a unique sequence of all these
- * hashes is found and then all of them are stored.
- *
- * - tree structure is represented as individual strictly bounded "siblings". Each "siblings" begins
- * with its metadata, which consist of 1) the whole "sibling" length in bytes and 2) number
- * of included metadata chunks of nested "siblings".
- *
- * - since length of a "sibling" is not known before it is printed, holes are first written and
- * after the "sibling" is printed, they are filled with actual valid metadata. As a consequence,
- * LYB data cannot be directly printed into streams!
- *
- * - data are preceded with information about all the used modules. It is needed because of
- * possible augments and deviations which must be known beforehand, otherwise schema hashes
- * could be matched to the wrong nodes.
- */
-
 /* just a shortcut */
 #define LYB_LAST_SIBLING(lybctx) lybctx->siblings[LY_ARRAY_COUNT(lybctx->siblings) - 1]
 
@@ -82,7 +101,7 @@
 #define LYB_SIBLING_STEP 4
 
 /* current LYB format version */
-#define LYB_VERSION_NUM 0x02
+#define LYB_VERSION_NUM 0x03
 
 /* LYB format version mask of the header byte */
 #define LYB_VERSION_MASK 0x0F
diff --git a/src/parser_lyb.c b/src/parser_lyb.c
index 5e84cc1..202319b 100644
--- a/src/parser_lyb.c
+++ b/src/parser_lyb.c
@@ -195,54 +195,47 @@
  * @brief Read a string.
  *
  * @param[in] str Destination buffer, is allocated.
- * @param[in] with_length Whether the string is preceded with its length or it ends at the end of this "sibling".
+ * @param[in] len_size Number of bytes on which the length of the string is written.
  * @param[in] lybctx LYB context.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_read_string(char **str, ly_bool with_length, struct lylyb_ctx *lybctx)
+lyb_read_string(char **str, uint8_t len_size, struct lylyb_ctx *lybctx)
 {
-    ly_bool next_chunk = 0;
-    size_t len = 0, cur_len;
+    uint64_t len = 0;
+
+    assert((len_size == 1) || (len_size == 2) || (len_size == 4) || (len_size == 8));
 
     *str = NULL;
 
-    if (with_length) {
-        lyb_read_number(&len, sizeof len, 2, lybctx);
-    } else {
-        /* read until the end of this "sibling" */
-        len = LYB_LAST_SIBLING(lybctx).written;
-        if (LYB_LAST_SIBLING(lybctx).position) {
-            next_chunk = 1;
-        }
-    }
+    lyb_read_number(&len, sizeof len, len_size, lybctx);
 
     *str = malloc((len + 1) * sizeof **str);
     LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
 
     lyb_read((uint8_t *)*str, len, lybctx);
 
-    while (next_chunk) {
-        cur_len = LYB_LAST_SIBLING(lybctx).written;
-        if (LYB_LAST_SIBLING(lybctx).position) {
-            next_chunk = 1;
-        } else {
-            next_chunk = 0;
-        }
-
-        *str = ly_realloc(*str, (len + cur_len + 1) * sizeof **str);
-        LY_CHECK_ERR_RET(!*str, LOGMEM(lybctx->ctx), LY_EMEM);
-
-        lyb_read(((uint8_t *)*str) + len, cur_len, lybctx);
-
-        len += cur_len;
-    }
-
     (*str)[len] = '\0';
     return LY_SUCCESS;
 }
 
 /**
+ * @brief Skip string.
+ *
+ * @param[in] len_size Number of bytes on which the length of the string is written.
+ * @param[in] lybctx LYB context.
+ */
+static void
+lyb_skip_string(uint8_t len_size, struct lylyb_ctx *lybctx)
+{
+    size_t len = 0;
+
+    lyb_read_number(&len, sizeof len, len_size, lybctx);
+
+    lyb_read(NULL, len, lybctx);
+}
+
+/**
  * @brief Read value of term node.
  *
  * @param[in] term Compiled term node.
@@ -254,7 +247,7 @@
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_read_term_value(const struct lysc_node_leaf *term, uint8_t **term_value, uint32_t *term_value_len,
+lyb_read_term_value(const struct lysc_node_leaf *term, uint8_t **term_value, uint64_t *term_value_len,
         struct lylyb_ctx *lybctx)
 {
     uint32_t allocated_size;
@@ -438,27 +431,25 @@
 
     /* read attributes */
     for (i = 0; i < count; ++i) {
-        ret = lyb_read_start_siblings(lybctx->lybctx);
-        LY_CHECK_GOTO(ret, cleanup);
-
         /* find model */
         ret = lyb_parse_model(lybctx->lybctx, lybctx->parse_opts, &mod);
         LY_CHECK_GOTO(ret, cleanup);
 
         if (!mod) {
-            /* skip it */
-            do {
-                lyb_read(NULL, LYB_LAST_SIBLING(lybctx->lybctx).written, lybctx->lybctx);
-            } while (LYB_LAST_SIBLING(lybctx->lybctx).written);
-            goto stop_sibling;
+            /* skip meta name */
+            lyb_skip_string(sizeof(uint16_t), lybctx->lybctx);
+
+            /* skip meta value */
+            lyb_skip_string(sizeof(uint16_t), lybctx->lybctx);
+            continue;
         }
 
         /* meta name */
-        ret = lyb_read_string(&meta_name, 1, lybctx->lybctx);
+        ret = lyb_read_string(&meta_name, sizeof(uint16_t), lybctx->lybctx);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* meta value */
-        ret = lyb_read_string(&meta_value, 0, lybctx->lybctx);
+        ret = lyb_read_string(&meta_value, sizeof(uint64_t), lybctx->lybctx);
         LY_CHECK_GOTO(ret, cleanup);
         dynamic = 1;
 
@@ -475,10 +466,6 @@
         }
 
         LY_CHECK_GOTO(ret, cleanup);
-
-stop_sibling:
-        ret = lyb_read_stop_siblings(lybctx->lybctx);
-        LY_CHECK_GOTO(ret, cleanup);
     }
 
 cleanup:
@@ -521,10 +508,10 @@
             ns = calloc(1, sizeof *ns);
 
             /* prefix */
-            LY_CHECK_GOTO(ret = lyb_read_string(&ns->prefix, 1, lybctx), cleanup);
+            LY_CHECK_GOTO(ret = lyb_read_string(&ns->prefix, sizeof(uint16_t), lybctx), cleanup);
 
             /* namespace */
-            LY_CHECK_GOTO(ret = lyb_read_string(&ns->uri, 1, lybctx), cleanup);
+            LY_CHECK_GOTO(ret = lyb_read_string(&ns->uri, sizeof(uint16_t), lybctx), cleanup);
 
             LY_CHECK_GOTO(ret = ly_set_add(set, ns, 1, NULL), cleanup);
             ns = NULL;
@@ -577,11 +564,8 @@
 
     /* read attributes */
     for (i = 0; i < count; ++i) {
-        ret = lyb_read_start_siblings(lybctx);
-        LY_CHECK_GOTO(ret, cleanup);
-
         /* prefix, may be empty */
-        ret = lyb_read_string(&prefix, 1, lybctx);
+        ret = lyb_read_string(&prefix, sizeof(uint16_t), lybctx);
         LY_CHECK_GOTO(ret, cleanup);
         if (!prefix[0]) {
             free(prefix);
@@ -589,7 +573,7 @@
         }
 
         /* namespace, may be empty */
-        ret = lyb_read_string(&module_name, 1, lybctx);
+        ret = lyb_read_string(&module_name, sizeof(uint16_t), lybctx);
         LY_CHECK_GOTO(ret, cleanup);
         if (!module_name[0]) {
             free(module_name);
@@ -597,7 +581,7 @@
         }
 
         /* name */
-        ret = lyb_read_string(&name, 1, lybctx);
+        ret = lyb_read_string(&name, sizeof(uint16_t), lybctx);
         LY_CHECK_GOTO(ret, cleanup);
 
         /* format */
@@ -608,7 +592,7 @@
         LY_CHECK_GOTO(ret, cleanup);
 
         /* value */
-        ret = lyb_read_string(&value, 0, lybctx);
+        ret = lyb_read_string(&value, sizeof(uint64_t), lybctx);
         LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
         dynamic = 1;
 
@@ -630,7 +614,6 @@
             *attr = attr2;
         }
 
-        ret = lyb_read_stop_siblings(lybctx);
         LY_CHECK_GOTO(ret, cleanup);
     }
 
@@ -977,7 +960,7 @@
     LY_ERR ret;
     ly_bool dynamic;
     uint8_t *term_value;
-    uint32_t term_value_len;
+    uint64_t term_value_len;
 
     ret = lyb_read_term_value((struct lysc_node_leaf *)snode, &term_value, &term_value_len, lybctx->lybctx);
     LY_CHECK_RET(ret);
@@ -1059,19 +1042,19 @@
     lyb_read_number(&flags, sizeof flags, sizeof flags, lybctx->lybctx);
 
     /* parse prefix */
-    ret = lyb_read_string(&prefix, 1, lybctx->lybctx);
+    ret = lyb_read_string(&prefix, sizeof(uint16_t), lybctx->lybctx);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* parse module key */
-    ret = lyb_read_string(&module_key, 1, lybctx->lybctx);
+    ret = lyb_read_string(&module_key, sizeof(uint16_t), lybctx->lybctx);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* parse name */
-    ret = lyb_read_string(&name, 1, lybctx->lybctx);
+    ret = lyb_read_string(&name, sizeof(uint16_t), lybctx->lybctx);
     LY_CHECK_GOTO(ret, cleanup);
 
     /* parse value */
-    ret = lyb_read_string(&value, 1, lybctx->lybctx);
+    ret = lyb_read_string(&value, sizeof(uint64_t), lybctx->lybctx);
     LY_CHECK_ERR_GOTO(ret, ly_free_prefix_data(format, val_prefix_data), cleanup);
     dynamic = 1;
 
@@ -1161,7 +1144,7 @@
     }
 
     /* read anydata content */
-    ret = lyb_read_string(&value, 1, lybctx->lybctx);
+    ret = lyb_read_string(&value, sizeof(uint64_t), lybctx->lybctx);
     LY_CHECK_GOTO(ret, error);
 
     if (value_type == LYD_ANYDATA_LYB) {
diff --git a/src/plugins_types/integer.c b/src/plugins_types/integer.c
index cca3a23..5a50306 100644
--- a/src/plugins_types/integer.c
+++ b/src/plugins_types/integer.c
@@ -98,19 +98,23 @@
         LY_CHECK_GOTO(ret, cleanup);
     }
 
-    /* set the value, matters for big-endian */
+    /* set the value (matters for big-endian) and get the correct int64 number */
     switch (type->basetype) {
     case LY_TYPE_INT8:
         storage->int8 = num;
+        num = storage->int8;
         break;
     case LY_TYPE_INT16:
         storage->int16 = num;
+        num = storage->int16;
         break;
     case LY_TYPE_INT32:
         storage->int32 = num;
+        num = storage->int32;
         break;
     case LY_TYPE_INT64:
         storage->int64 = num;
+        num = storage->int64;
         break;
     default:
         break;
diff --git a/src/printer_lyb.c b/src/printer_lyb.c
index 26f33d2..846c5e2 100644
--- a/src/printer_lyb.c
+++ b/src/printer_lyb.c
@@ -239,9 +239,9 @@
     uint64_t num = 0;
 
     /* write the meta chunk information */
-    num = htole64(sib->written & LYB_SIZE_MAX);
+    num = htole64((uint64_t)sib->written & LYB_SIZE_MAX);
     memcpy(meta_buf, &num, LYB_SIZE_BYTES);
-    num = htole64(sib->inner_chunks & LYB_INCHUNK_MAX);
+    num = htole64((uint64_t)sib->inner_chunks & LYB_INCHUNK_MAX);
     memcpy(meta_buf + LYB_SIZE_BYTES, &num, LYB_INCHUNK_BYTES);
 
     LY_CHECK_RET(ly_write_skipped(out, sib->position, (char *)&meta_buf, LYB_META_BYTES));
@@ -397,30 +397,47 @@
  *
  * @param[in] str String to write.
  * @param[in] str_len Length of @p str.
- * @param[in] with_length Whether to precede the string with its length.
+ * @param[in] len_size Size of @ str_len in bytes.
  * @param[in] out Out structure.
  * @param[in] lybctx LYB context.
  * @return LY_ERR value.
  */
 static LY_ERR
-lyb_write_string(const char *str, size_t str_len, ly_bool with_length, struct ly_out *out, struct lylyb_ctx *lybctx)
+lyb_write_string(const char *str, size_t str_len, uint8_t len_size, struct ly_out *out, struct lylyb_ctx *lybctx)
 {
+    ly_bool error;
+
     if (!str) {
         str = "";
         LY_CHECK_ERR_RET(str_len, LOGINT(lybctx->ctx), LY_EINT);
     }
+
     if (!str_len) {
         str_len = strlen(str);
     }
 
-    if (with_length) {
-        /* print length on 2 bytes */
-        if (str_len > UINT16_MAX) {
-            LOGINT(lybctx->ctx);
-            return LY_EINT;
-        }
-        LY_CHECK_RET(lyb_write_number(str_len, 2, out, lybctx));
+    switch (len_size) {
+    case sizeof(uint8_t):
+        error = str_len > UINT8_MAX;
+        break;
+    case sizeof(uint16_t):
+        error = str_len > UINT16_MAX;
+        break;
+    case sizeof(uint32_t):
+        error = str_len > UINT32_MAX;
+        break;
+    case sizeof(uint64_t):
+        error = str_len > UINT64_MAX;
+        break;
+    default:
+        error = 1;
     }
+    if (error) {
+        LOGINT(lybctx->ctx);
+        return LY_EINT;
+    }
+
+    LY_CHECK_RET(lyb_write_number(str_len, len_size, out, lybctx));
 
     LY_CHECK_RET(lyb_write(out, (const uint8_t *)str, str_len, lybctx));
 
@@ -442,7 +459,7 @@
 
     /* model name length and model name */
     if (mod) {
-        LY_CHECK_RET(lyb_write_string(mod->name, 0, 1, out, lybctx));
+        LY_CHECK_RET(lyb_write_string(mod->name, 0, sizeof(uint16_t), out, lybctx));
     } else {
         lyb_write_number(0, 2, out, lybctx);
         return LY_SUCCESS;
@@ -610,10 +627,10 @@
             ns = set->objs[i];
 
             /* prefix */
-            LY_CHECK_RET(lyb_write_string(ns->prefix, 0, 1, out, lybctx));
+            LY_CHECK_RET(lyb_write_string(ns->prefix, 0, sizeof(uint16_t), out, lybctx));
 
             /* namespace */
-            LY_CHECK_RET(lyb_write_string(ns->uri, 0, 1, out, lybctx));
+            LY_CHECK_RET(lyb_write_string(ns->uri, 0, sizeof(uint16_t), out, lybctx));
         }
         break;
     case LY_VALUE_JSON:
@@ -668,8 +685,8 @@
             goto cleanup;
         }
 
-        /* Print the length of the data as 32-bit unsigned integer. */
-        ret = lyb_write_number(value_len, sizeof(uint32_t), out, lybctx);
+        /* Print the length of the data as 64-bit unsigned integer. */
+        ret = lyb_write_number(value_len, sizeof(uint64_t), out, lybctx);
         LY_CHECK_GOTO(ret, cleanup);
     } else {
         /* Fixed-length data. */
@@ -739,29 +756,21 @@
 
     if (wd_mod) {
         /* write the "default" metadata */
-        LY_CHECK_RET(lyb_write_start_siblings(out, lybctx->lybctx));
         LY_CHECK_RET(lyb_print_model(out, wd_mod, lybctx->lybctx));
-        LY_CHECK_RET(lyb_write_string("default", 0, 1, out, lybctx->lybctx));
-        LY_CHECK_RET(lyb_write_string("true", 0, 0, out, lybctx->lybctx));
-        LY_CHECK_RET(lyb_write_stop_siblings(out, lybctx->lybctx));
+        LY_CHECK_RET(lyb_write_string("default", 0, sizeof(uint16_t), out, lybctx->lybctx));
+        LY_CHECK_RET(lyb_write_string("true", 0, sizeof(uint16_t), out, lybctx->lybctx));
     }
 
     /* write all the node metadata */
     LY_LIST_FOR(node->meta, iter) {
-        /* each metadata is a sibling */
-        LY_CHECK_RET(lyb_write_start_siblings(out, lybctx->lybctx));
-
         /* model */
         LY_CHECK_RET(lyb_print_model(out, iter->annotation->module, lybctx->lybctx));
 
         /* annotation name with length */
-        LY_CHECK_RET(lyb_write_string(iter->name, 0, 1, out, lybctx->lybctx));
+        LY_CHECK_RET(lyb_write_string(iter->name, 0, sizeof(uint16_t), out, lybctx->lybctx));
 
         /* metadata value */
-        LY_CHECK_RET(lyb_write_string(lyd_get_meta_value(iter), 0, 0, out, lybctx->lybctx));
-
-        /* finish metadata sibling */
-        LY_CHECK_RET(lyb_write_stop_siblings(out, lybctx->lybctx));
+        LY_CHECK_RET(lyb_write_string(lyd_get_meta_value(iter), 0, sizeof(uint64_t), out, lybctx->lybctx));
     }
 
     return LY_SUCCESS;
@@ -794,17 +803,14 @@
 
     /* write all the attributes */
     LY_LIST_FOR(node->attr, iter) {
-        /* each attribute is a sibling */
-        LY_CHECK_RET(lyb_write_start_siblings(out, lybctx));
-
         /* prefix */
-        LY_CHECK_RET(lyb_write_string(iter->name.prefix, 0, 1, out, lybctx));
+        LY_CHECK_RET(lyb_write_string(iter->name.prefix, 0, sizeof(uint16_t), out, lybctx));
 
         /* namespace */
-        LY_CHECK_RET(lyb_write_string(iter->name.module_name, 0, 1, out, lybctx));
+        LY_CHECK_RET(lyb_write_string(iter->name.module_name, 0, sizeof(uint16_t), out, lybctx));
 
         /* name */
-        LY_CHECK_RET(lyb_write_string(iter->name.name, 0, 1, out, lybctx));
+        LY_CHECK_RET(lyb_write_string(iter->name.name, 0, sizeof(uint16_t), out, lybctx));
 
         /* format */
         LY_CHECK_RET(lyb_write_number(iter->format, 1, out, lybctx));
@@ -813,10 +819,7 @@
         LY_CHECK_RET(lyb_print_prefix_data(out, iter->format, iter->val_prefix_data, lybctx));
 
         /* value */
-        LY_CHECK_RET(lyb_write_string(iter->value, 0, 0, out, lybctx));
-
-        /* finish attribute sibling */
-        LY_CHECK_RET(lyb_write_stop_siblings(out, lybctx));
+        LY_CHECK_RET(lyb_write_string(iter->value, 0, sizeof(uint64_t), out, lybctx));
     }
 
     return LY_SUCCESS;
@@ -959,16 +962,16 @@
     LY_CHECK_RET(lyb_write_number(opaq->flags, sizeof opaq->flags, out, lybctx));
 
     /* prefix */
-    LY_CHECK_RET(lyb_write_string(opaq->name.prefix, 0, 1, out, lybctx));
+    LY_CHECK_RET(lyb_write_string(opaq->name.prefix, 0, sizeof(uint16_t), out, lybctx));
 
     /* module reference */
-    LY_CHECK_RET(lyb_write_string(opaq->name.module_name, 0, 1, out, lybctx));
+    LY_CHECK_RET(lyb_write_string(opaq->name.module_name, 0, sizeof(uint16_t), out, lybctx));
 
     /* name */
-    LY_CHECK_RET(lyb_write_string(opaq->name.name, 0, 1, out, lybctx));
+    LY_CHECK_RET(lyb_write_string(opaq->name.name, 0, sizeof(uint16_t), out, lybctx));
 
     /* value */
-    LY_CHECK_RET(lyb_write_string(opaq->value, 0, 1, out, lybctx));
+    LY_CHECK_RET(lyb_write_string(opaq->value, 0, sizeof(uint64_t), out, lybctx));
 
     /* format */
     LY_CHECK_RET(lyb_write_number(opaq->format, 1, out, lybctx));
@@ -1032,7 +1035,7 @@
     }
 
     /* followed by the content */
-    LY_CHECK_GOTO(ret = lyb_write_string(str, (size_t)len, 1, out, lybctx), cleanup);
+    LY_CHECK_GOTO(ret = lyb_write_string(str, (size_t)len, sizeof(uint64_t), out, lybctx), cleanup);
 
 cleanup:
     ly_out_free(out2, NULL, 1);
@@ -1185,24 +1188,6 @@
 /**
  * @brief Print siblings.
  *
- * @verbatim
-
- sb          = siblings_start
- se          = siblings_end
- siblings    = zero-LYB_SIZE_BYTES | (sb instance+ se)
- instance    = model hash node
- model       = 16bit_zero | (model_name_length model_name revision)
- node        = opaq | leaflist | list | any | inner | leaf
- opaq        = opaq_data siblings
- leaflist    = sb leaf+ se
- list        = sb (node_header siblings)+ se
- any         = node_header anydata_data
- inner       = node_header siblings
- leaf        = node_header term_value
- node_header = metadata node_flags
-
- @endverbatim
- *
  * @param[in] out Out structure.
  * @param[in] node Current data node to print.
  * @param[in] lybctx LYB context.
diff --git a/src/xpath.c b/src/xpath.c
index 9f4d173..9491ddb 100644
--- a/src/xpath.c
+++ b/src/xpath.c
@@ -1211,9 +1211,8 @@
     set->val.nodes[idx].pos = pos;
     ++set->used;
 
-    if (set->val.nodes[idx].type == LYXP_NODE_ELEM) {
-        set_insert_node_hash(set, (struct lyd_node *)node, node_type);
-    }
+    /* add into hash table */
+    set_insert_node_hash(set, (struct lyd_node *)node, node_type);
 }
 
 LY_ERR
diff --git a/tools/lint/main_ni.c b/tools/lint/main_ni.c
index 2900a3f..f63e97a 100644
--- a/tools/lint/main_ni.c
+++ b/tools/lint/main_ni.c
@@ -63,6 +63,7 @@
     /* specification of printing schema node subtree, option --schema-node */
     const char *schema_node_path;
     const struct lysc_node *schema_node;
+    const char *submodule;
 
     /* value of --format in case of schema format */
     LYS_OUTFORMAT schema_out_format;
@@ -133,22 +134,16 @@
             "  -v, --version Show version number and exit.\n"
             "  -V, --verbose Show verbose messages, can be used multiple times to\n"
             "                increase verbosity.\n");
-#ifndef NDEBUG
-    printf("  -G GROUPS, --debug=GROUPS\n"
-            "                Enable printing of specific debugging message group\n"
-            "                (nothing will be printed unless verbosity is set to debug):\n"
-            "                <group>[,<group>]* (dict, xpath)\n\n");
-#endif
 
-    printf("  -d MODE, --default=MODE\n"
-            "                Print data with default values, according to the MODE\n"
-            "                (to print attributes, ietf-netconf-with-defaults model\n"
-            "                must be loaded):\n"
-            "      all             - Add missing default nodes.\n"
-            "      all-tagged      - Add missing default nodes and mark all the default\n"
-            "                        nodes with the attribute.\n"
-            "      trim            - Remove all nodes with a default value.\n"
-            "      implicit-tagged - Add missing nodes and mark them with the attribute.\n\n");
+    printf("  -f FORMAT, --format=FORMAT\n"
+            "                Convert input into FORMAT. Supported formats: \n"
+            "                yang, yin, tree and info for schemas,\n"
+            "                xml, json for data.\n\n");
+
+    printf("  -p PATH, --path=PATH\n"
+            "                Search path for schema (YANG/YIN) modules. The option can be\n"
+            "                used multiple times. The current working directory and the\n"
+            "                path of the module being added is used implicitly.\n\n");
 
     printf("  -D, --disable-searchdir\n"
             "                Do not implicitly search in current working directory for\n"
@@ -156,11 +151,6 @@
             "                search in the module directory (all modules must be \n"
             "                explicitly specified).\n\n");
 
-    printf("  -p PATH, --path=PATH\n"
-            "                Search path for schema (YANG/YIN) modules. The option can be\n"
-            "                used multiple times. The current working directory and the\n"
-            "                path of the module being added is used implicitly.\n\n");
-
     printf("  -F FEATURES, --features=FEATURES\n"
             "                Features to support, default all.\n"
             "                <modname>:[<feature>,]*\n\n");
@@ -170,23 +160,6 @@
             "                module also implemented. If specified a second time, all the\n"
             "                modules are set implemented.\n\n");
 
-    printf("  -l, --list    Print info about the loaded schemas.\n"
-            "                (i - imported module, I - implemented module)\n"
-            "                In case the -f option with data encoding is specified,\n"
-            "                the list is printed as ietf-yang-library data.\n\n");
-
-    printf("  -L LINE_LENGTH, --tree-line-length=LINE_LENGTH\n"
-            "                The limit of the maximum line length on which the 'tree'\n"
-            "                format will try to be printed.\n\n");
-
-    printf("  -o OUTFILE, --output=OUTFILE\n"
-            "                Write the output to OUTFILE instead of stdout.\n\n");
-
-    printf("  -f FORMAT, --format=FORMAT\n"
-            "                Convert input into FORMAT. Supported formats: \n"
-            "                yang, yin, tree and info for schemas,\n"
-            "                xml, json for data.\n\n");
-
     printf("  -P PATH, --schema-node=PATH\n"
             "                Print only the specified subtree of the schema.\n"
             "                The PATH is the XPath subset mentioned in documentation as\n"
@@ -196,6 +169,9 @@
             "                Supplement to the --schema-node option to print information\n"
             "                only about a single node specified as PATH argument.\n\n");
 
+    printf("  -s SUBMODULE, --submodule=SUBMODULE\n"
+            "                Print the specific submodule instead of the main module.\n\n");
+
     printf("  -n, --not-strict\n"
             "                Do not require strict data parsing (silently skip unknown data),\n"
             "                has no effect for schemas.\n\n");
@@ -220,7 +196,29 @@
             "                        RPC/Action. This is necessary to identify appropriate\n"
             "                        data definitions in the schema module.\n"
             "        notif         - Notification instance (content of the <notification>\n"
-            "                        element without <eventTime>).\n");
+            "                        element without <eventTime>).\n\n");
+
+    printf("  -d MODE, --default=MODE\n"
+            "                Print data with default values, according to the MODE\n"
+            "                (to print attributes, ietf-netconf-with-defaults model\n"
+            "                must be loaded):\n"
+            "      all             - Add missing default nodes.\n"
+            "      all-tagged      - Add missing default nodes and mark all the default\n"
+            "                        nodes with the attribute.\n"
+            "      trim            - Remove all nodes with a default value.\n"
+            "      implicit-tagged - Add missing nodes and mark them with the attribute.\n\n");
+
+    printf("  -l, --list    Print info about the loaded schemas.\n"
+            "                (i - imported module, I - implemented module)\n"
+            "                In case the -f option with data encoding is specified,\n"
+            "                the list is printed as ietf-yang-library data.\n\n");
+
+    printf("  -L LINE_LENGTH, --tree-line-length=LINE_LENGTH\n"
+            "                The limit of the maximum line length on which the 'tree'\n"
+            "                format will try to be printed.\n\n");
+
+    printf("  -o OUTFILE, --output=OUTFILE\n"
+            "                Write the output to OUTFILE instead of stdout.\n\n");
 
     printf("  -O FILE, --operational=FILE\n"
             "                Provide optional data to extend validation of the 'rpc',\n"
@@ -235,6 +233,13 @@
             "                Load and implement internal \"ietf-yang-library\" YANG module.\n"
             "                Note that this module includes definitions of mandatory state\n"
             "                data that can result in unexpected data validation errors.\n\n");
+
+#ifndef NDEBUG
+    printf("  -G GROUPS, --debug=GROUPS\n"
+            "                Enable printing of specific debugging message group\n"
+            "                (nothing will be printed unless verbosity is set to debug):\n"
+            "                <group>[,<group>]* (dict, xpath)\n\n");
+#endif
 }
 
 static void
@@ -356,29 +361,30 @@
 
     int opt, opt_index;
     struct option options[] = {
-        {"default",          required_argument, NULL, 'd'},
-        {"disable-searchdir", no_argument,      NULL, 'D'},
-        {"present",          no_argument,       NULL, 'e'},
+        {"help",             no_argument,       NULL, 'h'},
+        {"version",          no_argument,       NULL, 'v'},
+        {"verbose",          no_argument,       NULL, 'V'},
         {"format",           required_argument, NULL, 'f'},
+        {"path",             required_argument, NULL, 'p'},
+        {"disable-searchdir", no_argument,      NULL, 'D'},
         {"features",         required_argument, NULL, 'F'},
+        {"makeimplemented",  no_argument,       NULL, 'i'},
+        {"schema-node",      required_argument, NULL, 'P'},
+        {"single-node",      no_argument,       NULL, 'q'},
+        {"submodule",        required_argument, NULL, 's'},
+        {"not-strict",       no_argument,       NULL, 'n'},
+        {"present",          no_argument,       NULL, 'e'},
+        {"type",             required_argument, NULL, 't'},
+        {"default",          required_argument, NULL, 'd'},
+        {"list",             no_argument,       NULL, 'l'},
+        {"tree-line-length", required_argument, NULL, 'L'},
+        {"output",           required_argument, NULL, 'o'},
+        {"operational",      required_argument, NULL, 'O'},
+        {"merge",            no_argument,       NULL, 'm'},
+        {"yang-library",     no_argument,       NULL, 'y'},
 #ifndef NDEBUG
         {"debug",            required_argument, NULL, 'G'},
 #endif
-        {"help",             no_argument,       NULL, 'h'},
-        {"makeimplemented",  no_argument,       NULL, 'i'},
-        {"list",             no_argument,       NULL, 'l'},
-        {"tree-line-length", required_argument, NULL, 'L'},
-        {"merge",            no_argument,       NULL, 'm'},
-        {"yang-library",     no_argument,       NULL, 'y'},
-        {"output",           required_argument, NULL, 'o'},
-        {"operational",      required_argument, NULL, 'O'},
-        {"path",             required_argument, NULL, 'p'},
-        {"schema-node",      required_argument, NULL, 'P'},
-        {"single-node",      no_argument,       NULL, 'q'},
-        {"not-strict",       no_argument,       NULL, 'n'},
-        {"type",             required_argument, NULL, 't'},
-        {"version",          no_argument,       NULL, 'v'},
-        {"verbose",          no_argument,       NULL, 'V'},
         {NULL,               0,                 NULL, 0}
     };
 
@@ -389,93 +395,28 @@
     c->line_length = 0;
 
 #ifndef NDEBUG
-    while ((opt = getopt_long(argc, argv, "d:Def:F:hilL:myo:p:P:qnt:vV", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVf:p:DF:iP:qs:net:d:lL:o:Omy", options, &opt_index)) != -1) {
 #else
-    while ((opt = getopt_long(argc, argv, "d:Def:F:G:hilL:myo:p:P:qnt:vV", options, &opt_index)) != -1) {
+    while ((opt = getopt_long(argc, argv, "hvVf:p:DF:iP:qs:net:d:lL:o:OmyG:", options, &opt_index)) != -1) {
 #endif
         switch (opt) {
-        case 'd': /* --default */
-            if (!strcasecmp(optarg, "all")) {
-                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL;
-            } else if (!strcasecmp(optarg, "all-tagged")) {
-                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL_TAG;
-            } else if (!strcasecmp(optarg, "trim")) {
-                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_TRIM;
-            } else if (!strcasecmp(optarg, "implicit-tagged")) {
-                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_IMPL_TAG;
-            } else {
-                YLMSG_E("Unknown default mode %s\n", optarg);
-                help(1);
-                return -1;
+        case 'h': /* --help */
+            help(0);
+            return 1;
+
+        case 'v': /* --version */
+            version();
+            return 1;
+
+        case 'V': { /* --verbose */
+            LY_LOG_LEVEL verbosity = ly_log_level(LY_LLERR);
+            ly_log_level(verbosity);
+
+            if (verbosity < LY_LLDBG) {
+                ly_log_level(verbosity + 1);
             }
             break;
-
-        case 'D': /* --disable-search */
-            if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
-                YLMSG_W("The -D option specified too many times.\n");
-            }
-            if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
-                options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
-                options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
-            } else {
-                options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
-            }
-            break;
-
-        case 'p': { /* --path */
-            struct stat st;
-
-            if (stat(optarg, &st) == -1) {
-                YLMSG_E("Unable to use search path (%s) - %s.\n", optarg, strerror(errno));
-                return -1;
-            }
-            if (!S_ISDIR(st.st_mode)) {
-                YLMSG_E("Provided search path is not a directory.\n");
-                return -1;
-            }
-
-            if (ly_set_add(&c->searchpaths, optarg, 0, NULL)) {
-                YLMSG_E("Storing searchpath failed.\n");
-                return -1;
-            }
-
-            break;
-        } /* case 'p' */
-
-        case 'i': /* --makeimplemented */
-            if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
-                options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
-                options_ctx |= LY_CTX_ALL_IMPLEMENTED;
-            } else {
-                options_ctx |= LY_CTX_REF_IMPLEMENTED;
-            }
-            break;
-
-        case 'F': /* --features */
-            if (parse_features(optarg, &c->schema_features)) {
-                return -1;
-            }
-            break;
-
-        case 'l': /* --list */
-            c->list = 1;
-            break;
-
-        case 'L': /* --tree-line-length */
-            c->line_length = atoi(optarg);
-            break;
-
-        case 'o': /* --output */
-            if (c->out) {
-                YLMSG_E("Only a single output can be specified.\n");
-                return -1;
-            } else {
-                if (ly_out_new_filepath(optarg, &c->out)) {
-                    YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
-                    return -1;
-                }
-            }
-            break;
+        } /* case 'V' */
 
         case 'f': /* --format */
             if (!strcasecmp(optarg, "yang")) {
@@ -503,6 +444,53 @@
             }
             break;
 
+        case 'p': { /* --path */
+            struct stat st;
+
+            if (stat(optarg, &st) == -1) {
+                YLMSG_E("Unable to use search path (%s) - %s.\n", optarg, strerror(errno));
+                return -1;
+            }
+            if (!S_ISDIR(st.st_mode)) {
+                YLMSG_E("Provided search path is not a directory.\n");
+                return -1;
+            }
+
+            if (ly_set_add(&c->searchpaths, optarg, 0, NULL)) {
+                YLMSG_E("Storing searchpath failed.\n");
+                return -1;
+            }
+
+            break;
+        } /* case 'p' */
+
+        case 'D': /* --disable-search */
+            if (options_ctx & LY_CTX_DISABLE_SEARCHDIRS) {
+                YLMSG_W("The -D option specified too many times.\n");
+            }
+            if (options_ctx & LY_CTX_DISABLE_SEARCHDIR_CWD) {
+                options_ctx &= ~LY_CTX_DISABLE_SEARCHDIR_CWD;
+                options_ctx |= LY_CTX_DISABLE_SEARCHDIRS;
+            } else {
+                options_ctx |= LY_CTX_DISABLE_SEARCHDIR_CWD;
+            }
+            break;
+
+        case 'F': /* --features */
+            if (parse_features(optarg, &c->schema_features)) {
+                return -1;
+            }
+            break;
+
+        case 'i': /* --makeimplemented */
+            if (options_ctx & LY_CTX_REF_IMPLEMENTED) {
+                options_ctx &= ~LY_CTX_REF_IMPLEMENTED;
+                options_ctx |= LY_CTX_ALL_IMPLEMENTED;
+            } else {
+                options_ctx |= LY_CTX_REF_IMPLEMENTED;
+            }
+            break;
+
         case 'P': /* --schema-node */
             c->schema_node_path = optarg;
             break;
@@ -511,6 +499,10 @@
             c->schema_print_options |= LYS_PRINT_NO_SUBSTMT;
             break;
 
+        case 's': /* --submodule */
+            c->submodule = optarg;
+            break;
+
         case 'n': /* --not-strict */
             c->data_parse_options &= ~LYD_PARSE_STRICT;
             break;
@@ -551,6 +543,42 @@
             data_type_set = 1;
             break;
 
+        case 'd': /* --default */
+            if (!strcasecmp(optarg, "all")) {
+                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL;
+            } else if (!strcasecmp(optarg, "all-tagged")) {
+                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_ALL_TAG;
+            } else if (!strcasecmp(optarg, "trim")) {
+                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_TRIM;
+            } else if (!strcasecmp(optarg, "implicit-tagged")) {
+                c->data_print_options = (c->data_print_options & ~LYD_PRINT_WD_MASK) | LYD_PRINT_WD_IMPL_TAG;
+            } else {
+                YLMSG_E("Unknown default mode %s\n", optarg);
+                help(1);
+                return -1;
+            }
+            break;
+
+        case 'l': /* --list */
+            c->list = 1;
+            break;
+
+        case 'L': /* --tree-line-length */
+            c->line_length = atoi(optarg);
+            break;
+
+        case 'o': /* --output */
+            if (c->out) {
+                YLMSG_E("Only a single output can be specified.\n");
+                return -1;
+            } else {
+                if (ly_out_new_filepath(optarg, &c->out)) {
+                    YLMSG_E("Unable open output file %s (%s)\n", optarg, strerror(errno));
+                    return -1;
+                }
+            }
+            break;
+
         case 'O': /* --operational */
             if (c->data_operational.path) {
                 YLMSG_E("The operational datastore (-O) cannot be set multiple times.\n");
@@ -567,24 +595,6 @@
             options_ctx &= ~LY_CTX_NO_YANGLIBRARY;
             break;
 
-        case 'h': /* --help */
-            help(0);
-            return 1;
-
-        case 'v': /* --version */
-            version();
-            return 1;
-
-        case 'V': { /* --verbose */
-            LY_LOG_LEVEL verbosity = ly_log_level(LY_LLERR);
-            ly_log_level(verbosity);
-
-            if (verbosity < LY_LLDBG) {
-                ly_log_level(verbosity + 1);
-            }
-            break;
-        } /* case 'V' */
-
 #ifndef NDEBUG
         case 'G': { /* --debug */
             uint32_t dbg_groups = 0;
@@ -729,6 +739,18 @@
                     YLMSG_E("Unable to print schema node %s.\n", c.schema_node_path);
                     goto cleanup;
                 }
+            } else if (c.submodule) {
+                const struct lysp_submodule *submod = ly_ctx_get_submodule_latest(c.ctx, c.submodule);
+                if (!submod) {
+                    YLMSG_E("Unable to find submodule %s.\n", c.submodule);
+                    goto cleanup;
+                }
+
+                ret = lys_print_submodule(c.out, submod, c.schema_out_format, c.line_length, c.schema_print_options);
+                if (ret) {
+                    YLMSG_E("Unable to print submodule %s.\n", submod->name);
+                    goto cleanup;
+                }
             } else {
                 for (uint32_t u = 0; u < c.schema_modules.count; ++u) {
                     ret = lys_print_module(c.out, (struct lys_module *)c.schema_modules.objs[u], c.schema_out_format,