/**
 * Destructor
 */
ODe_Style_MasterPage::~ODe_Style_MasterPage() {
    if (m_pHeaderContentTemp != NULL) {
        ODe_gsf_output_close(m_pHeaderContentTemp);
    }
 
    if (m_pHeaderEvenContentTemp != NULL) {
        ODe_gsf_output_close(m_pHeaderEvenContentTemp);
    }

    if (m_pFooterContentTemp != NULL) {
        ODe_gsf_output_close(m_pFooterContentTemp);
    }

    if (m_pFooterEvenContentTemp != NULL) {
        ODe_gsf_output_close(m_pFooterEvenContentTemp);
    }
}
/**
 * Writes all pictures inside the Pictures subdirectory.
 */
bool ODe_PicturesWriter::writePictures(PD_Document* pDoc, GsfOutfile* pODT) 
{
    const char * szName;
    std::string mimeType;
	std::string extension;
	std::string fullName;
    const UT_ByteBuf * pByteBuf;
    GsfOutput* pImg;
    GsfOutput* pPicsDir = NULL;
    
    for (UT_uint32 k=0;
         (pDoc->enumDataItems(k,
                              NULL,
                              &szName,
                              &pByteBuf,
                              &mimeType));
         k++) {
            		
        // We must avoid saving RDF data as image
        if (!mimeType.empty() && (mimeType != "application/rdf+xml")) {
            if (pPicsDir == NULL) {
                // create Pictures directory
                pPicsDir = gsf_outfile_new_child(pODT, "Pictures", TRUE);
            }
			pDoc->getDataItemFileExtension(szName, extension, true);
			fullName = szName + extension;
            pImg = gsf_outfile_new_child(GSF_OUTFILE(pPicsDir),
                                         fullName.c_str(), FALSE);    
                                                    
            ODe_gsf_output_write(pImg, pByteBuf->getLength(),
                                pByteBuf->getPointer(0));
    
            ODe_gsf_output_close(pImg);
        }
    }

    if (pPicsDir != NULL) {
        ODe_gsf_output_close(pPicsDir);
    }

    return true;
}
/**
 * Destructor
 */
ODe_DocumentData::~ODe_DocumentData() {
    UT_GenericVector<ODe_Style_MasterPage*>* pMasterPageVector;
    UT_uint32 count, i;
    
    pMasterPageVector = m_masterStyles.enumerate();
    count = pMasterPageVector->getItemCount();
    for (i=0; i<count; i++) {
        delete (*pMasterPageVector)[i];
    }    
    DELETEP(pMasterPageVector);
    
    if (m_pOfficeTextTemp != NULL) {
        ODe_gsf_output_close(m_pOfficeTextTemp);
    }
}
Exemple #4
0
/**
 * Convert the RDF contained in pDoc->getDocumenrRDF() to RDF/XML and
 * store that in manifest.rdf updating the pDoc so that a manifest
 * entry is created in META_INF by the manifest writing code.
 */
bool ODe_RDFWriter::writeRDF( PD_Document* pDoc, GsfOutfile* pODT, PD_RDFModelHandle additionalRDF )
{
#ifndef WITH_REDLAND
    UT_UNUSED(pDoc);
    UT_UNUSED(pODT);
    UT_UNUSED(additionalRDF);
    return true;
#else
    UT_DEBUGMSG(("writeRDF() \n"));
    GsfOutput* oss = gsf_outfile_new_child(GSF_OUTFILE(pODT), "manifest.rdf", FALSE);


    //
    // Convert the native RDF model into a redland one
    //
    PD_DocumentRDFHandle rdf = pDoc->getDocumentRDF();
    std::list< PD_RDFModelHandle > ml;
    ml.push_back( rdf );
    ml.push_back( additionalRDF );
    std::string rdfxml = toRDFXML( ml );
    ODe_gsf_output_write (oss, rdfxml.size(), (const guint8*)rdfxml.data() );
    ODe_gsf_output_close(oss);
    
    //
    // add an entry that the manifest writing code will pick up
    //
    {
        UT_ByteBufPtr pByteBuf(new UT_ByteBuf);
        std::string mime_type = "application/rdf+xml";
        PD_DataItemHandle* ppHandle = NULL;

        if(!pDoc->createDataItem("manifest.rdf", 0, pByteBuf,
                                   mime_type, ppHandle))
        {
            UT_DEBUGMSG(("writeRDF() setting up manifest entry failed!\n"));
        }

        // This is to test to new dnode manifest code.
        // pDoc->createDataItem( "some/many/directories/foo.xml", 0, &pByteBuf, 
        //                       mime_type, ppHandle );
    }

    UT_DEBUGMSG(("writeRDF() complete\n"));
    return true;
#endif
}
bool ODe_SettingsWriter::writeSettings(PD_Document* /*pDoc*/, GsfOutfile* oo)
{
    GsfOutput* pSettings = gsf_outfile_new_child (oo, "settings.xml", FALSE);

    static const char * const contents [] = 
    {
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
        "<office:document-settings"
            " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
            " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
            " xmlns:config=\"urn:oasis:names:tc:opendocument:xmlns:config:1.0\""
            " xmlns:ooo=\"http://openoffice.org/2004/office\" office:version=\"1.1\">\n",
        "</office:document-settings>"
    };

    ODe_writeToStream (pSettings, contents, G_N_ELEMENTS(contents));

    ODe_gsf_output_close(pSettings);

    return true;
}
ODe_AuxiliaryData::~ODe_AuxiliaryData() {
    if (m_pTOCContents)
        ODe_gsf_output_close(m_pTOCContents);
}
/**
 * This writes out our AbiWord file as an OpenOffice
 * compound document
 */
