summaryrefslogtreecommitdiffstats
path: root/sw/source/filter/ww8/ww8par4.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/filter/ww8/ww8par4.cxx')
-rw-r--r--sw/source/filter/ww8/ww8par4.cxx547
1 files changed, 547 insertions, 0 deletions
diff --git a/sw/source/filter/ww8/ww8par4.cxx b/sw/source/filter/ww8/ww8par4.cxx
new file mode 100644
index 0000000000..46bfa7325d
--- /dev/null
+++ b/sw/source/filter/ww8/ww8par4.cxx
@@ -0,0 +1,547 @@
+/* -*- 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 <doc.hxx>
+#include <IDocumentContentOperations.hxx>
+#include "writerhelper.hxx"
+#include <com/sun/star/embed/XClassifiedObject.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+
+#include <cstddef>
+#include <osl/endian.h>
+#include <sot/storage.hxx>
+#include <com/sun/star/drawing/XShape.hpp>
+#include <hintids.hxx>
+#include <svx/svdoole2.hxx>
+#include <filter/msfilter/msdffimp.hxx>
+#include "sprmids.hxx"
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+
+#include <sot/exchange.hxx>
+#include <fmtanchr.hxx>
+#include <frmfmt.hxx>
+#include <pam.hxx>
+#include <docsh.hxx>
+#include <mdiexp.hxx>
+#include <fltshell.hxx>
+#include <shellio.hxx>
+
+#include <vcl/wmf.hxx>
+#include <vcl/gdimtf.hxx>
+
+#include "ww8scan.hxx"
+#include "ww8par.hxx"
+#include "ww8par2.hxx"
+
+namespace {
+
+struct OLE_MFP
+{
+ sal_Int16 mm; // 0x6 int
+ sal_Int16 xExt; // 0x8 int in 1/100 mm
+ sal_Int16 yExt; // 0xa int in 1/100 mm
+ sal_Int16 hMF; // 0xc int
+};
+
+}
+
+using namespace ::com::sun::star;
+
+static bool SwWw8ReadScaling(tools::Long& rX, tools::Long& rY, tools::SvRef<SotStorage> const & rSrc1)
+{
+ // Getting the scaling factor:
+ // Information in the PIC-stream (by trying out)
+ // 0x0 (l)cb
+ // 0x08 .. 0x0a Flags ??
+ // 0x08 contains: 1 / 0
+ // 0x09 contains: 0,8,0x18
+ // 0x0a contains: always 8, MAP_ANISOTROPIC ???
+ // 0x0b contains: always 0
+ // 0x0c, 0x10 original size x,y in 1/100 mm
+ // 0x14, 0x16 original size x,y in tw
+ // 0x2c, 0x30 scaling x,y in per thousand
+ // 0x34, 0x38, 0x3c, 0x40 Crop Left, Top, Right, Bot in tw
+
+ tools::SvRef<SotStorageStream> xSrc3 = rSrc1->OpenSotStream( "\3PIC",
+ StreamMode::STD_READ );
+ SotStorageStream* pS = xSrc3.get();
+ pS->SetEndian( SvStreamEndian::LITTLE );
+
+ OSL_ENSURE( pS->TellEnd() >= 76, "+OLE-PIC-Stream is shorter than 76 Byte" );
+
+ sal_Int32 nOrgWidth,
+ nOrgHeight,
+ nScaleX,
+ nScaleY,
+ nCropLeft,
+ nCropTop,
+ nCropRight,
+ nCropBottom;
+ pS->Seek( 0x14 );
+ pS->ReadInt32( nOrgWidth ) // Original Size in 1/100 mm
+ .ReadInt32( nOrgHeight );
+ pS->Seek( 0x2c );
+ pS->ReadInt32( nScaleX ) // Scaling in Promille
+ .ReadInt32( nScaleY )
+ .ReadInt32( nCropLeft ) // Cropping in 1/100 mm
+ .ReadInt32( nCropTop )
+ .ReadInt32( nCropRight )
+ .ReadInt32( nCropBottom );
+
+ rX = nOrgWidth - nCropLeft - nCropRight;
+ rY = nOrgHeight - nCropTop - nCropBottom;
+ if (10 > nScaleX || 65536 < nScaleX || 10 > nScaleY || 65536 < nScaleY)
+ {
+ OSL_ENSURE( !pS, "+OLE-scaling information in PIC-stream wrong" );
+ return false;
+ }
+ else
+ {
+ rX = (rX * nScaleX) / 1000;
+ rY = (rY * nScaleY) / 1000;
+ }
+ return true;
+}
+
+static bool SwWw6ReadMetaStream(GDIMetaFile& rWMF, OLE_MFP* pMfp,
+ tools::SvRef<SotStorage> const & rSrc1)
+{
+ tools::SvRef<SotStorageStream> xSrc2 = rSrc1->OpenSotStream( "\3META",
+ StreamMode::STD_READ );
+ SotStorageStream* pSt = xSrc2.get();
+ pSt->SetEndian( SvStreamEndian::LITTLE );
+ size_t const nRead = pSt->ReadBytes(pMfp, sizeof(*pMfp));
+ // read mini-placable-header
+ if (nRead != sizeof(*pMfp))
+ return false;
+
+#if defined OSL_BIGENDIAN
+ pMfp->mm = OSL_SWAPWORD( pMfp->mm );
+ pMfp->xExt = OSL_SWAPWORD( pMfp->xExt );
+ pMfp->yExt = OSL_SWAPWORD( pMfp->yExt );
+#endif // OSL_BIGENDIAN
+
+ if( pMfp->mm == 94 || pMfp->mm == 99 )
+ {
+ SAL_WARN("sw.ww8", "+OLE: wrong metafile type");
+ return false;
+ }
+ if( pMfp->mm != 8 )
+ {
+ SAL_WARN("sw.ww8", "OLE: wrong mMetafile type (not anisotropic)");
+ }
+ if( !pMfp->xExt || !pMfp->yExt )
+ {
+ SAL_WARN("sw.ww8", "+OLE: size of 0?");
+ return false;
+ }
+ bool bOk = ReadWindowMetafile( *pSt, rWMF ); // read WMF
+ // *pSt >> aWMF doesn't work without the placable header
+ if (!bOk || pSt->GetError() || rWMF.GetActionSize() == 0)
+ {
+ SAL_WARN("sw.ww8", "+OLE: could not read the metafile");
+ return false;
+ }
+
+ rWMF.SetPrefMapMode( MapMode( MapUnit::Map100thMM ) );
+
+ // Scale MetaFile to new size and save new size to MetaFile
+ Size aOldSiz( rWMF.GetPrefSize() );
+ Size aNewSiz( pMfp->xExt, pMfp->yExt );
+ Fraction aFracX( aNewSiz.Width(), aOldSiz.Width() );
+ Fraction aFracY( aNewSiz.Height(), aOldSiz.Height() );
+
+ rWMF.Scale( aFracX, aFracY );
+ rWMF.SetPrefSize( aNewSiz );
+
+ return true;
+}
+
+static bool SwWw6ReadMacPICTStream(Graphic& rGraph, tools::SvRef<SotStorage> const & rSrc1)
+{
+ // 03-META-stream does not exist. Maybe a 03-PICT?
+ tools::SvRef<SotStorageStream> xSrc4 = rSrc1->OpenSotStream("\3PICT");
+ SotStorageStream* pStp = xSrc4.get();
+ pStp->SetEndian( SvStreamEndian::LITTLE );
+ sal_uInt8 aTestA[10]; // Does the 01Ole-stream even exist?
+ size_t const nReadTst = pStp->ReadBytes(aTestA, sizeof(aTestA));
+ if (nReadTst != sizeof(aTestA))
+ return false;
+
+ pStp->Seek( STREAM_SEEK_TO_BEGIN );
+
+ // Mac-Pict is in the 03PICT-StorageStream but without the first 512 Bytes
+ // which are not relevant in a MAC-PICT (they are not evaluated)
+ return SwWW8ImplReader::GetPictGrafFromStream(rGraph, *pStp);
+}
+
+SwFlyFrameFormat* SwWW8ImplReader::InsertOle(SdrOle2Obj &rObject,
+ const SfxItemSet &rFlySet, const SfxItemSet *rGrfSet)
+{
+ SfxObjectShell *pPersist = m_rDoc.GetPersist();
+ OSL_ENSURE(pPersist, "No persist, cannot insert objects correctly");
+ if (!pPersist)
+ return nullptr;
+
+ SwFlyFrameFormat *pRet = nullptr;
+
+ std::optional<SfxItemSet> pMathFlySet;
+ uno::Reference < embed::XClassifiedObject > xClass = rObject.GetObjRef();
+ if( xClass.is() )
+ {
+ SvGlobalName aClassName( xClass->getClassID() );
+ if (SotExchange::IsMath(aClassName))
+ {
+ // StarMath sets it own fixed size, so its counter productive to use
+ // the size Word says it is. i.e. Don't attempt to override its size.
+ pMathFlySet.emplace(rFlySet);
+ pMathFlySet->ClearItem(RES_FRM_SIZE);
+ }
+ }
+
+ /*
+ Take complete responsibility of the object away from SdrOle2Obj and to
+ me here locally. This utility class now owns the object.
+ */
+
+ // TODO/MBA: is the object inserted multiple times here? Testing!
+ // And is it a problem that we now use the same naming scheme as in the other apps?
+ sw::hack::DrawingOLEAdaptor aOLEObj(rObject, *pPersist);
+ OUString sNewName;
+ bool bSuccess = aOLEObj.TransferToDoc(sNewName);
+
+ OSL_ENSURE(bSuccess, "Insert OLE failed");
+ if (bSuccess)
+ {
+ const SfxItemSet *pFlySet = pMathFlySet ? &*pMathFlySet : &rFlySet;
+ pRet = m_rDoc.getIDocumentContentOperations().InsertOLE(*m_pPaM, sNewName, rObject.GetAspect(), pFlySet, rGrfSet);
+ }
+ return pRet;
+}
+
+SwFrameFormat* SwWW8ImplReader::ImportOle(const Graphic* pGrf,
+ const SfxItemSet* pFlySet, const SfxItemSet *pGrfSet, const tools::Rectangle& aVisArea )
+{
+ ::SetProgressState(m_nProgress, m_pDocShell); // Update
+ SwFrameFormat* pFormat = nullptr;
+
+ GraphicCtor();
+
+ Graphic aGraph;
+ rtl::Reference<SdrObject> pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );
+
+ // create flyset
+ std::optional<SfxItemSet> pTempSet;
+ if( !pFlySet )
+ {
+ pTempSet.emplace( m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN,
+ RES_FRMATR_END-1> );
+
+ pFlySet = &*pTempSet;
+
+ // Remove distance/borders
+ Reader::ResetFrameFormatAttrs( *pTempSet );
+
+ SwFormatAnchor aAnchor( RndStdIds::FLY_AS_CHAR );
+ aAnchor.SetAnchor( m_pPaM->GetPoint() );
+ pTempSet->Put( aAnchor );
+
+ const Size aSizeTwip = OutputDevice::LogicToLogic(
+ aGraph.GetPrefSize(), aGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
+
+ pTempSet->Put( SwFormatFrameSize( SwFrameSize::Fixed, aSizeTwip.Width(),
+ aSizeTwip.Height() ) );
+ pTempSet->Put( SwFormatVertOrient( 0, text::VertOrientation::TOP, text::RelOrientation::FRAME ));
+
+ if (m_xSFlyPara)
+ {
+ // Resize the frame to the picture size if there is an OLE object
+ // in the frame (only if auto-width)
+ m_xSFlyPara->BoxUpWidth(aSizeTwip.Width());
+ }
+ }
+
+ if (pRet) // OLE object was inserted
+ {
+ if (SdrOle2Obj *pOleObj = dynamic_cast<SdrOle2Obj*>(pRet.get()))
+ {
+ pFormat = InsertOle(*pOleObj, *pFlySet, pGrfSet);
+ pRet.clear(); // we don't need this anymore
+ }
+ else
+ pFormat = m_rDoc.getIDocumentContentOperations().InsertDrawObj(*m_pPaM, *pRet, *pFlySet );
+ }
+ else if (
+ GraphicType::GdiMetafile == aGraph.GetType() ||
+ GraphicType::Bitmap == aGraph.GetType()
+ )
+ {
+ pFormat = m_rDoc.getIDocumentContentOperations().InsertGraphic(
+ *m_pPaM, OUString(), OUString(), &aGraph, pFlySet,
+ pGrfSet, nullptr);
+ }
+ return pFormat;
+}
+
+bool SwWW8ImplReader::ImportOleWMF(const tools::SvRef<SotStorage>& xSrc1, GDIMetaFile& rWMF,
+ tools::Long& rX, tools::Long& rY)
+{
+ bool bOk = false;
+ OLE_MFP aMfp;
+ if( SwWw6ReadMetaStream( rWMF, &aMfp, xSrc1 ) )
+ {
+ // take scaling factor as found in PIC and apply it to graphic.
+ SwWw8ReadScaling( rX, rY, xSrc1 );
+ Size aFinalSize, aOrigSize;
+ aFinalSize.setWidth( rX );
+ aFinalSize.setHeight( rY );
+ aFinalSize = OutputDevice::LogicToLogic(
+ aFinalSize, MapMode(MapUnit::MapTwip), rWMF.GetPrefMapMode() );
+ aOrigSize = rWMF.GetPrefSize();
+ Fraction aScaleX(aFinalSize.Width(),aOrigSize.Width());
+ Fraction aScaleY(aFinalSize.Height(),aOrigSize.Height());
+ rWMF.Scale( aScaleX, aScaleY );
+ bOk = true;
+ }
+ return bOk;
+}
+
+rtl::Reference<SdrObject> SwWW8ImplReader::ImportOleBase( Graphic& rGraph,
+ const Graphic* pGrf, const SfxItemSet* pFlySet, const tools::Rectangle& aVisArea )
+{
+ if (!m_pStg)
+ {
+ SAL_WARN("sw.ww8", "no storage for ole objects");
+ return nullptr;
+ }
+
+ ::SetProgressState( m_nProgress, m_rDoc.GetDocShell() ); // Update
+
+ tools::Long nX=0, nY=0; // nX, nY is graphic size
+ bool bOleOk = true;
+
+ // results in the name "_4711"
+ OUString aSrcStgName = "_" + OUString::number( m_nObjLocFc );
+
+ tools::SvRef<SotStorage> xSrc0 = m_pStg->OpenSotStorage(SL::aObjectPool);
+ tools::SvRef<SotStorage> xSrc1 = xSrc0->OpenSotStorage( aSrcStgName );
+
+ if (pGrf)
+ {
+ rGraph = *pGrf;
+ const Size aSizeTwip = OutputDevice::LogicToLogic(
+ rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
+ nX = aSizeTwip.Width();
+ nY = aSizeTwip.Height();
+ }
+ else
+ {
+ GDIMetaFile aWMF;
+
+ if (ImportOleWMF(xSrc1,aWMF,nX,nY))
+ rGraph = Graphic( aWMF );
+ else if( SwWw6ReadMacPICTStream( rGraph, xSrc1 ) )
+ {
+ // 03-META stream is not available. Maybe it's a 03-PICT?
+ const Size aSizeTwip = OutputDevice::LogicToLogic(
+ rGraph.GetPrefSize(), rGraph.GetPrefMapMode(), MapMode(MapUnit::MapTwip));
+ nX = aSizeTwip.Width();
+ nY = aSizeTwip.Height();
+ // PICT: no WMF available -> Graphic instead of OLE
+ bOleOk = false;
+ }
+ } // StorageStreams closed again
+
+ tools::Rectangle aRect(0, 0, nX, nY);
+
+ if (pFlySet)
+ {
+ if (const SwFormatFrameSize* pSize = pFlySet->GetItem<SwFormatFrameSize>(RES_FRM_SIZE, false))
+ {
+ aRect.SetSize(pSize->GetSize());
+ }
+ }
+
+ rtl::Reference<SdrObject> pRet;
+
+ if (!(m_bIsHeader || m_bIsFooter))
+ {
+ //Can't put them in headers/footers :-(
+ uno::Reference< drawing::XShape > xRef;
+ OSL_ENSURE(m_xFormImpl, "Impossible");
+ if (m_xFormImpl && m_xFormImpl->ReadOCXStream(xSrc1, &xRef))
+ {
+ pRet = SdrObject::getSdrObjectFromXShape(xRef);
+ OSL_ENSURE(pRet, "Impossible");
+ if (pRet)
+ pRet->SetLogicRect(aRect);
+ return pRet;
+ }
+ }
+
+ if (GraphicType::GdiMetafile == rGraph.GetType() ||
+ GraphicType::Bitmap == rGraph.GetType())
+ {
+ ::SetProgressState(m_nProgress, m_pDocShell); // Update
+
+ if (bOleOk)
+ {
+ sal_uInt64 nOldPos = m_pDataStream->Tell();
+ SvStream *pTmpData = nullptr;
+ if (m_nObjLocFc < m_pDataStream->TellEnd())
+ {
+ pTmpData = m_pDataStream;
+ pTmpData->Seek( m_nObjLocFc );
+ }
+
+ sal_Int64 nAspect = embed::Aspects::MSOLE_CONTENT;
+
+ {
+ tools::SvRef<SotStorageStream> xObjInfoSrc = xSrc1->OpenSotStream("\3ObjInfo",
+ StreamMode::STD_READ );
+ if ( xObjInfoSrc.is() && !xObjInfoSrc->GetError() )
+ {
+ sal_uInt8 nByte = 0;
+ xObjInfoSrc->ReadUChar( nByte );
+ if ( ( nByte >> 4 ) & embed::Aspects::MSOLE_ICON )
+ nAspect = embed::Aspects::MSOLE_ICON;
+ }
+ }
+
+ ErrCode nError = ERRCODE_NONE;
+ GraphicCtor();
+
+ pRet = SvxMSDffManager::CreateSdrOLEFromStorage(
+ *m_pDrawModel,
+ aSrcStgName,
+ xSrc0,
+ m_pDocShell->GetStorage(),
+ rGraph,
+ aRect,
+ aVisArea,
+ pTmpData,
+ nError,
+ SwMSDffManager::GetFilterFlags(),
+ nAspect,
+ GetBaseURL());
+ m_pDataStream->Seek( nOldPos );
+ }
+ }
+ return pRet;
+}
+
+void SwWW8ImplReader::ReadRevMarkAuthorStrTabl( SvStream& rStrm,
+ sal_Int32 nTablePos, sal_Int32 nTableSiz, SwDoc& rDocOut )
+{
+ std::vector<OUString> aAuthorNames;
+ WW8ReadSTTBF( !m_bVer67, rStrm, nTablePos, nTableSiz, m_bVer67 ? 2 : 0,
+ m_eStructCharSet, aAuthorNames );
+
+ sal_uInt16 nCount = static_cast< sal_uInt16 >(aAuthorNames.size());
+ for( sal_uInt16 nAuthor = 0; nAuthor < nCount; ++nAuthor )
+ {
+ // Store author in doc
+ std::size_t nSWId = rDocOut.getIDocumentRedlineAccess().InsertRedlineAuthor(aAuthorNames[nAuthor]);
+ // Store matchpair
+ m_aAuthorInfos[nAuthor] = nSWId;
+ }
+}
+
+/*
+ Revision Marks ( == Redlining )
+*/
+// insert or delete content (change char attributes resp.)
+void SwWW8ImplReader::Read_CRevisionMark(RedlineType eType,
+ const sal_uInt8* pData, short nLen )
+{
+ // there *must* be a SprmCIbstRMark[Del] and a SprmCDttmRMark[Del]
+ // pointing to the very same char position as our SprmCFRMark[Del]
+ if (!m_xPlcxMan)
+ return;
+ const sal_uInt8* pSprmCIbstRMark;
+ const sal_uInt8* pSprmCDttmRMark;
+ if( RedlineType::Format == eType )
+ {
+ pSprmCIbstRMark = nLen >= 3 ? pData+1 : nullptr;
+ pSprmCDttmRMark = nLen >= 7 ? pData+3 : nullptr;
+ }
+ else
+ {
+ /* It is possible to have a number of date stamps for the created time
+ * of the change, (possibly a word bug) so we must use the "get a full
+ * list" variant of HasCharSprm and take the last one as the true one.
+ */
+ std::vector<SprmResult> aResult;
+ bool bIns = (RedlineType::Insert == eType);
+ if( m_bVer67 )
+ {
+ m_xPlcxMan->HasCharSprm(69, aResult);
+ pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
+ aResult.clear();
+ m_xPlcxMan->HasCharSprm(70, aResult);
+ pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
+ }
+ else
+ {
+ m_xPlcxMan->HasCharSprm( bIns ? 0x4804 : 0x4863, aResult);
+ pSprmCIbstRMark = (aResult.empty() || aResult.back().nRemainingData < 2) ? nullptr : aResult.back().pSprm;
+ aResult.clear();
+ m_xPlcxMan->HasCharSprm( bIns ? 0x6805 : NS_sprm::CDttmRMarkDel::val, aResult);
+ pSprmCDttmRMark = (aResult.empty() || aResult.back().nRemainingData < 4) ? nullptr : aResult.back().pSprm;
+ }
+ }
+
+ if (nLen < 0)
+ m_xRedlineStack->close(*m_pPaM->GetPoint(), eType, m_xTableDesc.get());
+ else
+ {
+ // start of new revision mark, if not there default to first entry
+ sal_uInt16 nWWAutNo = pSprmCIbstRMark ? SVBT16ToUInt16(pSprmCIbstRMark) : 0;
+ sal_uInt32 nWWDate = pSprmCDttmRMark ? SVBT32ToUInt32(pSprmCDttmRMark): 0;
+ DateTime aStamp(msfilter::util::DTTM2DateTime(nWWDate));
+ std::size_t nAuthorNo = m_aAuthorInfos[nWWAutNo];
+ SwFltRedline aNewAttr(eType, nAuthorNo, aStamp);
+ NewAttr(aNewAttr);
+ }
+}
+
+// insert new content
+void SwWW8ImplReader::Read_CFRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ Read_CRevisionMark( RedlineType::Insert, pData, nLen );
+}
+
+// delete old content
+void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ Read_CRevisionMark( RedlineType::Delete, pData, nLen );
+}
+
+// change properties of content ( == char formatting)
+void SwWW8ImplReader::Read_CPropRMark(sal_uInt16 , const sal_uInt8* pData, short nLen)
+{
+ // complex (len is always 7)
+ // 1 byte - chp.fPropRMark
+ // 2 bytes - chp.ibstPropRMark
+ // 4 bytes - chp.dttmPropRMark;
+ Read_CRevisionMark( RedlineType::Format, pData, nLen );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */