MOBI_RET mobi_write_ncx(MOBIRawml *rawml, const NCX *ncx, const OPF *opf, uint32_t maxlevel) {
    const xmlChar * NCXNamespace = BAD_CAST "http://www.daisy.org/z3986/2005/ncx/";
    xmlBufferPtr buf = xmlBufferCreate();
    if (buf == NULL) {
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0);
    if (writer == NULL) {
        xmlBufferFree(buf);
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    xmlTextWriterSetIndent(writer, 1);
    int xml_ret = xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "ncx", NCXNamespace);
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "2005-1");
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang", BAD_CAST opf->metadata->dc_meta->language[0]);
    if (xml_ret < 0) { goto cleanup; }
    
    MOBI_RET ret = mobi_write_ncx_header(writer, opf, maxlevel);
    if (ret != MOBI_SUCCESS) { goto cleanup; }
    
    /* start <navMap> */
    xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "navMap");
    if (xml_ret < 0) { goto cleanup; }
    if (ncx && rawml->ncx->entries_count > 0) {
        const size_t count = rawml->ncx->entries_count;
        size_t seq = 1;
        ret = mobi_write_ncx_level(writer, ncx, 0, 0, count - 1, &seq);
        if (ret != MOBI_SUCCESS) { goto cleanup; }
    }

    /* end <navMap> */
    xml_ret = xmlTextWriterEndDocument(writer);
    if (xml_ret < 0) { goto cleanup; }
    xmlFreeTextWriter(writer);
    const char *ncx_xml = (const char *) buf->content;
    mobi_ncx_add_to_rawml(ncx_xml, rawml);
    xmlBufferFree(buf);
    return MOBI_SUCCESS;
    
cleanup:
    xmlFreeTextWriter(writer);
    xmlBufferFree(buf);
    debug_print("%s\n", "XML writing failed");
    return MOBI_XML_ERR;
}
MOBI_RET mobi_write_ncx(MOBIRawml *rawml, const NCX *ncx, const OPF *opf, uint32_t maxlevel) {
    const xmlChar * NCXNamespace = BAD_CAST "http://www.daisy.org/z3986/2005/ncx/";
    xmlBufferPtr buf = xmlBufferCreate();
    if (buf == NULL) {
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    xmlTextWriterPtr writer = xmlNewTextWriterMemory(buf, 0);
    if (writer == NULL) {
        xmlBufferFree(buf);
        debug_print("%s\n", "Memory allocation failed");
        return MOBI_MALLOC_FAILED;
    }
    xmlTextWriterSetIndent(writer, 1);
    int xml_ret = xmlTextWriterStartDocument(writer, NULL, NULL, NULL);
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterStartElementNS(writer, NULL, BAD_CAST "ncx", NCXNamespace);
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "version", BAD_CAST "2005-1");
    if (xml_ret < 0) { goto cleanup; }
    xml_ret = xmlTextWriterWriteAttribute(writer, BAD_CAST "xml:lang", BAD_CAST opf->metadata->dc_meta->language[0]);
    if (xml_ret < 0) { goto cleanup; }
    
    MOBI_RET ret = mobi_write_ncx_header(writer, opf, maxlevel);
    if (ret != MOBI_SUCCESS) { goto cleanup; }
    
     
    xml_ret = xmlTextWriterStartElement(writer, BAD_CAST "navMap");
    if (xml_ret < 0) { goto cleanup; }
    if (ncx && rawml->ncx->entries_count > 0) {
        const size_t count = rawml->ncx->entries_count;
        size_t seq = 1;
        ret = mobi_write_ncx_level(writer, ncx, 0, 0, count - 1, &seq);
        if (ret != MOBI_SUCCESS) { goto cleanup; }
    }

     
    xml_ret = xmlTextWriterEndDocument(writer);
    if (xml_ret < 0) { goto cleanup; }
    xmlFreeTextWriter(writer);
    const char *ncx_xml = (const char *) buf->content;
    mobi_ncx_add_to_rawml(ncx_xml, rawml);
    xmlBufferFree(buf);
    return MOBI_SUCCESS;
    
cleanup:
    xmlFreeTextWriter(writer);
    xmlBufferFree(buf);
    debug_print("%s\n", "XML writing failed");
    return MOBI_XML_ERR;
}