UT_Error IE_Exp_OpenDocument::_writeDocument(void)
{
	ODe_DocumentData docData(getDoc());
	ODe_AuxiliaryData auxData;
	ODe_AbiDocListener* pAbiDocListener = NULL;
	ODe_AbiDocListenerImpl* pAbiDocListenerImpl = NULL;
    
	UT_return_val_if_fail (getFp(), UT_ERROR);

    PD_DocumentRDFHandle rdf = getDoc()->getDocumentRDF();
    auxData.m_additionalRDF = rdf->createScratchModel();
    
	const std::string & prop = getProperty ("uncompressed");
	
	if (!prop.empty() && UT_parseBool (prop.c_str (), false))
	  {
	    m_odt = GSF_OUTFILE(g_object_ref(G_OBJECT(getFp())));
	  }
	else
	  {
	    GError* error = NULL;
	    m_odt = GSF_OUTFILE (gsf_outfile_zip_new (getFp(), &error));
	    
	    if (error)
	      {
		UT_DEBUGMSG(("Error writing odt file: %s\n", error->message));
		UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
	      }
	  }

	UT_return_val_if_fail(m_odt, UT_ERROR);

	// Needed to ensure that all *printf writes numbers correctly,
	// like "45.56mm" instead of "45,56mm".
	UT_LocaleTransactor numericLocale (LC_NUMERIC, "C");
	{
		GsfOutput * mimetype = gsf_outfile_new_child_full (m_odt, "mimetype", FALSE, "compression-level", 0, (void*)0);
		if (!mimetype)
		{
			ODe_gsf_output_close(GSF_OUTPUT(m_odt));
			return UT_ERROR;
		}

		ODe_gsf_output_write(mimetype,
				39 /*39 == strlen("application/vnd.oasis.opendocument.text")*/,
				(const guint8 *)"application/vnd.oasis.opendocument.text");

		ODe_gsf_output_close(mimetype);
    }

	if (!ODe_MetaDataWriter::writeMetaData(getDoc(), m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}

    if (!ODe_SettingsWriter::writeSettings(getDoc(), m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
	return UT_ERROR;
	}

	if (!ODe_PicturesWriter::writePictures(getDoc(), m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}


	if (!ODe_ManifestWriter::writeManifest(getDoc(), m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}


    // Gather all paragraph style names used by heading paragraphs
    // (ie. all paragraph styles that are used to build up TOCs).

    pAbiDocListenerImpl = new ODe_HeadingSearcher_Listener(docData.m_styles, auxData);
    pAbiDocListener = new ODe_AbiDocListener(getDoc(),
                                             pAbiDocListenerImpl, false);

	if (!getDoc()->tellListener(static_cast<PL_Listener *>(pAbiDocListener)))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}
    pAbiDocListener->finished();
    
    DELETEP(pAbiDocListener);
    DELETEP(pAbiDocListenerImpl);

    // Now that we have all paragraph styles that build up the TOCs in the 
    // document (if any), we can build up the TOC bodies. We do this because
    // OpenOffice.org requires the TOC bodies to be present and filled
    // when initially opening the document. Without it, it will show 
    // an empty TOC until the user regenerates it, which is not that pretty.
    // Annoyingly we have to build up the TOC ourselves during export, as
    // it doesn't exist within AbiWord's PieceTable. Until that changes, this
    // is the best we can do.

    if (auxData.m_pTOCContents) {
        pAbiDocListenerImpl = new ODe_TOC_Listener(auxData);
        pAbiDocListener = new ODe_AbiDocListener(getDoc(),
                                                 pAbiDocListenerImpl, false);

	    if (!getDoc()->tellListener(static_cast<PL_Listener *>(pAbiDocListener)))
	    {
		    ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		    return UT_ERROR;
	    }
        pAbiDocListener->finished();
        
        DELETEP(pAbiDocListener);
        DELETEP(pAbiDocListenerImpl);
    }

    
    // Gather document content and styles

    if (!docData.doPreListeningWork()) {
      ODe_gsf_output_close(GSF_OUTPUT(m_odt));
      return UT_ERROR;
    }

    pAbiDocListenerImpl = new ODe_Main_Listener(docData, auxData);
    pAbiDocListener = new ODe_AbiDocListener(getDoc(),
                                             pAbiDocListenerImpl, false);

	if (!getDoc()->tellListener(static_cast<PL_Listener *>(pAbiDocListener)))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}
	pAbiDocListener->finished();
    
	DELETEP(pAbiDocListener);
	DELETEP(pAbiDocListenerImpl);
    
	if (!docData.doPostListeningWork())
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}

    // Write RDF.
    if (!ODe_RDFWriter::writeRDF(getDoc(), m_odt, auxData.m_additionalRDF ))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}
    
    // Write content and styles
        
	if (!docData.writeStylesXML(m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}
	if (!docData.writeContentXML(m_odt))
	{
		ODe_gsf_output_close(GSF_OUTPUT(m_odt));
		return UT_ERROR;
	}

	ODe_gsf_output_close(GSF_OUTPUT(m_odt));
	return UT_OK;
}
bool ODe_MetaDataWriter::writeMetaData(PD_Document* pDoc, GsfOutfile* oo) {
    
    GsfOutput* meta = gsf_outfile_new_child (oo, "meta.xml", FALSE);

    static const UT_UTF8String preamble =
        UT_UTF8String("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
        "<office:document-meta"
            " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
            " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
            " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
            " xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\""
            " xmlns:ooo=\"http://openoffice.org/2004/office\""
            " office:version=\"1.1\">\n"
        "<office:meta>\n"
        "<meta:generator>AbiWord/") + PACKAGE_VERSION + " (" + PLATFORM + ", " + TOOLKIT + ")</meta:generator>\n";

    static const char * const postamble [] = {
        "</office:meta>\n",
        "</office:document-meta>\n"
    };

    ODe_writeUTF8String(meta, preamble);

    UT_UTF8String meta_val, val;
    
#define WRITE_METADATA_ELEMENT(abiwordKey, odElementName) if (pDoc->getMetaDataProp(abiwordKey, meta_val) && meta_val.size()) { \
                                                               meta_val.escapeXML(); \
                                                               val = UT_UTF8String_sprintf("<%s>%s</%s>\n", odElementName, meta_val.utf8_str(), odElementName); \
                                                               ODe_writeUTF8String (meta, val); \
                                                          }
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_TITLE, "dc:title");
    WRITE_METADATA_ELEMENT(PD_META_KEY_DESCRIPTION, "dc:description");
    WRITE_METADATA_ELEMENT(PD_META_KEY_SUBJECT, "dc:subject");

    //Each keyword needs to be exported individually:

    UT_UTF8String keywords;
    if (pDoc->getMetaDataProp (PD_META_KEY_KEYWORDS, keywords) && keywords.size())
    {
        UT_UTF8String buf = "";
        UT_UCS4String keyword = keywords.utf8_str();

        for(UT_uint32 i = 0;i < keyword.length(); i++)
        {
            if(keyword[i] != ' ')
            {
                buf += keyword[i];
            }
            else
            {
                if(buf.empty())  //only blank space encountered
                    continue;

                buf.escapeXML();
                val = UT_UTF8String_sprintf("<meta:keyword>%s</meta:keyword>\n", buf.utf8_str());
                ODe_writeUTF8String(meta, val);
                buf.clear();
            }
        }

        if(buf.length())  //there may only be one keyword (i.e. no spaces encountered)
        {
            buf.escapeXML();
            val = UT_UTF8String_sprintf("<meta:keyword>%s</meta:keyword>\n", buf.utf8_str());
            ODe_writeUTF8String(meta, val);
        }
    }

    // Should have a PD_META_KEY_INITIAL_CREATOR macro for this one, but only
    // if it gets implemented on the document properties dialog.
    WRITE_METADATA_ELEMENT("meta:initial-creator", "meta:initial-creator");
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_CREATOR, "dc:creator");
    
    WRITE_METADATA_ELEMENT("meta:printed-by", "meta:printed-by");
    
    // ATTENTION: I'm assuming that dc.date is used by AbiWord as
    // the document creation date & time.
    WRITE_METADATA_ELEMENT(PD_META_KEY_DATE, "meta:creation-date");
    
    // Note that, for the OpenDocument standard, dc.date
    // is the last modification date & time.
    WRITE_METADATA_ELEMENT(PD_META_KEY_DATE_LAST_CHANGED, "dc:date");
    
    WRITE_METADATA_ELEMENT("meta:print-date", "meta:print-date");
    
    WRITE_METADATA_ELEMENT(PD_META_KEY_LANGUAGE, "dc:language");
    
