fdo#76356 : Docx file contianing chart in footer/header gets corrupted.

    -  Docx file with chart in footer/header or .bin file referred in chart
       was getting corrupted.
    -  Embedded file for footer.xml was not grabbaged.
    -  .bin embedded files were not grab baged.
    -  Added grab bag support for both case.
    -  Added UT to check .bin files are grab baged properly.

Reviewed on:
	https://gerrit.libreoffice.org/8674

Change-Id: I221e3867798fc2a3a42f6385d687e80b80a3678f
diff --git a/chart2/qa/extras/chart2export.cxx b/chart2/qa/extras/chart2export.cxx
index 5a57ea4..c0d20f17 100644
--- a/chart2/qa/extras/chart2export.cxx
+++ b/chart2/qa/extras/chart2export.cxx
@@ -52,6 +52,7 @@ public:
    void testErrorBarDataRangeODS();
    void testChartCrash();
    void testPieChartRotation();
    void testEmbeddingsOleObjectGrabBag();

    CPPUNIT_TEST_SUITE(Chart2ExportTest);
    CPPUNIT_TEST(test);
@@ -76,6 +77,7 @@ public:
    CPPUNIT_TEST(testErrorBarDataRangeODS);
    CPPUNIT_TEST(testChartCrash);
    CPPUNIT_TEST(testPieChartRotation);
    CPPUNIT_TEST(testEmbeddingsOleObjectGrabBag);
    CPPUNIT_TEST_SUITE_END();

protected:
@@ -673,6 +675,43 @@ void Chart2ExportTest::testPieChartRotation()
    assertXPath(pXmlDoc, "/c:chartSpace/c:chart/c:view3D/c:rotY", "val", "30");
}

void Chart2ExportTest::testEmbeddingsOleObjectGrabBag()
{
   // The problem was that .bin files were missing from docx file from embeddings folder
   // after saving file.
   // This test case tests whether embeddings files grabbagged properly in correct object.

   load("/chart2/qa/extras/data/docx/", "testchartoleobjectembeddings.docx" );
   uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY);
   uno::Reference<beans::XPropertySet> xTextDocumentPropertySet(xTextDocument, uno::UNO_QUERY);
   uno::Sequence<beans::PropertyValue> aGrabBag(0);
   xTextDocumentPropertySet->getPropertyValue(OUString("InteropGrabBag")) >>= aGrabBag;
   CPPUNIT_ASSERT(aGrabBag.hasElements()); // Grab Bag not empty
   bool bEmbeddings = false;
   const char* testEmbeddedFileNames[1] = {"word/embeddings/oleObject1.bin"};
   for(int i = 0; i < aGrabBag.getLength(); ++i)
   {
       if (aGrabBag[i].Name == "OOXEmbeddings")
       {
           bEmbeddings = true;
           uno::Sequence<beans::PropertyValue> aEmbeddingsList(0);
           uno::Reference<io::XInputStream> aEmbeddingXlsxStream;
           OUString aEmbeddedfileName;
           CPPUNIT_ASSERT(aGrabBag[i].Value >>= aEmbeddingsList); // PropertyValue of proper type
           sal_Int32 length = aEmbeddingsList.getLength();
           CPPUNIT_ASSERT_EQUAL(sal_Int32(1), length);
           for(int j = 0; j < length; ++j)
           {
               aEmbeddingsList[j].Value >>= aEmbeddingXlsxStream;
               aEmbeddedfileName = aEmbeddingsList[j].Name;
               CPPUNIT_ASSERT(aEmbeddingXlsxStream.get()); // Reference not empty
               CPPUNIT_ASSERT_EQUAL(OUString::createFromAscii(testEmbeddedFileNames[j]),aEmbeddedfileName);
           }
       }
   }
   CPPUNIT_ASSERT(bEmbeddings); // Grab Bag has all the expected elements
}

CPPUNIT_TEST_SUITE_REGISTRATION(Chart2ExportTest);

CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/chart2/qa/extras/data/docx/testchartoleobjectembeddings.docx b/chart2/qa/extras/data/docx/testchartoleobjectembeddings.docx
new file mode 100644
index 0000000..8167de7
--- /dev/null
+++ b/chart2/qa/extras/data/docx/testchartoleobjectembeddings.docx
Binary files differ
diff --git a/oox/source/export/chartexport.cxx b/oox/source/export/chartexport.cxx
index 91d761f..0d30e29 100644
--- a/oox/source/export/chartexport.cxx
+++ b/oox/source/export/chartexport.cxx
@@ -801,8 +801,12 @@ void ChartExport::exportExternalData( Reference< ::com::sun::star::chart::XChart
            }
        }
        FSHelperPtr pFS = GetFS();
        OUString type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package";
        if (relationPath.endsWith(OUString(".bin")))
            type = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject";

        OUString sRelId = GetFB()->addRelation(pFS->getOutputStream(),
                        "http://schemas.openxmlformats.org/officeDocument/2006/relationships/package",
                        type,
                        relationPath);
        pFS->singleElementNS( XML_c, XML_externalData,
                FSNS(XML_r, XML_id), OUStringToOString(sRelId, RTL_TEXTENCODING_UTF8),
diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx
index 5e20cc3..ff74f3a 100644
--- a/sw/source/filter/ww8/docxexport.cxx
+++ b/sw/source/filter/ww8/docxexport.cxx
@@ -1217,6 +1217,8 @@ void DocxExport::WriteEmbeddings()
        OUString contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        if (embeddingPath.endsWith(OUString(".xlsm")))
            contentType = "application/vnd.ms-excel.sheet.macroEnabled.12";
        else if (embeddingPath.endsWith(OUString(".bin")))
            contentType = "application/vnd.openxmlformats-officedocument.oleObject";

        if ( embeddingsStream.is() )
        {
diff --git a/writerfilter/inc/ooxml/OOXMLDocument.hxx b/writerfilter/inc/ooxml/OOXMLDocument.hxx
index 7f104ab..c7b4ec1 100644
--- a/writerfilter/inc/ooxml/OOXMLDocument.hxx
+++ b/writerfilter/inc/ooxml/OOXMLDocument.hxx
@@ -77,7 +77,7 @@ class WRITERFILTER_OOXML_DLLPUBLIC OOXMLStream
{
public:
    enum StreamType_t { UNKNOWN, DOCUMENT, STYLES, WEBSETTINGS, FONTTABLE, NUMBERING,
        FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT };
        FOOTNOTES, ENDNOTES, COMMENTS, THEME, CUSTOMXML, CUSTOMXMLPROPS, ACTIVEX, ACTIVEXBIN, GLOSSARY, CHARTS, EMBEDDINGS, SETTINGS, VBAPROJECT, FOOTER, HEADER };
    typedef boost::shared_ptr<OOXMLStream> Pointer_t;

    virtual ~OOXMLStream() {}
diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
index 83cdb58..9a1c50c 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.cxx
@@ -233,6 +233,10 @@ void OOXMLDocumentImpl::importSubStreamRelations(OOXMLStream::Pointer_t pStream,
            // imporing activex.bin files for activex.xml from activeX folder.
            mxEmbeddings = xcpInputStream;
        }
        else if(OOXMLStream::CHARTS == nType)
        {
            importSubStreamRelations(cStream, OOXMLStream::EMBEDDINGS);
        }
    }


@@ -494,7 +498,7 @@ void OOXMLDocumentImpl::resolve(Stream & rStream)
        if (mxGlossaryDocDom.is())
            resolveGlossaryStream(rStream);

        resolveEmbeddingsStream(rStream);
        resolveEmbeddingsStream(mpStream);

        // Custom xml's are handled as part of grab bag.
        resolveCustomXmlStream(rStream);
@@ -705,20 +709,25 @@ void OOXMLDocumentImpl::resolveGlossaryStream(Stream & /*rStream*/)
      }
}

