diff --git a/Knot.files b/Knot.files
index 6814b951b5f9504b27451d3d28aa7a3fc6938296..d21873e1e2a276bc4581db6542571e2137cd5e66 100644
--- a/Knot.files
+++ b/Knot.files
@@ -13,6 +13,8 @@ src/libknot/dname.h
 src/libknot/dname.c
 src/libknot/rrset.h
 src/libknot/rrset.c
+src/libknot/rrset-dump.h
+src/libknot/rrset-dump.c
 src/libknot/edns.h
 src/libknot/edns.c
 src/libknot/nsec3.h
@@ -56,8 +58,6 @@ src/libknot/zone/zone.h
 src/libknot/zone/zone.c
 src/libknot/zone/zone-contents.c
 src/libknot/zone/zone-contents.h
-src/libknot/zone/zone-dump.h
-src/libknot/zone/zone-dump.c
 src/libknot/zone/zone-tree.h
 src/libknot/zone/zone-tree.c
 src/Makefile.am
@@ -160,6 +160,8 @@ src/knot/conf/conf.c
 src/knot/conf/conf.h
 src/knot/conf/logconf.c
 src/knot/conf/logconf.h
+src/knot/zone/zone-dump.c
+src/knot/zone/zone-dump.h
 src/knot/zone/zone-load.c
 src/knot/zone/zone-load.h
 src/tests/unittests_main.c
diff --git a/src/Makefile.am b/src/Makefile.am
index e7403f37d6514e600bc9f4e4c88e8fc49906c557..f701edbd7b1a3f7b493504be42ee8c13bddd69ca 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -99,8 +99,6 @@ libknot_la_SOURCES =				\
 	libknot/zone/node.c			\
 	libknot/zone/zone-diff.h		\
 	libknot/zone/zone-diff.c		\
-	libknot/zone/zone-dump.h		\
-	libknot/zone/zone-dump.c		\
 	libknot/hash/hash-functions.c		\
 	libknot/hash/cuckoo-hash-table.c	\
 	libknot/hash/universal-system.c		\
@@ -115,16 +113,18 @@ libknot_la_SOURCES =				\
 	libknot/updates/xfr-in.c		\
 	libknot/updates/ddns.h			\
 	libknot/updates/ddns.c			\
-	libknot/edns.c				\
-	libknot/rrset.c				\
-	libknot/dname.c				\
-	libknot/nsec3.c				\
 	libknot/consts.h			\
+	libknot/dname.h				\
+	libknot/dname.c				\
 	libknot/edns.h				\
+	libknot/edns.c				\
 	libknot/libknot.h			\
-	libknot/dname.h				\
-	libknot/rrset.h				\
 	libknot/nsec3.h				\
+	libknot/nsec3.c				\
+	libknot/rrset.h				\
+	libknot/rrset.c				\
+	libknot/rrset-dump.h			\
+	libknot/rrset-dump.c			\
 	libknot/tsig.h				\
 	libknot/tsig.c				\
 	libknot/tsig-op.h			\
@@ -228,6 +228,8 @@ libknotd_la_SOURCES =				\
 	knot/server/zones.h			\
 	knot/zone/semantic-check.c		\
 	knot/zone/semantic-check.h		\
+	knot/zone/zone-dump.h			\
+	knot/zone/zone-dump.c			\
 	knot/zone/zone-load.h			\
 	knot/zone/zone-load.c			\
 	knot/server/server.h
diff --git a/src/knot/server/zones.c b/src/knot/server/zones.c
index c7767d56b737754e3f1394349f9aa9d32a267748..3ce9da64bea44463d689ef405777f9af19ff7864 100644
--- a/src/knot/server/zones.c
+++ b/src/knot/server/zones.c
@@ -21,7 +21,7 @@
 #include "common/prng.h"
 #include "libknot/dname.h"
 #include "libknot/util/wire.h"
-#include "libknot/zone/zone-dump.h"
+#include "knot/zone/zone-dump.h"
 #include "knot/zone/zone-load.h"
 #include "libknot/zone/zone.h"
 #include "libknot/zone/zonedb.h"