#undef WRITE_METADATA_ELEMENT

    ODe_writeToStream(meta, postamble, G_N_ELEMENTS(postamble));

    ODe_gsf_output_close(meta);

    return true;
}
bool ODe_DocumentData::writeContentXML(GsfOutfile* pOdt) {
    GsfOutput* pContentStream;
    
    pContentStream = gsf_outfile_new_child (pOdt, "content.xml", FALSE);
    
    const char * const preamble [] = {
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
    "\n",
    "<office:document-content"
    " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
    " xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\""
    " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\""
    " xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\""
    " xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\""
    " xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\""
    " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
    " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
    " xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\""
    " xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\""
    " xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\""
    " xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\""
    " xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\""
    " xmlns:math=\"http://www.w3.org/1998/Math/MathML\""
    " xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\""
    " xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\""
    " xmlns:ooo=\"http://openoffice.org/2004/office\""
    " xmlns:ooow=\"http://openoffice.org/2004/writer\""
    " xmlns:oooc=\"http://openoffice.org/2004/calc\""
    " xmlns:dom=\"http://www.w3.org/2001/xml-events\""
    " xmlns:xforms=\"http://www.w3.org/2002/xforms\""
    " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
    " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
    " xmlns:delta=\"http://www.deltaxml.com/ns/track-changes/delta-namespace\""
    " xmlns:ac=\"http://www.deltaxml.com/ns/track-changes/attribute-change-namespace\""
    " xmlns:split=\"http://www.deltaxml.com/ns/track-changes/split-namespace\""
    " office:version=\"1.1\">\n"};
    
    ODe_writeToStream(pContentStream, preamble, G_N_ELEMENTS(preamble));
    
    m_contentXMLFontDecls.write( pContentStream );
    
    m_contentAutoStyles.write( pContentStream );

    m_contentRevisions.write( pContentStream, m_pAbiDoc );
    
    ODe_writeUTF8String(pContentStream, " <office:body>\n"
                                        "  <office:text>\n");
    // FIXME: here OR the one above?
//    m_contentRevisions.write( pContentStream, m_pAbiDoc );
       
    ODe_gsf_output_write(pContentStream, gsf_output_size (m_pOfficeTextTemp),
			 gsf_output_memory_get_bytes (GSF_OUTPUT_MEMORY (m_pOfficeTextTemp)));
    
    ODe_gsf_output_close (m_pOfficeTextTemp);
    m_pOfficeTextTemp = NULL;
    
    ODe_writeUTF8String(pContentStream,
        "  </office:text>\n"
        " </office:body>\n"
        "</office:document-content>");
        
    ODe_gsf_output_close(pContentStream);
    
    return true;
}
bool ODe_DocumentData::writeStylesXML(GsfOutfile* pOdt) const {
    GsfOutput* pStylesStream;
    UT_GenericVector<ODe_Style_MasterPage*>* pMasterPageVector;    
    bool ok;
    UT_uint32 count, i;
    
    pStylesStream = gsf_outfile_new_child (pOdt, "styles.xml", FALSE);
    
    const char * const preamble [] = {
    "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
    "\n",
    "<office:document-styles"
    " xmlns:office=\"urn:oasis:names:tc:opendocument:xmlns:office:1.0\""
    " xmlns:style=\"urn:oasis:names:tc:opendocument:xmlns:style:1.0\""
    " xmlns:text=\"urn:oasis:names:tc:opendocument:xmlns:text:1.0\""
    " xmlns:table=\"urn:oasis:names:tc:opendocument:xmlns:table:1.0\""
    " xmlns:draw=\"urn:oasis:names:tc:opendocument:xmlns:drawing:1.0\""
    " xmlns:fo=\"urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0\""
    " xmlns:xlink=\"http://www.w3.org/1999/xlink\""
    " xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
    " xmlns:meta=\"urn:oasis:names:tc:opendocument:xmlns:meta:1.0\""
    " xmlns:number=\"urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0\""
    " xmlns:svg=\"urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0\""
    " xmlns:chart=\"urn:oasis:names:tc:opendocument:xmlns:chart:1.0\""
    " xmlns:dr3d=\"urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0\""
    " xmlns:math=\"http://www.w3.org/1998/Math/MathML\""
    " xmlns:form=\"urn:oasis:names:tc:opendocument:xmlns:form:1.0\""
    " xmlns:script=\"urn:oasis:names:tc:opendocument:xmlns:script:1.0\""
    " xmlns:ooo=\"http://openoffice.org/2004/office\""
    " xmlns:ooow=\"http://openoffice.org/2004/writer\""
    " xmlns:oooc=\"http://openoffice.org/2004/calc\""
    " xmlns:dom=\"http://www.w3.org/2001/xml-events\""
    " office:version=\"1.1\">\n"};
    
    ODe_writeToStream(pStylesStream, preamble, G_N_ELEMENTS(preamble));
    
    m_stylesXMLFontDecls.write(pStylesStream);
    
    m_styles.write(pStylesStream);
    m_stylesAutoStyles.write(pStylesStream);
    
    ODe_writeUTF8String(pStylesStream, " <office:master-styles>\n");
    
    pMasterPageVector = m_masterStyles.enumerate();
    count = pMasterPageVector->getItemCount();
    for (i=0; i<count; i++) {
        ok = (*pMasterPageVector)[i]->write(pStylesStream);
        
        if (!ok) {
            return false;
        }
    }    
    
    ODe_writeUTF8String(pStylesStream, " </office:master-styles>\n");
    
    ODe_writeUTF8String(pStylesStream, "</office:document-styles>");
    
    ODe_gsf_output_close(pStylesStream);
    
    return true;
}
bool ODe_ManifestWriter::writeManifest(PD_Document* pDoc, GsfOutfile* pODT)
{
    // Create META-INF directory
    GsfOutput* meta_inf = gsf_outfile_new_child(pODT, "META-INF", TRUE);
    
    GsfOutput* manifest = gsf_outfile_new_child(
                            GSF_OUTFILE(meta_inf), "manifest.xml", FALSE);

    std::string name;

    static const char * const preamble [] = {
        "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n",
        "<!DOCTYPE manifest:manifest PUBLIC \"-//OpenOffice.org//DTD Manifest 1.0//EN\" \"Manifest.dtd\">\n",
        "<manifest:manifest xmlns:manifest=\"urn:oasis:names:tc:opendocument:xmlns:manifest:1.0\">\n",
        " <manifest:file-entry manifest:media-type=\"application/vnd.oasis.opendocument.text\" manifest:full-path=\"/\"/>\n",
        " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"content.xml\"/>\n",
        " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"styles.xml\"/>\n",
        " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"meta.xml\"/>\n",
        " <manifest:file-entry manifest:media-type=\"text/xml\" manifest:full-path=\"settings.xml\"/>\n"
    };

    static const char * const postamble [] = {
        "</manifest:manifest>\n"
    };

    typedef std::set< std::string > absolutePathMimeTypes_t;
    static absolutePathMimeTypes_t absolutePathMimeTypes;
    if( absolutePathMimeTypes.empty() )
    {
        absolutePathMimeTypes.insert("application/rdf+xml");
    }
    
    ODe_writeToStream (manifest, preamble, G_N_ELEMENTS(preamble));

    const char* szName;
    std::string mimeType;
    const UT_ByteBuf* pByteBuf;
    std::set< std::string > pathsAlreadyWritten;
    
    for (UT_uint32 k = 0;
         (pDoc->enumDataItems(k,
                              NULL,
                              &szName,
                              &pByteBuf,
                              &mimeType)); k++) {
                                
        if (!mimeType.empty()) {

            ensureDirectoryManifest( pDoc, manifest, szName, pathsAlreadyWritten );

            std::string automaticPathPrefix = "Pictures/";
            if( absolutePathMimeTypes.count(mimeType) )
                automaticPathPrefix = "";
            
            name = UT_std_string_sprintf(
                " <manifest:file-entry manifest:media-type=\"%s\" manifest:full-path=\"%s%s\"/>\n",
                mimeType.c_str(), automaticPathPrefix.c_str(), szName);
            
            ODe_gsf_output_write (manifest, name.size(),
                reinterpret_cast<const guint8 *>(name.c_str()));
        }
    }

    ODe_writeToStream (manifest, postamble, G_N_ELEMENTS(postamble));

    ODe_gsf_output_close(manifest);
    ODe_gsf_output_close(meta_inf);

    return true;
}