#include <stdlib.h>
#if HAVE_LIBXML_XMLWRITER_H
#include <libxml/xmlwriter.h>
+#if defined(LIBXML_VERSION) && LIBXML_VERSION >= 20703
+#define XAR_WRITER_HAS_XML
+#endif /* LIBXML_VERSION */
#endif
#ifdef HAVE_BZLIB_H
#include <bzlib.h>
*
*/
-#if !(defined(HAVE_LIBXML_XMLWRITER_H) && defined(LIBXML_VERSION) &&\
- LIBXML_VERSION >= 20703) ||\
+#if !defined(XAR_WRITER_HAS_XML) ||\
!defined(HAVE_ZLIB_H) || \
!defined(ARCHIVE_HAS_MD5) || !defined(ARCHIVE_HAS_SHA1)
/*
#else /* Support xar format */
-/*#define DEBUG_PRINT_TOC 1 */
+struct xml_writer;
+static int xml_writer_create(struct xml_writer **pctx);
+static int xml_writer_start_document(struct xml_writer *ctx);
+static int xml_writer_end_document(struct xml_writer *ctx);
+static int xml_writer_set_indent(struct xml_writer *ctx, unsigned int indent);
+static int xml_writer_start_element(struct xml_writer *ctx,
+ const char *localName);
+static int xml_writer_write_attribute(struct xml_writer *ctx, const char *key,
+ const char *value);
+static int xml_writer_write_attributef(struct xml_writer *ctx, const char *key,
+ const char *format, ...);
+static int xml_writer_write_string(struct xml_writer *ctx, const char *string);
+static int xml_writer_write_base64(struct xml_writer* ctx,
+ const char *data, size_t start, size_t len);
+static int xml_writer_end_element(struct xml_writer *ctx);
+static int xml_writer_get_final_content_and_length(struct xml_writer *ctx,
+ const char **out, size_t *size);
+static int xml_writer_destroy(struct xml_writer *ctx);
-#define BAD_CAST_CONST (const xmlChar *)
+/*#define DEBUG_PRINT_TOC 1 */
#define HEADER_MAGIC 0x78617221
#define HEADER_SIZE 28
}
static int
-xmlwrite_string_attr(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_string_attr(struct archive_write *a, struct xml_writer *writer,
const char *key, const char *value,
const char *attrkey, const char *attrvalue)
{
int r;
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
+ r = xml_writer_start_element(writer, key);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
if (attrkey != NULL && attrvalue != NULL) {
- r = xmlTextWriterWriteAttribute(writer,
- BAD_CAST_CONST(attrkey), BAD_CAST_CONST(attrvalue));
+ r = xml_writer_write_attribute(writer, attrkey, attrvalue);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
+ "xml_writer_write_attribute() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
if (value != NULL) {
- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
+ r = xml_writer_write_string(writer, value);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteString() failed: %d", r);
+ "xml_writer_write_string() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
static int
-xmlwrite_string(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_string(struct archive_write *a, struct xml_writer *writer,
const char *key, const char *value)
{
int r;
if (value == NULL)
return (ARCHIVE_OK);
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(key));
+ r = xml_writer_start_element(writer, key);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
if (value != NULL) {
- r = xmlTextWriterWriteString(writer, BAD_CAST_CONST(value));
+ r = xml_writer_write_string(writer, value);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteString() failed: %d", r);
+ "xml_writer_write_string() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
return (ARCHIVE_OK);
}
static int
-xmlwrite_fstring(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_fstring(struct archive_write *a, struct xml_writer *writer,
const char *key, const char *fmt, ...)
{
struct xar *xar;
}
static int
-xmlwrite_time(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_time(struct archive_write *a, struct xml_writer *writer,
const char *key, time_t t, int z)
{
char timestr[100];
}
static int
-xmlwrite_mode(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_mode(struct archive_write *a, struct xml_writer *writer,
const char *key, mode_t mode)
{
char ms[5];
}
static int
-xmlwrite_sum(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_sum(struct archive_write *a, struct xml_writer *writer,
const char *key, struct chksumval *sum)
{
const char *algname;
}
static int
-xmlwrite_heap(struct archive_write *a, xmlTextWriterPtr writer,
+xmlwrite_heap(struct archive_write *a, struct xml_writer *writer,
struct heap_data *heap)
{
const char *encname;
* Our implements records both <flags> and <ext2> if it's necessary.
*/
static int
-make_fflags_entry(struct archive_write *a, xmlTextWriterPtr writer,
+make_fflags_entry(struct archive_write *a, struct xml_writer *writer,
const char *element, const char *fflags_text)
{
static const struct flagentry {
} while (p != NULL);
if (n > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST_CONST(element));
+ r = xml_writer_start_element(writer, element);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
for (i = 0; i < n; i++) {
return (r);
}
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
return (ARCHIVE_OK);
}
+/*
+ * This function determines whether a UTF-8 string contains
+ * only codepoints that are convertible to Latin-1. Strings
+ * beyond Latin-1 are stored base64-encoded in the XAR TOC.
+ */
static int
-make_file_entry(struct archive_write *a, xmlTextWriterPtr writer,
+is_u8_zstring_latin1(const char *in)
+{
+ unsigned int c;
+ while (*in) {
+ c = *in++;
+ if (c < 0x80) continue;
+ /*
+ * Filter out non-continuation, any continuation of 2-3
+ * bytes, and any continuation of 1 byte whose high 3 bits
+ * are non-zero. Recall, 1-byte continuations can store 11
+ * bits whereas Latin-1 codepoints are only 8 bits wide.
+ */
+ if ((c & 0xFC) != 0xC0)
+ return (0);
+ c = *in++;
+ /*
+ * If we get any non-continuation byte (including 0x00!),
+ * the string is not valid UTF-8.
+ */
+ if ((c & 0xC0) != 0x80)
+ return (0); /* invalid unicode */
+ }
+ return (1);
+}
+
+static int
+make_file_entry(struct archive_write *a, struct xml_writer *writer,
struct file *file)
{
struct xar *xar;
const char *filetype, *filelink, *fflags;
struct archive_string linkto;
struct heap_data *heap;
- unsigned char *tmp;
const char *p;
size_t len;
- int r, r2, l, ll;
+ int r, r2;
xar = (struct xar *)a->format_data;
r2 = ARCHIVE_OK;
/*
* Make a file name entry, "<name>".
*/
- l = ll = (int)archive_strlen(&(file->basename));
- tmp = malloc(l);
- if (tmp == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory");
- return (ARCHIVE_FATAL);
- }
- r = UTF8Toisolat1(tmp, &l, BAD_CAST(file->basename.s), &ll);
- free(tmp);
- if (r < 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("name"));
+ if (!is_u8_zstring_latin1(file->basename.s)) {
+ r = xml_writer_start_element(writer, "name");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
- r = xmlTextWriterWriteAttribute(writer,
- BAD_CAST("enctype"), BAD_CAST("base64"));
+ r = xml_writer_write_attribute(writer,
+ "enctype", "base64");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
+ "xml_writer_write_attribute() failed: %d", r);
return (ARCHIVE_FATAL);
}
- r = xmlTextWriterWriteBase64(writer, file->basename.s,
+ r = xml_writer_write_base64(writer, file->basename.s,
0, (int)archive_strlen(&(file->basename)));
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteBase64() failed: %d", r);
+ "xml_writer_write_base64() failed: %d", r);
return (ARCHIVE_FATAL);
}
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
} else {
break;
case AE_IFCHR:
case AE_IFBLK:
- r = xmlTextWriterStartElement(writer, BAD_CAST("device"));
+ r = xml_writer_start_element(writer, "device");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
r = xmlwrite_fstring(a, writer, "major",
"%d", archive_entry_rdevminor(file->entry));
if (r < 0)
return (ARCHIVE_FATAL);
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
break;
archive_entry_xattr_next(file->entry,
&name, &value, &size);
- r = xmlTextWriterStartElement(writer, BAD_CAST("ea"));
+ r = xml_writer_start_element(writer, "ea");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
- r = xmlTextWriterWriteFormatAttribute(writer,
- BAD_CAST("id"), "%d", heap->id);
+ r = xml_writer_write_attributef(writer,
+ "id", "%d", heap->id);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
+ "xml_writer_write_attributef() failed: %d", r);
return (ARCHIVE_FATAL);
}
r = xmlwrite_heap(a, writer, heap);
if (r < 0)
return (ARCHIVE_FATAL);
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
* Make a file data entry, "<data>".
*/
if (file->data.length > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("data"));
+ r = xml_writer_start_element(writer, "data");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
if (r < 0)
return (ARCHIVE_FATAL);
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
if (archive_strlen(&file->script) > 0) {
- r = xmlTextWriterStartElement(writer, BAD_CAST("content"));
+ r = xml_writer_start_element(writer, "content");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
if (r < 0)
return (ARCHIVE_FATAL);
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
return (ARCHIVE_FATAL);
}
}
{
struct xar *xar;
struct file *np;
- xmlBufferPtr bp;
- xmlTextWriterPtr writer;
+ struct xml_writer *writer;
+ const char* content;
+ size_t use;
int algsize;
int r, ret;
* Initialize xml writer.
*/
writer = NULL;
- bp = xmlBufferCreate();
- if (bp == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "xmlBufferCreate() "
- "couldn't create xml buffer");
- goto exit_toc;
- }
- writer = xmlNewTextWriterMemory(bp, 0);
- if (writer == NULL) {
+ r = xml_writer_create(&writer);
+ if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlNewTextWriterMemory() "
- "couldn't create xml writer");
+ "xml_writer_create() failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterStartDocument(writer, "1.0", "UTF-8", NULL);
+ r = xml_writer_set_indent(writer, 4);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartDocument() failed: %d", r);
+ "xml_writer_set_indent() failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterSetIndent(writer, 4);
+ r = xml_writer_start_document(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterSetIndent() failed: %d", r);
+ "xml_writer_start_document() failed: %d", r);
goto exit_toc;
}
/*
* Start recording TOC
*/
- r = xmlTextWriterStartElement(writer, BAD_CAST("xar"));
+ r = xml_writer_start_element(writer, "xar");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterStartElement(writer, BAD_CAST("toc"));
+ r = xml_writer_start_element(writer, "toc");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartDocument() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
goto exit_toc;
}
/*
* Record TOC checksum
*/
- r = xmlTextWriterStartElement(writer, BAD_CAST("checksum"));
+ r = xml_writer_start_element(writer, "checksum");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() failed: %d", r);
+ "xml_writer_start_element() failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterWriteAttribute(writer, BAD_CAST("style"),
- BAD_CAST_CONST(getalgname(xar->opt_toc_sumalg)));
+ r = xml_writer_write_attribute(writer, "style",
+ getalgname(xar->opt_toc_sumalg));
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() failed: %d", r);
+ "xml_writer_write_attribute() failed: %d", r);
goto exit_toc;
}
if (r < 0)
goto exit_toc;
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() failed: %d", r);
+ "xml_writer_end_element() failed: %d", r);
goto exit_toc;
}
}
if (np->dir && np->children.first != NULL) {
/* Enter to sub directories. */
np = np->children.first;
- r = xmlTextWriterStartElement(writer,
- BAD_CAST("file"));
+ r = xml_writer_start_element(writer,
+ "file");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() "
+ "xml_writer_start_element() "
"failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterWriteFormatAttribute(
- writer, BAD_CAST("id"), "%d", np->id);
+ r = xml_writer_write_attributef(
+ writer, "id", "%d", np->id);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() "
+ "xml_writer_write_attributef() "
"failed: %d", r);
goto exit_toc;
}
continue;
}
while (np != np->parent) {
- r = xmlTextWriterEndElement(writer);
+ r = xml_writer_end_element(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndElement() "
+ "xml_writer_end_element() "
"failed: %d", r);
goto exit_toc;
}
np = np->parent;
} else {
np = np->chnext;
- r = xmlTextWriterStartElement(writer,
- BAD_CAST("file"));
+ r = xml_writer_start_element(writer,
+ "file");
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterStartElement() "
+ "xml_writer_start_element() "
"failed: %d", r);
goto exit_toc;
}
- r = xmlTextWriterWriteFormatAttribute(
- writer, BAD_CAST("id"), "%d", np->id);
+ r = xml_writer_write_attributef(
+ writer, "id", "%d", np->id);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterWriteAttribute() "
+ "xml_writer_write_attributef() "
"failed: %d", r);
goto exit_toc;
}
}
} while (np != np->parent);
- r = xmlTextWriterEndDocument(writer);
+ r = xml_writer_end_document(writer);
if (r < 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_MISC,
- "xmlTextWriterEndDocument() failed: %d", r);
+ "xml_writer_end_document() failed: %d", r);
goto exit_toc;
}
+
+ r = xml_writer_get_final_content_and_length(writer, &content, &use);
+ if (r < 0) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "xml_writer_get_final_content_and_length() failed: %d", r);
+ goto exit_toc;
+ }
+
#if DEBUG_PRINT_TOC
fprintf(stderr, "\n---TOC-- %d bytes --\n%s\n",
- strlen((const char *)bp->content), bp->content);
+ (int)strlen(content), content);
#endif
/*
* Compress the TOC and calculate the sum of the TOC.
*/
xar->toc.temp_offset = xar->temp_offset;
- xar->toc.size = bp->use;
+ xar->toc.size = (uint64_t)use;
checksum_init(&(xar->a_sumwrk), xar->opt_toc_sumalg);
r = compression_init_encoder_gzip(&(a->archive),
&(xar->stream), 6, 1);
if (r != ARCHIVE_OK)
goto exit_toc;
- xar->stream.next_in = bp->content;
- xar->stream.avail_in = bp->use;
+ xar->stream.next_in = (const unsigned char *)content;
+ xar->stream.avail_in = use;
xar->stream.total_in = 0;
xar->stream.next_out = xar->wbuff;
xar->stream.avail_out = sizeof(xar->wbuff);
ret = ARCHIVE_OK;
exit_toc:
if (writer)
- xmlFreeTextWriter(writer);
- if (bp)
- xmlBufferFree(bp);
+ xml_writer_destroy(writer);
return (ret);
}
}
}
+#if HAVE_LIBXML_XMLWRITER_H
+
+#define BAD_CAST_CONST (const xmlChar *)
+
+struct xml_writer {
+ xmlTextWriterPtr writer;
+ xmlBufferPtr bp;
+ unsigned int indent;
+};
+
+static int
+xml_writer_create(struct xml_writer **pctx)
+{
+ struct xml_writer *ctx = calloc(1, sizeof(struct xml_writer));
+ if (ctx == NULL) {
+ return (-1);
+ }
+
+ ctx->bp = xmlBufferCreate();
+ if (ctx->bp == NULL) {
+ free(ctx);
+ return (-1);
+ }
+
+ ctx->writer = xmlNewTextWriterMemory(ctx->bp, 0);
+ if (ctx->writer == NULL) {
+ xmlBufferFree(ctx->bp);
+ free(ctx);
+ return (-1);
+ }
+
+ *pctx = ctx;
+ return (0);
+}
+
+static int
+xml_writer_destroy(struct xml_writer *ctx)
+{
+ xmlFreeTextWriter(ctx->writer);
+ xmlBufferFree(ctx->bp);
+ free(ctx);
+ return (0);
+}
+
+static int
+xml_writer_start_document(struct xml_writer *ctx)
+{
+ int r;
+ r = xmlTextWriterStartDocument(ctx->writer, "1.0", "UTF-8", NULL);
+ if (r < 0) {
+ return (r);
+ }
+
+ r = xmlTextWriterSetIndent(ctx->writer, (int)ctx->indent);
+ return (r);
+}
+
+static int
+xml_writer_end_document(struct xml_writer *ctx)
+{
+ return (xmlTextWriterEndDocument(ctx->writer));
+}
+
+static int
+xml_writer_set_indent(struct xml_writer *ctx, unsigned int indent)
+{
+ /* libxml2 only lets you set the indent after starting the document */
+ ctx->indent = indent;
+ return (0);
+}
+
+static int
+xml_writer_start_element(struct xml_writer *ctx, const char *localName)
+{
+ return (xmlTextWriterStartElement(ctx->writer,
+ BAD_CAST_CONST(localName)));
+}
+
+static int
+xml_writer_write_attribute(struct xml_writer *ctx,
+ const char *key, const char *value)
+{
+ return (xmlTextWriterWriteAttribute(ctx->writer,
+ BAD_CAST_CONST(key), BAD_CAST_CONST(value)));
+}
+
+static int
+xml_writer_write_attributef(struct xml_writer *ctx,
+ const char *key, const char *format, ...)
+{
+ va_list ap;
+ int ret;
+ va_start(ap, format);
+ ret = xmlTextWriterWriteVFormatAttribute(ctx->writer,
+ BAD_CAST_CONST(key), format, ap);
+ va_end(ap);
+ return (ret);
+}
+
+static int
+xml_writer_write_string(struct xml_writer *ctx, const char *string)
+{
+ return (xmlTextWriterWriteString(ctx->writer, BAD_CAST_CONST(string)));
+}
+
+static int
+xml_writer_write_base64(struct xml_writer* ctx,
+ const char *data, size_t start, size_t len)
+{
+ return (xmlTextWriterWriteBase64(ctx->writer, data,
+ (int)start, (int)len));
+}
+
+static int
+xml_writer_end_element(struct xml_writer *ctx)
+{
+ return (xmlTextWriterEndElement(ctx->writer));
+}
+
+static int
+xml_writer_get_final_content_and_length(struct xml_writer *ctx,
+ const char **out, size_t *size)
+{
+ *out = (const char*)ctx->bp->content;
+ *size = (size_t)ctx->bp->use;
+ return (0);
+}
+#endif /* HAVE_LIBXML_XMLWRITER_H */
+
#endif /* Support xar format */