void OOXMLDocumentImpl::resolveEmbeddingsStream(Stream & /*rStream*/)
void OOXMLDocumentImpl::resolveEmbeddingsStream(OOXMLStream::Pointer_t pStream)
{
    uno::Reference<embed::XRelationshipAccess> mxRelationshipAccess;
    mxRelationshipAccess.set((dynamic_cast<OOXMLStreamImpl&>(*mpStream.get())).accessDocumentStream(), uno::UNO_QUERY_THROW);
    mxRelationshipAccess.set((dynamic_cast<OOXMLStreamImpl&>(*pStream.get())).accessDocumentStream(), uno::UNO_QUERY_THROW);
    if (mxRelationshipAccess.is())
    {
        OUString sChartType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
        OUString sChartTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
        OUString sFootersType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
        OUString sFootersTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
        OUString sHeaderType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
        OUString sHeaderTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/header");

        OUString sTarget("Target");
        bool bFound = false;
        sal_Int32 counter = 0;
        bool bHeaderFooterFound = false;
        OOXMLStream::StreamType_t streamType;
        uno::Sequence< uno::Sequence< beans::StringPair > >aSeqs =
                mxRelationshipAccess->getAllRelationships();
        uno::Sequence<beans::PropertyValue > mxEmbeddingsListTemp(aSeqs.getLength());
        for (sal_Int32 j = 0; j < aSeqs.getLength(); j++)
        {
            uno::Sequence< beans::StringPair > aSeq = aSeqs[j];
@@ -727,34 +736,65 @@ void OOXMLDocumentImpl::resolveEmbeddingsStream(Stream & /*rStream*/)
                beans::StringPair aPair = aSeq[i];
                if (aPair.Second.compareTo(sChartType) == 0 ||
                        aPair.Second.compareTo(sChartTypeStrict) == 0)
                {
                    bFound = true;
                else if(aPair.First.compareTo(sTarget) == 0 && bFound)
                }
                else if(aPair.Second.compareTo(sFootersType) == 0 ||
                        aPair.Second.compareTo(sFootersTypeStrict) == 0)
                {
                    bHeaderFooterFound = true;
                    streamType = OOXMLStream::FOOTER;
                }
                else if(aPair.Second.compareTo(sHeaderType) == 0 ||
                        aPair.Second.compareTo(sHeaderTypeStrict) == 0)
                {
                    bHeaderFooterFound = true;
                    streamType = OOXMLStream::HEADER;
                }
                else if(aPair.First.compareTo(sTarget) == 0 && ( bFound || bHeaderFooterFound ))
                {
                    // Adding value to extern variable customTarget. It will be used in ooxmlstreamimpl
                    // to ensure chart.xml target is visited in lcl_getTarget.
                    customTarget = aPair.Second;
                }
            }
            if(bFound)
            if(( bFound || bHeaderFooterFound))
            {
                uno::Reference<xml::dom::XDocument> chartTemp = importSubStream(OOXMLStream::CHARTS);
                if(bFound)
                {
                    importSubStreamRelations(pStream, OOXMLStream::CHARTS);
                }
                if(bHeaderFooterFound)
                {
                    OOXMLStream::Pointer_t Stream = OOXMLDocumentFactory::createStream(pStream, streamType);
                    if(Stream)
                        resolveEmbeddingsStream(Stream);
                }

                beans::PropertyValue embeddingsTemp;
                // This will add all ActiveX[n].xml to grabbag list.
                if(chartTemp.is())
                // This will add all .xlsx and .bin to grabbag list.
                if(bFound)
                {
                    if(mxEmbeddings.is())
                    {
                        embeddingsTemp.Name = embeddingsTarget;
                        embeddingsTemp.Value = uno::makeAny(mxEmbeddings);
                        mxEmbeddingsListTemp[counter] = embeddingsTemp;
                        mxEmbeddingsListTemp.push_back(embeddingsTemp);
                        mxEmbeddings.clear();
                    }
                    counter++;
                }
                bFound = false;
                bHeaderFooterFound = false;
            }
        }
        mxEmbeddingsListTemp.realloc(counter);
        mxEmbeddingsList = mxEmbeddingsListTemp;
    }
    if(0 != mxEmbeddingsListTemp.size())
    {
        mxEmbeddingsList.realloc(mxEmbeddingsListTemp.size());
        for (size_t i = 0; i < mxEmbeddingsListTemp.size(); i++)
        {
            mxEmbeddingsList[i] = mxEmbeddingsListTemp[i];
        }
    }
}

