    /* -*- 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 <algorithm>
    #include <cstddef>
    #include <functional>
    #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 <svx/unoapi.hxx>
    #include <sal/log.hxx>

    #include <sot/exchange.hxx>
    #include <swtypes.hxx>
    #include <fmtanchr.hxx>
    #include <fmtcntnt.hxx>
    #include <dcontact.hxx>
    #include <frmfmt.hxx>
    #include <pam.hxx>
    #include <ndgrf.hxx>
    #include <docsh.hxx>
    #include <mdiexp.hxx>
    #include <redline.hxx>
    #include <fltshell.hxx>
    #include <unodraw.hxx>
    #include <shellio.hxx>
    #include <ndole.hxx>

    #include <vcl/graphicfilter.hxx>
    #include <vcl/wmf.hxx>

    #include "ww8scan.hxx"
    #include "ww8par.hxx"
    #include "ww8par2.hxx"

    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(long& rX, 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 );
        pS->Seek( STREAM_SEEK_TO_END );

        OSL_ENSURE( pS->Tell() >=  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;

        SfxItemSet *pMathFlySet = nullptr;
        uno::Reference < embed::XClassifiedObject > xClass( rObject.GetObjRef(), uno::UNO_QUERY );
        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 = new SfxItemSet(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);
        }
        delete pMathFlySet;
        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;

        GrafikCtor();

        Graphic aGraph;
        SdrObject* pRet = ImportOleBase(aGraph, pGrf, pFlySet, aVisArea );

        // create flyset
        SfxItemSet* pTempSet = nullptr;
        if( !pFlySet )
        {
            pTempSet = new SfxItemSet( m_rDoc.GetAttrPool(), svl::Items<RES_FRMATR_BEGIN,
                RES_FRMATR_END-1>{});

            pFlySet = pTempSet;

            // Remove distance/borders
            if (!m_bNewDoc)
                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( ATT_FIX_SIZE, 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))
            {
                pFormat = InsertOle(*pOleObj, *pFlySet, pGrfSet);
                SdrObject::Free(pRet);     // 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);
        }
        delete pTempSet;
        return pFormat;
    }

    bool SwWW8ImplReader::ImportOleWMF(const tools::SvRef<SotStorage>& xSrc1, GDIMetaFile& rWMF,
                                       long& rX, 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;
    }

    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

        long nX=0, nY=0;                // nX, nY is graphic size
        bool bOleOk = true;

        OUString aSrcStgName('_');
        // results in the name "_4711"
        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());
            }
        }

        SdrObject* pRet = nullptr;

        if (!(m_bIsHeader || m_bIsFooter))
        {
            //Can't put them in headers/footers :-(
            uno::Reference< drawing::XShape > xRef;
            OSL_ENSURE(m_xFormImpl.get(), "Impossible");
            if (m_xFormImpl && m_xFormImpl->ReadOCXStream(xSrc1, &xRef))
            {
                pRet = 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_uLong nOldPos = m_pDataStream->Tell();
                m_pDataStream->Seek(STREAM_SEEK_TO_END);
                SvStream *pTmpData = nullptr;
                if (m_nObjLocFc < m_pDataStream->Tell())
                {
                    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;
                GrafikCtor();

                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_t 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( nsRedlineType_t::REDLINE_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 = (nsRedlineType_t::REDLINE_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::sprmCDttmRMarkDel, 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 ? SVBT16ToShort(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( nsRedlineType_t::REDLINE_INSERT, pData, nLen );
    }

    // delete old content
    void SwWW8ImplReader::Read_CFRMarkDel(sal_uInt16 , const sal_uInt8* pData, short nLen)
    {
        Read_CRevisionMark( nsRedlineType_t::REDLINE_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( nsRedlineType_t::REDLINE_FORMAT, pData, nLen );
    }

    /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

↑ V1029 Numeric Truncation Error. Result of the 'size' function is written to the 16-bit variable.