/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include "docxexport.hxx"
#include "docxexportfilter.hxx"
#include "docxattributeoutput.hxx"
#include "docxsdrexport.hxx"
#include "docxhelper.hxx"
#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/document/XDocumentProperties.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/xml/dom/XDocument.hpp>
#include <com/sun/star/xml/sax/XSAXSerializable.hpp>
#include <com/sun/star/xml/sax/Writer.hpp>
#include <com/sun/star/awt/XControlModel.hpp>
#include <oox/token/namespaces.hxx>
#include <oox/token/tokens.hxx>
#include <oox/export/drawingml.hxx>
#include <oox/export/vmlexport.hxx>
#include <oox/export/chartexport.hxx>
#include <oox/export/shapes.hxx>
#include <oox/helper/propertyset.hxx>
#include <oox/token/relationship.hxx>
#include <oox/helper/binaryoutputstream.hxx>
#include <oox/ole/olestorage.hxx>
#include <oox/ole/olehelper.hxx>
#include <map>
#include <algorithm>
#include <IMark.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentLayoutAccess.hxx>
#include <IDocumentStylePoolAccess.hxx>
#include <docsh.hxx>
#include <ndtxt.hxx>
#include "wrtww8.hxx"
#include <fltini.hxx>
#include <fmtline.hxx>
#include <fmtpdsc.hxx>
#include <frmfmt.hxx>
#include <section.hxx>
#include <ftninfo.hxx>
#include <pagedesc.hxx>
#include <editeng/unoprnms.hxx>
#include <editeng/editobj.hxx>
#include <editeng/outlobj.hxx>
#include <editeng/brushitem.hxx>
#include <editeng/hyphenzoneitem.hxx>
#include <docary.hxx>
#include <numrule.hxx>
#include <charfmt.hxx>
#include <viewsh.hxx>
#include <viewopt.hxx>
#include "ww8par.hxx"
#include "ww8scan.hxx"
#include <oox/token/properties.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/storagehelper.hxx>
#include <rtl/ustrbuf.hxx>
#include <sal/log.hxx>
#include <vcl/font.hxx>
#include <unotools/ucbstreamhelper.hxx>
using namespace sax_fastparser;
using namespace ::comphelper;
using namespace ::com::sun::star;
using namespace ::oox;
using oox::vml::VMLExport;
using sw::mark::IMark;
AttributeOutputBase& DocxExport::AttrOutput() const
{
return *m_pAttrOutput;
}
DocxAttributeOutput& DocxExport::DocxAttrOutput() const
{
return *m_pAttrOutput;
}
MSWordSections& DocxExport::Sections() const
{
return *m_pSections;
}
bool DocxExport::CollapseScriptsforWordOk( sal_uInt16 nScript, sal_uInt16 nWhich )
{
// TODO FIXME is this actually true for docx? - this is ~copied from WW8
if ( nScript == i18n::ScriptType::ASIAN )
{
// for asian in ww8, there is only one fontsize
// and one fontstyle (posture/weight)
switch ( nWhich )
{
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_POSTURE:
case RES_CHRATR_WEIGHT:
return false;
default:
break;
}
}
else if ( nScript != i18n::ScriptType::COMPLEX )
{
// for western in ww8, there is only one fontsize
// and one fontstyle (posture/weight)
switch ( nWhich )
{
case RES_CHRATR_CJK_FONTSIZE:
case RES_CHRATR_CJK_POSTURE:
case RES_CHRATR_CJK_WEIGHT:
return false;
default:
break;
}
}
return true;
}
void DocxExport::AppendBookmarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
{
std::vector< OUString > aStarts;
std::vector< OUString > aEnds;
IMarkVector aMarks;
if ( GetBookmarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
{
for ( IMarkVector::const_iterator it = aMarks.begin(), end = aMarks.end();
it != end; ++it )
{
IMark* pMark = (*it);
const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
if ( nStart == nCurrentPos )
aStarts.push_back( pMark->GetName() );
if ( nEnd == nCurrentPos )
aEnds.push_back( pMark->GetName() );
}
}
const OUString& aStr( rNode.GetText() );
const sal_Int32 nEnd = aStr.getLength();
if ( nCurrentPos == nEnd )
m_pAttrOutput->WriteFinalBookmarks_Impl( aStarts, aEnds );
else
m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
}
void DocxExport::AppendBookmark( const OUString& rName )
{
std::vector< OUString > aStarts;
std::vector< OUString > aEnds;
aStarts.push_back( rName );
aEnds.push_back( rName );
m_pAttrOutput->WriteBookmarks_Impl( aStarts, aEnds );
}
void DocxExport::AppendAnnotationMarks( const SwTextNode& rNode, sal_Int32 nCurrentPos, sal_Int32 nLen )
{
std::vector< OUString > aStarts;
std::vector< OUString > aEnds;
IMarkVector aMarks;
if ( GetAnnotationMarks( rNode, nCurrentPos, nCurrentPos + nLen, aMarks ) )
{
for ( IMarkVector::const_iterator it = aMarks.begin(), end = aMarks.end();
it != end; ++it )
{
IMark* pMark = (*it);
const sal_Int32 nStart = pMark->GetMarkStart().nContent.GetIndex();
const sal_Int32 nEnd = pMark->GetMarkEnd().nContent.GetIndex();
if ( nStart == nCurrentPos )
aStarts.push_back( pMark->GetName() );
if ( nEnd == nCurrentPos )
aEnds.push_back( pMark->GetName() );
}
}
m_pAttrOutput->WriteAnnotationMarks_Impl( aStarts, aEnds );
}
void DocxExport::ExportGrfBullet(const SwTextNode&)
{
// Just collect the bullets for now, numbering.xml is not yet started.
CollectGrfsOfBullets();
}
OString DocxExport::AddRelation( const OUString& rType, const OUString& rTarget )
{
OUString sId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
rType, rTarget, true );
return sId.toUtf8();
}
bool DocxExport::DisallowInheritingOutlineNumbering( const SwFormat& rFormat )
{
bool bRet( false );
if (SfxItemState::SET != rFormat.GetItemState(RES_PARATR_NUMRULE, false))
{
if (const SwFormat *pParent = rFormat.DerivedFrom())
{
if (static_cast<const SwTextFormatColl*>(pParent)->IsAssignedToListLevelOfOutlineStyle())
{
::sax_fastparser::FSHelperPtr pSerializer = m_pAttrOutput->GetSerializer( );
// Level 9 disables the outline
pSerializer->singleElementNS( XML_w, XML_outlineLvl,
FSNS( XML_w, XML_val ), "9" ,
FSEND );
bRet = true;
}
}
}
return bRet;
}
void DocxExport::WriteHeadersFooters( sal_uInt8 nHeadFootFlags,
const SwFrameFormat& rFormat, const SwFrameFormat& rLeftFormat, const SwFrameFormat& rFirstPageFormat, sal_uInt8 nBreakCode )
{
m_nHeadersFootersInSection = 1;
// Turn ON flag for 'Writing Headers \ Footers'
m_pAttrOutput->SetWritingHeaderFooter( true );
// headers
if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_EVEN )
WriteHeaderFooter( &rLeftFormat, true, "even" );
if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_ODD )
WriteHeaderFooter( &rFormat, true, "default" );
if ( nHeadFootFlags & nsHdFtFlags::WW8_HEADER_FIRST )
WriteHeaderFooter( &rFirstPageFormat, true, "first" );
if( (nHeadFootFlags & (nsHdFtFlags::WW8_HEADER_EVEN
| nsHdFtFlags::WW8_HEADER_ODD
| nsHdFtFlags::WW8_HEADER_FIRST)) == 0
&& m_bHasHdr && nBreakCode == 2 ) // 2: nexPage
WriteHeaderFooter( nullptr, true, "default" );
// footers
if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_EVEN )
WriteHeaderFooter( &rLeftFormat, false, "even" );
if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_ODD )
WriteHeaderFooter( &rFormat, false, "default" );
if ( nHeadFootFlags & nsHdFtFlags::WW8_FOOTER_FIRST )
WriteHeaderFooter( &rFirstPageFormat, false, "first" );
if( (nHeadFootFlags & (nsHdFtFlags::WW8_FOOTER_EVEN
| nsHdFtFlags::WW8_FOOTER_ODD
| nsHdFtFlags::WW8_FOOTER_FIRST)) == 0
&& m_bHasFtr && nBreakCode == 2 ) // 2: nexPage
WriteHeaderFooter( nullptr, false, "default");
if ( nHeadFootFlags & ( nsHdFtFlags::WW8_FOOTER_EVEN | nsHdFtFlags::WW8_HEADER_EVEN ))
m_aSettings.evenAndOddHeaders = true;
// Turn OFF flag for 'Writing Headers \ Footers'
m_pAttrOutput->SetWritingHeaderFooter( false );
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "DocxExport::WriteHeadersFooters() - nBreakCode introduced, but ignored\n" );
#endif
}
void DocxExport::OutputField( const SwField* pField, ww::eField eFieldType, const OUString& rFieldCmd, FieldFlags nMode )
{
m_pAttrOutput->WriteField_Impl( pField, eFieldType, rFieldCmd, nMode );
}
void DocxExport::WriteFormData( const ::sw::mark::IFieldmark& rFieldmark )
{
m_pAttrOutput->WriteFormData_Impl( rFieldmark );
}
void DocxExport::WriteHyperlinkData( const ::sw::mark::IFieldmark& /*rFieldmark*/ )
{
#if OSL_DEBUG_LEVEL > 1
fprintf( stderr, "TODO DocxExport::WriteHyperlinkData()\n" );
#endif
}
void DocxExport::DoComboBox(const OUString& rName,
const OUString& rHelp,
const OUString& rToolTip,
const OUString& rSelected,
uno::Sequence<OUString>& rListItems)
{
m_pDocumentFS->startElementNS( XML_w, XML_ffData, FSEND );
m_pDocumentFS->singleElementNS( XML_w, XML_name,
FSNS( XML_w, XML_val ), OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(),
FSEND );
m_pDocumentFS->singleElementNS( XML_w, XML_enabled, FSEND );
if ( !rHelp.isEmpty() )
m_pDocumentFS->singleElementNS( XML_w, XML_helpText,
FSNS( XML_w, XML_val ), OUStringToOString( rHelp, RTL_TEXTENCODING_UTF8 ).getStr(),
FSEND );
if ( !rToolTip.isEmpty() )
m_pDocumentFS->singleElementNS( XML_w, XML_statusText,
FSNS( XML_w, XML_val ), OUStringToOString( rToolTip, RTL_TEXTENCODING_UTF8 ).getStr(),
FSEND );
m_pDocumentFS->startElementNS( XML_w, XML_ddList, FSEND );
// Output the 0-based index of the selected value
sal_uInt32 nListItems = rListItems.getLength();
sal_Int32 nId = 0;
sal_uInt32 nI = 0;
while ( ( nI < nListItems ) && ( nId == 0 ) )
{
if ( rListItems[nI] == rSelected )
nId = nI;
nI++;
}
m_pDocumentFS->singleElementNS( XML_w, XML_result,
FSNS( XML_w, XML_val ), OString::number( nId ).getStr( ),
FSEND );
// Loop over the entries
for (sal_uInt32 i = 0; i < nListItems; i++)
{
m_pDocumentFS->singleElementNS( XML_w, XML_listEntry,
FSNS( XML_w, XML_val ), OUStringToOString( rListItems[i], RTL_TEXTENCODING_UTF8 ).getStr(),
FSEND );
}
m_pDocumentFS->endElementNS( XML_w, XML_ddList );
m_pDocumentFS->endElementNS( XML_w, XML_ffData );
}
void DocxExport::DoFormText(const SwInputField* /*pField*/)
{
SAL_INFO("sw.ww8", "TODO DocxExport::ForFormText()" );
}
OString DocxExport::OutputChart( uno::Reference< frame::XModel > const & xModel, sal_Int32 nCount, ::sax_fastparser::FSHelperPtr const & m_pSerializer )
{
OUString aFileName = "charts/chart" + OUString::number(nCount) + ".xml";
OUString sId = m_pFilter->addRelation( m_pSerializer->getOutputStream(),
oox::getRelationship(Relationship::CHART),
aFileName );
aFileName = "word/charts/chart" + OUString::number(nCount) + ".xml";
::sax_fastparser::FSHelperPtr pChartFS =
m_pFilter->openFragmentStreamWithSerializer( aFileName,
"application/vnd.openxmlformats-officedocument.drawingml.chart+xml" );
oox::drawingml::ChartExport aChartExport(XML_w, pChartFS, xModel, m_pFilter, oox::drawingml::DOCUMENT_DOCX);
aChartExport.ExportContent();
return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
}
OString DocxExport::WriteOLEObject(SwOLEObj& rObject, OUString & io_rProgID)
{
uno::Reference <embed::XEmbeddedObject> xObj( rObject.GetOleRef() );
uno::Reference<uno::XComponentContext> const xContext(
GetFilter().getComponentContext());
OUString sMediaType;
OUString sRelationType;
OUString sSuffix;
const char * pProgID(nullptr);
uno::Reference<io::XInputStream> const xInStream =
oox::GetOLEObjectStream(xContext, xObj, io_rProgID,
sMediaType, sRelationType, sSuffix, pProgID);
if (!xInStream.is())
{
return OString();
}
assert(!sMediaType.isEmpty());
assert(!sRelationType.isEmpty());
assert(!sSuffix.isEmpty());
OUString sFileName = "embeddings/oleObject" + OUString::number( ++m_nOLEObjects ) + "." + sSuffix;
uno::Reference<io::XOutputStream> const xOutStream =
GetFilter().openFragmentStream("word/" + sFileName, sMediaType);
assert(xOutStream.is()); // no reason why that could fail
try
{
::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
}
catch (uno::Exception const& e)
{
SAL_WARN("sw.ww8", "DocxExport::WriteOLEObject: " << e);
return OString();
}
OUString const sId = m_pFilter->addRelation( GetFS()->getOutputStream(),
sRelationType, sFileName );
if (pProgID)
{
io_rProgID = OUString::createFromAscii(pProgID);
}
return OUStringToOString( sId, RTL_TEXTENCODING_UTF8 );
}
std::pair<OString, OString> DocxExport::WriteActiveXObject(const uno::Reference<drawing::XShape>& rxShape,
const uno::Reference<awt::XControlModel>& rxControlModel)
{
++m_nActiveXControls;
// Write out ActiveX binary
const OUString sBinaryFileName = "word/activeX/activeX" + OUString::number(m_nActiveXControls) + ".bin";
OString sGUID;
OString sName;
uno::Reference<io::XStream> xOutStorage(m_pFilter->openFragmentStream(sBinaryFileName, "application/vnd.ms-office.activeX"), uno::UNO_QUERY);
if(xOutStorage.is())
{
oox::ole::OleStorage aOleStorage(m_pFilter->getComponentContext(), xOutStorage, false);
uno::Reference<io::XOutputStream> xOutputStream(aOleStorage.openOutputStream("contents"), uno::UNO_SET_THROW);
uno::Reference< css::frame::XModel > xModel( m_pDoc->GetDocShell() ? m_pDoc->GetDocShell()->GetModel() : nullptr );
oox::ole::OleFormCtrlExportHelper exportHelper(comphelper::getProcessComponentContext(), xModel, rxControlModel);
if ( !exportHelper.isValid() )
return std::make_pair<OString, OString>(OString(), OString());
sGUID = OUStringToOString(exportHelper.getGUID(), RTL_TEXTENCODING_UTF8);
sName = OUStringToOString(exportHelper.getName(), RTL_TEXTENCODING_UTF8);
exportHelper.exportControl(xOutputStream, rxShape->getSize(), true);
aOleStorage.commit();
}
// Write out ActiveX fragment
const OUString sXMLFileName = "word/activeX/activeX" + OUString::number( m_nActiveXControls ) + ".xml";
::sax_fastparser::FSHelperPtr pActiveXFS = m_pFilter->openFragmentStreamWithSerializer(sXMLFileName, "application/vnd.ms-office.activeX+xml" );
const OUString sBinaryId = m_pFilter->addRelation( pActiveXFS->getOutputStream(),
oox::getRelationship(Relationship::ACTIVEXCONTROLBINARY),
sBinaryFileName.copy(sBinaryFileName.lastIndexOf("/") + 1) );
pActiveXFS->singleElementNS(XML_ax, XML_ocx,
FSNS(XML_xmlns, XML_ax), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(ax)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS(XML_xmlns, XML_r), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS(XML_ax, XML_classid), OString("{" + sGUID + "}").getStr(),
FSNS(XML_ax, XML_persistence), "persistStorage",
FSNS(XML_r, XML_id), OUStringToOString(sBinaryId, RTL_TEXTENCODING_UTF8).getStr(), FSEND);
OString sXMLId = OUStringToOString(m_pFilter->addRelation(m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::CONTROL),
sXMLFileName.copy(sBinaryFileName.indexOf("/") + 1)),
RTL_TEXTENCODING_UTF8);
return std::pair<OString, OString>(sXMLId, sName);
}
void DocxExport::OutputDML(uno::Reference<drawing::XShape> const & xShape)
{
uno::Reference<lang::XServiceInfo> xServiceInfo(xShape, uno::UNO_QUERY_THROW);
sal_Int32 nNamespace = XML_wps;
if (xServiceInfo->supportsService("com.sun.star.drawing.GroupShape"))
nNamespace = XML_wpg;
else if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape"))
nNamespace = XML_pic;
oox::drawingml::ShapeExport aExport(nNamespace, m_pAttrOutput->GetSerializer(), nullptr, m_pFilter, oox::drawingml::DOCUMENT_DOCX, m_pAttrOutput.get());
aExport.WriteShape(xShape);
}
ErrCode DocxExport::ExportDocument_Impl()
{
// Set the 'Track Revisions' flag in the settings structure
m_aSettings.trackRevisions = bool( RedlineFlags::On & m_nOrigRedlineFlags );
InitStyles();
// init sections
m_pSections.reset(new MSWordSections( *this ));
// Make sure images are counted from one, even when exporting multiple documents.
oox::drawingml::DrawingML::ResetCounters();
WriteMainText();
WriteFootnotesEndnotes();
WritePostitFields();
WriteNumbering();
WriteFonts();
WriteSettings();
WriteTheme();
WriteGlossary();
WriteCustomXml();
WriteEmbeddings();
WriteVBA();
m_aLinkedTextboxesHelper.clear(); //final cleanup
delete m_pStyles;
m_pStyles = nullptr;
m_pSections.reset();
return ERRCODE_NONE;
}
void DocxExport::AppendSection( const SwPageDesc *pPageDesc, const SwSectionFormat* pFormat, sal_uLong nLnNum )
{
AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
m_pSections->AppendSection( pPageDesc, pFormat, nLnNum, m_pAttrOutput->IsFirstParagraph() );
}
void DocxExport::OutputEndNode( const SwEndNode& rEndNode )
{
MSWordExportBase::OutputEndNode( rEndNode );
if ( TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsSectionNode() )
{
// this originally comes from WW8Export::WriteText(), and looks like it
// could have some code common with SectionNode()...
const SwSection& rSect = rEndNode.StartOfSectionNode()->GetSectionNode()->GetSection();
if ( m_bStartTOX && TOX_CONTENT_SECTION == rSect.GetType() )
m_bStartTOX = false;
SwNodeIndex aIdx( rEndNode, 1 );
const SwNode& rNd = aIdx.GetNode();
if ( rNd.IsEndNode() && rNd.StartOfSectionNode()->IsSectionNode() )
return;
bool isInTable = IsInTable();
if ( !rNd.IsSectionNode() && isInTable ) // No sections in table
{
const SwSectionFormat* pParentFormat = rSect.GetFormat()->GetParent();
if( !pParentFormat )
pParentFormat = reinterpret_cast<SwSectionFormat*>(sal_IntPtr(-1));
sal_uLong nRstLnNum;
if( rNd.IsContentNode() )
nRstLnNum = rNd.GetContentNode()->GetSwAttrSet().GetLineNumber().GetStartValue();
else
nRstLnNum = 0;
AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo( ) );
m_pSections->AppendSection( m_pCurrentPageDesc, pParentFormat, nRstLnNum );
}
else
{
AttrOutput().SectionBreaks( rEndNode );
}
}
else if (TXT_MAINTEXT == m_nTextTyp && rEndNode.StartOfSectionNode()->IsTableNode())
// End node of a table: see if a section break should be written after the table.
AttrOutput().SectionBreaks(rEndNode);
}
void DocxExport::OutputGrfNode( const SwGrfNode& )
{
SAL_INFO("sw.ww8", "TODO DocxExport::OutputGrfNode( const SwGrfNode& )" );
}
void DocxExport::OutputOLENode( const SwOLENode& )
{
SAL_INFO("sw.ww8", "TODO DocxExport::OutputOLENode( const SwOLENode& )" );
}
void DocxExport::OutputLinkedOLE( const OUString& )
{
// Nothing to implement here: WW8 only
}
sal_uLong DocxExport::ReplaceCr( sal_uInt8 )
{
// Completely unused for Docx export... only here for code sharing
// purpose with binary export
return 0;
}
void DocxExport::PrepareNewPageDesc( const SfxItemSet* pSet,
const SwNode& rNd, const SwFormatPageDesc* pNewPgDescFormat,
const SwPageDesc* pNewPgDesc )
{
// tell the attribute output that we are ready to write the section
// break [has to be output inside paragraph properties]
AttrOutput().SectionBreak( msword::PageBreak, m_pSections->CurrentSectionInfo() );
const SwSectionFormat* pFormat = GetSectionFormat( rNd );
const sal_uLong nLnNm = GetSectionLineNo( pSet, rNd );
OSL_ENSURE( pNewPgDescFormat || pNewPgDesc, "Neither page desc format nor page desc provided." );
if ( pNewPgDescFormat )
{
m_pSections->AppendSection( *pNewPgDescFormat, rNd, pFormat, nLnNm );
}
else if ( pNewPgDesc )
{
m_pSections->AppendSection( pNewPgDesc, rNd, pFormat, nLnNm );
}
}
void DocxExport::InitStyles()
{
m_pStyles = new MSWordStyles( *this, /*bListStyles =*/ true );
// setup word/styles.xml and the relations + content type
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::STYLES),
"styles.xml" );
::sax_fastparser::FSHelperPtr pStylesFS =
m_pFilter->openFragmentStreamWithSerializer( "word/styles.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml" );
// switch the serializer to redirect the output to word/styles.xml
m_pAttrOutput->SetSerializer( pStylesFS );
// do the work
m_pStyles->OutputStylesTable();
// switch the serializer back
m_pAttrOutput->SetSerializer( m_pDocumentFS );
}
void DocxExport::WriteFootnotesEndnotes()
{
if ( m_pAttrOutput->HasFootnotes() )
{
// setup word/styles.xml and the relations + content type
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::FOOTNOTES),
"footnotes.xml" );
::sax_fastparser::FSHelperPtr pFootnotesFS =
m_pFilter->openFragmentStreamWithSerializer( "word/footnotes.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml" );
// switch the serializer to redirect the output to word/footnotes.xml
m_pAttrOutput->SetSerializer( pFootnotesFS );
// tdf#99227
m_pSdrExport->setSerializer( pFootnotesFS );
// tdf#107969
m_pVMLExport->SetFS(pFootnotesFS);
// do the work
m_pAttrOutput->FootnotesEndnotes( true );
// switch the serializer back
m_pVMLExport->SetFS(m_pDocumentFS);
m_pSdrExport->setSerializer( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
}
if ( m_pAttrOutput->HasEndnotes() )
{
// setup word/styles.xml and the relations + content type
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::ENDNOTES),
"endnotes.xml" );
::sax_fastparser::FSHelperPtr pEndnotesFS =
m_pFilter->openFragmentStreamWithSerializer( "word/endnotes.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml" );
// switch the serializer to redirect the output to word/endnotes.xml
m_pAttrOutput->SetSerializer( pEndnotesFS );
// tdf#99227
m_pSdrExport->setSerializer( pEndnotesFS );
// tdf#107969
m_pVMLExport->SetFS(pEndnotesFS);
// do the work
m_pAttrOutput->FootnotesEndnotes( false );
// switch the serializer back
m_pVMLExport->SetFS(m_pDocumentFS);
m_pSdrExport->setSerializer( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
}
}
void DocxExport::WritePostitFields()
{
if ( m_pAttrOutput->HasPostitFields() )
{
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::COMMENTS),
"comments.xml" );
::sax_fastparser::FSHelperPtr pPostitFS =
m_pFilter->openFragmentStreamWithSerializer( "word/comments.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" );
pPostitFS->startElementNS( XML_w, XML_comments, MainXmlNamespaces());
m_pAttrOutput->SetSerializer( pPostitFS );
m_pAttrOutput->WritePostitFields();
m_pAttrOutput->SetSerializer( m_pDocumentFS );
pPostitFS->endElementNS( XML_w, XML_comments );
}
}
void DocxExport::WriteNumbering()
{
if ( !m_pUsedNumTable )
return; // no numbering is used
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::NUMBERING),
"numbering.xml" );
::sax_fastparser::FSHelperPtr pNumberingFS = m_pFilter->openFragmentStreamWithSerializer( "word/numbering.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml" );
// switch the serializer to redirect the output to word/numbering.xml
m_pAttrOutput->SetSerializer( pNumberingFS );
m_pDrawingML->SetFS( pNumberingFS );
pNumberingFS->startElementNS( XML_w, XML_numbering,
FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr(),
FSEND );
BulletDefinitions();
AbstractNumberingDefinitions();
NumberingDefinitions();
pNumberingFS->endElementNS( XML_w, XML_numbering );
// switch the serializer back
m_pDrawingML->SetFS( m_pDocumentFS );
m_pAttrOutput->SetSerializer( m_pDocumentFS );
}
void DocxExport::WriteHeaderFooter( const SwFormat* pFormat, bool bHeader, const char* pType )
{
// setup the xml stream
OUString aRelId;
::sax_fastparser::FSHelperPtr pFS;
if ( bHeader )
{
OUString aName( "header" + OUString::number( ++m_nHeaders ) + ".xml" );
aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::HEADER),
aName );
pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
"application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" );
pFS->startElementNS( XML_w, XML_hdr, MainXmlNamespaces());
}
else
{
OUString aName( "footer" + OUString::number( ++m_nFooters ) + ".xml" );
aRelId = m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::FOOTER),
aName );
pFS = m_pFilter->openFragmentStreamWithSerializer( "word/" + aName,
"application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" );
pFS->startElementNS( XML_w, XML_ftr, MainXmlNamespaces());
}
// switch the serializer to redirect the output to word/styles.xml
m_pAttrOutput->SetSerializer( pFS );
m_pVMLExport->SetFS( pFS );
m_pSdrExport->setSerializer(pFS);
SetFS( pFS );
{
DocxTableExportContext aTableExportContext(*m_pAttrOutput);
//When the stream changes the cache which is maintained for the graphics in case of alternate content is not cleared.
//So clearing the alternate content graphic cache.
m_pAttrOutput->PushRelIdCache();
// do the work
if (pFormat == nullptr)
AttrOutput().EmptyParagraph();
else
WriteHeaderFooterText(*pFormat, bHeader);
m_pAttrOutput->PopRelIdCache();
m_pAttrOutput->EndParaSdtBlock();
}
// switch the serializer back
m_pAttrOutput->SetSerializer( m_pDocumentFS );
m_pVMLExport->SetFS( m_pDocumentFS );
m_pSdrExport->setSerializer(m_pDocumentFS);
SetFS( m_pDocumentFS );
// close the tag
sal_Int32 nReference;
if ( bHeader )
{
pFS->endElementNS( XML_w, XML_hdr );
nReference = XML_headerReference;
}
else
{
pFS->endElementNS( XML_w, XML_ftr );
nReference = XML_footerReference;
}
// and write the reference
m_pDocumentFS->singleElementNS( XML_w, nReference,
FSNS( XML_w, XML_type ), pType,
FSNS( XML_r, XML_id ), aRelId.toUtf8().getStr(),
FSEND );
}
void DocxExport::WriteFonts()
{
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::FONTTABLE),
"fontTable.xml" );
::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
"word/fontTable.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml" );
pFS->startElementNS( XML_w, XML_fonts,
FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr(),
FSEND );
// switch the serializer to redirect the output to word/styles.xml
m_pAttrOutput->SetSerializer( pFS );
// do the work
m_aFontHelper.WriteFontTable( *m_pAttrOutput );
// switch the serializer back
m_pAttrOutput->SetSerializer( m_pDocumentFS );
pFS->endElementNS( XML_w, XML_fonts );
}
void DocxExport::WriteProperties( )
{
// Write the core properties
SwDocShell* pDocShell( m_pDoc->GetDocShell( ) );
uno::Reference<document::XDocumentProperties> xDocProps;
bool bSecurityOptOpenReadOnly = false;
if ( pDocShell )
{
uno::Reference<document::XDocumentPropertiesSupplier> xDPS(
pDocShell->GetModel( ), uno::UNO_QUERY );
xDocProps = xDPS->getDocumentProperties();
bSecurityOptOpenReadOnly = pDocShell->IsSecurityOptOpenReadOnly();
}
m_pFilter->exportDocumentProperties( xDocProps, bSecurityOptOpenReadOnly );
}
void DocxExport::WriteSettings()
{
SwViewShell *pViewShell(m_pDoc->getIDocumentLayoutAccess().GetCurrentViewShell());
if( !pViewShell && !m_aSettings.hasData() && !m_pAttrOutput->HasFootnotes() && !m_pAttrOutput->HasEndnotes())
return;
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::SETTINGS),
"settings.xml" );
::sax_fastparser::FSHelperPtr pFS = m_pFilter->openFragmentStreamWithSerializer(
"word/settings.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml" );
pFS->startElementNS( XML_w, XML_settings,
FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr(),
FSEND );
// View
if (pViewShell && pViewShell->GetViewOptions()->getBrowseMode())
{
pFS->singleElementNS(XML_w, XML_view, FSNS(XML_w, XML_val), "web", FSEND);
}
// Zoom
if (pViewShell)
{
OString aZoom(OString::number(pViewShell->GetViewOptions()->GetZoom()));
pFS->singleElementNS(XML_w, XML_zoom, FSNS(XML_w, XML_percent), aZoom.getStr(), FSEND);
}
// Display Background Shape
if (boost::optional<SvxBrushItem> oBrush = getBackground())
{
// Turn on the 'displayBackgroundShape'
pFS->singleElementNS( XML_w, XML_displayBackgroundShape, FSEND );
}
// Track Changes
if ( m_aSettings.trackRevisions )
pFS->singleElementNS( XML_w, XML_trackRevisions, FSEND );
// Mirror Margins
if(isMirroredMargin())
pFS->singleElementNS( XML_w, XML_mirrorMargins, FSEND );
// Embed Fonts
if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_FONTS ))
pFS->singleElementNS( XML_w, XML_embedTrueTypeFonts, FSEND );
// Embed System Fonts
if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::EMBED_SYSTEM_FONTS ))
pFS->singleElementNS( XML_w, XML_embedSystemFonts, FSEND );
// Default Tab Stop
if( m_aSettings.defaultTabStop != 0 )
pFS->singleElementNS( XML_w, XML_defaultTabStop, FSNS( XML_w, XML_val ),
OString::number( m_aSettings.defaultTabStop).getStr(), FSEND );
// Do not justify lines with manual break
if( m_pDoc->getIDocumentSettingAccess().get( DocumentSettingId::DO_NOT_JUSTIFY_LINES_WITH_MANUAL_BREAK ))
{
pFS->startElementNS( XML_w, XML_compat, FSEND );
pFS->singleElementNS( XML_w, XML_doNotExpandShiftReturn, FSEND );
pFS->endElementNS( XML_w, XML_compat );
}
// Automatic hyphenation: it's a global setting in Word, it's a paragraph setting in Writer.
// Use the setting from the default style.
SwTextFormatColl* pColl = m_pDoc->getIDocumentStylePoolAccess().GetTextCollFromPool(RES_POOLCOLL_STANDARD, /*bRegardLanguage=*/false);
const SfxPoolItem* pItem;
if (pColl && SfxItemState::SET == pColl->GetItemState(RES_PARATR_HYPHENZONE, false, &pItem))
{
pFS->singleElementNS(XML_w, XML_autoHyphenation,
FSNS(XML_w, XML_val), OString::boolean(static_cast<const SvxHyphenZoneItem*>(pItem)->IsHyphen()),
FSEND);
}
// Even and Odd Headers
if( m_aSettings.evenAndOddHeaders )
pFS->singleElementNS( XML_w, XML_evenAndOddHeaders, FSEND );
// Has Footnotes
if( m_pAttrOutput->HasFootnotes())
DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_footnotePr, m_pDoc->GetFootnoteInfo(), XML_footnote );
// Has Endnotes
if( m_pAttrOutput->HasEndnotes())
DocxAttributeOutput::WriteFootnoteEndnotePr( pFS, XML_endnotePr, m_pDoc->GetEndNoteInfo(), XML_endnote );
// Has themeFontLang information
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
bool hasProtectionProperties = false;
uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
const OUString aGrabBagName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
if ( xPropSetInfo->hasPropertyByName( aGrabBagName ) )
{
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aGrabBagName ) >>= propList;
for( sal_Int32 i=0; i < propList.getLength(); ++i )
{
if ( propList[i].Name == "ThemeFontLangProps" )
{
uno::Sequence< beans::PropertyValue > themeFontLangProps;
propList[i].Value >>= themeFontLangProps;
OUString aValues[3];
for( sal_Int32 j=0; j < themeFontLangProps.getLength(); ++j )
{
if( themeFontLangProps[j].Name == "val" )
themeFontLangProps[j].Value >>= aValues[0];
else if( themeFontLangProps[j].Name == "eastAsia" )
themeFontLangProps[j].Value >>= aValues[1];
else if( themeFontLangProps[j].Name == "bidi" )
themeFontLangProps[j].Value >>= aValues[2];
}
pFS->singleElementNS( XML_w, XML_themeFontLang,
FSNS( XML_w, XML_val ), OUStringToOString( aValues[0], RTL_TEXTENCODING_UTF8 ).getStr(),
FSNS( XML_w, XML_eastAsia ), OUStringToOString( aValues[1], RTL_TEXTENCODING_UTF8 ).getStr(),
FSNS( XML_w, XML_bidi ), OUStringToOString( aValues[2], RTL_TEXTENCODING_UTF8 ).getStr(),
FSEND );
}
else if ( propList[i].Name == "CompatSettings" )
{
pFS->startElementNS( XML_w, XML_compat, FSEND );
uno::Sequence< beans::PropertyValue > aCompatSettingsSequence;
propList[i].Value >>= aCompatSettingsSequence;
for(sal_Int32 j=0; j < aCompatSettingsSequence.getLength(); ++j)
{
uno::Sequence< beans::PropertyValue > aCompatSetting;
aCompatSettingsSequence[j].Value >>= aCompatSetting;
OUString aName;
OUString aUri;
OUString aValue;
for(sal_Int32 k=0; k < aCompatSetting.getLength(); ++k)
{
if( aCompatSetting[k].Name == "name" )
aCompatSetting[k].Value >>= aName;
else if( aCompatSetting[k].Name == "uri" )
aCompatSetting[k].Value >>= aUri;
else if( aCompatSetting[k].Name == "val" )
aCompatSetting[k].Value >>= aValue;
}
pFS->singleElementNS( XML_w, XML_compatSetting,
FSNS( XML_w, XML_name ), OUStringToOString(aName, RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_w, XML_uri ), OUStringToOString(aUri, RTL_TEXTENCODING_UTF8).getStr(),
FSNS( XML_w, XML_val ), OUStringToOString(aValue, RTL_TEXTENCODING_UTF8).getStr(),
FSEND);
}
pFS->endElementNS( XML_w, XML_compat );
}
else if (propList[i].Name == "DocumentProtection")
{
uno::Sequence< beans::PropertyValue > rAttributeList;
propList[i].Value >>= rAttributeList;
if (rAttributeList.getLength())
{
sax_fastparser::FastAttributeList* pAttributeList = sax_fastparser::FastSerializerHelper::createAttrList();
for (sal_Int32 j = 0; j < rAttributeList.getLength(); ++j)
{
static DocxStringTokenMap const aTokens[] =
{
{ "edit", XML_edit },
{ "enforcement", XML_enforcement },
{ "formatting", XML_formatting },
{ "cryptProviderType", XML_cryptProviderType },
{ "cryptAlgorithmClass", XML_cryptAlgorithmClass },
{ "cryptAlgorithmType", XML_cryptAlgorithmType },
{ "cryptAlgorithmSid", XML_cryptAlgorithmSid },
{ "cryptSpinCount", XML_cryptSpinCount },
{ "hash", XML_hash },
{ "salt", XML_salt },
{ nullptr, 0 }
};
if (sal_Int32 nToken = DocxStringGetToken(aTokens, rAttributeList[j].Name))
pAttributeList->add(FSNS(XML_w, nToken), rAttributeList[j].Value.get<OUString>().toUtf8());
}
// we have document protection from input DOCX file
sax_fastparser::XFastAttributeListRef xAttributeList(pAttributeList);
pFS->singleElementNS(XML_w, XML_documentProtection, xAttributeList);
hasProtectionProperties = true;
}
}
}
}
// Protect form
// Section-specific write protection
if (! hasProtectionProperties)
{
if (m_pDoc->getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_FORM) ||
m_pSections->DocumentIsProtected())
{
// we have form protection from Writer or from input ODT file
pFS->singleElementNS(XML_w, XML_documentProtection,
FSNS(XML_w, XML_edit), "forms",
FSNS(XML_w, XML_enforcement), "true",
FSEND);
}
}
// finish settings.xml
pFS->endElementNS( XML_w, XML_settings );
}
void DocxExport::WriteTheme()
{
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
if ( !xPropSetInfo->hasPropertyByName( aName ) )
return;
uno::Reference<xml::dom::XDocument> themeDom;
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aName ) >>= propList;
for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
{
OUString propName = propList[nProp].Name;
if ( propName == "OOXTheme" )
{
propList[nProp].Value >>= themeDom;
break;
}
}
// no theme dom to write
if ( !themeDom.is() )
return;
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::THEME),
"theme/theme1.xml" );
uno::Reference< xml::sax::XSAXSerializable > serializer( themeDom, uno::UNO_QUERY );
uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
writer->setOutputStream( GetFilter().openFragmentStream( "word/theme/theme1.xml",
"application/vnd.openxmlformats-officedocument.theme+xml" ) );
serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
}
void DocxExport::WriteGlossary()
{
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
if ( !xPropSetInfo->hasPropertyByName( aName ) )
return;
uno::Reference<xml::dom::XDocument> glossaryDocDom;
uno::Sequence< uno::Sequence< uno::Any> > glossaryDomList;
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aName ) >>= propList;
sal_Int32 collectedProperties = 0;
for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
{
OUString propName = propList[nProp].Name;
if ( propName == "OOXGlossary" )
{
propList[nProp].Value >>= glossaryDocDom;
collectedProperties++;
}
if (propName == "OOXGlossaryDom")
{
propList[nProp].Value >>= glossaryDomList;
collectedProperties++;
}
if (collectedProperties == 2)
break;
}
// no glossary dom to write
if ( !glossaryDocDom.is() )
return;
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::GLOSSARYDOCUMENT),
"glossary/document.xml" );
uno::Reference< io::XOutputStream > xOutputStream = GetFilter().openFragmentStream( "word/glossary/document.xml",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document.glossary+xml" );
uno::Reference< xml::sax::XSAXSerializable > serializer( glossaryDocDom, uno::UNO_QUERY );
uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
writer->setOutputStream( xOutputStream );
serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
sal_Int32 length = glossaryDomList.getLength();
for ( int i =0; i < length; i++)
{
uno::Sequence< uno::Any> glossaryElement = glossaryDomList[i];
OUString gTarget, gType, gId, contentType;
uno::Reference<xml::dom::XDocument> xDom;
glossaryElement[0] >>= xDom;
glossaryElement[1] >>= gId;
glossaryElement[2] >>= gType;
glossaryElement[3] >>= gTarget;
glossaryElement[4] >>= contentType;
gId = gId.copy(3); //"rId" only save the numeric value
PropertySet aProps(xOutputStream);
aProps.setAnyProperty( PROP_RelId, uno::makeAny( gId.toInt32() ));
m_pFilter->addRelation( xOutputStream, gType, gTarget);
uno::Reference< xml::sax::XSAXSerializable > gserializer( xDom, uno::UNO_QUERY );
writer->setOutputStream(GetFilter().openFragmentStream( "word/glossary/" + gTarget, contentType ) );
gserializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
}
}
void DocxExport::WriteCustomXml()
{
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
static const OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
if ( !xPropSetInfo->hasPropertyByName( aName ) )
return;
uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomlist;
uno::Sequence<uno::Reference<xml::dom::XDocument> > customXmlDomPropslist;
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aName ) >>= propList;
for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
{
const OUString propName = propList[nProp].Name;
if ( propName == "OOXCustomXml" )
{
propList[nProp].Value >>= customXmlDomlist;
break;
}
}
for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
{
OUString propName = propList[nProp].Name;
if ( propName == "OOXCustomXmlProps" )
{
propList[nProp].Value >>= customXmlDomPropslist;
break;
}
}
for (sal_Int32 j = 0; j < customXmlDomlist.getLength(); j++)
{
uno::Reference<xml::dom::XDocument> customXmlDom = customXmlDomlist[j];
uno::Reference<xml::dom::XDocument> customXmlDomProps = customXmlDomPropslist[j];
if (customXmlDom.is())
{
m_pFilter->addRelation( m_pDocumentFS->getOutputStream(),
oox::getRelationship(Relationship::CUSTOMXML),
"../customXml/item"+OUString::number((j+1))+".xml" );
uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDom, uno::UNO_QUERY );
uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
writer->setOutputStream( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
"application/xml" ) );
serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
}
if (customXmlDomProps.is())
{
uno::Reference< xml::sax::XSAXSerializable > serializer( customXmlDomProps, uno::UNO_QUERY );
uno::Reference< xml::sax::XWriter > writer = xml::sax::Writer::create( comphelper::getProcessComponentContext() );
writer->setOutputStream( GetFilter().openFragmentStream( "customXml/itemProps"+OUString::number((j+1))+".xml",
"application/vnd.openxmlformats-officedocument.customXmlProperties+xml" ) );
serializer->serialize( uno::Reference< xml::sax::XDocumentHandler >( writer, uno::UNO_QUERY_THROW ),
uno::Sequence< beans::StringPair >() );
// Adding itemprops's relationship entry to item.xml.rels file
m_pFilter->addRelation( GetFilter().openFragmentStream( "customXml/item"+OUString::number((j+1))+".xml",
"application/xml" ) ,
oox::getRelationship(Relationship::CUSTOMXMLPROPS),
"itemProps"+OUString::number((j+1))+".xml" );
}
}
}
void DocxExport::WriteVBA()
{
uno::Reference<document::XStorageBasedDocument> xStorageBasedDocument(m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY);
if (!xStorageBasedDocument.is())
return;
uno::Reference<embed::XStorage> xDocumentStorage(xStorageBasedDocument->getDocumentStorage(), uno::UNO_QUERY);
OUString aMacrosName("_MS_VBA_Macros");
if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aMacrosName))
return;
const sal_Int32 nOpenMode = embed::ElementModes::READ;
uno::Reference<io::XStream> xMacrosStream(xDocumentStorage->openStreamElement(aMacrosName, nOpenMode), uno::UNO_QUERY);
uno::Reference<io::XOutputStream> xProjectStream;
if (xMacrosStream.is())
{
// First handle the project stream, this sets xProjectStream.
std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xMacrosStream));
xProjectStream = GetFilter().openFragmentStream("word/vbaProject.bin", "application/vnd.ms-office.vbaProject");
uno::Reference<io::XStream> xOutputStream(xProjectStream, uno::UNO_QUERY);
if (!xOutputStream.is())
return;
std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
// Write the stream.
pOut->WriteStream(*pIn);
// Write the relationship.
m_pFilter->addRelation(m_pDocumentFS->getOutputStream(), oox::getRelationship(Relationship::VBAPROJECT), "vbaProject.bin");
}
OUString aDataName("_MS_VBA_Macros_XML");
if (!xDocumentStorage.is() || !xDocumentStorage->hasByName(aDataName))
return;
uno::Reference<io::XStream> xDataStream(xDocumentStorage->openStreamElement(aDataName, nOpenMode), uno::UNO_QUERY);
if (xDataStream.is())
{
// Then the data stream, which wants to work with an already set
// xProjectStream.
std::unique_ptr<SvStream> pIn(utl::UcbStreamHelper::CreateStream(xDataStream));
uno::Reference<io::XStream> xOutputStream(GetFilter().openFragmentStream("word/vbaData.xml", "application/vnd.ms-word.vbaData+xml"), uno::UNO_QUERY);
if (!xOutputStream.is())
return;
std::unique_ptr<SvStream> pOut(utl::UcbStreamHelper::CreateStream(xOutputStream));
// Write the stream.
pOut->WriteStream(*pIn);
// Write the relationship.
if (!xProjectStream.is())
return;
m_pFilter->addRelation(xProjectStream, oox::getRelationship(Relationship::WORDVBADATA), "vbaData.xml");
}
}
void DocxExport::WriteEmbeddings()
{
uno::Reference< beans::XPropertySet > xPropSet( m_pDoc->GetDocShell()->GetBaseModel(), uno::UNO_QUERY_THROW );
uno::Reference< beans::XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
OUString aName = UNO_NAME_MISC_OBJ_INTEROPGRABBAG;
if ( !xPropSetInfo->hasPropertyByName( aName ) )
return;
uno::Sequence< beans::PropertyValue > embeddingsList;
uno::Sequence< beans::PropertyValue > propList;
xPropSet->getPropertyValue( aName ) >>= propList;
for ( sal_Int32 nProp=0; nProp < propList.getLength(); ++nProp )
{
OUString propName = propList[nProp].Name;
if ( propName == "OOXEmbeddings" )
{
propList[nProp].Value >>= embeddingsList;
break;
}
}
for (sal_Int32 j = 0; j < embeddingsList.getLength(); j++)
{
OUString embeddingPath = embeddingsList[j].Name;
uno::Reference<io::XInputStream> embeddingsStream;
embeddingsList[j].Value >>= embeddingsStream;
OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
// FIXME: this .xlsm hack is silly - if anything the mime-type for an existing embedded object should be read from [Content_Types].xml
if (embeddingPath.endsWith(".xlsm"))
contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
else if (embeddingPath.endsWith(".bin"))
contentType = "application/vnd.openxmlformats-officedocument.oleObject";
if ( embeddingsStream.is() )
{
uno::Reference< io::XOutputStream > xOutStream = GetFilter().openFragmentStream(embeddingPath,
contentType);
try
{
sal_Int32 nBufferSize = 512;
uno::Sequence< sal_Int8 > aDataBuffer(nBufferSize);
sal_Int32 nRead;
do
{
nRead = embeddingsStream->readBytes( aDataBuffer, nBufferSize );
if( nRead )
{
if( nRead < nBufferSize )
{
nBufferSize = nRead;
aDataBuffer.realloc(nRead);
}
xOutStream->writeBytes( aDataBuffer );
}
}
while( nRead );
xOutStream->flush();
}
catch(const uno::Exception&)
{
SAL_WARN("sw.ww8", "WriteEmbeddings() ::Failed to copy Inputstream to outputstream exception caught!");
}
xOutStream->closeOutput();
}
}
}
bool DocxExport::isMirroredMargin()
{
bool bMirroredMargins = false;
if ( UseOnPage::Mirror == (UseOnPage::Mirror & m_pDoc->GetPageDesc(0).ReadUseOn()) )
{
bMirroredMargins = true;
}
return bMirroredMargins;
}
void DocxExport::WriteMainText()
{
// setup the namespaces
m_pDocumentFS->startElementNS( XML_w, XML_document, MainXmlNamespaces());
// reset the incrementing linked-textboxes chain ID before re-saving.
m_nLinkedTextboxesChainId=0;
m_aLinkedTextboxesHelper.clear();
// Write background page color
if (boost::optional<SvxBrushItem> oBrush = getBackground())
{
Color backgroundColor = oBrush->GetColor();
OString aBackgroundColorStr = msfilter::util::ConvertColor(backgroundColor);
m_pDocumentFS->singleElementNS( XML_w, XML_background, FSNS( XML_w, XML_color ), aBackgroundColorStr, FSEND );
}
// body
m_pDocumentFS->startElementNS( XML_w, XML_body, FSEND );
m_pCurPam->GetPoint()->nNode = m_pDoc->GetNodes().GetEndOfContent().StartOfSectionNode()->GetIndex();
// the text
WriteText();
// clear linked textboxes since old ones can't be linked to frames in a different section (correct?)
m_aLinkedTextboxesHelper.clear();
// the last section info
m_pAttrOutput->EndParaSdtBlock();
const WW8_SepInfo *pSectionInfo = m_pSections? m_pSections->CurrentSectionInfo(): nullptr;
if ( pSectionInfo )
SectionProperties( *pSectionInfo );
// finish body and document
m_pDocumentFS->endElementNS( XML_w, XML_body );
m_pDocumentFS->endElementNS( XML_w, XML_document );
}
XFastAttributeListRef DocxExport::MainXmlNamespaces()
{
FastAttributeList* pAttr = FastSerializerHelper::createAttrList();
pAttr->add( FSNS( XML_xmlns, XML_o ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlOffice)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_r ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(officeRel)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_v ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vml)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_w ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(doc)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_w10 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(vmlWord)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_wp ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(dmlWordDr)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_wps ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wps)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_wpg ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wpg)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_mc ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(mce)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_wp14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(wp14)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_xmlns, XML_w14 ), OUStringToOString(m_pFilter->getNamespaceURL(OOX_NS(w14)), RTL_TEXTENCODING_UTF8).getStr() );
pAttr->add( FSNS( XML_mc, XML_Ignorable ), "w14 wp14" );
return XFastAttributeListRef( pAttr );
}
bool DocxExport::ignoreAttributeForStyleDefaults( sal_uInt16 nWhich ) const
{
if( nWhich == RES_TEXTGRID )
return true; // w:docGrid is written only to document.xml, not to styles.xml
if (nWhich == RES_PARATR_HYPHENZONE)
return true; // w:suppressAutoHyphens is only a formatting exception, not a default
return MSWordExportBase::ignoreAttributeForStyleDefaults( nWhich );
}
void DocxExport::WriteOutliner(const OutlinerParaObject& rParaObj, sal_uInt8 nTyp)
{
const EditTextObject& rEditObj = rParaObj.GetTextObject();
MSWord_SdrAttrIter aAttrIter( *this, rEditObj, nTyp );
sal_Int32 nPara = rEditObj.GetParagraphCount();
for( sal_Int32 n = 0; n < nPara; ++n )
{
if( n )
aAttrIter.NextPara( n );
AttrOutput().StartParagraph( ww8::WW8TableNodeInfo::Pointer_t());
rtl_TextEncoding eChrSet = aAttrIter.GetNodeCharSet();
OUString aStr( rEditObj.GetText( n ));
sal_Int32 nCurrentPos = 0;
const sal_Int32 nEnd = aStr.getLength();
do {
AttrOutput().StartRun( nullptr, 0 );
const sal_Int32 nNextAttr = std::min(aAttrIter.WhereNext(), nEnd);
rtl_TextEncoding eNextChrSet = aAttrIter.GetNextCharSet();
bool bTextAtr = aAttrIter.IsTextAttr( nCurrentPos );
if( !bTextAtr )
{
if( nCurrentPos == 0 && nNextAttr - nCurrentPos == aStr.getLength())
AttrOutput().RunText( aStr, eChrSet );
else
{
OUString tmp( aStr.copy( nCurrentPos, nNextAttr - nCurrentPos ));
AttrOutput().RunText( tmp, eChrSet );
}
}
AttrOutput().StartRunProperties();
aAttrIter.OutAttr( nCurrentPos );
AttrOutput().EndRunProperties( nullptr );
nCurrentPos = nNextAttr;
eChrSet = eNextChrSet;
aAttrIter.NextPos();
AttrOutput().EndRun( nullptr, 0 );
} while( nCurrentPos < nEnd );
// aAttrIter.OutParaAttr(false);
AttrOutput().EndParagraph( ww8::WW8TableNodeInfoInner::Pointer_t());
}
}
void DocxExport::SetFS( ::sax_fastparser::FSHelperPtr const & pFS )
{
mpFS = pFS;
}
DocxExport::DocxExport( DocxExportFilter *pFilter, SwDoc *pDocument, SwPaM *pCurrentPam, SwPaM *pOriginalPam, bool bDocm )
: MSWordExportBase( pDocument, pCurrentPam, pOriginalPam ),
m_pFilter( pFilter ),
m_nHeaders( 0 ),
m_nFooters( 0 ),
m_nOLEObjects( 0 ),
m_nActiveXControls( 0 ),
m_nHeadersFootersInSection(0),
m_bDocm(bDocm)
{
// Write the document properties
WriteProperties( );
// relations for the document
m_pFilter->addRelation( oox::getRelationship(Relationship::OFFICEDOCUMENT),
"word/document.xml" );
// DOCM needs a different media type for the document.xml stream.
OUString aMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml";
if (m_bDocm)
aMediaType = "application/vnd.ms-word.document.macroEnabled.main+xml";
// the actual document
m_pDocumentFS = m_pFilter->openFragmentStreamWithSerializer( "word/document.xml", aMediaType );
SetFS(m_pDocumentFS);
// the DrawingML access
m_pDrawingML.reset(new oox::drawingml::DrawingML(m_pDocumentFS, m_pFilter, oox::drawingml::DOCUMENT_DOCX));
// the attribute output for the document
m_pAttrOutput.reset(new DocxAttributeOutput( *this, m_pDocumentFS, m_pDrawingML.get() ));
// the related VMLExport
m_pVMLExport.reset(new VMLExport( m_pDocumentFS, m_pAttrOutput.get() ));
// the related drawing export
m_pSdrExport.reset(new DocxSdrExport( *this, m_pDocumentFS, m_pDrawingML.get() ));
}
DocxExport::~DocxExport()
{
}
DocxSettingsData::DocxSettingsData()
: evenAndOddHeaders( false )
, defaultTabStop( 0 )
, trackRevisions( false )
{
}
bool DocxSettingsData::hasData() const
{
if( evenAndOddHeaders )
return true;
if( defaultTabStop != 0 )
return true;
if ( trackRevisions )
return true;
return false;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V586 The 'clear' function is called twice for deallocation of the same resource. Check lines: 1442, 1462.