diff --git a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
index 4af7570..c36945a 100644
--- a/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
+++ b/writerfilter/source/ooxml/OOXMLDocumentImpl.hxx
@@ -53,6 +53,7 @@ class OOXMLDocumentImpl : public OOXMLDocument
    uno::Reference<io::XInputStream> mxActiveXBin;
    uno::Reference<io::XInputStream> mxEmbeddings;
    uno::Sequence < beans::PropertyValue > mxEmbeddingsList;
    std::vector<beans::PropertyValue> mxEmbeddingsListTemp;
    bool mbIsSubstream;
    /// How many paragraphs equal to 1 percent?
    sal_Int32 mnPercentSize;
@@ -87,7 +88,7 @@ protected:
    void resolveCustomXmlStream(Stream & rStream);
    void resolveActiveXStream(Stream & rStream);
    void resolveGlossaryStream(Stream & rStream);
    void resolveEmbeddingsStream(Stream & rStream);
    void resolveEmbeddingsStream(OOXMLStream::Pointer_t pStream);
public:
    OOXMLDocumentImpl(OOXMLStream::Pointer_t pStream, const uno::Reference<task::XStatusIndicator>& xStatusIndicator);
    virtual ~OOXMLDocumentImpl();
diff --git a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
index 8f81842..6c6b2ee 100644
--- a/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
+++ b/writerfilter/source/ooxml/OOXMLStreamImpl.cxx
@@ -119,6 +119,9 @@ bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
    static OUString sSettingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings");
    static OUString sChartType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart");
    static OUString sEmbeddingsType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/package");
    static OUString sFooterType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer");
    static OUString sHeaderType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/header");
    static OUString sOleObjectType("http://schemas.openxmlformats.org/officeDocument/2006/relationships/oleObject");
    // OOXML strict
    static OUString sDocumentTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/officeDocument");
    static OUString sStylesTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/styles");
@@ -136,6 +139,9 @@ bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
    static OUString sSettingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/settings");
    static OUString sChartTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/chart");
    static OUString sEmbeddingsTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/package");
    static OUString sFootersTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/footer");
    static OUString sHeaderTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/header");
    static OUString sOleObjectTypeStrict("http://purl.oclc.org/ooxml/officeDocument/relationships/oleObject");
    static OUString sTarget("Target");
    static OUString sTargetMode("TargetMode");
    static OUString sExternal("External");
@@ -218,6 +224,14 @@ bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
            sStreamType = sEmbeddingsType;
            sStreamTypeStrict = sEmbeddingsTypeStrict;
          break;
        case FOOTER:
            sStreamType = sFooterType;
            sStreamTypeStrict = sFootersTypeStrict;
          break;
        case HEADER:
            sStreamType = sHeaderType;
            sStreamTypeStrict = sHeaderTypeStrict;
          break;
        default:
            break;
    }
@@ -241,13 +255,20 @@ bool OOXMLStreamImpl::lcl_getTarget(uno::Reference<embed::XRelationshipAccess>
                    ( aPair.Second.compareTo(sStreamType) == 0 ||
                      aPair.Second.compareTo(sStreamTypeStrict) == 0))
                    bFound = true;
                else if(aPair.First.compareTo(sType) == 0 &&
                        ((aPair.Second.compareTo(sOleObjectType) == 0 ||
                          aPair.Second.compareTo(sOleObjectTypeStrict) == 0) &&
                          nStreamType == EMBEDDINGS))
                {
                    bFound = true;
                }
                else if (aPair.First.compareTo(sId) == 0 &&
                         aPair.Second.compareTo(rId) == 0)
                    bFound = true;
                else if (aPair.First.compareTo(sTarget) == 0)
                {
                    // checking item[n].xml or activex[n].xml is not visited already.
                    if(customTarget != aPair.Second && (sStreamType == sCustomType || sStreamType == sActiveXType || sStreamType == sChartType))
                    if(customTarget != aPair.Second && (sStreamType == sCustomType || sStreamType == sActiveXType || sStreamType == sChartType || sStreamType == sFooterType || sStreamType == sHeaderType))
                    {
                        bFound = false;
                    }