/* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */ /* AbiWord * Copyright (C) 1998 AbiSource, Inc. * * 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 2 * 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, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA * 02111-1307, USA. */ #include #include #include "ut_locale.h" #include "ut_string.h" #include "ut_types.h" #include "ut_bytebuf.h" #include "ut_base64.h" #include "ut_debugmsg.h" #include "ut_string_class.h" #include "ut_uuid.h" #ifdef ENABLE_RESOURCE_MANAGER #include "xap_ResourceManager.h" #endif #include "xap_App.h" #include "pt_Types.h" #include "pd_Document.h" #include "pd_Style.h" #include "pp_AttrProp.h" #include "pp_Author.h" #include "px_ChangeRecord.h" #include "px_CR_Object.h" #include "px_CR_Span.h" #include "px_CR_Strux.h" #include "fd_Field.h" #include "fl_AutoNum.h" #include "fp_PageSize.h" #include "ie_impexp_AbiWord_1.h" #include "ie_exp_AbiWord_1.h" #include "ap_Prefs.h" #include // the fileformat that used to be defined here is now defined at the // top of pd_Document.cpp /*****************************************************************/ /*****************************************************************/ IE_Exp_AbiWord_1_Sniffer::IE_Exp_AbiWord_1_Sniffer () : IE_ExpSniffer(IE_IMPEXPNAME_AWML11) { // } UT_Confidence_t IE_Exp_AbiWord_1_Sniffer::supportsMIME (const char * szMIME) { if (strcmp (szMIME, IE_MIMETYPE_AbiWord) == 0) { return UT_CONFIDENCE_GOOD; } return UT_CONFIDENCE_ZILCH; } bool IE_Exp_AbiWord_1_Sniffer::recognizeSuffix(const char * szSuffix) { return (!g_ascii_strcasecmp(szSuffix,".abw") || !g_ascii_strcasecmp(szSuffix,".zabw") || !g_ascii_strcasecmp(szSuffix, ".abw.gz")); } UT_Error IE_Exp_AbiWord_1_Sniffer::constructExporter(PD_Document * pDocument, IE_Exp ** ppie) { *ppie = new IE_Exp_AbiWord_1(pDocument); return UT_OK; } bool IE_Exp_AbiWord_1_Sniffer::getDlgLabels(const char ** pszDesc, const char ** pszSuffixList, IEFileType * ft) { *pszDesc = "AbiWord (.abw, .zabw, abw.gz)"; *pszSuffixList = "*.abw; *.zabw; *.abw.gz"; *ft = getFileType(); return true; } /*****************************************************************/ /*****************************************************************/ IE_Exp_AbiWord_1::IE_Exp_AbiWord_1(PD_Document * pDocument, bool isTemplate, bool isCompressed) : IE_Exp(pDocument), m_bIsTemplate(isTemplate), m_bIsCompressed(isCompressed), m_pListener(0), m_output(0) { m_error = 0; UT_ASSERT_HARMLESS( pDocument ); // depending on how this document came to be, it might contain fragments without xid; // this is legitimate and desirable while the doc is loade, but once we are saving to // disk, we want to assing xids to any frags that should have them and do not if(pDocument) pDocument->fixMissingXIDs(); } IE_Exp_AbiWord_1::~IE_Exp_AbiWord_1() { } UT_uint32 IE_Exp_AbiWord_1::_writeBytes(const UT_Byte * pBytes, UT_uint32 length) { if(!pBytes || !length) return 0; if (m_output) { gsf_output_write(m_output, length, pBytes); return length; } else { return IE_Exp::_writeBytes(pBytes, length); } } void IE_Exp_AbiWord_1::_setupFile() { // allow people to override this on the command line or otherwise const std::string & prop = (getProperty ("compress")); if (!prop.empty()) m_bIsCompressed = UT_parseBool(prop.c_str (), m_bIsCompressed); if (m_bIsCompressed) { GsfOutput * gzip = gsf_output_gzip_new(getFp (), NULL); m_output = gzip; } else { m_output = 0; } } static void close_gsf_handle(GsfOutput * output) { if (output) { gsf_output_close (output); g_object_unref (G_OBJECT (output)); } } /*****************************************************************/ /*****************************************************************/ #ifdef ENABLE_RESOURCE_MANAGER class ABI_EXPORT s_AbiWord_1_Listener : public PL_Listener, XAP_ResourceManager::Writer #else class ABI_EXPORT s_AbiWord_1_Listener : public PL_Listener #endif { public: s_AbiWord_1_Listener(PD_Document * pDocument, IE_Exp_AbiWord_1 * pie, bool isTemplate); virtual ~s_AbiWord_1_Listener(); virtual bool populate(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool populateStrux(PL_StruxDocHandle sdh, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh); virtual bool change(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr); virtual bool insertStrux(PL_StruxFmtHandle sfh, const PX_ChangeRecord * pcr, PL_StruxDocHandle sdh, PL_ListenerId lid, void (* pfnBindHandles)(PL_StruxDocHandle sdhNew, PL_ListenerId lid, PL_StruxFmtHandle sfhNew)); virtual bool signal(UT_uint32 iSignal); /* implementation of XAP_[Internal]Resource[Manager]::Writer */ UT_Error write_base64 (void * context, const char * base64, UT_uint32 length, bool final); UT_Error write_xml (void * context, const char * name, const char * const * atts); UT_Error write_xml (void * context, const char * name); protected: void _closeTable(void); void _closeCell(void); void _closeSection(void); void _closeBlock(void); void _closeSpan(void); void _closeField(void); void _closeHyperlink(void); void _closeAnnotation(void); void _closeTag(void); void _openSpan(PT_AttrPropIndex apiSpan); void _openTag(const char * szPrefix, const char * szSuffix, bool bNewLineAfter, PT_AttrPropIndex api, UT_uint32 iXID, bool bIgnoreProperties = false); void _outputData(const UT_UCSChar * p, UT_uint32 length); void _outputXMLChar(const gchar * data, UT_uint32 length); void _handleStyles(void); void _handleLists(void); void _handlePageSize(void); void _handleDataItems(void); void _handleMetaData(void); void _handleRevisions(void); void _handleHistory(void); void _handleAuthors(void); PD_Document * m_pDocument; IE_Exp_AbiWord_1 * m_pie; bool m_bIsTemplate; bool m_bInSection; bool m_bInBlock; bool m_bInSpan; // bool m_bInTag; bool m_bInHyperlink; UT_sint32 m_iInTable; UT_sint32 m_iInCell; PT_AttrPropIndex m_apiLastSpan; fd_Field * m_pCurrentField; bool m_bOpenChar; UT_GenericVector m_vecSnapNames; bool m_bInAnnotation; private: // despite being a std::string, it will store an UTF-8 buffer typedef std::set string_set; string_set m_pUsedImages; const gchar* getObjectKey(const PT_AttrPropIndex& api, const gchar* key); }; void s_AbiWord_1_Listener::_closeSection(void) { if (!m_bInSection) return; m_pie->write("\n"); m_bInSection = false; return; } void s_AbiWord_1_Listener::_closeTable(void) { if (m_iInTable == 0) return; m_pie->write("\n"); m_iInTable--; return; } void s_AbiWord_1_Listener::_closeCell(void) { if (m_iInCell == 0) return; m_pie->write("\n"); m_iInCell--; return; } void s_AbiWord_1_Listener::_closeBlock(void) { if (!m_bInBlock) return; m_pie->write("

