emfplus: make VectorFormats Emf/Wmf/Svg work

make complete turn around and internal buffering
for Emf/Wmf/Svg work, including images in ODF and
re-save from UI. The correct FileType has to be
determined. It has shown that *.wmf exist that really
contain *.emf, so this turn around will not alter
the binary data, but may change the mimetype

Change-Id: I4fd92629236c12114f7b7c30234a3d3a9917dfaf
diff --git a/include/svx/svdstr.hrc b/include/svx/svdstr.hrc
index 9016360..69bc66a 100644
--- a/include/svx/svdstr.hrc
+++ b/include/svx/svdstr.hrc
@@ -159,8 +159,12 @@
// Svg support
#define STR_ObjNameSingulGRAFSVG            (STR_ObjNameBegin + 147)
#define STR_ObjNamePluralGRAFSVG            (STR_ObjNameBegin + 148)
#define STR_ObjNameSingulGRAFWMF            (STR_ObjNameBegin + 149)
#define STR_ObjNamePluralGRAFWMF            (STR_ObjNameBegin + 150)
#define STR_ObjNameSingulGRAFEMF            (STR_ObjNameBegin + 151)
#define STR_ObjNamePluralGRAFEMF            (STR_ObjNameBegin + 152)

#define STR_ObjNameEnd                      (STR_ObjNamePluralGRAFSVG)
#define STR_ObjNameEnd                      (STR_ObjNamePluralGRAFEMF)

#define STR_EditBegin                (STR_ObjNameEnd+1)
#define STR_EditWithCopy             (STR_EditBegin  +  0)
diff --git a/include/vcl/vectorgraphicdata.hxx b/include/vcl/vectorgraphicdata.hxx
index f46be43..6a259a5 100644
--- a/include/vcl/vectorgraphicdata.hxx
+++ b/include/vcl/vectorgraphicdata.hxx
@@ -74,11 +74,14 @@ public:
    VectorGraphicData(
        const VectorGraphicDataArray& rVectorGraphicDataArray,
        const OUString& rPath,
        VectorGraphicDataType eVectorDataType); // = VectorGraphicDataType::Svg);
        VectorGraphicDataType eVectorDataType);
    VectorGraphicData(
        const OUString& rPath,
        VectorGraphicDataType eVectorDataType);

    /// compare op
    bool operator==(const VectorGraphicData& rCandidate) const;

    /// data read
    const VectorGraphicDataArray& getVectorGraphicDataArray() const { return maVectorGraphicDataArray; }
    sal_uInt32 getVectorGraphicDataArrayLength() const { return maVectorGraphicDataArray.getLength(); }