diff --git a/src/knot/zone/zone-dump.c b/src/knot/zone/zone-dump.c
new file mode 100644
index 0000000000000000000000000000000000000000..38b8f97f7822c8f748c2869a27545489f7f7c559
--- /dev/null
+++ b/src/knot/zone/zone-dump.c
@@ -0,0 +1,121 @@
+/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "knot/zone/zone-dump.h"
+
+#include <config.h>
+
+#include "common/descriptor_new.h"
+#include "libknot/libknot.h"
+
+#define DUMP_BUF_LEN (70 * 1024)
+
+typedef struct {
+	int    ret;
+	FILE   *file;
+	char   *buf;
+	size_t buflen;
+	const knot_dname_t *origin;
+} dump_params_t;
+
+static void apex_node_dump_text(knot_node_t *node, dump_params_t *params)
+{
+	knot_rrset_t *rr = knot_node_get_rrset(node, KNOT_RRTYPE_SOA);
+
+	int ret = knot_rrset_txt_dump(rr, params->buf, params->buflen);
+	if (ret < 0) {
+		params->ret = KNOT_ENOMEM;
+		return;
+	}
+	fprintf(params->file, "%s", params->buf);
+
+	const knot_rrset_t **rrsets = knot_node_rrsets(node);
+	
+	for (int i = 0; i < node->rrset_count; i++) {
+		if (rrsets[i]->type != KNOT_RRTYPE_SOA) {
+			ret = knot_rrset_txt_dump(rrsets[i], params->buf,
+			                          params->buflen);
+			if (ret < 0) {
+				free(rrsets);
+				params->ret = KNOT_ENOMEM;
+				return;
+			}
+			fprintf(params->file, "%s", params->buf);
+		}
+	}
+
+	free(rrsets);
+
+	params->ret = KNOT_EOK;
+}
+
+void node_dump_text(knot_node_t *node, void *data)
+{
+	dump_params_t *params = (dump_params_t *)data;
+
+	if (node->owner == params->origin) {
+		apex_node_dump_text(node, params);
+		return;
+	}
+
+	const knot_rrset_t **rrsets = knot_node_rrsets(node);
+
+	int ret;
+	for (int i = 0; i < node->rrset_count; i++) {
+		ret = knot_rrset_txt_dump(rrsets[i], params->buf, params->buflen);
+		if (ret < 0) {
+			params->ret = KNOT_ENOMEM;
+			return;
+		}
+	}
+
+	free(rrsets);
+
+	params->ret = KNOT_EOK;
+}
+
+int zone_dump_text(knot_zone_contents_t *zone, FILE *file)
+{
+	if (zone == NULL || file == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	char *buf = malloc(DUMP_BUF_LEN);
+	if (buf == NULL) {
+		return KNOT_ENOMEM;
+	}
+
+	fprintf(file, ";Dumped using %s v. %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+
+	dump_params_t params;
+	params.ret = KNOT_ERROR;
+	params.file = file;
+	params.buf = buf;
+	params.buflen = DUMP_BUF_LEN;
+	params.origin = knot_node_owner(knot_zone_contents_apex(zone));
+
+	knot_zone_contents_tree_apply_inorder(zone, node_dump_text, &params);
+	if (params.ret != KNOT_EOK) {
+		return params.ret;
+	}
+
+	knot_zone_contents_nsec3_apply_inorder(zone, node_dump_text, &params);
+	if (params.ret != KNOT_EOK) {
+		return params.ret;
+	}
+
+	return KNOT_EOK;
+}
diff --git a/src/libknot/zone/zone-dump.h b/src/knot/zone/zone-dump.h
similarity index 75%
rename from src/libknot/zone/zone-dump.h
rename to src/knot/zone/zone-dump.h
index 391f2b744b3d452260e9e5fd4507906b51b4fb6f..8b8cb0b7b82638767a8211257991c9da2b8b4de4 100644
--- a/src/libknot/zone/zone-dump.h
+++ b/src/knot/zone/zone-dump.h
@@ -20,26 +20,26 @@
  *
  * \brief Zone text dump facility.
  *
- * \addtogroup libknot
+ * \addtogroup zone-load-dump
  * @{
  */
 
-#ifndef _KNOT_ZONE_DUMP_H_
-#define _KNOT_ZONE_DUMP_H_
+#ifndef _KNOTD_ZONEDUMP_H_
+#define _KNOTD_ZONEDUMP_H_
 
 #include "libknot/zone/zone.h"
 
 /*!
- * \brief Dumps given zone to text (BIND-like) file.
+ * \brief Dumps given zone to text file.
  *
  * \param zone Zone to be saved.
- * \param File file to write to.
+ * \param file File to write to.
  *
  * \retval KNOT_EOK on success.
- * \retval KNOT_EINVAL if the specified file is not valid for writing.
+ * \retval < 0 if error.
  */
-int zone_dump_text(knot_zone_contents_t *zone, FILE *f);
+int zone_dump_text(knot_zone_contents_t *zone, FILE *file);
 
-#endif // _KNOT_ZONE_DUMP_H_
+#endif // _KNOTD_ZONEDUMP_H_
 
 /*! @} */
diff --git a/src/libknot/libknot.h b/src/libknot/libknot.h
index 593f09764b313b1f89fbfe5e02b7a2e821f5f721..c1176c69e08efbc538d7974323dd597043a250ee 100644
--- a/src/libknot/libknot.h
+++ b/src/libknot/libknot.h
@@ -36,6 +36,7 @@
 #include "util/wire.h"
 #include "packet/response.h"
 #include "rrset.h"
+#include "rrset-dump.h"
 #include "util/tolower.h"
 #include "util/utils.h"
 #include "zone/zone.h"
diff --git a/src/libknot/rrset-dump.c b/src/libknot/rrset-dump.c
new file mode 100644
index 0000000000000000000000000000000000000000..697f29b0af2177cd601a953aab4d5d84f6770f23
--- /dev/null
+++ b/src/libknot/rrset-dump.c
@@ -0,0 +1,803 @@
+/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "libknot/rrset-dump.h"
+
+#include <stdlib.h>			// free
+#include <stdbool.h>			// bool
+#include <string.h>			// memcpy
+#include <time.h>			// strftime
+#include <ctype.h>			// isprint
+#include <arpa/inet.h>			// ntohs
+
+#include "common/errcode.h"		// KNOT_EOK
+#include "common/base64.h"		// base64
+#include "common/base32hex.h"		// base32hex
+#include "common/descriptor_new.h"	// KNOT_RRTYPE
+
+#define BLOCK_WIDTH		40
+#define BLOCK_INDENT		"\n\t\t\t\t"
+#define BLOCK_INDENT_LEN	5
+
+inline static uint32_t write_indent(char *out) {
+	// Write padding block.
+	memcpy(out, &BLOCK_INDENT, BLOCK_INDENT_LEN);
+
+	return BLOCK_INDENT_LEN;
+}
+
+static int32_t wire_num8_to_str(const uint8_t  *in,
+                                char           *out,
+                                const uint32_t out_len)
+{
+	uint8_t data = *in;
+	int32_t ret;
+
+	// Write number.
+	ret = snprintf(out, out_len, "%u", data);
+
+	// Check output length.
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int32_t wire_num16_to_str(const uint8_t  *in,
+                                 char           *out,
+                                 const uint32_t out_len)
+{
+	uint16_t data;
+	int32_t  ret;
+
+	// Copy input data correctly.
+	if (memcpy(&data, in, sizeof(data)) == NULL) {
+		return -1;
+	}
+
+	// Write number.
+	ret = snprintf(out, out_len, "%u", ntohs(data));
+
+	// Check output length.
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int32_t wire_num32_to_str(const uint8_t  *in,
+                                 char           *out,
+                                 const uint32_t out_len)
+{
+	uint32_t data;
+	int32_t  ret;
+
+	// Copy input data correctly.
+	if (memcpy(&data, in, sizeof(data)) == NULL) {
+		return -1;
+	}
+
+	// Write number.
+	ret = snprintf(out, out_len, "%u", ntohl(data));
+
+	// Check output length.
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int32_t wire_ipv4_to_str(const uint8_t  *in,
+                                char           *out,
+                                const uint32_t out_len)
+{
+	struct in_addr addr4;
+
+	// Fill address structure.
+	if (memcpy(&(addr4.s_addr), in, sizeof(addr4.s_addr)) == NULL) {
+		return -1;
+	}
+
+	// Write address.
+	if (inet_ntop(AF_INET, &addr4, out, out_len) == NULL) {
+		return -1;
+	}
+
+	return strlen(out);
+}
+
+static int32_t wire_ipv6_to_str(const uint8_t  *in,
+                                char           *out,
+                                const uint32_t out_len)
+{
+	struct in6_addr addr6;
+
+	// Fill address structure.
+	if (memcpy(&(addr6.s6_addr), in, sizeof(addr6.s6_addr)) == NULL) {
+		return -1;
+	}
+
+	// Write address.
+	if (inet_ntop(AF_INET6, &addr6, out, out_len) == NULL) {
+		return -1;
+	}
+
+	return strlen(out);
+}
+
+static int32_t wire_type_to_str(const uint8_t  *in,
+                                char           *out,
+                                const uint32_t out_len)
+{
+	uint16_t data;
+	int32_t  ret;
+	char     type[32];
+
+	// Copy input data correctly.
+	if (memcpy(&data, in, sizeof(data)) == NULL) {
+		return -1;
+	}
+
+	// Write record type name.
+	if (knot_rrtype_to_string(ntohs(data), type, sizeof(type)) <= 0) {
+		return -1;
+	}
+
+	ret = snprintf(out, out_len, "%s", type);
+
+	// Check output length.
+	if (ret <= 0 || ret >= out_len) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int32_t wire_base64_to_str(const uint8_t  *in,
+                                  const uint32_t in_len,
+                                  char           *out,
+                                  const uint32_t out_len,
+                                  const bool     wrap)
+{
+	int32_t  ret;
+	uint32_t total_len = 0;
+
+	// One-line vs multi-line mode.
+	if (wrap == false) {
+		// Encode data directly to the output.
+		ret = base64_encode(in, in_len, (uint8_t *)out, out_len);
+
+		// Check output.
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len = ret;
+	} else {
+		int32_t src_begin, src_len;
+		char    *buf;
+
+		// Encode data to the temporary buffer.
+		ret = base64_encode_alloc(in, in_len, (uint8_t **)&buf);
+
+		// Check output and output buffer for additional characters.
+		if (ret <= 0 ||
+		    //               2 ~ 1 final indent + 1 int rounding.
+		    out_len < ret + (2 + ret / BLOCK_WIDTH) * BLOCK_INDENT_LEN)
+		{
+			return -1;
+		}
+
+		// Loop which wraps base64 block in more lines.
+		for (src_begin = 0; src_begin < ret; src_begin += BLOCK_WIDTH) {
+			// Write indent block.
+			total_len += write_indent(out + total_len);
+
+			// Compute block length (the last one can be shorter).
+			src_len = (ret - src_begin) < BLOCK_WIDTH ?
+			          (ret - src_begin) : BLOCK_WIDTH;
+
+			// Write data block.
+			memcpy(out + total_len, buf + src_begin, src_len);
+			total_len += src_len;
+		}
+
+		// Write trailing indent block.
+		total_len += write_indent(out + total_len);
+
+		// Destroy temporary buffer.
+		free(buf);
+	}
+
+	// String termination.
+	if (out_len > total_len) {
+		out[total_len] = '\0';
+	} else {
+		return -1;
+	}
+
+	return total_len;
+}
+
+static int32_t wire_base32hex_to_str(const uint8_t  *in,
+                                     const uint32_t in_len,
+                                     char           *out,
+                                     const uint32_t out_len,
+                                     const bool     wrap)
+{
+	int32_t  ret;
+	uint32_t total_len = 0;
+
+	// One-line vs multi-line mode.
+	if (wrap == false) {
+		// Encode data directly to the output.
+		ret = base32hex_encode(in, in_len, (uint8_t *)out, out_len);
+
+		// Check output.
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len = ret;
+	} else {
+		int32_t src_begin, src_len;
+		char    *buf;
+
+		// Encode data to the temporary buffer.
+		ret = base32hex_encode_alloc(in, in_len, (uint8_t **)&buf);
+
+		// Check output and output buffer for additional characters.
+		if (ret <= 0 ||
+		    //               2 ~ 1 final indent + 1 int rounding.
+		    out_len < ret + (2 + ret / BLOCK_WIDTH) * BLOCK_INDENT_LEN)
+		{
+			return -1;
+		}
+
+		// Loop which wraps base32hex block in more lines.
+		for (src_begin = 0; src_begin < ret; src_begin += BLOCK_WIDTH) {
+			// Write indent block.
+			total_len += write_indent(out + total_len);
+
+			// Compute block length (the last one can be shorter).
+			src_len = (ret - src_begin) < BLOCK_WIDTH ?
+			          (ret - src_begin) : BLOCK_WIDTH;
+
+			// Write data block.
+			memcpy(out + total_len, buf + src_begin, src_len);
+			total_len += src_len;
+		}
+
+		// Write trailing indent block.
+		total_len += write_indent(out + total_len);
+
+		// Destroy temporary buffer.
+		free(buf);
+	}
+
+	// String termination.
+	if (out_len > total_len) {
+		out[total_len] = '\0';
+	} else {
+		return -1;
+	}
+
+	return total_len;
+}
+
+static void hex_dump(const uint8_t *in, const uint32_t in_len, char *out)
+{
+	static const char hex[] = "0123456789ABCDEF";
+
+	uint32_t i;
+
+	for (i = 0; i < in_len; i++) {
+		out[2 * i]     = hex[in[i] / 16];
+		out[2 * i + 1] = hex[in[i] % 16];
+	}
+}
+
+static int32_t wire_hex_to_str(const uint8_t  *in,
+                               const uint32_t in_len,
+                               char           *out,
+                               const uint32_t out_len,
+                               const bool     wrap)
+{
+	uint32_t total_len = 0;
+
+	// One-line vs multi-line mode.
+	if (wrap == false) {
+		// Check output (including termination).
+		if (out_len <= 2 * in_len) {
+			return -1;
+		}
+
+		// Encode data directly to the output.
+		hex_dump(in, in_len, out);
+
+		total_len = 2 * in_len;
+	} else {
+		int32_t src_begin, src_len;
+
+		// Check output buffer (including termination).
+		//           = ~ '\0'    2 ~ 1 final indent + 1 int rounding.
+		if (out_len <= in_len + (2 + (2 * in_len) / BLOCK_WIDTH) *
+		              BLOCK_INDENT_LEN)
+		{
+			return -1;
+		}
+
+		// Loop which wraps hex block in more lines.
+		for (src_begin = 0; src_begin < in_len;
+		     src_begin += BLOCK_WIDTH / 2)
+		{
+			// Write indent block.
+			total_len += write_indent(out + total_len);
+
+			// Compute block length (the last one can be shorter).
+			src_len = (in_len - src_begin) < (BLOCK_WIDTH / 2) ?
+			          (in_len - src_begin) : (BLOCK_WIDTH / 2);
+
+			// Write data block.
+			hex_dump(in + src_begin, src_len, out + total_len);
+			total_len += 2 * src_len;
+		}
+
+		// Write trailing indent block.
+		total_len += write_indent(out + total_len);
+	}
+
+	// String termination.
+	out[total_len] = '\0';
+
+	return total_len;
+}
+
+static int32_t wire_text_to_str(const uint8_t  *in,
+                                const uint32_t in_len,
+                                char           *out,
+                                const uint32_t out_len)
+{
+	char     ch;
+	uint32_t i, total_len = 0;
+
+	// Check length of the output buffer (+ 2x'"' + 1x'\0').
+	if (out_len < in_len + 3) {
+		return -1;
+	}
+
+	// Opening quoatition.
+	out[total_len++] = '"';
+
+	// Loop over all characters.
+	for (i = 0; i < in_len; i++) {
+		ch = (char)in[i];
+
+		if (isprint(ch) != 0) {
+			// For special chars print leading slash.
+			if (ch == '\\' || ch == '"') {
+				out[total_len++] = '\\';
+			}
+
+			out[total_len++] = ch;
+		} else {
+			// Check output buffer length for additional space.
+			if (out_len <= total_len + 5) {
+				return -1;
+			}
+
+			// Unprintable chars encode via \ddd notation..
+			sprintf(out + total_len, "\\%03u", ch);
+			total_len += 4;
+		}
+	}
+
+	// Closing quoatition.
+	out[total_len++] = '"';
+	out[total_len] = '\0';
+
+	return total_len;
+}
+
+static int32_t wire_timestamp_to_str(const uint8_t  *in,
+                                     char           *out,
+                                     const uint32_t out_len)
+{
+	uint32_t  data;
+	int32_t   ret;
+	time_t    timestamp;
+
+	// Copy input data correctly.
+	if (memcpy(&data, in, sizeof(data)) == NULL) {
+		return -1;
+	}
+
+	// Convert number from network to host byte order.
+	timestamp = ntohl(data);
+
+	// Write formated timestamp.
+	ret = strftime(out, out_len, "%Y%m%d%H%M%S", gmtime(&timestamp));
+
+	// Check output length.
+	if (ret <= 0) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int32_t time_to_human_str(uint32_t       data,
+                                 char           *out,
+                                 const uint32_t out_len)
+{
+	uint32_t  num, total_len = 0;
+	int32_t   ret;
+
+	// Process days.
+	num = data / 86400;
+	if (num > 0) {
+		ret = snprintf(out + total_len, out_len - total_len,
+		               "%ud", num);
+
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len += ret;
+		data -= num * 86400;
+	}
+
+	// Process hours.
+	num = data / 3600;
+	if (num > 0) {
+		ret = snprintf(out + total_len, out_len - total_len,
+		               "%uh", num);
+
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len += ret;
+		data -= num * 3600;
+	}
+
+	// Process minutes.
+	num = data / 60;
+	if (num > 0) {
+		ret = snprintf(out + total_len, out_len - total_len,
+		               "%um", num);
+
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len += ret;
+		data -= num * 60;
+	}
+
+	// Process seconds.
+	num = data;
+	if (num > 0) {
+		ret = snprintf(out + total_len, out_len - total_len,
+		               "%us", num);
+
+		if (ret <= 0) {
+			return -1;
+		}
+
+		total_len += ret;
+	}
+
+	return total_len;
+}
+
+static int32_t wire_time_to_human_str(const uint8_t  *in,
+                                      char           *out,
+                                      const uint32_t out_len)
+{
+	uint32_t  data;
+
+	// Copy input data correctly.
+	if (memcpy(&data, in, sizeof(data)) == NULL) {
+		return -1;
+	}
+
+	// Convert number from network to host byte order.
+	data = ntohl(data);
+
+	return time_to_human_str(data, out, out_len);
+}
+
+static int32_t wire_bitmap_to_str(const uint8_t  *in,
+                                  const uint32_t in_len,
+                                  char           *out,
+                                  const uint32_t out_len)
+{
+	uint32_t i = 0, j, total_len = 0;
+	uint16_t type_num;
+	uint8_t  win, bitmap_len;
+	char     type[32];
+
+	// Loop over bitmap window array (can be empty).
+	while (i < in_len) {
+		// First byte is window number.
+		win = in[i++];
+
+		// Check window length (len must follow).
+		if (i >= in_len) {
+			return -1;
+		}
+
+		// Second byte is window length.
+		bitmap_len = in[i++];
+
+		// Check window length (len bytes must follow).
+		if (i + bitmap_len > in_len) {
+			return -1;
+		}
+
+		// Bitmap processing.
+		for (j = 0; j < (bitmap_len * 8); j++) {
+			if ((in[i + j / 8] & (128 >> (j % 8))) != 0) {
+				type_num = win * 256 + j;
+
+				if (knot_rrtype_to_string(type_num, type,
+				                          sizeof(type)) <= 0) {
+					return -1;
+				}
+
+				printf("%s ", type);
+			}
+		}
+
+		i += bitmap_len;
+	}
+
+	return total_len;
+}
+
+static int32_t dname_to_str(const uint8_t  *in,
+                            char           *out,
+                            const uint32_t out_len)
+{
+	knot_dname_t *dname;
+	memcpy(&dname, in, sizeof(knot_dname_t *));
+
+	char *dname_str = knot_dname_to_str(dname);
+
+	int ret = snprintf(out, out_len, "%s", dname_str);
+
+	free(dname_str);
+
+	if (ret < 0 || ret >= out_len) {
+		return -1;
+	}
+
+	return ret;
+}
+
+static int dump_rdata_a(const uint8_t *data, const size_t len, char *dst,
+                        const size_t maxlen)
+{
+	return wire_ipv4_to_str(data, dst, maxlen);
+}
+
+static int dump_rdata_ns(const uint8_t *data, const size_t len, char *dst,
+                         const size_t maxlen)
+{
+
+	return dname_to_str(data, dst, maxlen);
+}
+
+static int dump_rdata_aaaa(const uint8_t *data, const size_t len, char *dst,
+                           const size_t maxlen)
+{
+	return wire_ipv6_to_str(data, dst, maxlen);
+}
+
+int knot_rrset_txt_dump_data(const knot_rrset_t *rrset, const size_t pos,
+                             char *dst, const size_t maxlen)
+{
+	if (rrset == NULL || dst == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	const uint8_t *data = knot_rrset_get_rdata(rrset, pos);
+	size_t        data_len = rrset_rdata_item_size(rrset, pos);
+
+	int ret;
+
+	switch (knot_rrset_type(rrset)) {
+		case KNOT_RRTYPE_A:
+			ret = dump_rdata_a(data, data_len, dst, maxlen);
+			break;
+		case KNOT_RRTYPE_NS:
+			ret = dump_rdata_ns(data, data_len, dst, maxlen);
+			break;
+		case KNOT_RRTYPE_CNAME:
+			break;
+		case KNOT_RRTYPE_SOA:
+			break;
+		case KNOT_RRTYPE_PTR:
+			break;
+		case KNOT_RRTYPE_HINFO:
+			break;
+		case KNOT_RRTYPE_MINFO:
+			break;
+		case KNOT_RRTYPE_MX:
+			break;
+		case KNOT_RRTYPE_TXT:
+			break;
+		case KNOT_RRTYPE_RP:
+			break;
+		case KNOT_RRTYPE_AFSDB:
+			break;
+		case KNOT_RRTYPE_RT:
+			break;
+		case KNOT_RRTYPE_KEY:
+			break;
+		case KNOT_RRTYPE_AAAA:
+			ret = dump_rdata_aaaa(data, data_len, dst, maxlen);
+			break;
+		case KNOT_RRTYPE_LOC:
+			break;
+		case KNOT_RRTYPE_SRV:
+			break;
+		case KNOT_RRTYPE_NAPTR:
+			break;
+		case KNOT_RRTYPE_KX:
+			break;
+		case KNOT_RRTYPE_CERT:
+			break;
+		case KNOT_RRTYPE_DNAME:
+			break;
+		case KNOT_RRTYPE_APL:
+			break;
+		case KNOT_RRTYPE_DS:
+			break;
+		case KNOT_RRTYPE_SSHFP:
+			break;
+		case KNOT_RRTYPE_IPSECKEY:
+			break;
+		case KNOT_RRTYPE_RRSIG:
+			break;
+		case KNOT_RRTYPE_NSEC:
+			break;
+		case KNOT_RRTYPE_DNSKEY:
+			break;
+		case KNOT_RRTYPE_DHCID:
+			break;
+		case KNOT_RRTYPE_NSEC3:
+			break;
+		case KNOT_RRTYPE_NSEC3PARAM:
+			break;
+		case KNOT_RRTYPE_TLSA:
+			break;
+		case KNOT_RRTYPE_SPF:
+			break;
+		default:
+			break;
+	}
+
+	return ret;
+}
+
+int knot_rrset_txt_dump_header(const knot_rrset_t *rrset, char *dst,
+                               const size_t maxlen)
+{
+	if (rrset == NULL || dst == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	size_t len = 0;
+	char   buf[32];
+	int    ret;
+
+	// Dump rrset owner.
+	char *name = knot_dname_to_str(rrset->owner);
+	ret = snprintf(dst + len, maxlen - len, "%-20s\t", name);
+	free(name);
+	if (ret < 0 || ret >= maxlen - len) {
+		return KNOT_ESPACE;
+	}
+	len += ret;
+
+	// Dump rrset ttl.
+	if (1) {	
+		ret = snprintf(dst + len, maxlen - len, "%6u\t", rrset->ttl);
+	} else {
+		ret = snprintf(dst + len, maxlen - len, "     \t");
+	}
+	if (ret < 0 || ret >= maxlen - len) {
+		return KNOT_ESPACE;
+	}
+	len += ret;
+
+	// Dump rrset class.
+	if (1) {
+		if (knot_rrclass_to_string(rrset->rclass, buf, sizeof(buf)) < 0)
+		{
+			return KNOT_ESPACE;
+		}
+		ret = snprintf(dst + len, maxlen - len, "%-2s\t", buf);
+	} else {
+		ret = snprintf(dst + len, maxlen - len, "  \t");
+	}
+	if (ret < 0 || ret >= maxlen - len) {
+		return KNOT_ESPACE;
+	}
+	len += ret;
+
+	// Dump rrset type.
+	if (knot_rrtype_to_string(rrset->type, buf, sizeof(buf)) < 0) {
+		return KNOT_ESPACE;
+	}
+	ret = snprintf(dst + len, maxlen - len, "%-5s\t", buf);
+	if (ret < 0 || ret >= maxlen - len) {
+		return KNOT_ESPACE;
+	}
+	len += ret;
+	
+	return len;
+}
+
+int knot_rrset_txt_dump(const knot_rrset_t *rrset, char *dst, const size_t maxlen)
+{
+	if (rrset == NULL || dst == NULL) {
+		return KNOT_EINVAL;
+	}
+
+	size_t len = 0;
+	int    ret;
+
+	// Loop over rdata in rrset.
+	for (size_t i = 0; i < rrset->rdata_count; i++) {
+		// Dump rdata owner, class, ttl and type.
+		ret = knot_rrset_txt_dump_header(rrset, dst + len, maxlen - len);
+		if (ret < 0) {
+			return KNOT_ESPACE;
+		}
+		len += ret;
+
+		// Dump rdata as such.
+		ret = knot_rrset_txt_dump_data(rrset, i, dst + len, maxlen - len);
+		if (ret < 0) {
+			return KNOT_ESPACE;
+		}
+		len += ret;
+
+		// Terminate line.
+		if (len >= maxlen) {
+			return KNOT_ESPACE;
+		}
+		dst[len++] = '\n';
+		dst[len] = '\0';
+	}
+
+	// Dump RRSIG records if any via recursion call.
+	if (rrset->rrsigs != NULL) {
+		ret = knot_rrset_txt_dump(rrset->rrsigs, dst + len, maxlen - len);
+		if (ret < 0) {
+			return KNOT_ESPACE;
+		}
+		len += ret;
+	}
+
+	return len;
+}
diff --git a/src/libknot/rrset-dump.h b/src/libknot/rrset-dump.h
new file mode 100644
index 0000000000000000000000000000000000000000..db01d61a575154b7b07b913a5dae118365b9c8a7
--- /dev/null
+++ b/src/libknot/rrset-dump.h
@@ -0,0 +1,38 @@
+/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+/*!
+ * \file rrset-dump.h
+ *
+ * \author Daniel Salzman <daniel.salzman@nic.cz>
+ *
+ * \brief RRset text dump facility.
+ *
+ * \addtogroup libknot
+ * @{
+ */
+
+#ifndef _KNOT_RRSETDUMP_H_
+#define _KNOT_RRSETDUMP_H_
+
+//#include <std>
+
+#include "libknot/rrset.h"
+
+int knot_rrset_txt_dump(const knot_rrset_t *rrset, char *dst, const size_t maxlen);
+
+#endif // _KNOT_RRSETDUMP_H_
+
+/*! @} */
diff --git a/src/libknot/zone/zone-dump.c b/src/libknot/zone/zone-dump.c
deleted file mode 100644
index 2ed8518825f81bfb3faa4aa2f3173f1c7ffc4d8b..0000000000000000000000000000000000000000
--- a/src/libknot/zone/zone-dump.c
+++ /dev/null
@@ -1,1236 +0,0 @@
-/*  Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
-
-    This program is free software: you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation, either version 3 of the License, or
-    (at your option) any later version.
-
-    This program is distributed in the hope that it will be useful,
-    but WITHOUT ANY WARRANTY; without even the implied warranty of
-    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-    GNU General Public License for more details.
-
-    You should have received a copy of the GNU General Public License
-    along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "common/descriptor_new.h"
-#include <config.h>
-
-#include "common/print.h"		// hex_printf
-#include "libknot/dname.h"
-
-#include <ctype.h>
-#include <assert.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include "libknot/libknot.h"
-#include "libknot/common.h"
-#include "common/skip-list.h"
-#include "common/base32hex.h"
-
-#ifdef GRR
-/*!< \todo #1683 Find all maximum lengths to be used in strcnat. */
-
-enum uint_max_length {
-	U8_MAX_STR_LEN = 4, U16_MAX_STR_LEN = 6,
-	U32_MAX_STR_LEN = 11, MAX_RR_TYPE_LEN = 20,
-	MAX_NSEC_BIT_STR_LEN = 4096,
-	};
-
-#define APL_NEGATION_MASK      0x80U
-#define APL_LENGTH_MASK	       (~APL_NEGATION_MASK)
-
-/* RFC 4025 - codes for different types that IPSECKEY can hold. */
-#define IPSECKEY_NOGATEWAY 0
-#define IPSECKEY_IP4 1
-#define IPSECKEY_IP6 2
-#define IPSECKEY_DNAME 3
-
-/* Following copyrights are only valid for b64_ntop function */
-/*
- * Copyright (c) 1996, 1998 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
- * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
- * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
- * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
- * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
- * SOFTWARE.
- */
-
-/*
- * Portions Copyright (c) 1995 by International Business Machines, Inc.
- *
- * International Business Machines, Inc. (hereinafter called IBM) grants
- * permission under its copyrights to use, copy, modify, and distribute this
- * Software with or without fee, provided that the above copyright notice and
- * all paragraphs of this notice appear in all copies, and that the name of IBM
- * not be used in connection with the marketing of any product incorporating
- * the Software or modifications thereof, without specific, written prior
- * permission.
- *
- * To the extent it has a right to do so, IBM grants an immunity from suit
- * under its patents, if any, for the use, sale or manufacture of products to
- * the extent that such products are used for performing Domain Name System
- * dynamic updates in TCP/IP networks by means of the Software.  No immunity is
- * granted for any product per se or for any other function of any product.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE.  IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
- * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
- * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
- * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
- */
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define Assert(Cond) if (!(Cond)) abort()
-
-static const char Base64[] =
-	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-static const char Pad64 = '=';
-
-/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
-   The following encoding technique is taken from RFC 1521 by Borenstein
-   and Freed.  It is reproduced here in a slightly edited form for
-   convenience.
-
-   A 65-character subset of US-ASCII is used, enabling 6 bits to be
-   represented per printable character. (The extra 65th character, "=",
-   is used to signify a special processing function.)
-
-   The encoding process represents 24-bit groups of input bits as output
-   strings of 4 encoded characters. Proceeding from left to right, a
-   24-bit input group is formed by concatenating 3 8-bit input groups.
-   These 24 bits are then treated as 4 concatenated 6-bit groups, each
-   of which is translated into a single digit in the base64 alphabet.
-
-   Each 6-bit group is used as an index into an array of 64 printable
-   characters. The character referenced by the index is placed in the
-   output string.
-
-                         Table 1: The Base64 Alphabet
-
-      Value Encoding  Value Encoding  Value Encoding  Value Encoding
-          0 A            17 R            34 i            51 z
-          1 B            18 S            35 j            52 0
-          2 C            19 T            36 k            53 1
-          3 D            20 U            37 l            54 2
-          4 E            21 V            38 m            55 3
-          5 F            22 W            39 n            56 4
-          6 G            23 X            40 o            57 5
-          7 H            24 Y            41 p            58 6
-          8 I            25 Z            42 q            59 7
-          9 J            26 a            43 r            60 8
-         10 K            27 b            44 s            61 9
-         11 L            28 c            45 t            62 +
-         12 M            29 d            46 u            63 /
-         13 N            30 e            47 v
-         14 O            31 f            48 w         (pad) =
-         15 P            32 g            49 x
-         16 Q            33 h            50 y
-
-   Special processing is performed if fewer than 24 bits are available
-   at the end of the data being encoded.  A full encoding quantum is
-   always completed at the end of a quantity.  When fewer than 24 input
-   bits are available in an input group, zero bits are added (on the
-   right) to form an integral number of 6-bit groups.  Padding at the
-   end of the data is performed using the '=' character.
-
-   Since all base64 input is an integral number of octets, only the
-         -------------------------------------------------
-   following cases can arise:
-
-       (1) the final quantum of encoding input is an integral
-           multiple of 24 bits; here, the final unit of encoded
-	   output will be an integral multiple of 4 characters
-	   with no "=" padding,
-       (2) the final quantum of encoding input is exactly 8 bits;
-           here, the final unit of encoded output will be two
-	   characters followed by two "=" padding characters, or
-       (3) the final quantum of encoding input is exactly 16 bits;
-           here, the final unit of encoded output will be three
-	   characters followed by one "=" padding character.
-   */
-
-int b64_ntop(uint8_t const *src, size_t srclength, char *target,
-	     size_t targsize) {
-	size_t datalength = 0;
-	uint8_t input[3];
-	uint8_t output[4];
-	size_t i;
-
-	while (2 < srclength) {
-		input[0] = *src++;
-		input[1] = *src++;
-		input[2] = *src++;
-		srclength -= 3;
-
-		output[0] = input[0] >> 2;
-		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
-		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
-		output[3] = input[2] & 0x3f;
-		Assert(output[0] < 64);
-		Assert(output[1] < 64);
-		Assert(output[2] < 64);
-		Assert(output[3] < 64);
-
-		if (datalength + 4 > targsize)
-			return (-1);
-		target[datalength++] = Base64[output[0]];
-		target[datalength++] = Base64[output[1]];
-		target[datalength++] = Base64[output[2]];
-		target[datalength++] = Base64[output[3]];
-	}
-
-	/* Now we worry about padding. */
-	if (0 != srclength) {
-		/* Get what's left. */
-		input[0] = input[1] = input[2] = '\0';
-		for (i = 0; i < srclength; i++)
-			input[i] = *src++;
-
-		output[0] = input[0] >> 2;
-		output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
-		output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
-		Assert(output[0] < 64);
-		Assert(output[1] < 64);
-		Assert(output[2] < 64);
-
-		if (datalength + 4 > targsize)
-			return (-1);
-		target[datalength++] = Base64[output[0]];
-		target[datalength++] = Base64[output[1]];
-		if (srclength == 1)
-			target[datalength++] = Pad64;
-		else
-			target[datalength++] = Base64[output[2]];
-		target[datalength++] = Pad64;
-	}
-	if (datalength >= targsize)
-		return (-1);
-	target[datalength] = '\0';	/* Returned value doesn't count \0. */
-	return (datalength);
-}
-
-/* Taken from RFC 4398, section 2.1.  */
-knot_lookup_table_t knot_dns_certificate_types[] = {
-/*	0		Reserved */
-	{ 1, "PKIX" },	/* X.509 as per PKIX */
-	{ 2, "SPKI" },	/* SPKI cert */
-	{ 3, "PGP" },	/* OpenPGP packet */
-	{ 4, "IPKIX" },	/* The URL of an X.509 data object */
-	{ 5, "ISPKI" },	/* The URL of an SPKI certificate */
-	{ 6, "IPGP" },	/* The fingerprint and URL of an OpenPGP packet */
-	{ 7, "ACPKIX" },	/* Attribute Certificate */
-	{ 8, "IACPKIX" },	/* The URL of an Attribute Certificate */
-	{ 253, "URI" },	/* URI private */
-	{ 254, "OID" },	/* OID private */
-/*	255 		Reserved */
-/* 	256-65279	Available for IANA assignment */
-/*	65280-65534	Experimental */
-/*	65535		Reserved */
-	{ 0, NULL }
-};
-
-/* Taken from RFC 2535, section 7.  */
-knot_lookup_table_t knot_dns_algorithms[] = {
-	{ 1, "RSAMD5" },	/* RFC 2537 */
-	{ 2, "DH" },		/* RFC 2539 */
-	{ 3, "DSA" },		/* RFC 2536 */
-	{ 4, "ECC" },
-	{ 5, "RSASHA1" },	/* RFC 3110 */
-	{ 252, "INDIRECT" },
-	{ 253, "PRIVATEDNS" },
-	{ 254, "PRIVATEOID" },
-	{ 0, NULL }
-};
-
-static int get_bit(uint8_t bits[], size_t index)
-{
-	/*
-	 * The bits are counted from left to right, so bit #0 is the
-	 * left most bit.
-	 */
-	return bits[index / 8] & (1 << (7 - index % 8));
-}
-
-static inline uint8_t * rdata_item_data(knot_rdata_item_t item)
-{
-	return (uint8_t *)(item.raw_data + 1);
-}
-
-static inline uint16_t rdata_item_size(knot_rdata_item_t item)
-{
-	return item.raw_data[0];
-}
-
-static char *rdata_dname_to_string(knot_rdata_item_t item)
-{
-	return knot_dname_to_str(item.dname);
-}
-
-static char *rdata_binary_dname_to_string(knot_rdata_item_t item)
-{
-	if (item.raw_data == NULL) {
-		return NULL;
-	}
-	
-	if (item.raw_data[0] == 0) {
-		return NULL;
-	}
-	
-	/* Create new dname frow raw data - probably the easiest way. */
-	knot_dname_t *dname = knot_dname_new_from_wire((uint8_t *)(item.raw_data + 1),
-	                                               item.raw_data[0], NULL);
-	if (dname == NULL) {
-		return NULL;
-	}
-	
-	/* Create string. */
-	char *str = knot_dname_to_str(dname);
-	knot_dname_free(&dname);
-	
-	return str;
-}
-
-static char *rdata_dns_name_to_string(knot_rdata_item_t item)
-{
-	return knot_dname_to_str(item.dname);
-}
-
-static char *rdata_txt_data_to_string(const uint8_t *data, uint32_t *count)
-{
-    uint8_t length = data[0];
-    uint32_t i = 0;
-    /*
-     * * 4 because: unprintable chars look like \123.
-     * + 3 because: opening '"', closing '"' and \0 at the end.
-     * + 1 because: malloc + gcc optimization requires out_length >= 4.
-     *
-     * NOTE: length can be 0.
-     */
-    uint32_t out_length = length * 4 + 3 + 1;
-
-    char *ret = malloc(out_length);
-    if (ret == NULL) {
-            ERR_ALLOC_FAILED;
-            return NULL;
-    }
-    memset(ret, 0, out_length);
-
-    // Opening '"'
-    strcat(ret, "\"");
-
-    for (i = 1; i <= length; i++) {
-            char ch = (char) data[i];
-            char tmp_str[5];
-
-            if (isprint((int)ch)) {
-                    if (ch == '"' || ch == '\\') {
-                            strcat(ret, "\\");
-                    }
-                    tmp_str[0] = ch;
-                    tmp_str[1] = 0;
-                    strcat(ret, tmp_str);
-            } else {
-                    sprintf(tmp_str, "\\%03u", ch);
-                    strcat(ret, tmp_str);
-            }
-    }
-
-    // Closing '"'
-    strcat(ret, "\"");
-
-    *count = length + 1; // 1 - leading length byte.
-
-    return ret;
-}
-
-static char *rdata_text_array_to_string(knot_rdata_item_t item)
-{
-    /* Create delimiter. */
-    char *del = " ";
-
-    uint16_t size = item.raw_data[0];
-    /*
-     * * 6 because: item can consists of one length unprintable char strings
-     *              "\123" "\123" ...
-     * + 1 because: ending \0.
-     *
-     * NOTE: txt_size is always bigger than 4 bytes (zero string has size = 1).
-     */
-    uint32_t txt_size = size * 6 + 1;
-
-    char *ret = malloc(txt_size);
-    if (ret == NULL) {
-            ERR_ALLOC_FAILED;
-            return NULL;
-    }
-    memset(ret, 0, txt_size);
-
-    const uint8_t *data = (uint8_t *)(item.raw_data + 1);
-    uint32_t read_count = 0;
-
-    while (read_count < size) {
-            uint32_t txt_count = 0;
-
-            char *txt = rdata_txt_data_to_string(data + read_count, &txt_count);
-            if (txt == NULL) {
-                    free(ret);
-                    return NULL;
-            }
-
-            /* Append text string to output. */
-            strcat(ret, txt);
-            read_count += txt_count;
-
-            if (read_count < size) {
-                    strcat(ret, del);
-            }
-
-            free(txt);
-    }
-
-    return ret;
-}
-
-static char *rdata_byte_to_string(knot_rdata_item_t item)
-{
-	assert(item.raw_data[0] == 1);
-	uint8_t data = *((uint8_t *)(item.raw_data + 1));
-	char *ret = malloc(sizeof(char) * U8_MAX_STR_LEN);
-	snprintf(ret, U8_MAX_STR_LEN, "%d", (char) data);
-	return ret;
-}
-
-static char *rdata_short_to_string(knot_rdata_item_t item)
-{
-	uint16_t data = knot_wire_read_u16(rdata_item_data(item));
-	char *ret = malloc(sizeof(char) * U16_MAX_STR_LEN);
-	snprintf(ret, U16_MAX_STR_LEN, "%u", data);
-	/* XXX Use proper macros - see response tests*/
-	/* XXX check return value, return NULL on failure */
-	return ret;
-}
-
-static char *rdata_long_to_string(knot_rdata_item_t item)
-{
-	uint32_t data = knot_wire_read_u32(rdata_item_data(item));
-	char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN);
-	/* u should be enough */
-	snprintf(ret, U32_MAX_STR_LEN, "%u", data);
-	return ret;
-}
-
-static char *rdata_a_to_string(knot_rdata_item_t item)
-{
-	/* 200 seems like a little too much */
-	char *ret = malloc(sizeof(char) * 200);
-	if (inet_ntop(AF_INET, rdata_item_data(item), ret, 200)) {
-		return ret;
-	} else {
-		return NULL;
-	}
-}
-
-static char *rdata_aaaa_to_string(knot_rdata_item_t item)
-{
-	char *ret = malloc(sizeof(char) * 200);
-	if (inet_ntop(AF_INET6, rdata_item_data(item), ret, 200)) {
-		return ret;
-	} else {
-		return NULL;
-	}
-}
-
-static char *rdata_rrtype_to_string(knot_rdata_item_t item)
-{
-	char buff[32];
-
-	uint16_t type = knot_wire_read_u16(rdata_item_data(item));
-
-	if (knot_rrtype_to_string(type, buff, sizeof(buff)) < 0)
-		return NULL;
-
-	char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
-	strncpy(ret, buff, MAX_RR_TYPE_LEN);
-	return ret;
-}
-
-static char *rdata_algorithm_to_string(knot_rdata_item_t item)
-{
-	uint8_t id = *rdata_item_data(item);
-	char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
-	knot_lookup_table_t *alg
-		= knot_lookup_by_id(knot_dns_algorithms, id);
-	if (alg) {
-		strncpy(ret, alg->name, MAX_RR_TYPE_LEN);
-	} else {
-		snprintf(ret, U8_MAX_STR_LEN, "%u", id);
-	}
-
-	return ret;
-}
-
-static char *rdata_certificate_type_to_string(knot_rdata_item_t item)
-{
-	uint16_t id = knot_wire_read_u16(rdata_item_data(item));
-	char *ret = malloc(sizeof(char) * MAX_RR_TYPE_LEN);
-	knot_lookup_table_t *type
-		= knot_lookup_by_id(knot_dns_certificate_types, id);
-	if (type) {
-		strncpy(ret, type->name, MAX_RR_TYPE_LEN);
-	} else {
-		snprintf(ret, U16_MAX_STR_LEN, "%u", id);
-	}
-
-	return ret;
-}
-
-static char *rdata_period_to_string(knot_rdata_item_t item)
-{
-	/* uint32 but read 16 XXX */
-	uint32_t period = knot_wire_read_u32(rdata_item_data(item));
-	char *ret = malloc(sizeof(char) * U32_MAX_STR_LEN);
-	snprintf(ret, U32_MAX_STR_LEN, "%u", period);
-	return ret;
-}
-
-static char *rdata_time_to_string(knot_rdata_item_t item)
-{
-	time_t time = (time_t) knot_wire_read_u32(rdata_item_data(item));
-	struct tm tm_conv;
-	if (gmtime_r(&time, &tm_conv) == 0) {
-		return 0;
-	}
-	char *ret = malloc(sizeof(char) * 15);
-	if (strftime(ret, 15, "%Y%m%d%H%M%S", &tm_conv)) {
-		return ret;
-	} else {
-		free(ret);
-		return 0;
-	}
-}
-
-static char *rdata_base32_to_string(knot_rdata_item_t item)
-{
-	char *ret = NULL;
-	size_t size = rdata_item_size(item);
-
-	if (size == 0) {
-		ret = malloc(2);
-
-		ret[0] = '-';
-		ret[1] = '\0';
-	} else {
-		int32_t  b32_out;
-		uint32_t out_len = ((size + 4) / 5) * 8;
-
-		ret = malloc(out_len + 1);
-
-		b32_out = base32hex_encode(rdata_item_data(item) + 1,
-					   size - 1,
-					   (uint8_t *)ret,
-					   out_len);
-		if (b32_out <= 0) {
-			free(ret);
-			return NULL;
-		}
-
-		ret[b32_out] = '\0';
-	}
-
-	return ret;
-}
-
-/*!< \todo Replace with function from .../common after release. */
-static char *rdata_base64_to_string(knot_rdata_item_t item)
-{
-	int length;
-	size_t size = rdata_item_size(item);
-	char *ret = malloc((sizeof(char) * 2 * size) + 1 * sizeof(char));
-	length = b64_ntop(rdata_item_data(item), size,
-			  ret, (sizeof(char)) * (size * 2 + 1));
-	if (length > 0) {
-		return ret;
-	} else {
-		free(ret);
-		return NULL;
-	}
-}
-
-static char *knot_hex_to_string(const uint8_t *data, size_t size)
-{
-	static const char hexdigits[] = {
-		'0', '1', '2', '3', '4', '5', '6', '7',
-		'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-	};
-	size_t i;
-
-	char *ret = malloc(sizeof(char) * (size * 2 + 1));
-
-	for (i = 0; i < size * 2; i += 2) {
-		uint8_t octet = *data++;
-		ret[i] = hexdigits [octet >> 4];
-		ret[i + 1] = hexdigits [octet & 0x0f];
-	}
-
-	ret[i] = '\0';
-
-	return ret;
-}
-
-char *rdata_hex_to_string(knot_rdata_item_t item)
-{
-	return knot_hex_to_string(rdata_item_data(item), rdata_item_size(item));
-}
-
-char *rdata_hexlen_to_string(knot_rdata_item_t item)
-{
-	if(rdata_item_size(item) <= 1) {
-		// NSEC3 salt hex can be empty
-		char *ret = malloc(sizeof(char) * 2);
-		ret[0] = '-';
-		ret[1] = '\0';
-		return ret;
-	} else {
-		return knot_hex_to_string(rdata_item_data(item) + 1,
-		                          rdata_item_size(item) - 1);
-	}
-}
-
-char *rdata_nsap_to_string(knot_rdata_item_t item)
-{
-	char *ret = malloc(sizeof(char) * ((rdata_item_size(item) * 2) + 7));
-	if (ret == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
-
-	memset(ret, 0, sizeof(char) * ((rdata_item_size(item) * 2) + 7));
-
-	/* String is already terminated. */
-	memcpy(ret, "0x", strlen("0x"));
-	char *converted = knot_hex_to_string(rdata_item_data(item),
-	                                     rdata_item_size(item));
-	if (converted == NULL) {
-		free(ret);
-		return NULL;
-	}
-
-	strncat(ret, converted, rdata_item_size(item) * 2 + 1);
-	free(converted);
-	return ret;
-}
-
-char *rdata_apl_to_string(knot_rdata_item_t item)
-{
-	uint8_t *data = rdata_item_data(item);
-	size_t read = 0;
-	char *pos = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
-	if (pos == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
-	memset(pos, 0, MAX_NSEC_BIT_STR_LEN);
-	
-	char *ret_base = pos;
-	
-	while (read < rdata_item_size(item)) {
-		uint16_t address_family = knot_wire_read_u16(data);
-		uint8_t prefix = data[2];
-		uint8_t length = data[3];
-		int negated = length & APL_NEGATION_MASK;
-		int af = -1;
-
-		length &= APL_LENGTH_MASK;
-		switch (address_family) {
-			case 1: af = AF_INET; break;
-			case 2: af = AF_INET6; break;
-		}
-
-		if (af != -1) {
-			char text_address[1024];
-			memset(text_address, 0, sizeof(text_address));
-			uint8_t address[128];
-			memset(address, 0, sizeof(address));
-			memcpy(address, data + 4, length);
-			/* Only valid data should be present here. */
-			assert((data + 4) - rdata_item_data(item) <= rdata_item_size(item));
-			/* Move pointer at the end of already written data. */
-			pos = ret_base + strlen(ret_base);
-			if (inet_ntop(af, address,
-				      text_address,
-				      sizeof(text_address))) {
-				snprintf(pos, sizeof(text_address) +
-					 U32_MAX_STR_LEN * 2,
-					 "%s%d:%s/%d%s",
-					 negated ? "!" : "",
-					 (int) address_family,
-					 text_address,
-					 (int) prefix,
-					 /* Last item should not have trailing space. */
-					 (read + 4 + length < rdata_item_size(item))
-					 ? " " : "");
-			}
-		}
-
-		data += 4 + length;
-		read += 4 + length;
-	}
-
-	return ret_base;
-}
-
-char *rdata_services_to_string(knot_rdata_item_t item)
-{
-	uint8_t *data = rdata_item_data(item);
-	uint8_t protocol_number = data[0];
-	ssize_t bitmap_size = rdata_item_size(item) - 1;
-	uint8_t *bitmap = data + 1;
-	struct protoent *proto = getprotobynumber(protocol_number);
-
-	char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
-
-	memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
-
-	if (proto) {
-		int i;
-
-		strncpy(ret, proto->p_name, strlen(proto->p_name));
-		strncat(ret, " ", 2);
-
-		for (i = 0; i < bitmap_size * 8; ++i) {
-			if (get_bit(bitmap, i)) {
-				struct servent *service =
-					getservbyport((int)htons(i),
-						      proto->p_name);
-				if (service) {
-					strncat(ret, service->s_name,
-					        strlen(service->s_name));
-					strncat(ret, " ", 2);
-				} else {
-					char tmp[U32_MAX_STR_LEN];
-					snprintf(tmp, U32_MAX_STR_LEN,
-						 "%d ", i);
-					strncat(ret, tmp, U32_MAX_STR_LEN);
-				}
-			}
-		}
-	}
-
-	return ret;
-}
-
-char *rdata_ipsecgateway_to_string(knot_rdata_item_t item,
-                                   const knot_rrset_t *rrset)
-{
-	const knot_rdata_item_t *gateway_type_item =
-		knot_rdata_item(knot_rrset_rdata(rrset), 1);
-	if (gateway_type_item == NULL) {
-		return NULL;
-	}
-	/* First two bytes store length. */
-	int gateway_type = ((uint8_t *)(gateway_type_item->raw_data))[2];
-	switch(gateway_type) {
-	case IPSECKEY_NOGATEWAY: {
-		char *ret = malloc(sizeof(char) * 4);
-		if (ret == NULL) {
-			ERR_ALLOC_FAILED;
-			return NULL;
-		}
-		memset(ret, 0, sizeof(char) * 4);
-		memcpy(ret, "\".\"", 4);
-		return ret;
-	}
-	case IPSECKEY_IP4:
-		return rdata_a_to_string(item);
-	case IPSECKEY_IP6:
-		return rdata_aaaa_to_string(item);
-	case IPSECKEY_DNAME:
-		return rdata_binary_dname_to_string(item);
-	default:
-		return NULL;
-	}
-
-	/* Flow *should* not get here. */
-	return NULL;
-}
-
-char *rdata_nxt_to_string(knot_rdata_item_t item)
-{
-	char buff[32];
-	size_t i;
-	uint8_t *bitmap = rdata_item_data(item);
-	size_t bitmap_size = rdata_item_size(item);
-
-	char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
-
-	memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
-
-	for (i = 0; i < bitmap_size * 8; ++i) {
-		if (get_bit(bitmap, i)) {
-			if (knot_rrtype_to_string(i, buff, sizeof(buff)) < 0) {
-				free(ret);
-				return NULL;
-			}
-
-			strncat(ret, buff, MAX_RR_TYPE_LEN);
-			strncat(ret, " ", 2);
-		}
-	}
-
-	return ret;
-}
-
-
-char *rdata_nsec_to_string(knot_rdata_item_t item)
-{
-	char buff[32];
-
-	char *ret = malloc(sizeof(char) * MAX_NSEC_BIT_STR_LEN);
-	if (ret == NULL) {
-		ERR_ALLOC_FAILED;
-		return NULL;
-	}
-	memset(ret, 0, MAX_NSEC_BIT_STR_LEN);
-	uint8_t *data = rdata_item_data(item);
-
-	int increment = 0;
-	for (int i = 0; i < rdata_item_size(item); i += increment) {
-		increment = 0;
-		uint8_t window = data[i];
-		increment++;
-
-		uint8_t bitmap_size = data[i + increment];
-		increment++;
-
-		uint8_t *bitmap = malloc(sizeof(uint8_t) * bitmap_size);
-
-		memcpy(bitmap, data + i + increment,
-		       bitmap_size);
-
-		increment += bitmap_size;
-
-		for (int j = 0; j < bitmap_size * 8; j++) {
-			if (get_bit(bitmap, j)) {
-				if (knot_rrtype_to_string(j + window * 256,
-				                          buff, sizeof(buff))
-				    < 0) {
-					free(bitmap);
-					free(ret);
-					return NULL;
-				}
-				strncat(ret, buff, MAX_RR_TYPE_LEN);
-				strncat(ret, " ", 2);
-			}
-		}
-
-		free(bitmap);
-	}
-
-	return ret;
-}
-
-char *rdata_unknown_to_string(knot_rdata_item_t item)
-{
- 	uint16_t size = rdata_item_size(item);
-	char *ret =
-		malloc(sizeof(char) * (2 * rdata_item_size(item) +
-				       strlen("\\# ") + U16_MAX_STR_LEN + 1));
-	if (ret == NULL) {
-		return NULL;
-	}
-	memcpy(ret, "\\# \0", strlen("\\# \0"));
-	snprintf(ret + strlen("\\# "),
-	         strlen("\\# ") + U16_MAX_STR_LEN + 1, "%lu ",
-		 (unsigned long) size);
-	char *converted = knot_hex_to_string(rdata_item_data(item), size);
-	strncat(ret, converted, size * 2 + 1);
-	free(converted);
-	return ret;
-}
-
-char *rdata_loc_to_string(knot_rdata_item_t item)
-{
-	return rdata_unknown_to_string(item);
-}
-
-typedef char * (*item_to_string_t)(knot_rdata_item_t);
-
-static item_to_string_t item_to_string_table[KNOT_RDATA_ZF_UNKNOWN + 1] = {
-	rdata_dname_to_string,
-	rdata_dns_name_to_string,
-	rdata_text_array_to_string,
-	rdata_text_array_to_string,
-	rdata_byte_to_string,
-	rdata_short_to_string,
-	rdata_long_to_string,
-	rdata_a_to_string,
-	rdata_aaaa_to_string,
-	rdata_rrtype_to_string,
-	rdata_algorithm_to_string,
-	rdata_certificate_type_to_string,
-	rdata_period_to_string,
-	rdata_time_to_string,
-	rdata_base64_to_string,
-	rdata_base32_to_string,
-	rdata_hex_to_string,
-	rdata_hexlen_to_string,
-	rdata_nsap_to_string,
-	rdata_apl_to_string,
-	NULL, //rdata_ipsecgateway_to_string,
-	rdata_services_to_string,
-	rdata_nxt_to_string,
-	rdata_nsec_to_string,
-	rdata_loc_to_string,
-	rdata_unknown_to_string
-};
-
-char *rdata_item_to_string(knot_rdata_zoneformat_t type,
-                           knot_rdata_item_t item)
-{
-	return item_to_string_table[type](item);
-}
-
-int rdata_dump_text(const knot_rdata_t *rdata, uint16_t type, FILE *f,
-                     const knot_rrset_t *rrset)
-{
-	if (rdata == NULL || rrset == NULL) {
-		return KNOT_EINVAL;
-	}
-	
-	knot_rrtype_descriptor_t *desc =
-		knot_rrtype_descriptor_by_type(type);
-	char *item_str = NULL;
-	assert(rdata->count <= desc->length);
-	for (int i = 0; i < rdata->count; i++) {
-		/* Workaround for IPSec gateway. */
-		if (desc->zoneformat[i] == KNOT_RDATA_ZF_IPSECGATEWAY) {
-			item_str = rdata_ipsecgateway_to_string(rdata->items[i],
-			                                        rrset);
-		} else {
-			item_str = rdata_item_to_string(desc->zoneformat[i],
-						rdata->items[i]);
-		}
-		if (item_str == NULL) {
-			item_str =
-				rdata_item_to_string(KNOT_RDATA_ZF_UNKNOWN,
-						     rdata->items[i]);
-		}
-
-		if (item_str == NULL) {
-			/* Fatal error. */
-			return KNOT_ERROR;
-		}
-
-		if (i != rdata->count - 1) {
-			fprintf(f, "%s ", item_str);
-		} else {
-			fprintf(f, "%s", item_str);
-		}
-
-		free(item_str);
-	}
-	fprintf(f, "\n");
-
-	return KNOT_EOK;
-}
-
-#endif
-
-int knot_rrset_txt_dump_header(const knot_rrset_t *rrset, char *dst,
-                               const size_t maxlen)
-{
-	if (rrset == NULL || dst == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	size_t len = 0;
-	char   buf[32];
-	int    ret;
-
-	// Dump rrset owner.
-	char *name = knot_dname_to_str(rrset->owner);
-	ret = snprintf(dst + len, maxlen - len, "%-20s\t", name);
-	free(name);
-	if (ret < 0 || ret >= maxlen - len) {
-		return KNOT_ESPACE;
-	}
-	len += ret;
-
-	// Dump rrset ttl.
-	if (1) {	
-		ret = snprintf(dst + len, maxlen - len, "%6u\t", rrset->ttl);
-	} else {
-		ret = snprintf(dst + len, maxlen - len, "     \t");
-	}
-	if (ret < 0 || ret >= maxlen - len) {
-		return KNOT_ESPACE;
-	}
-	len += ret;
-
-	// Dump rrset class.
-	if (1) {
-		if (knot_rrclass_to_string(rrset->rclass, buf, sizeof(buf)) < 0)
-		{
-			return KNOT_ESPACE;
-		}
-		ret = snprintf(dst + len, maxlen - len, "%-2s\t", buf);
-	} else {
-		ret = snprintf(dst + len, maxlen - len, "  \t");
-	}
-	if (ret < 0 || ret >= maxlen - len) {
-		return KNOT_ESPACE;
-	}
-	len += ret;
-
-	// Dump rrset type.
-	if (knot_rrtype_to_string(rrset->type, buf, sizeof(buf)) < 0) {
-		return KNOT_ESPACE;
-	}
-	ret = snprintf(dst + len, maxlen - len, "%-5s\t", buf);
-	if (ret < 0 || ret >= maxlen - len) {
-		return KNOT_ESPACE;
-	}
-	len += ret;
-	
-	return len;
-}
-
-int knot_rrset_txt_dump_data(const knot_rrset_t *rrset, const size_t pos,
-                             char *dst, const size_t maxlen)
-{
-	if (rrset == NULL || dst == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	const uint8_t *rdata = knot_rrset_get_rdata(rrset, pos);
-	size_t data_len = rrset_rdata_item_size(rrset, pos);
-
-	switch (knot_rrset_type(rrset)) {
-		case KNOT_RRTYPE_A:
-			break;
-		case KNOT_RRTYPE_NS:
-			break;
-		case KNOT_RRTYPE_CNAME:
-			break;
-		case KNOT_RRTYPE_SOA:
-			break;
-		case KNOT_RRTYPE_PTR:
-			break;
-		case KNOT_RRTYPE_HINFO:
-			break;
-		case KNOT_RRTYPE_MINFO:
-			break;
-		case KNOT_RRTYPE_MX:
-			break;
-		case KNOT_RRTYPE_TXT:
-			break;
-		case KNOT_RRTYPE_RP:
-			break;
-		case KNOT_RRTYPE_AFSDB:
-			break;
-		case KNOT_RRTYPE_RT:
-			break;
-		case KNOT_RRTYPE_KEY:
-			break;
-		case KNOT_RRTYPE_AAAA:
-			break;
-		case KNOT_RRTYPE_LOC:
-			break;
-		case KNOT_RRTYPE_SRV:
-			break;
-		case KNOT_RRTYPE_NAPTR:
-			break;
-		case KNOT_RRTYPE_KX:
-			break;
-		case KNOT_RRTYPE_CERT:
-			break;
-		case KNOT_RRTYPE_DNAME:
-			break;
-		case KNOT_RRTYPE_APL:
-			break;
-		case KNOT_RRTYPE_DS:
-			break;
-		case KNOT_RRTYPE_SSHFP:
-			break;
-		case KNOT_RRTYPE_IPSECKEY:
-			break;
-		case KNOT_RRTYPE_RRSIG:
-			break;
-		case KNOT_RRTYPE_NSEC:
-			break;
-		case KNOT_RRTYPE_DNSKEY:
-			break;
-		case KNOT_RRTYPE_DHCID:
-			break;
-		case KNOT_RRTYPE_NSEC3:
-			break;
-		case KNOT_RRTYPE_NSEC3PARAM:
-			break;
-		case KNOT_RRTYPE_TLSA:
-			break;
-		case KNOT_RRTYPE_SPF:
-			break;
-		default:
-			break;
-	}
-
-	return KNOT_EOK;
-}
-
-int knot_rrset_txt_dump(const knot_rrset_t *rrset, char *dst, const size_t maxlen)
-{
-	if (rrset == NULL || dst == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	size_t len = 0;
-	int    ret;
-
-	// Loop over rdata in rrset.
-	for (size_t i = 0; i < rrset->rdata_count; i++) {
-		// Dump rdata owner, class, ttl and type.
-		ret = knot_rrset_txt_dump_header(rrset, dst + len, maxlen - len);
-		if (ret < 0) {
-			return KNOT_ESPACE;
-		}
-		len += ret;
-
-		// Dump rdata as such.
-		ret = knot_rrset_txt_dump_data(rrset, i, dst + len, maxlen - len);
-		if (ret < 0) {
-			return KNOT_ESPACE;
-		}
-		len += ret;
-	}
-
-	// Dump RRSIG records if any via recursion call.
-	if (rrset->rrsigs != NULL) {
-		ret = knot_rrset_txt_dump(rrset->rrsigs, dst + len, maxlen - len);
-		if (ret < 0) {
-			return KNOT_ESPACE;
-		}
-		len += ret;
-	}
-
-	return len;
-}
-
-typedef struct {
-	int    ret;
-	FILE   *file;
-	char   *buf;
-	size_t buflen;
-	const knot_dname_t *origin;
-} dump_params_t;
-
-static void apex_node_dump_text(knot_node_t *node, dump_params_t *params)
-{
-	knot_rrset_t *rr = knot_node_get_rrset(node, KNOT_RRTYPE_SOA);
-
-	int ret = knot_rrset_txt_dump(rr, params->buf, params->buflen);
-	if (ret < 0) {
-		params->ret = KNOT_ENOMEM;
-		return;
-	}
-	fprintf(params->file, "%s\n", params->buf);
-
-	const knot_rrset_t **rrsets = knot_node_rrsets(node);
-	
-	for (int i = 0; i < node->rrset_count; i++) {
-		if (rrsets[i]->type != KNOT_RRTYPE_SOA) {
-			ret = knot_rrset_txt_dump(rrsets[i], params->buf,
-			                          params->buflen);
-			if (ret < 0) {
-				free(rrsets);
-				params->ret = KNOT_ENOMEM;
-				return;
-			}
-			fprintf(params->file, "%s\n", params->buf);
-		}
-	}
-
-	free(rrsets);
-
-	params->ret = KNOT_EOK;
-}
-
-void node_dump_text(knot_node_t *node, void *data)
-{
-	dump_params_t *params = (dump_params_t *)data;
-
-	if (node->owner == params->origin) {
-		apex_node_dump_text(node, params);
-		return;
-	}
-
-	const knot_rrset_t **rrsets = knot_node_rrsets(node);
-
-	int ret;
-	for (int i = 0; i < node->rrset_count; i++) {
-		ret = knot_rrset_txt_dump(rrsets[i], params->buf, params->buflen);
-		if (ret < 0) {
-			params->ret = KNOT_ENOMEM;
-			return;
-		}
-	}
-
-	free(rrsets);
-
-	params->ret = KNOT_EOK;
-}
-
-#define DUMP_BUF_LEN (70 * 1024)
-
-int zone_dump_text(knot_zone_contents_t *zone, FILE *file)
-{
-	if (zone == NULL || file == NULL) {
-		return KNOT_EINVAL;
-	}
-
-	char *buf = malloc(DUMP_BUF_LEN);
-	if (buf == NULL) {
-		return KNOT_ENOMEM;
-	}
-
-	fprintf(file, ";Dumped using %s v. %s\n", PACKAGE_NAME, PACKAGE_VERSION);
-
-	dump_params_t params;
-	params.ret = KNOT_ERROR;
-	params.file = file;
-	params.buf = buf;
-	params.buflen = DUMP_BUF_LEN;
-	params.origin = knot_node_owner(knot_zone_contents_apex(zone));
-
-	knot_zone_contents_tree_apply_inorder(zone, node_dump_text, &params);
-	if (params.ret != KNOT_EOK) {
-		return params.ret;
-	}
-
-	knot_zone_contents_nsec3_apply_inorder(zone, node_dump_text, &params);
-	if (params.ret != KNOT_EOK) {
-		return params.ret;
-	}
-
-	return KNOT_EOK;
-}