/* -*- 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 += "";
}
else
{
if (szSuffix)
if (*szSuffix == '/')
tag += "/";
tag += ">";
if (bNewLineAfter) tag += "\n";
}
m_pie->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 += "";
}
else
{
if (szSuffix)
if (*szSuffix == '/')
tag += "/";
tag += ">";
if (bNewLineAfter) tag += "\n";
}
m_pie->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(" ");
tag += name;
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");
}