diff --git a/svx/source/core/graphichelper.cxx b/svx/source/core/graphichelper.cxx
index 3a6df2b..632c6b0 100644
--- a/svx/source/core/graphichelper.cxx
+++ b/svx/source/core/graphichelper.cxx
@@ -63,6 +63,27 @@ namespace drawing = com::sun::star::drawing;
void GraphicHelper::GetPreferredExtension( OUString& rExtension, const Graphic& rGraphic )
{
    OUString aExtension = "png";
    const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());

    if (aVectorGraphicDataPtr.get() && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength())
    {
        switch (aVectorGraphicDataPtr->getVectorGraphicDataType())
        {
        case VectorGraphicDataType::Wmf:
            aExtension = "wmf";
            break;
        case VectorGraphicDataType::Emf:
            aExtension = "emf";
            break;
        default: // case VectorGraphicDataType::Svg:
            aExtension = "svg";
            break;
        }

        rExtension = aExtension;
        return;
    }

    switch( rGraphic.GetLink().GetType() )
    {
        case GfxLinkType::NativeGif:
diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx
index 0bf0505..82bdf58 100644
--- a/svx/source/svdraw/svdograf.cxx
+++ b/svx/source/svdraw/svdograf.cxx
@@ -748,7 +748,24 @@ OUString SdrGrafObj::TakeObjNameSingul() const

    if(rVectorGraphicDataPtr.get())
    {
        sName.append(ImpGetResStr(STR_ObjNameSingulGRAFSVG));
        switch (rVectorGraphicDataPtr->getVectorGraphicDataType())
        {
        case VectorGraphicDataType::Wmf:
        {
            sName.append(ImpGetResStr(STR_ObjNameSingulGRAFWMF));
            break;
        }
        case VectorGraphicDataType::Emf:
        {
            sName.append(ImpGetResStr(STR_ObjNameSingulGRAFEMF));
            break;
        }
        default: // case VectorGraphicDataType::Svg:
        {
            sName.append(ImpGetResStr(STR_ObjNameSingulGRAFSVG));
            break;
        }
        }
    }
    else
    {
@@ -801,7 +818,24 @@ OUString SdrGrafObj::TakeObjNamePlural() const

    if(rVectorGraphicDataPtr.get())
    {
        sName.append(ImpGetResStr(STR_ObjNamePluralGRAFSVG));
        switch (rVectorGraphicDataPtr->getVectorGraphicDataType())
        {
        case VectorGraphicDataType::Wmf:
        {
            sName.append(ImpGetResStr(STR_ObjNamePluralGRAFWMF));
            break;
        }
        case VectorGraphicDataType::Emf:
        {
            sName.append(ImpGetResStr(STR_ObjNamePluralGRAFEMF));
            break;
        }
        default: // case VectorGraphicDataType::Svg:
        {
            sName.append(ImpGetResStr(STR_ObjNamePluralGRAFSVG));
            break;
        }
        }
    }
    else
    {
diff --git a/svx/source/svdraw/svdstr.src b/svx/source/svdraw/svdstr.src
index d704475..79d5726 100644
--- a/svx/source/svdraw/svdstr.src
+++ b/svx/source/svdraw/svdstr.src
@@ -394,8 +394,7 @@ String STR_ObjNamePluralCUSTOMSHAPE
    Text [ en-US ] =  "Shapes";
};

// Svg support

// Vector Data support
String STR_ObjNameSingulGRAFSVG
{
    Text [ en-US ] = "SVG" ;
@@ -404,6 +403,22 @@ String STR_ObjNamePluralGRAFSVG
{
    Text [ en-US ] = "SVGs" ;
};
String STR_ObjNameSingulGRAFWMF
{
    Text [ en-US ] = "WMF" ;
};
String STR_ObjNamePluralGRAFWMF
{
    Text [ en-US ] = "WMFs" ;
};
String STR_ObjNameSingulGRAFEMF
{
    Text [ en-US ] = "EMF" ;
};
String STR_ObjNamePluralGRAFEMF
{
    Text [ en-US ] = "EMFs" ;
};

String STR_ObjNameSingulOLE2
{
diff --git a/svx/source/xoutdev/_xoutbmp.cxx b/svx/source/xoutdev/_xoutbmp.cxx
index db5474e..939c5ab 100644
--- a/svx/source/xoutdev/_xoutbmp.cxx
+++ b/svx/source/xoutdev/_xoutbmp.cxx
@@ -151,26 +151,32 @@ ErrCode XOutBitmap::WriteGraphic( const Graphic& rGraphic, OUString& rFileName,
        const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());

        if(aVectorGraphicDataPtr.get()
            && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength()
            && rFilterName.equalsIgnoreAsciiCase("svg"))
            && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength())
        {
            if(!(nFlags & XOutFlags::DontAddExtension))
            const bool bIsSvg(rFilterName.equalsIgnoreAsciiCase("svg") && VectorGraphicDataType::Svg == aVectorGraphicDataPtr->getVectorGraphicDataType());
            const bool bIsWmf(rFilterName.equalsIgnoreAsciiCase("wmf") && VectorGraphicDataType::Wmf == aVectorGraphicDataPtr->getVectorGraphicDataType());
            const bool bIsEmf(rFilterName.equalsIgnoreAsciiCase("emf") && VectorGraphicDataType::Emf == aVectorGraphicDataPtr->getVectorGraphicDataType());

            if (bIsSvg || bIsWmf || bIsEmf)
            {
                aURL.setExtension(rFilterName);
            }

            rFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
            SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE|StreamMode::SHARE_DENYNONE|StreamMode::TRUNC);
            SvStream* pOStm = aMedium.GetOutStream();

            if(pOStm)
            {
                pOStm->WriteBytes(aVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr->getVectorGraphicDataArrayLength());
                aMedium.Commit();

                if(!aMedium.GetError())
                if (!(nFlags & XOutFlags::DontAddExtension))
                {
                    nErr = ERRCODE_NONE;
                    aURL.setExtension(rFilterName);
                }

                rFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE);
                SfxMedium aMedium(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE), StreamMode::WRITE | StreamMode::SHARE_DENYNONE | StreamMode::TRUNC);
                SvStream* pOStm = aMedium.GetOutStream();

                if (pOStm)
                {
                    pOStm->WriteBytes(aVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr->getVectorGraphicDataArrayLength());
                    aMedium.Commit();

                    if (!aMedium.GetError())
                    {
                        nErr = ERRCODE_NONE;
                    }
                }
            }
        }
