bool xml_document::to_string(buffer& buf, bool pretty_print, const struct node* node, unsigned depth) const
{
	do {
		if (pretty_print) {
			// If not the first node...
			if (node != _M_nodes) {
				if (!buf.append("\r\n", 2)) {
					return false;
				}
			}
		}

		if (!node_to_string(buf, pretty_print, node, depth)) {
			return false;
		}

		if (node->child != -1) {
			if (!to_string(buf, pretty_print, &(_M_nodes[node->child]), depth + 1)) {
				return false;
			}

			if (pretty_print) {
				if (!buf.append("\r\n", 2)) {
					return false;
				}

				for (unsigned i = 0; i < depth; i++) {
					if (!buf.append('\t')) {
						return false;
					}
				}
			}

			if (!buf.format("</%.*s>", node->len, _M_buf.data() + node->text)) {
				return false;
			}
		}

		if (node->next < 0) {
			return true;
		}

		node = &(_M_nodes[node->next]);
	} while (true);
}
bool xml_document::node_to_string(buffer& buf, bool pretty_print, const struct node* node, unsigned depth) const
{
	if (pretty_print) {
		for (unsigned i = 0; i < depth; i++) {
			if (!buf.append('\t')) {
				return false;
			}
		}
	}

	switch (node->type) {
		case DOCTYPE_NODE:
			return buf.format("<!DOCTYPE %.*s>", node->len, _M_buf.data() + node->text);
		case PROCESSING_INSTRUCTION_NODE:
			return buf.format("<?%.*s?>", node->len, _M_buf.data() + node->text);
		case COMMENT_NODE:
			return buf.format("<!-- %.*s -->", node->len, _M_buf.data() + node->text);
		case ELEMENT_NODE:
			if (!buf.format("<%.*s", node->len, _M_buf.data() + node->text)) {
				return false;
			}

			if (node->attributes) {
				const char* name;
				size_t namelen;
				const char* value;
				size_t valuelen;

				for (size_t i = 0; node->attributes->get(i, name, namelen, value, valuelen); i++) {
					char quotes = (memchr(value, '"', valuelen)) ? '\'' : '"';
					if (!buf.format(" %.*s=%c%.*s%c", namelen, name, quotes, valuelen, value, quotes)) {
						return false;
					}
				}
			}

			if (node->child > 0) {
				return buf.append('>');
			} else {
				return buf.append("/>", 2);
			}

		case TEXT_NODE:
			return buf.format("%.*s", node->len, _M_buf.data() + node->text);
		default:
			return false;
	}
}