\n"); m_bInBlock = false; return; } void s_AbiWord_1_Listener::_closeSpan(void) { if (!m_bInSpan) return; _closeTag(); m_bInSpan = false; return; } void s_AbiWord_1_Listener::_closeTag(void) { if (m_bOpenChar) m_pie->write(""); m_bOpenChar = false; } void s_AbiWord_1_Listener::_closeField(void) { if (!m_pCurrentField) return; _closeSpan(); m_pie->write(""); m_pCurrentField = NULL; return; } void s_AbiWord_1_Listener::_closeHyperlink(void) { if (!m_bInHyperlink) return; _closeSpan(); m_pie->write(""); m_bInHyperlink = false; return; } void s_AbiWord_1_Listener::_closeAnnotation(void) { if (!m_bInAnnotation) return; UT_DEBUGMSG(("Doing close annotation object method \n")); _closeSpan(); m_pie->write(""); m_bInAnnotation = false; return; } void s_AbiWord_1_Listener::_openSpan(PT_AttrPropIndex apiSpan) { if (m_bInSpan) { if (m_apiLastSpan == apiSpan) return; _closeSpan(); } if (!apiSpan) // don't write tag for empty A/P return; _openTag("c","",false,apiSpan,0); m_bInSpan = true; m_apiLastSpan = apiSpan; return; } void s_AbiWord_1_Listener::_openTag(const char * szPrefix, const char * szSuffix, bool bNewLineAfter, PT_AttrPropIndex api, UT_uint32 iXID, bool bIgnoreProperties) { #ifdef ENABLE_RESOURCE_MANAGER UT_ASSERT_HARMLESS (!m_bOpenChar); UT_UTF8String tag("<"); UT_UTF8String url; UT_UTF8String esc; tag += szPrefix; const PP_AttrProp * pAP = NULL; bool bHaveProp = m_pDocument->getAttrProp (api, &pAP); if (bHaveProp && pAP) { const gchar * szName = 0; const gchar * szValue = 0; UT_uint32 k = 0; while (pAP->getNthAttribute (k++, szName, szValue)) { #if 0 // // Strip out Author attributes for now. // if( !m_pDocument->isExportAuthorAtts() && strcmp(szName,PT_AUTHOR_NAME) == 0) continue; #endif tag += " "; tag += szName; tag += "=\""; if ((strcmp (szName, "href") == 0) || (strcmp (szName, "xlink:href") == 0)) { if(*szValue == '/') { XAP_ResourceManager & RM = m_pDocument->resourceManager (); XAP_ExternalResource * re = dynamic_cast(RM.resource (szValue, false)); if (re) { url = re->URL (); url.escapeURL(); tag += url; } } else { url = szValue; url.escapeURL(); tag += url; } } else { esc = szValue; esc.escapeXML(); tag += esc; } tag += "\""; } if(iXID != 0) { // insert xid attribute tag += " "; tag += PT_XID_ATTRIBUTE_NAME; tag += "=\""; UT_UTF8String s; UT_UTF8String_sprintf(s, "%d\"", iXID); tag += s; } if (!bIgnoreProperties) { k = 0; while (pAP->getNthProperty (k++, szName, szValue)) { if (k == 1) { tag += " "; tag += PT_PROPS_ATTRIBUTE_NAME; tag += "=\""; } else tag += "; "; tag += szName; tag += ":"; esc = szValue; esc.escapeXML(); tag += esc; } if (k > 1) tag += "\""; } } if (szSuffix) if (*szSuffix == '/') tag += "/"; tag += ">"; if (bNewLineAfter) tag += "\n"; m_pie->write (tag.utf8_str (), tag.byteLength()); if (strcmp (szPrefix, "c") == 0) m_bOpenChar = true; #else /* ENABLE_RESOURCE_MANAGER */ const PP_AttrProp * pAP = NULL; bool bHaveProp = m_pDocument->getAttrProp(api,&pAP); xxx_UT_DEBUGMSG(("_openTag: api %d, bHaveProp %d\n",api, bHaveProp)); UT_return_if_fail(szPrefix && *szPrefix); m_pie->write("<"); if(strcmp(szPrefix,"c")== 0) m_bOpenChar = true; m_pie->write(szPrefix); if (bHaveProp && pAP) { UT_UTF8String url; const gchar * szName; const gchar * szValue; UT_uint32 k = 0; while (pAP->getNthAttribute(k++,szName,szValue)) { // TODO we force double-quotes on all values. // TODO consider scanning the value to see if it has one // TODO in it and escaping it or using single-quotes. // Let's also escape ampersands and other goodies. // // Strip out Author attributes for now. // if( !m_pDocument->isExportAuthorAtts() && strcmp(szName,PT_AUTHOR_NAME) == 0) continue; m_pie->write(" "); m_pie->write(static_cast(szName)); m_pie->write("=\""); if ((strcmp (szName, "href") == 0) || (strcmp (szName, "xlink:href") == 0)) { url = szValue; url.escapeURL(); _outputXMLChar(url.utf8_str(), url.byteLength()); } else { _outputXMLChar(szValue, strlen(szValue)); } m_pie->write("\""); } if(iXID != 0) { // insert xid attribute m_pie->write(" "); m_pie->write(PT_XID_ATTRIBUTE_NAME); m_pie->write("=\""); UT_String s; UT_String_sprintf(s, "%d\"", iXID); m_pie->write(s.c_str()); } if (!bIgnoreProperties && pAP->getNthProperty(0,szName,szValue)) { m_pie->write(" "); m_pie->write(static_cast(PT_PROPS_ATTRIBUTE_NAME)); m_pie->write("=\""); m_pie->write(static_cast(szName)); m_pie->write(":"); _outputXMLChar(szValue, strlen(szValue)); UT_uint32 j = 1; while (pAP->getNthProperty(j++,szName,szValue)) { // TMN: Patched this since I got an assert. What's the fix? // is it to write out a quoted empty string, or not to write // the property at all? For now I fixed it by the latter. if (*szValue) { m_pie->write("; "); m_pie->write(static_cast(szName)); m_pie->write(":"); _outputXMLChar(szValue, strlen(szValue)); } } m_pie->write("\""); } } if(strcmp(szPrefix,"math") == 0) { UT_UTF8String tag; const char * szPropVal = NULL; pAP->getAttribute("dataid",szPropVal); if(szPropVal != NULL) { tag = ">"; if (bNewLineAfter) tag += "\n"; m_pie->write (tag.utf8_str (), tag.byteLength()); tag.clear(); tag = "getProperty("height", szPropVal); UT_UTF8String sVal; if(bFound) { double dInch = static_cast(atoi(szPropVal))/UT_LAYOUT_RESOLUTION; UT_UTF8String_sprintf(sVal,"%fin",dInch); tag += "height:"; tag += sVal; tag += "; "; } bFound = pAP->getProperty("width", szPropVal); if(bFound) { double dInch = static_cast(atoi(szPropVal))/UT_LAYOUT_RESOLUTION; UT_UTF8String_sprintf(sVal,"%fin",dInch); tag += "width:"; tag += sVal; } tag += "\""; tag += "/"; tag += ">"; tag += "write (tag.utf8_str (), tag.byteLength()); } else if(strcmp(szPrefix,"embed") == 0) { UT_UTF8String tag; const char * szPropVal = NULL; pAP->getAttribute("dataid",szPropVal); if(szPropVal != NULL) { tag = ">"; if (bNewLineAfter) tag += "\n"; m_pie->write (tag.utf8_str (), tag.byteLength()); tag.clear(); tag = "getProperty("height", szPropVal); UT_UTF8String sVal; if(bFound) { double dInch = static_cast(atoi(szPropVal))/UT_LAYOUT_RESOLUTION; UT_UTF8String_sprintf(sVal,"%fin",dInch); tag += "height:"; tag += sVal; tag += "; "; } bFound = pAP->getProperty("width", szPropVal); if(bFound) { double dInch = static_cast(atoi(szPropVal))/UT_LAYOUT_RESOLUTION; UT_UTF8String_sprintf(sVal,"%fin",dInch); tag += "width:"; tag += sVal; } tag += "\""; tag += "/"; tag += ">"; tag += "write (tag.utf8_str (), tag.byteLength()); } else { if (szSuffix) if (*szSuffix == '/') m_pie->write ("/"); m_pie->write (">"); if (bNewLineAfter) m_pie->write ("\n"); } // m_bInTag = true; #endif /* ENABLE_RESOURCE_MANAGER */ } // This method is very much like _outputData but uses gchars instead of UT_UCS4_Char's. void s_AbiWord_1_Listener::_outputXMLChar(const gchar * data, UT_uint32 length) { UT_UTF8String sBuf (data, length); sBuf.escapeXML(); m_pie->write(sBuf.utf8_str(),sBuf.byteLength()); } void s_AbiWord_1_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length) { UT_UTF8String sBuf; const UT_UCSChar * pData; UT_return_if_fail(sizeof(UT_Byte) == sizeof(char)); sBuf.reserve(length); for (pData=data; (pData': sBuf += ">"; pData++; break; case '&': sBuf += "&"; pData++; break; case UCS_LF: // LF -- representing a Forced-Line-Break sBuf += "
"; pData++; break; case UCS_VTAB: // VTAB -- representing a Forced-Column-Break sBuf += ""; pData++; break; case UCS_TAB: sBuf += "\t"; pData++; break; case UCS_FF: // FF -- representing a Forced-Page-Break sBuf += ""; pData++; break; default: if (*pData < 0x20) // Silently eat these characters. pData++; else { sBuf.appendUCS4 (pData, 1); pData++; } } } m_pie->write(sBuf.utf8_str(),sBuf.byteLength()); } s_AbiWord_1_Listener::s_AbiWord_1_Listener(PD_Document * pDocument, IE_Exp_AbiWord_1 * pie, bool isTemplate) : m_pUsedImages() { m_bIsTemplate = isTemplate; m_pDocument = pDocument; m_pie = pie; m_bInSection = false; m_bInBlock = false; m_bInSpan = false; // m_bInTag = false; m_bInHyperlink = false; m_bOpenChar = false; m_apiLastSpan = 0; m_pCurrentField = 0; m_iInTable = 0; m_iInCell = 0; m_bInAnnotation = false; m_pie->write("\n"); m_pie->write ("\n"); /*********************************************************************************** The fixed attributes of the token that used to reside here are now found in PD_Document::setAttrProp() ************************************************************************************/ // we want to update the XID counter and the template status UT_String s; UT_String_sprintf(s, "%d", pDocument->getTopXID()); const gchar *attr[5]; attr[0] = "template"; attr[1] = m_bIsTemplate ? "true" : "false"; attr[2] = "xid-max"; attr[3] = s.c_str(); attr[4] = NULL; pDocument->setAttributes(attr); _openTag("abiword", NULL, true, pDocument->getAttrPropIndex(),false,0); // NOTE we output the following preamble in XML comments. // NOTE this information is for human viewing only. m_pie->write("\n"); m_pie->write("\n"); m_pie->write("\n"); m_pie->write("\n"); m_pie->write("\n"); m_pie->write("\n\n"); // end of preamble. // now we begin the actual document. _handleMetaData(); _handleHistory(); _handleRevisions(); _handleStyles(); _handleLists(); _handlePageSize(); if(m_pDocument->isExportAuthorAtts()) _handleAuthors(); } s_AbiWord_1_Listener::~s_AbiWord_1_Listener() { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _closeSection(); _handleDataItems(); m_pie->write("\n"); UT_VECTOR_PURGEALL(UT_UTF8String * ,m_vecSnapNames); } const gchar* s_AbiWord_1_Listener::getObjectKey(const PT_AttrPropIndex& api, const gchar* key) { const PP_AttrProp * pAP = NULL; bool bHaveProp = m_pDocument->getAttrProp(api,&pAP); if (bHaveProp && pAP) { const gchar* value; if (pAP->getAttribute(key, value)) return value; } return 0; } bool s_AbiWord_1_Listener::populate(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * pcr) { switch (pcr->getType()) { case PX_ChangeRecord::PXT_InsertSpan: { const PX_ChangeRecord_Span * pcrs = static_cast (pcr); if (pcrs->getField()!=m_pCurrentField) { _closeField(); } PT_AttrPropIndex api = pcr->getIndexAP(); _openSpan(api); PT_BufIndex bi = pcrs->getBufIndex(); _outputData(m_pDocument->getPointer(bi),pcrs->getLength()); return true; } case PX_ChangeRecord::PXT_InsertObject: { const PX_ChangeRecord_Object * pcro = static_cast (pcr); PT_AttrPropIndex api = pcr->getIndexAP(); switch (pcro->getObjectType()) { case PTO_Image: { _closeSpan(); _closeField(); #ifndef ENABLE_RESOURCE_MANAGER const gchar* image_name = getObjectKey(api, static_cast("dataid")); if (image_name) m_pUsedImages.insert(image_name); #endif _openTag("image","/",false,api,pcr->getXID()); return true; } case PTO_Field: { _closeSpan(); _closeField(); _openTag("field","",false,api,pcr->getXID()); m_pCurrentField = pcro->getField(); UT_ASSERT_HARMLESS(m_pCurrentField); return true; } case PTO_Math: { _closeSpan(); _closeField(); _openTag("math","/",false,api,pcr->getXID()); const gchar* image_name = getObjectKey(api, static_cast("dataid")); if (image_name) { UT_DEBUGMSG(("resource name #%s# recorded \n",image_name)); m_pUsedImages.insert(image_name); UT_UTF8String * sPNGname = new UT_UTF8String("snapshot-png-"); m_vecSnapNames.addItem(sPNGname); *sPNGname += image_name; UT_DEBUGMSG(("resource name #%s# recorded \n",sPNGname->utf8_str())); m_pUsedImages.insert(sPNGname->utf8_str()); } const gchar* latex_name = getObjectKey(api, static_cast("latexid")); if(latex_name) { UT_DEBUGMSG(("resource name #%s# recorded \n",latex_name)); m_pUsedImages.insert(latex_name); } return true; } case PTO_Embed: { _closeSpan(); _closeField(); _openTag("embed","/",false,api,pcr->getXID()); const gchar* image_name = getObjectKey(api, static_cast("dataid")); if (image_name) { UT_DEBUGMSG(("resource name #%s# recorded \n",image_name)); m_pUsedImages.insert(image_name); UT_UTF8String * sPNGname = new UT_UTF8String("snapshot-png-"); m_vecSnapNames.addItem(sPNGname); *sPNGname += image_name; UT_DEBUGMSG(("resource name #%s# recorded \n",sPNGname->utf8_str())); m_pUsedImages.insert(sPNGname->utf8_str()); } return true; } case PTO_Bookmark: { _closeSpan(); _closeField(); _openTag("bookmark", "/",false, api,pcr->getXID(),true); return true; } case PTO_Hyperlink: { _closeSpan(); _closeField(); const PP_AttrProp * pAP = NULL; m_pDocument->getAttrProp(api,&pAP); const gchar * pName; const gchar * pValue; bool bFound = false; UT_uint32 k = 0; while(pAP->getNthAttribute(k++, pName, pValue)) { bFound = (0 == g_ascii_strncasecmp(pName,"xlink:href",10)); if(bFound) break; } if(bFound) { //this is the start of the hyperlink _openTag("a", "",false, api,pcr->getXID(),true); m_bInHyperlink = true; } else { _closeHyperlink(); } return true; } case PTO_Annotation: { _closeSpan(); _closeField(); const PP_AttrProp * pAP = NULL; m_pDocument->getAttrProp(api,&pAP); const gchar * pName; const gchar * pValue; bool bFound = false; UT_uint32 k = 0; while(!bFound && pAP->getNthAttribute(k++, pName, pValue)) { bFound = (0 == g_ascii_strncasecmp(pName,"Annotation",10)); } if(bFound) { //this is the start of the Annotation _openTag("ann", "",false, api,pcr->getXID(),true); UT_DEBUGMSG(("Doing open annotation object \n")); m_bInAnnotation = true; } else { UT_DEBUGMSG(("Doing close annotation object \n")); _closeAnnotation(); } return true; } default: UT_ASSERT_NOT_REACHED(); return false; } } case PX_ChangeRecord::PXT_InsertFmtMark: #if 1 // This code was commented by tf for reasons we can't remember // Reinstate it to fix bug - 11629 blank lines lose their // properties on export. if(m_bOpenChar) _closeTag(); _openTag("c","",false,pcr->getIndexAP(),0); _closeTag(); #endif return true; default: UT_ASSERT_NOT_REACHED(); return false; } } bool s_AbiWord_1_Listener::populateStrux(PL_StruxDocHandle /*sdh*/, const PX_ChangeRecord * pcr, PL_StruxFmtHandle * psfh) { UT_return_val_if_fail(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux, false); const PX_ChangeRecord_Strux * pcrx = static_cast (pcr); *psfh = 0; // we don't need it. #ifndef ENABLE_RESOURCE_MANAGER PT_AttrPropIndex api = pcr->getIndexAP(); const gchar* image_name = getObjectKey(api, static_cast(PT_STRUX_IMAGE_DATAID)); if (image_name) m_pUsedImages.insert(image_name); #endif switch (pcrx->getStruxType()) { case PTX_Section: case PTX_SectionHdrFtr: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _closeSection(); _openTag("section","",true,pcr->getIndexAP(),pcr->getXID()); m_bInSection = true; return true; } case PTX_SectionTable: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _openTag("table","",true,pcr->getIndexAP(),pcr->getXID()); m_iInTable++; return true; } case PTX_SectionCell: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _openTag("cell","",true,pcr->getIndexAP(),pcr->getXID()); m_iInCell++; return true; } case PTX_SectionFootnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); m_bInBlock = false; _openTag("foot","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_SectionAnnotation: { // spans and field have been closed by the annotation // _closeSpan(); // _closeField(); // We may have to close hyperlinks but I hope not. // _closeHyperlink(); UT_DEBUGMSG(("Found start annotation strux \n")); m_bInBlock = false; _openTag("annotate","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_SectionEndnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); m_bInBlock = false; _openTag("endnote","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_SectionTOC: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); m_bInBlock = false; _openTag("toc","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_SectionMarginnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _openTag("margin","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_SectionFrame: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _openTag("frame","",true,pcr->getIndexAP(),pcr->getXID()); return true; } case PTX_EndTable: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _closeTable(); return true; } case PTX_EndCell: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); _closeCell(); return true; } case PTX_EndFootnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); m_pie->write(""); m_bInBlock = true; return true; } case PTX_EndAnnotation: { UT_DEBUGMSG(("End of annotation strux \n")); _closeSpan(); _closeField(); // Lets not close out hyperlinks to start with // _closeHyperlink(); _closeBlock(); m_pie->write(""); m_bInBlock = true; return true; } case PTX_EndEndnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); m_pie->write(""); m_bInBlock = true; return true; } case PTX_EndTOC: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); m_pie->write(""); return true; } case PTX_EndMarginnote: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); return true; } case PTX_EndFrame: { _closeSpan(); _closeField(); _closeHyperlink(); _closeAnnotation(); _closeBlock(); m_pie->write(""); return true; } case PTX_Block: { _closeSpan(); _closeField(); _closeHyperlink(); _closeBlock(); _openTag("p","",false,pcr->getIndexAP(),pcr->getXID()); m_bInBlock = true; return true; } default: UT_ASSERT_NOT_REACHED(); return false; } } bool s_AbiWord_1_Listener::change(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/) { UT_ASSERT_NOT_REACHED(); return false; } bool s_AbiWord_1_Listener::insertStrux(PL_StruxFmtHandle /*sfh*/, const PX_ChangeRecord * /*pcr*/, PL_StruxDocHandle /*sdh*/, PL_ListenerId /* lid */, void (* /*pfnBindHandles*/)(PL_StruxDocHandle /* sdhNew */, PL_ListenerId /* lid */, PL_StruxFmtHandle /* sfhNew */)) { UT_ASSERT_NOT_REACHED(); // this function is not used. return false; } bool s_AbiWord_1_Listener::signal(UT_uint32 /* iSignal */) { UT_ASSERT_NOT_REACHED(); return false; } /* base64-encoded object data */ UT_Error s_AbiWord_1_Listener::write_base64 (void * /*context*/, const char * base64, UT_uint32 length, bool /*final*/) { m_pie->write (base64, length); m_pie->write ("\n"); return UT_OK; } /* start tag & attributes */ UT_Error s_AbiWord_1_Listener::write_xml (void * /*context*/, const char * name, const char * const * atts) { UT_UTF8String tag(" <"); tag += name; const char * const * attr = atts; while (*attr) { tag += " "; tag += *attr++; tag += "=\""; tag += *attr++; tag += "\""; } tag += ">\n"; m_pie->write (tag.utf8_str (), tag.byteLength()); return UT_OK; } /* end tag */ UT_Error s_AbiWord_1_Listener::write_xml (void * /*context*/, const char * name) { UT_UTF8String tag(" \n"; m_pie->write (tag.utf8_str (), tag.byteLength()); return UT_OK; } /*****************************************************************/ /*****************************************************************/ UT_Error IE_Exp_AbiWord_1::_writeDocument(void) { _setupFile(); m_pListener = new s_AbiWord_1_Listener(getDoc(),this, m_bIsTemplate); if (!m_pListener) { close_gsf_handle(m_output); return UT_IE_NOMEMORY; } if (getDocRange()) { if(!getDoc()->tellListenerSubset(static_cast(m_pListener),getDocRange())) { close_gsf_handle(m_output); return UT_ERROR; } } else { if (!getDoc()->tellListener(static_cast(m_pListener))) { close_gsf_handle(m_output); return UT_ERROR; } } delete m_pListener; m_pListener = NULL; close_gsf_handle(m_output); return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK); } /*****************************************************************/ /*****************************************************************/ void s_AbiWord_1_Listener::_handleStyles(void) { bool bWroteOpenStyleSection = false; const PD_Style * pStyle=NULL; UT_GenericVector vecStyles; m_pDocument->getAllUsedStyles(&vecStyles); UT_sint32 k = 0; for (k=0; k < vecStyles.getItemCount(); k++) { pStyle = vecStyles.getNthItem(k); if (!bWroteOpenStyleSection) { m_pie->write("\n"); bWroteOpenStyleSection = true; } PT_AttrPropIndex api = pStyle->getIndexAP(); _openTag("s","/",true,api,0); } UT_GenericVector * pStyles = NULL; m_pDocument->enumStyles(pStyles); UT_ASSERT_HARMLESS( pStyles ); UT_sint32 iStyleCount = m_pDocument->getStyleCount(); for (k=0; (k < iStyleCount) && pStyles; k++) { pStyle = pStyles->getNthItem(k); UT_continue_if_fail( pStyle ); if (!pStyle->isUserDefined() || (vecStyles.findItem(const_cast(pStyle))) >= 0) continue; if (!bWroteOpenStyleSection) { m_pie->write("\n"); bWroteOpenStyleSection = true; } PT_AttrPropIndex api = pStyle->getIndexAP(); _openTag("s","/",true,api,0); } delete pStyles; if (bWroteOpenStyleSection) m_pie->write("\n"); return; } void s_AbiWord_1_Listener::_handleLists(void) { bool bWroteOpenListSection = false; //const char * szID; //const char * szPid; //const char * szProps; #define LCheck(str) (0 == strcmp(s.utf8_str(), str)) UT_UTF8String esc; fl_AutoNum * pAutoNum; for (UT_uint32 k = 0; (m_pDocument->enumLists(k, &pAutoNum )); k++) { const char ** attr0 = NULL; if (pAutoNum->isEmpty() == true) continue; std::vector vAttrs; pAutoNum->getAttributes (vAttrs, true); if (!bWroteOpenListSection) { m_pie->write("\n"); bWroteOpenListSection = true; } m_pie->write("write(" "); m_pie->write(s.utf8_str()); m_pie->write("=\""); m_pie->write(vAttrs[i+1].utf8_str()); m_pie->write("\""); } } m_pie->write("/>\n"); // No, no, you can't g_free attr and expect good things to happen. FREEP(attr0); } #undef LCheck if (bWroteOpenListSection) m_pie->write("\n"); return; } void s_AbiWord_1_Listener::_handleMetaData(void) { if (m_pie->isCopying ()) return; // set all of the important meta-data props m_pDocument->setMetaDataProp ( PD_META_KEY_GENERATOR, UT_UTF8String("AbiWord") ) ; m_pDocument->setMetaDataProp ( PD_META_KEY_FORMAT, UT_UTF8String(IE_MIMETYPE_AbiWord) ) ; #if 0 // get the saved time, remove trailing newline time_t now = time ( NULL ) ; UT_String now_str ( ctime(&now) ) ; now_str = now_str.substr ( 0, now_str.size() -1 ) ; m_pDocument->setMetaDataProp ( PD_META_KEY_DATE_LAST_CHANGED, UT_UTF8String(now_str.c_str()) ) ; #endif // TODO: set dc.date and abiword.date_created if document is new (i.e. first save) UT_GenericStringMap & ref = m_pDocument->getMetaData() ; // don't print out a thing if ( ref.size () == 0 ) return ; m_pie->write("\n"); UT_GenericStringMap::UT_Cursor cursor ( &ref ) ; const UT_UTF8String * val = NULL ; for ( val = cursor.first(); cursor.is_valid(); val = cursor.next () ) { if ( val ) { const UT_UTF8String *stringval = val; if( stringval->size () > 0 ) { m_pie->write( "write ( "\">" ) ; UT_UTF8String esc = *stringval; _outputXMLChar ( esc.utf8_str(), esc.byteLength() ) ; m_pie->write ( "\n" ) ; } } } m_pie->write("\n"); } void s_AbiWord_1_Listener::_handlePageSize(void) { // // Code to write out the PageSize Definitions to disk // m_pie->write("write(m_pDocument->m_docPageSize.getPredefinedName()); m_pie->write("\""); m_pie->write(" orientation=\""); if(m_pDocument->m_docPageSize.isPortrait() == true) m_pie->write("portrait\""); else m_pie->write("landscape\""); UT_Dimension docUnit = m_pDocument->m_docPageSize.getDims(); UT_LocaleTransactor t(LC_NUMERIC, "C"); m_pie->write( UT_String_sprintf(" width=\"%f\"", m_pDocument->m_docPageSize.Width(docUnit)).c_str() ); m_pie->write( UT_String_sprintf(" height=\"%f\"",m_pDocument->m_docPageSize.Height(docUnit)).c_str() ); m_pie->write(" units=\""); m_pie->write(UT_dimensionName(docUnit)); m_pie->write("\""); m_pie->write( UT_String_sprintf(" page-scale=\"%f\"/>\n",m_pDocument->m_docPageSize.getScale()).c_str() ); } void s_AbiWord_1_Listener::_handleDataItems(void) { #ifdef ENABLE_RESOURCE_MANAGER m_pDocument->resourceManager().write_xml (0, *this); #else bool bWroteOpenDataSection = false; const char * szName; std::string mimeType; const UT_ByteBuf * pByteBuf; UT_ByteBuf bbEncoded(1024); string_set::iterator end(m_pUsedImages.end()); UT_DEBUGMSG(("Used images are... \n")); for (UT_uint32 k=0; (m_pDocument->enumDataItems(k, NULL, &szName, &pByteBuf, &mimeType)); k++) { string_set::iterator it(m_pUsedImages.find(szName)); if (it == end) { // This data item is no longer used. Don't output it to a file. UT_DEBUGMSG(("item #%s# not found in set:\n", szName)); continue; } else { UT_DEBUGMSG(("item #%s# found:\n", szName)); m_pUsedImages.erase(it); } if (!bWroteOpenDataSection) { m_pie->write("\n"); bWroteOpenDataSection = true; } bool status = false; bool encoded = true; if (!mimeType.empty() && ((mimeType == "image/svg+xml") || (mimeType == "application/mathml+xml"))) { bbEncoded.truncate(0); bbEncoded.append(reinterpret_cast("getLength(); const UT_Byte * buf = pByteBuf->getPointer(0); while (off < len) { if (buf[off] == ']' && buf[off+1] == ']' && buf[off+2] == '>') { bbEncoded.append(buf, off-1); bbEncoded.append(reinterpret_cast("]]>"), 6); off += 3; len -= off; buf = pByteBuf->getPointer(off); off = 0; continue; } off++; } bbEncoded.append(buf, off); bbEncoded.append(reinterpret_cast("]]>\n"), 4); status = true; encoded = false; } else { status = UT_Base64Encode(&bbEncoded, pByteBuf); encoded = true; } if (status) { m_pie->write("write("\" mime-type=\""); _outputXMLChar(mimeType.c_str(), mimeType.size()); } if (encoded) { m_pie->write("\" base64=\"yes\">\n"); // break up the Base64 blob as a series lines // like MIME does. UT_uint32 jLimit = bbEncoded.getLength(); UT_uint32 jSize; UT_uint32 j; for (j=0; jwrite(reinterpret_cast(bbEncoded.getPointer(j)),jSize); m_pie->write("\n"); } } else { m_pie->write("\" base64=\"no\">\n"); m_pie->write(reinterpret_cast(bbEncoded.getPointer(0)), bbEncoded.getLength()); } m_pie->write("\n"); } } if (bWroteOpenDataSection) m_pie->write("\n"); #endif } void s_AbiWord_1_Listener::_handleRevisions(void) { bool bWroteOpenRevisionsSection = false; const AD_Revision * pRev=NULL; const UT_GenericVector & vRevisions = m_pDocument->getRevisions(); UT_sint32 k = 0; for (k=0; k < vRevisions.getItemCount(); k++) { pRev = vRevisions.getNthItem(k); UT_continue_if_fail(pRev); UT_String s; if (!bWroteOpenRevisionsSection) { UT_String_sprintf(s, "\n", m_pDocument->isShowRevisions(), m_pDocument->isMarkRevisions(), m_pDocument->getShowRevisionId(), m_pDocument->isAutoRevisioning()); m_pie->write(s.c_str()); bWroteOpenRevisionsSection = true; } UT_String_sprintf(s, "", pRev->getId(), (UT_uint64)pRev->getStartTime(), pRev->getVersion()); m_pie->write(s.c_str()); if(pRev->getDescription()) { _outputData(pRev->getDescription(), UT_UCS4_strlen(pRev->getDescription())); } m_pie->write("\n"); } if (bWroteOpenRevisionsSection) m_pie->write("\n"); return; } void s_AbiWord_1_Listener::_handleHistory(void) { bool bWroteOpenSection = false; UT_uint32 k = 0; const UT_uint32 iCount = m_pDocument->getHistoryCount(); for (k=0; k < iCount; k++) { UT_uint32 iVersion = m_pDocument->getHistoryNthId(k); const UT_UUID& UID = m_pDocument->getHistoryNthUID(k); time_t tStarted = m_pDocument->getHistoryNthTimeStarted(k); bool bAuto = m_pDocument->getHistoryNthAutoRevisioned(k); UT_uint32 iXID = m_pDocument->getHistoryNthTopXID(k); UT_UTF8String s, hUid; UID.toString(hUid); if (!bWroteOpenSection) { UT_UTF8String_sprintf(s, "\n", m_pDocument->getDocVersion(), static_cast(m_pDocument->getEditTime()), static_cast(m_pDocument->getLastSavedTime()), m_pDocument->getDocUUIDString()); m_pie->write(s.utf8_str()); bWroteOpenSection = true; } UT_UTF8String_sprintf(s, "\n", iVersion, static_cast(tStarted), hUid.utf8_str(),bAuto, iXID); m_pie->write(s.utf8_str()); } if (bWroteOpenSection) m_pie->write("\n"); return; } void s_AbiWord_1_Listener::_handleAuthors(void) { UT_sint32 nAuthors = m_pDocument-> getNumAuthors(); if(nAuthors <= 0) return; m_pie->write("\n"); UT_sint32 i = 0; UT_String sVal; for(i=0;igetNthAuthor(i); m_pie->write("getAuthorInt()); m_pie->write(sVal.c_str()); m_pie->write("\" "); PP_AttrProp * pAP = pAuthor->getAttrProp(); if(pAP->getPropertyCount()>0) { m_pie->write(static_cast(PT_PROPS_ATTRIBUTE_NAME)); m_pie->write("=\""); const gchar * szName = NULL; const gchar * szValue = NULL; UT_uint32 j = 0; while (pAP->getNthProperty(j++,szName,szValue)) { if (szName && *szName && szValue && *szValue) { if(j>1) m_pie->write("; "); m_pie->write(static_cast(szName)); m_pie->write(":"); _outputXMLChar(szValue, strlen(szValue)); } } m_pie->write("\""); } m_pie->write("/>\n"); } m_pie->write("\n"); }