/* 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_string.h"
#include "ut_bytebuf.h"
#include "ut_base64.h"
#include "ut_locale.h"
#include "ut_units.h"
#include "ut_debugmsg.h"
#include "pt_Types.h"
#include "ie_exp_WML.h"
#include "ie_TOC.h"
#include "pd_Document.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 "xap_App.h"
#include "pd_Style.h"
#include "ap_Strings.h"
#include "ut_path.h"
#include "xap_EncodingManager.h"
#include "ut_string_class.h"
/*****************************************************************/
/*****************************************************************/
IE_Exp_WML::IE_Exp_WML(PD_Document * pDocument)
: IE_Exp(pDocument)
{
m_error = 0;
m_pListener = NULL;
}
IE_Exp_WML::~IE_Exp_WML()
{
}
/*****************************************************************/
/*****************************************************************/
IE_Exp_WML_Sniffer::IE_Exp_WML_Sniffer (const char * _name) :
IE_ExpSniffer(_name)
{
//
}
bool IE_Exp_WML_Sniffer::recognizeSuffix(const char * szSuffix)
{
return (!g_ascii_strcasecmp(szSuffix,".wml"));
}
UT_Error IE_Exp_WML_Sniffer::constructExporter(PD_Document * pDocument,
IE_Exp ** ppie)
{
IE_Exp_WML * p = new IE_Exp_WML(pDocument);
*ppie = p;
return UT_OK;
}
bool IE_Exp_WML_Sniffer::getDlgLabels(const char ** pszDesc,
const char ** pszSuffixList,
IEFileType * ft)
{
*pszDesc = "WML (.wml)";
*pszSuffixList = "*.wml";
*ft = getFileType();
return true;
}
/*****************************************************************/
/*****************************************************************/
UT_Error IE_Exp_WML::_writeDocument(void)
{
m_pListener = new s_WML_Listener(getDoc(),this);
if (!m_pListener)
return UT_IE_NOMEMORY;
if (!getDoc()->tellListener(static_cast(m_pListener)))
return UT_ERROR;
DELETEP(m_pListener);
return ((m_error) ? UT_IE_COULDNOTWRITE : UT_OK);
}
/*****************************************************************/
/*****************************************************************/
s_WML_Listener::s_WML_Listener(PD_Document * pDocument,
IE_Exp_WML * pie)
: m_pDocument(pDocument),
m_pie(pie),
m_bInSection(false),
m_bInBlock(false),
m_bInSpan(false),
m_bInAnchor(false),
m_bInHyperlink(false),
m_bInCell(false),
m_bInRow(false),
m_bInTable(false),
m_bPendingClose(false),
m_bWasSpace(false),
m_iCards(1),
m_iTableDepth(0),
mTableHelper(pDocument),
m_toc(0),
m_heading_count(0)
{
m_pie->write("write("\t\"http://www.openwave.com/dtd/wml11.dtd\" >\n");
/* keep ads to a minimum. size is at a premium */
m_pie->write("\n");
m_pie->write("\n\n");
m_pie->write("\n");
_handleMetaData();
m_toc = new IE_TOCHelper(m_pDocument);
}
s_WML_Listener::~s_WML_Listener()
{
_closeSection();
if(m_bPendingClose)
m_pie->write("\n");
m_pie->write("\n");
_handleDataItems();
UT_VECTOR_FREEALL(char*, m_utvDataIDs);
DELETEP(m_toc);
}
/*****************************************************************/
/*****************************************************************/
static char *_stripSuffix(const char* from, char delimiter)
{
char * fremove_s = static_cast(g_try_malloc(strlen(from)+1));
strcpy(fremove_s, from);
char * p = fremove_s + strlen(fremove_s);
while ((p >= fremove_s) && (*p != delimiter))
p--;
if (p >= fremove_s)
*p = '\0';
return fremove_s;
}
static char *_stripSuffix(const UT_UTF8String &from, char delimiter)
{
return _stripSuffix(from.utf8_str(), delimiter);
}
void s_WML_Listener::_closeAnchor()
{
if(!m_bInAnchor)
{
return;
}
m_pie->write("");
m_bInAnchor = false;
}
void s_WML_Listener::_closeHyperlink()
{
if(!m_bInHyperlink)
{
return;
}
m_pie->write("");
m_bInHyperlink = false;
}
void s_WML_Listener::_closeTable()
{
if(!m_bInTable)
{
return;
}
_closeCell();
_closeRow();
m_pie->write("\n
\n");
m_bInTable = false;
}
void s_WML_Listener::_closeRow()
{
if(!m_bInRow || !m_bInTable)
{
return;
}
m_pie->write("\n");
m_bInRow = false;
}
void s_WML_Listener::_closeCell()
{
if(!m_bInCell || !m_bInTable)
{
return;
}
m_pie->write("\n");
m_bInCell = false;
if ( mTableHelper.getNumCols () == mTableHelper.getRight () )
{
// logical end of a row
_closeRow();
}
}
void s_WML_Listener::_openTable(PT_AttrPropIndex api)
{
if(!m_bInSection)
_openSection(api);
if(m_bInTable)
{
return; //no nested tables
}
UT_sint32 nCols = mTableHelper.getNumCols();
UT_UTF8String tableSpec = UT_UTF8String_sprintf("\n
\n",nCols);
m_pie->write(tableSpec.utf8_str(), tableSpec.size());
m_bInTable = true;
}
void s_WML_Listener::_openCell(void)
{
if(!m_bInTable)
{
return;
}
//note: wml 1.1 doesn't support colspan or rowspan
if(mTableHelper.isNewRow())
{
// beginning of a new row
_closeCell();
_closeRow();
_openRow();
}
m_pie->write("");
m_bInCell = true;
}
void s_WML_Listener::_openRow(void)
{
if(!m_bInRow)
{
m_pie->write(" | \n");
m_bInRow = true;
}
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_closeSection(void)
{
_closeSpan();
_closeBlock();
if(m_bInSection)
m_bPendingClose = true;
}
void s_WML_Listener::_openSection(PT_AttrPropIndex api)
{
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
const gchar * szValue = NULL;
if(pAP && bHaveProp && (pAP->getAttribute("strux-image-dataid", szValue)))
{
_openSpan(api);
_handleImage(api, true);
_closeSpan();
return; //don't open a new section
}
if(m_bPendingClose)
{
m_iCards++;
m_pie->write(UT_UTF8String_sprintf("\n", m_iCards).utf8_str());
m_pie->write("\n");
m_bInSection = false;
m_bPendingClose = false;
}
if(!m_bInSection)
{
m_pie->write(UT_UTF8String_sprintf("\n", m_iCards).utf8_str());
m_bInSection = true;
}
}
void s_WML_Listener::_closeBlock(void)
{
_closeAnchor();
_closeHyperlink();
if(!m_bInBlock)
{
return;
}
if(!m_bInTable)
{
m_pie->write("\n");
}
m_bInBlock = false;
return;
}
bool s_WML_Listener::_styleDescendsFrom(const char * style_name, const char * base_name)
{
PD_Style * style = 0;
m_pDocument->getStyle (style_name, &style);
UT_sint32 iLoop = 0;
while (style && (iLoop < 10))
{
if (g_ascii_strcasecmp (base_name, style->getName ()) == 0)
return true;
style = style->getBasedOn ();
iLoop++;
}
return false;
}
void s_WML_Listener::_openParagraph(PT_AttrPropIndex api)
{
xxx_UT_DEBUGMSG(("WML Export: OpenParagraph called!\n"));
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
if(!m_bInSection)
_openSection(api);
if (m_bInTable) // tags aren't allowed inside of table-related tags
{
m_bInBlock = true;
return;
}
if (bHaveProp && pAP)
{
const gchar * szValue;
m_pie->write("
getProperty("text-align", szValue))
{
if (!strcmp(szValue, "center"))
m_pie->write(" align=\"center\"");
else if (!strcmp(szValue, "right"))
m_pie->write(" align=\"right\"");
else //left or block-justify
m_pie->write(" align=\"left\"");
}
m_pie->write(">");
}
else
{
//
with no style attribute, and no properties either
m_pie->write("
");
}
const gchar * szStyle;
bool have_style = pAP->getAttribute (PT_STYLE_ATTRIBUTE_NAME, szStyle);
if (have_style && szStyle)
{
if (m_toc)
{
if (_styleDescendsFrom(szStyle, "Heading 1") || _styleDescendsFrom(szStyle, "Heading 2") ||
_styleDescendsFrom(szStyle, "Heading 3") || _styleDescendsFrom(szStyle, "Heading 4"))
{
UT_UTF8String tocAnchor(UT_UTF8String_sprintf("", m_heading_count));
m_pie->write(tocAnchor.utf8_str());
m_heading_count++;
}
}
}
m_bInBlock = true;
}
void s_WML_Listener::_emitTOC (PT_AttrPropIndex api) {
int level1_depth = 0;
int level2_depth = 0;
int level3_depth = 0;
int level4_depth = 0;
const PP_AttrProp * pAP = 0;
bool bHaveProp = (api ? (m_pDocument->getAttrProp (api, &pAP)) : false);
bool bEmitHeading = true;
const gchar * szValue = 0;
UT_UTF8String tocHeadingUTF8;
_closeSpan();
_closeBlock();
if(bHaveProp && pAP && pAP->getProperty("toc-has-heading", szValue) && szValue) //check to see if the TOC heading is hidden
{
if(atoi(szValue) == 0)
bEmitHeading = false;
}
if(bEmitHeading)
{
if(bHaveProp && pAP && pAP->getProperty("toc-heading", szValue) && szValue) // user-defined TOC heading
{
tocHeadingUTF8 = szValue;
}
else
{
const XAP_StringSet * pSS = XAP_App::getApp()->getStringSet();
if(pSS)
pSS->getValueUTF8(AP_STRING_ID_TOC_TocHeading, tocHeadingUTF8);
}
//TODO: query the style properties to determine whether to center the TOC heading
m_pie->write("
");
m_pie->write(tocHeadingUTF8.escapeXML().utf8_str());
m_pie->write("
\n");
}
for (int i = 0; i < m_toc->getNumTOCEntries(); i++) {
int tocLevel = 0;
UT_UCS4String tocText(m_toc->getNthTOCEntry(i, &tocLevel).utf8_str());
m_pie->write("");
UT_UCS4String tocLevelText;
if(tocLevel == 1) {
level1_depth++;
level2_depth = level3_depth = level4_depth = 0;
tocLevelText = UT_UTF8String_sprintf("[%d] ", level1_depth).ucs4_str();
} else if(tocLevel == 2) {
level2_depth++;
level3_depth = level4_depth = 0;
tocLevelText = UT_UTF8String_sprintf("[%d.%d] ", level1_depth, level2_depth).ucs4_str();
} else if(tocLevel == 3) {
level3_depth++;
level4_depth = 0;
tocLevelText = UT_UTF8String_sprintf("[%d.%d.%d] ", level1_depth, level2_depth, level3_depth).ucs4_str();
} else if(tocLevel == 4) {
level4_depth++;
tocLevelText = UT_UTF8String_sprintf("[%d.%d.%d.%d] ", level1_depth, level2_depth, level3_depth, level4_depth).ucs4_str();
}
UT_UTF8String tocLink(UT_UTF8String_sprintf("", i));
m_pie->write(tocLink.utf8_str(), tocLink.byteLength());
_outputDataUnchecked (tocLevelText.ucs4_str(), tocLevelText.length());
_outputDataUnchecked (tocText.ucs4_str(), tocText.length());
m_pie->write("", 4);
m_pie->write("
");
}
}
/*****************************************************************/
/*****************************************************************/
bool s_WML_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);
PT_AttrPropIndex api = pcr->getIndexAP();
if (api)
{
_openSpan(api);
}
PT_BufIndex bi = pcrs->getBufIndex();
_outputData(m_pDocument->getPointer(bi),pcrs->getLength());
if (api)
_closeSpan();
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:
{
_handleImage(api);
return true;
}
case PTO_Field:
{
_handleField(pcro, api);
return true;
}
case PTO_Hyperlink:
{
_handleHyperlink(api);
return true;
}
case PTO_Bookmark:
{
_handleBookmark(api);
return true;
}
case PTO_Embed:
{
_handleEmbedded(api);
return true;
}
case PTO_Math:
{
_handleMath(api);
return true;
}
case PTO_Annotation:
{
return true;
}
default:
UT_ASSERT_HARMLESS(UT_TODO);
return true;
}
}
case PX_ChangeRecord::PXT_InsertFmtMark:
return true;
default:
UT_ASSERT_HARMLESS(UT_TODO);
return true;
}
}
bool s_WML_Listener::populateStrux(PL_StruxDocHandle sdh,
const PX_ChangeRecord * pcr,
PL_StruxFmtHandle * psfh)
{
UT_ASSERT_HARMLESS(pcr->getType() == PX_ChangeRecord::PXT_InsertStrux);
const PX_ChangeRecord_Strux * pcrx = static_cast (pcr);
*psfh = 0; // we don't need it.
switch (pcrx->getStruxType())
{
case PTX_Section:
case PTX_SectionFrame:
case PTX_SectionHdrFtr:
{
if(!m_bInTable)
{
_closeSection();
_openSection(pcr->getIndexAP());
}
return true;
}
case PTX_Block:
{
_closeSpan();
_closeBlock();
_openParagraph(pcr->getIndexAP());
return true;
}
case PTX_SectionTable:
{
m_iTableDepth++;
if(m_iTableDepth == 1)
{
_closeSpan();
_closeBlock();
mTableHelper.OpenTable(sdh,pcr->getIndexAP());
_openTable(pcr->getIndexAP());
}
return true;
}
case PTX_EndTable:
{
m_iTableDepth--;
if(m_iTableDepth == 0)
{
_closeBlock();
_closeTable();
mTableHelper.CloseTable();
}
return true;
}
case PTX_SectionCell:
{
if(m_iTableDepth == 1)
{
mTableHelper.OpenCell(pcr->getIndexAP()) ;
_closeSpan();
_closeBlock();
_openCell();
}
return true;
}
case PTX_EndCell:
{
if(m_iTableDepth == 1)
{
_closeBlock();
_closeCell();
mTableHelper.CloseCell();
}
return true;
}
case PTX_EndFrame:
{
if(!m_bInTable)
{
_closeSection();
}
return true;
}
case PTX_EndEndnote:
case PTX_EndFootnote:
case PTX_EndAnnotation:
case PTX_SectionEndnote:
case PTX_SectionFootnote:
case PTX_SectionAnnotation:
{
return true;
}
case PTX_SectionTOC:
{
_emitTOC(pcr->getIndexAP());
return true;
}
case PTX_EndTOC:
{
return true;
}
case PTX_EndMarginnote:
case PTX_SectionMarginnote:
default:
UT_ASSERT_HARMLESS(UT_TODO);
return true;
}
}
bool s_WML_Listener::change(PL_StruxFmtHandle /*sfh*/,
const PX_ChangeRecord * /*pcr*/)
{
UT_ASSERT_NOT_REACHED(); // this function is not used.
return false;
}
bool s_WML_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_WML_Listener::signal(UT_uint32 /* iSignal */)
{
UT_ASSERT_NOT_REACHED();
return false;
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleMetaData()
{
UT_UTF8String metaProp("");
m_pie->write("\n");
#define WRITEMETA(name)\
metaProp.escapeXML();\
if(metaProp.length())\
m_pie->write(UT_UTF8String_sprintf("\n", name, metaProp.utf8_str()).utf8_str());\
if (m_pDocument->getMetaDataProp (PD_META_KEY_TITLE, metaProp) && metaProp.size())
{
WRITEMETA("title");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_CREATOR, metaProp) && metaProp.size())
{
WRITEMETA("author");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_SUBJECT, metaProp) && metaProp.size())
{
WRITEMETA("subject");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_DESCRIPTION, metaProp) && metaProp.size())
{
WRITEMETA("description");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_PUBLISHER, metaProp) && metaProp.size())
{
WRITEMETA("publisher");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_CONTRIBUTOR, metaProp) && metaProp.size())
{
WRITEMETA("contributor");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_DATE, metaProp) && metaProp.size())
{
WRITEMETA("date");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_SOURCE, metaProp) && metaProp.size())
{
WRITEMETA("source");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_RELATION, metaProp) && metaProp.size())
{
WRITEMETA("relation");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_COVERAGE, metaProp) && metaProp.size())
{
WRITEMETA("coverage");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_RIGHTS, metaProp) && metaProp.size())
{
WRITEMETA("rights");
}
if (m_pDocument->getMetaDataProp (PD_META_KEY_KEYWORDS, metaProp) && metaProp.size())
{
WRITEMETA("keywords");
}
#undef WRITEMETA
m_pie->write("\n");
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleEmbedded(PT_AttrPropIndex api)
{
//this should never happen, but it doesn't hurt to make sure
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const gchar* szValue = 0;
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
UT_return_if_fail(bHaveProp && pAP && pAP->getAttribute("dataid", szValue))
UT_UTF8String buf = "snapshot-png-";
buf += szValue;
char* dataid = g_strdup(buf.utf8_str());
m_utvDataIDs.push_back(dataid);
buf += ".png";
m_pie->write("write(UT_go_basename(m_pie->getFileName()).utf8_str());
m_pie->write("_data/");
m_pie->write(buf.utf8_str());
m_pie->write("\"");
UT_LocaleTransactor t(LC_NUMERIC, "C");
if(pAP->getProperty("height", szValue))
{
buf.clear();
UT_UTF8String_sprintf(buf, "%f", UT_convertToDimension(szValue, DIM_PX));
m_pie->write(" height=\"");
m_pie->write(buf.utf8_str());
m_pie->write("\"");
}
if(pAP->getProperty("width", szValue))
{
buf.clear();
UT_UTF8String_sprintf(buf, "%f", UT_convertToDimension(szValue, DIM_PX));
m_pie->write(" width=\"");
m_pie->write(buf.utf8_str());
m_pie->write("\"");
}
if(pAP->getProperty("lang", szValue))
{
m_pie->write(" xml:lang=\"");
m_pie->write(szValue);
m_pie->write("\"");
}
m_pie->write("/>");
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleField(const PX_ChangeRecord_Object * pcro, PT_AttrPropIndex api)
{
//this can happen with certain .doc files
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const PP_AttrProp * pAP = NULL;
const gchar* szValue = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
UT_return_if_fail(bHaveProp && pAP && pAP->getAttribute("type", szValue));
UT_UTF8String buf;
fd_Field * field = pcro->getField();
m_pie->populateFields ();
if(strcmp(szValue, "list_label") != 0)
{
buf = field->getValue(); //retrieve the field text
buf.escapeXML();
if(buf.length())
{
m_pie->write(buf.utf8_str());
}
}
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleBookmark(PT_AttrPropIndex api)
{
//this can happen with certain .doc files
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const PP_AttrProp * pAP = NULL;
const gchar* szValue = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
UT_UTF8String buf;
if(bHaveProp && pAP && pAP->getAttribute("type", szValue))
{
_closeAnchor(); //nested anchors are not allowed
if(strcmp(szValue, "start") == 0 && (m_bInHyperlink == 0) && pAP->getAttribute("name", szValue))
{
buf = szValue;
buf.escapeXML();
if(buf.length())
{
m_pie->write("write(buf.utf8_str());
m_pie->write("\">");
m_bInAnchor = true;
}
}
}
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleHyperlink(PT_AttrPropIndex api)
{
//this can happen with certain .doc files
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const PP_AttrProp * pAP = NULL;
const gchar* szValue = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
UT_UTF8String buf;
if(bHaveProp && pAP && pAP->getAttribute("xlink:href", szValue))
{
buf = szValue;
buf.escapeURL();
_closeAnchor();
_closeHyperlink();
if(buf.length())
{
m_pie->write("write(buf.utf8_str());
m_pie->write("\">");
m_bInHyperlink = true;
}
}
else
{
_closeHyperlink();
}
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleMath(PT_AttrPropIndex api)
{
//this should never happen, but it doesn't hurt to make sure
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const gchar* szValue = 0;
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
UT_return_if_fail(bHaveProp && pAP && pAP->getAttribute("dataid", szValue));
UT_UTF8String buf = "snapshot-png-";
buf += szValue;
char *dataid = g_strdup(buf.utf8_str());
m_utvDataIDs.push_back(dataid);
buf += ".png";
m_pie->write("write(UT_go_basename(m_pie->getFileName()).utf8_str());
m_pie->write("_data/");
m_pie->write(buf.utf8_str());
m_pie->write("\"");
if(pAP->getProperty("lang", szValue))
{
m_pie->write(" xml:lang=\"");
m_pie->write(szValue);
m_pie->write("\"");
}
m_pie->write("/>");
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleImage(PT_AttrPropIndex api, bool bPos)
{
//this should never happen, but it doesn't hurt to make sure
if((m_bInTable && (!m_bInRow || !m_bInCell)))
{
UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
return;
}
const PP_AttrProp * pAP = NULL;
const gchar* szValue = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
if(!(bHaveProp && pAP))
return;
bool bRes = false;
if(bPos)
bRes = pAP->getAttribute("strux-image-dataid", szValue);
else
bRes = pAP->getAttribute("dataid", szValue);
if(!(bRes && szValue && *szValue))
return;
char * dataid = g_strdup(static_cast(szValue));
UT_return_if_fail(dataid);
m_utvDataIDs.push_back(dataid);
char * temp = _stripSuffix(UT_go_basename(szValue), '_');
char * fstripped = _stripSuffix(temp, '.');
UT_UTF8String buf = fstripped;
FREEP(temp);
FREEP(fstripped);
std::string sExt;
if(!m_pDocument->getDataItemFileExtension(dataid, sExt))
sExt = ".png";
buf += sExt;
m_pie->write("getAttribute("alt", szValue)) // check for existing alt text
{
UT_UTF8String alt = szValue;
alt.escapeXML();
m_pie->write(alt.utf8_str());
}
else // fall back to the file name
{
m_pie->write("AbiWord Image ");
m_pie->write(buf.utf8_str());
}
m_pie->write("\" src=\"");
m_pie->write(UT_go_basename(m_pie->getFileName()).utf8_str());
m_pie->write("_data/");
m_pie->write(buf.utf8_str());
m_pie->write("\"");
const gchar * szWidth = 0;
const gchar * szHeight = 0;
UT_LocaleTransactor t(LC_NUMERIC, "C");
if(pAP->getProperty("width", szWidth) && szWidth && *szWidth)
{
UT_UTF8String_sprintf(buf, "%f", UT_convertToDimension(szWidth, DIM_PX));
m_pie->write (" width=\"");
m_pie->write (buf.utf8_str());
m_pie->write ("\"");
}
if(pAP->getProperty("height", szHeight) && szHeight && *szHeight)
{
UT_UTF8String_sprintf(buf, "%f", UT_convertToDimension(szHeight, DIM_PX));
m_pie->write (" height=\"");
m_pie->write (buf.utf8_str());
m_pie->write ("\"");
}
if(pAP->getProperty("lang", szValue) && szValue && *szValue)
{
m_pie->write(" xml:lang=\"");
m_pie->write(szValue);
m_pie->write("\"");
}
m_pie->write("/>");
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_handleDataItems(void)
{
const char * szName;
std::string mimeType;
const UT_ByteBuf * pByteBuf;
for (UT_uint32 k=0; (m_pDocument->enumDataItems(k,NULL,&szName,&pByteBuf,
&mimeType)); k++)
{
UT_sint32 loc = -1;
for (UT_sint32 i = 0; i < m_utvDataIDs.getItemCount(); i++)
{
if(strcmp(static_cast(m_utvDataIDs[i]), szName) == 0)
{
loc = i;
break;
}
}
if(loc > -1)
{
UT_UTF8String fname;
UT_UTF8String_sprintf(fname, "%s_data", m_pie->getFileName());
/* UT_sint32 result = */ UT_go_directory_create(fname.utf8_str(), 0750, NULL);
if (0 /* result < 0 */)
{
UT_DEBUGMSG(("WML Export: Failed to create directory\n"));
/* we might want to return an error here,
* but I don't think so. */
}
if (mimeType == "image/svg+xml")
{
UT_UTF8String_sprintf(fname, "%s/%s_%d.svg", fname.utf8_str(), szName, loc);
}
else if (mimeType == "application/mathml+xml")
{
UT_UTF8String_sprintf(fname, "%s/%s_%d.mathml", fname.utf8_str(), szName, loc);
}
else if (mimeType == "image/png")// PNG Image
{
char * temp = _stripSuffix(UT_go_basename(szName), '_');
char * fstripped = _stripSuffix(temp, '.');
FREEP(temp);
UT_UTF8String_sprintf(fname, "%s/%s.png", fname.utf8_str(), fstripped);
FREEP(fstripped);
}
else
{
UT_DEBUGMSG(("WML export: Unhandled/ignored mime type: %s\n", mimeType.c_str()));
}
GsfOutput *fp = UT_go_file_create (fname.utf8_str(), NULL);
if(!fp)
continue;
gsf_output_write(fp, pByteBuf->getLength(), (const guint8 *)pByteBuf->getPointer(0));
gsf_output_close(fp);
g_object_unref(G_OBJECT(fp));
}
}
}
/*****************************************************************/
/*****************************************************************/
void s_WML_Listener::_openSpan(PT_AttrPropIndex api)
{
if (!m_bInBlock || m_bInHyperlink || m_bInAnchor || (m_bInTable && (!m_bInRow || !m_bInCell)))
{
return;
}
const PP_AttrProp * pAP = NULL;
bool bHaveProp = m_pDocument->getAttrProp(api,&pAP);
if (bHaveProp && pAP)
{
const gchar * szValue = NULL;
if ((pAP->getProperty("font-weight", szValue))
&& !strcmp(szValue, "bold"))
{
m_pie->write("");
}
if ((pAP->getProperty("font-style", szValue))
&& !strcmp(szValue, "italic"))
{
m_pie->write("");
}
if ((pAP->getProperty("text-decoration", szValue)))
{
if(strstr(szValue,"underline"))
m_pie->write("");
}
// In my WML world...
// superscript = big
// subscript = small
if (pAP->getProperty("text-position", szValue))
{
if (!strcmp("superscript", szValue))
{
m_pie->write("");
}
else if (!strcmp("subscript", szValue))
{
m_pie->write("");
}
}
m_bInSpan = true;
m_pAP_Span = pAP;
}
}
void s_WML_Listener::_outputData(const UT_UCSChar * data, UT_uint32 length)
{
if (!m_bInBlock || (m_bInTable && (!m_bInRow || !m_bInCell)))
{
return;
}
_outputDataUnchecked(data, length);
}
void s_WML_Listener::_outputDataUnchecked(const UT_UCSChar * data, UT_uint32 length)
{
// TODO deal with unicode.
// TODO for now, just squish it into ascii.
UT_UTF8String sBuf;
const UT_UCSChar * pData;
m_bWasSpace = false;
sBuf.reserve(length);
for (pData=data; (pData':
sBuf += ">";
pData++;
break;
case '&':
sBuf += "&";
pData++;
break;
case UCS_VTAB: // column break, export as a linebreak for now
case UCS_FF: // page break, export as a linebreak for now
case UCS_LF: // LF -- representing a Forced-Line-Break
sBuf += "
";
pData++;
break;
case ' ':
case UCS_TAB:
// try to honor multiple spaces
// tabs get treated as a single space
//
if(m_bWasSpace)
{
sBuf += " ";
pData++;
}
else
{
// just tack on a single space to the textrun
m_bWasSpace = true;
sBuf += " ";
pData++;
}
break;
default:
{
if(*pData < 0x20) //invalid xml chars
{
pData++;
}
else
{
sBuf.appendUCS4(pData, 1);
pData++;
}
m_bWasSpace = false;
}
}
}
m_pie->write(sBuf.utf8_str(),sBuf.byteLength());
}
void s_WML_Listener::_closeSpan(void)
{
if (!m_bInSpan || m_bInHyperlink || m_bInAnchor)
return;
const PP_AttrProp * pAP = m_pAP_Span;
if (pAP)
{
const gchar * szValue = NULL;
if (pAP->getProperty("text-position", szValue))
{
if (!strcmp("superscript", szValue))
{
m_pie->write("");
}
else if (!strcmp("subscript", szValue))
{
m_pie->write("");
}
}
if ((pAP->getProperty("text-decoration", szValue)))
{
if(strstr(szValue,"underline"))
m_pie->write("");
}
if ((pAP->getProperty("font-style", szValue))
&& !strcmp(szValue, "italic"))
{
m_pie->write("");
}
if ((pAP->getProperty("font-weight", szValue))
&& !strcmp(szValue, "bold"))
{
m_pie->write("");
}
m_pAP_Span = NULL;
}
m_bInSpan = false;
return;
}