diff --git a/vcl/source/filter/graphicfilter.cxx b/vcl/source/filter/graphicfilter.cxx
index 98655ba..a436999 100644
--- a/vcl/source/filter/graphicfilter.cxx
+++ b/vcl/source/filter/graphicfilter.cxx
@@ -1766,8 +1766,8 @@ ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, 
        else if( aFilterName.equalsIgnoreAsciiCase( IMP_WMF ) ||
                aFilterName.equalsIgnoreAsciiCase( IMP_EMF ) )
        {
            static bool bCheckEmf = false;
            if (bCheckEmf)
            static bool bCheckEmfWmf = true;
            if (bCheckEmfWmf)
            {
                if (rGraphic.IsDummyContext())
                    rGraphic.SetDummyContext(false);
@@ -1782,14 +1782,20 @@ ErrCode GraphicFilter::ImportGraphic( Graphic& rGraphic, const OUString& rPath, 

                if (!rIStream.GetError())
                {
                    VectorGraphicDataPtr aVectorGraphicDataPtr(new VectorGraphicData(aNewData, rPath, VectorGraphicDataType::Emf));
                    const bool bIsWmf(aFilterName.equalsIgnoreAsciiCase(IMP_WMF));
                    const VectorGraphicDataType aDataType(bIsWmf ? VectorGraphicDataType::Wmf : VectorGraphicDataType::Emf);
                    VectorGraphicDataPtr aVectorGraphicDataPtr(
                        new VectorGraphicData(
                            aNewData,
                            rPath,
                            aDataType));
                    rGraphic = Graphic(aVectorGraphicDataPtr);
                    bOkay = true;
                }

                if (bOkay)
                {
                    eLinkType = GfxLinkType::NativeSvg;
                    eLinkType = GfxLinkType::NativeWmf;
                }
                else
                {
@@ -2114,21 +2120,69 @@ ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& r
            }
            else if ( aFilterName.equalsIgnoreAsciiCase( EXP_WMF ) )
            {
                // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
                if ( !ConvertGDIMetaFileToWMF( aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem ) )
                    nStatus = ERRCODE_GRFILTER_FORMATERROR;
                bool bDone(false);

                if( rOStm.GetError() )
                    nStatus = ERRCODE_GRFILTER_IOERROR;
                // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
                const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());

                if (aVectorGraphicDataPtr.get()
                    && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength()
                    && VectorGraphicDataType::Wmf == aVectorGraphicDataPtr->getVectorGraphicDataType())
                {
                    rOStm.WriteBytes(aVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr->getVectorGraphicDataArrayLength());

                    if (rOStm.GetError())
                    {
                        nStatus = ERRCODE_GRFILTER_IOERROR;
                    }
                    else
                    {
                        bDone = true;
                    }
                }

                if (!bDone)
                {
                    // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
                    if (!ConvertGDIMetaFileToWMF(aGraphic.GetGDIMetaFile(), rOStm, &aConfigItem))
                        nStatus = ERRCODE_GRFILTER_FORMATERROR;

                    if (rOStm.GetError())
                        nStatus = ERRCODE_GRFILTER_IOERROR;
                }
            }
            else if ( aFilterName.equalsIgnoreAsciiCase( EXP_EMF ) )
            {
                // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
                if ( !ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), rOStm))
                    nStatus = ERRCODE_GRFILTER_FORMATERROR;
                bool bDone(false);

                if( rOStm.GetError() )
                    nStatus = ERRCODE_GRFILTER_IOERROR;
                // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
                const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());

                if (aVectorGraphicDataPtr.get()
                    && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength()
                    && VectorGraphicDataType::Emf == aVectorGraphicDataPtr->getVectorGraphicDataType())
                {
                    rOStm.WriteBytes(aVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr->getVectorGraphicDataArrayLength());

                    if (rOStm.GetError())
                    {
                        nStatus = ERRCODE_GRFILTER_IOERROR;
                    }
                    else
                    {
                        bDone = true;
                    }
                }

                if (!bDone)
                {
                    // #i119735# just use GetGDIMetaFile, it will create a bufferd version of contained bitmap now automatically
                    if (!ConvertGDIMetaFileToEMF(aGraphic.GetGDIMetaFile(), rOStm))
                        nStatus = ERRCODE_GRFILTER_FORMATERROR;

                    if (rOStm.GetError())
                        nStatus = ERRCODE_GRFILTER_IOERROR;
                }
            }
            else if( aFilterName.equalsIgnoreAsciiCase( EXP_JPEG ) )
            {
@@ -2199,7 +2253,9 @@ ErrCode GraphicFilter::ExportGraphic( const Graphic& rGraphic, const OUString& r
                // do we have a native Vector Graphic Data RenderGraphic, whose data can be written directly?
                const VectorGraphicDataPtr& aVectorGraphicDataPtr(rGraphic.getVectorGraphicData());

                if (aVectorGraphicDataPtr.get() && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength())
                if (aVectorGraphicDataPtr.get()
                    && aVectorGraphicDataPtr->getVectorGraphicDataArrayLength()
                    && VectorGraphicDataType::Svg == aVectorGraphicDataPtr->getVectorGraphicDataType())
                {
                    rOStm.WriteBytes(aVectorGraphicDataPtr->getVectorGraphicDataArray().getConstArray(), aVectorGraphicDataPtr->getVectorGraphicDataArrayLength());

diff --git a/vcl/source/gdi/impgraph.cxx b/vcl/source/gdi/impgraph.cxx
index dfacf2c..14ccf01 100644
--- a/vcl/source/gdi/impgraph.cxx
+++ b/vcl/source/gdi/impgraph.cxx
@@ -284,20 +284,13 @@ bool ImpGraphic::operator==( const ImpGraphic& rImpGraphic ) const
                {
                    if(maVectorGraphicData == rImpGraphic.maVectorGraphicData)
                    {
                        // equal instances
                        bRet = true;
                    }
                    else if(rImpGraphic.maVectorGraphicData)
                    {
                        if(maVectorGraphicData->getVectorGraphicDataArrayLength() == rImpGraphic.maVectorGraphicData->getVectorGraphicDataArrayLength())
                        {
                            if(0 == memcmp(
                                maVectorGraphicData->getVectorGraphicDataArray().getConstArray(),
                                rImpGraphic.maVectorGraphicData->getVectorGraphicDataArray().getConstArray(),
                                maVectorGraphicData->getVectorGraphicDataArrayLength()))
                            {
                                bRet = true;
                            }
                        }
                        // equal content
                        bRet = (*maVectorGraphicData) == (*rImpGraphic.maVectorGraphicData);
                    }
                }
                else if (maPdfData.hasElements())
@@ -1513,12 +1506,14 @@ void ReadImpGraphic( SvStream& rIStm, ImpGraphic& rImpGraphic )
            // try to stream in Svg defining data (length, byte array and evtl. path)
            // See below (operator<<) for more information
            const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
            const sal_uInt32 nWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
            const sal_uInt32 nEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
            sal_uInt32 nMagic;
            rIStm.Seek(nStmPos1);
            rIStm.ResetError();
            rIStm.ReadUInt32( nMagic );

            if (nSvgMagic == nMagic)
            if (nSvgMagic == nMagic || nWmfMagic == nMagic || nEmfMagic == nMagic)
            {
                sal_uInt32 nVectorGraphicDataArrayLength(0);
                rIStm.ReadUInt32(nVectorGraphicDataArrayLength);
@@ -1532,7 +1527,18 @@ void ReadImpGraphic( SvStream& rIStm, ImpGraphic& rImpGraphic )

                    if (!rIStm.GetError())
                    {
                        VectorGraphicDataPtr aVectorGraphicDataPtr(new VectorGraphicData(aNewData, aPath, VectorGraphicDataType::Svg));
                        VectorGraphicDataType aDataType(VectorGraphicDataType::Svg);

                        if (nWmfMagic == nMagic)
                        {
                            aDataType = VectorGraphicDataType::Wmf;
                        }
                        else if (nEmfMagic == nMagic)
                        {
                            aDataType = VectorGraphicDataType::Emf;
                        }

                        VectorGraphicDataPtr aVectorGraphicDataPtr(new VectorGraphicData(aNewData, aPath, aDataType));
                        rImpGraphic = aVectorGraphicDataPtr;
                    }
                }
@@ -1606,13 +1612,32 @@ void WriteImpGraphic(SvStream& rOStm, const ImpGraphic& rImpGraphic)
            {
                if(rImpGraphic.getVectorGraphicData().get())
                {
                    // stream out Svg defining data (length, byte array and evtl. path)
                    // stream out Vector GHraphic defining data (length, byte array and evtl. path)
                    // this is used e.g. in swapping out graphic data and in transporting it over UNO API
                    // as sequence of bytes, but AFAIK not written anywhere to any kind of file, so it should be
                    // no problem to extend it; only used at runtime
                    const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
                    switch (rImpGraphic.getVectorGraphicData()->getVectorGraphicDataType())
                    {
                        case VectorGraphicDataType::Wmf:
                        {
                            const sal_uInt32 nWmfMagic((sal_uInt32('w') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
                            rOStm.WriteUInt32(nWmfMagic);
                            break;
                        }
                        case VectorGraphicDataType::Emf:
                        {
                            const sal_uInt32 nEmfMagic((sal_uInt32('e') << 24) | (sal_uInt32('m') << 16) | (sal_uInt32('f') << 8) | sal_uInt32('0'));
                            rOStm.WriteUInt32(nEmfMagic);
                            break;
                        }
                        default: // case VectorGraphicDataType::Svg:
                        {
                            const sal_uInt32 nSvgMagic((sal_uInt32('s') << 24) | (sal_uInt32('v') << 16) | (sal_uInt32('g') << 8) | sal_uInt32('0'));
                            rOStm.WriteUInt32(nSvgMagic);
                            break;
                        }
                    }

                    rOStm.WriteUInt32( nSvgMagic );
                    rOStm.WriteUInt32( rImpGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength() );
                    rOStm.WriteBytes(rImpGraphic.getVectorGraphicData()->getVectorGraphicDataArray().getConstArray(),
                        rImpGraphic.getVectorGraphicData()->getVectorGraphicDataArrayLength());
diff --git a/vcl/source/gdi/vectorgraphicdata.cxx b/vcl/source/gdi/vectorgraphicdata.cxx
index bb18ccc..d68cb80 100644
--- a/vcl/source/gdi/vectorgraphicdata.cxx
+++ b/vcl/source/gdi/vectorgraphicdata.cxx
@@ -106,6 +106,25 @@ size_t estimateSize(
    return nRet;
}

bool VectorGraphicData::operator==(const VectorGraphicData& rCandidate) const
{
    if (getVectorGraphicDataType() == rCandidate.getVectorGraphicDataType())
    {
        if (getVectorGraphicDataArrayLength() == rCandidate.getVectorGraphicDataArrayLength())
        {
            if (0 == memcmp(
                getVectorGraphicDataArray().getConstArray(),
                rCandidate.getVectorGraphicDataArray().getConstArray(),
                getVectorGraphicDataArrayLength()))
            {
                return true;
            }
        }
    }

    return false;
}

void VectorGraphicData::ensureReplacement()
{
    ensureSequenceAndRange();
@@ -128,12 +147,13 @@ void VectorGraphicData::ensureSequenceAndRange()

        if(myInputStream.is())
        {
            // create SVG interpreter
            // create Vector Graphic Data interpreter
            try
            {
                uno::Reference<uno::XComponentContext> xContext(::comphelper::getProcessComponentContext());

                if (VectorGraphicDataType::Emf == getVectorGraphicDataType())
                if (VectorGraphicDataType::Emf == getVectorGraphicDataType()
                    || VectorGraphicDataType::Wmf == getVectorGraphicDataType())
                {
                    const uno::Reference< graphic::XEmfParser > xEmfParser = graphic::EmfTools::create(xContext);