summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/xml/xmlexternaltabi.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/xml/xmlexternaltabi.cxx')
-rw-r--r--sc/source/filter/xml/xmlexternaltabi.cxx378
1 files changed, 378 insertions, 0 deletions
diff --git a/sc/source/filter/xml/xmlexternaltabi.cxx b/sc/source/filter/xml/xmlexternaltabi.cxx
new file mode 100644
index 000000000..91bb218bb
--- /dev/null
+++ b/sc/source/filter/xml/xmlexternaltabi.cxx
@@ -0,0 +1,378 @@
+/* -*- 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 "xmlexternaltabi.hxx"
+#include "xmlimprt.hxx"
+#include "xmltabi.hxx"
+#include "xmlstyli.hxx"
+
+#include <document.hxx>
+#include <documentimport.hxx>
+
+#include <svl/sharedstringpool.hxx>
+#include <xmloff/xmlnamespace.hxx>
+#include <xmloff/xmltoken.hxx>
+#include <xmloff/xmluconv.hxx>
+
+#include <sax/tools/converter.hxx>
+
+#include <com/sun/star/util/NumberFormat.hpp>
+
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::xmloff::token;
+
+using ::com::sun::star::uno::Reference;
+
+ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext(
+ ScXMLImport& rImport,
+ const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
+ ScXMLImportContext( rImport ),
+ mrExternalRefInfo(rRefInfo)
+{
+ using namespace ::xmloff::token;
+
+ if ( !rAttrList.is() )
+ return;
+
+ for (auto &it : *rAttrList)
+ {
+ sal_Int32 nAttrToken = it.getToken();
+ if ( nAttrToken == XML_ELEMENT( XLINK, XML_HREF ) )
+ maRelativeUrl = it.toString();
+ else if ( nAttrToken == XML_ELEMENT( TABLE, XML_TABLE_NAME ) )
+ // todo
+ ;
+ else if ( nAttrToken == XML_ELEMENT( TABLE, XML_FILTER_NAME ) )
+ maFilterName = it.toString();
+ else if ( nAttrToken == XML_ELEMENT( TABLE, XML_FILTER_OPTIONS ) )
+ maFilterOptions = it.toString();
+ }
+}
+
+ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext()
+{
+}
+
+/**
+ * Make sure the URL is a valid relative URL, mainly to avoid storing
+ * absolute URL as relative URL by accident. For now, we only check the first
+ * three characters which are assumed to be always '../', because the relative
+ * URL for an external document is always in reference to the content.xml
+ * fragment of the original document.
+ */
+static bool lcl_isValidRelativeURL(const OUString& rUrl)
+{
+ sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3));
+ if (n < 3)
+ return false;
+ const sal_Unicode* p = rUrl.getStr();
+ for (sal_Int32 i = 0; i < n; ++i)
+ {
+ sal_Unicode c = p[i];
+ if (i < 2 && c != '.')
+ // the path must begin with '..'
+ return false;
+ else if (i == 2 && c != '/')
+ // a '/' path separator must follow
+ return false;
+ }
+ return true;
+}
+
+void SAL_CALL ScXMLExternalRefTabSourceContext::endFastElement( sal_Int32 /*nElement*/ )
+{
+ ScDocument* pDoc = GetScImport().GetDocument();
+ if (!pDoc)
+ return;
+
+ ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
+ if (lcl_isValidRelativeURL(maRelativeUrl))
+ pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl);
+ pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions);
+}
+
+ScXMLExternalRefRowsContext::ScXMLExternalRefRowsContext(
+ ScXMLImport& rImport, ScXMLExternalTabData& rRefInfo ) :
+ ScXMLImportContext( rImport ),
+ mrExternalRefInfo(rRefInfo)
+{
+}
+
+ScXMLExternalRefRowsContext::~ScXMLExternalRefRowsContext()
+{
+}
+
+Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefRowsContext::createFastChildContext(
+ sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
+{
+ // #i101319# row elements inside group, rows or header-rows
+ // are treated like row elements directly in the table element
+
+ sax_fastparser::FastAttributeList *pAttribList =
+ &sax_fastparser::castToFastAttributeList( xAttrList );
+
+ switch (nElement)
+ {
+ case XML_ELEMENT(TABLE, XML_TABLE_ROW_GROUP):
+ case XML_ELEMENT(TABLE, XML_TABLE_HEADER_ROWS):
+ case XML_ELEMENT(TABLE, XML_TABLE_ROWS):
+ return new ScXMLExternalRefRowsContext(
+ GetScImport(), mrExternalRefInfo);
+ case XML_ELEMENT(TABLE, XML_TABLE_ROW):
+ return new ScXMLExternalRefRowContext(
+ GetScImport(), pAttribList, mrExternalRefInfo);
+ default:
+ XMLOFF_WARN_UNKNOWN_ELEMENT("sc", nElement);
+ }
+ return nullptr;
+}
+
+ScXMLExternalRefRowContext::ScXMLExternalRefRowContext(
+ ScXMLImport& rImport,
+ const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
+ ScXMLImportContext( rImport ),
+ mrScImport(rImport),
+ mrExternalRefInfo(rRefInfo),
+ mnRepeatRowCount(1)
+{
+ mrExternalRefInfo.mnCol = 0;
+
+ for (auto &it : *rAttrList)
+ {
+ switch (it.getToken())
+ {
+ case XML_ELEMENT(TABLE, XML_NUMBER_ROWS_REPEATED):
+ {
+ mnRepeatRowCount = std::max(it.toInt32(), static_cast<sal_Int32>(1));
+ }
+ break;
+ }
+ }
+}
+
+ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext()
+{
+}
+
+Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefRowContext::createFastChildContext(
+ sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
+{
+ sax_fastparser::FastAttributeList *pAttribList =
+ &sax_fastparser::castToFastAttributeList( xAttrList );
+
+ if (nElement == XML_ELEMENT(TABLE, XML_TABLE_CELL) || nElement == XML_ELEMENT(TABLE, XML_COVERED_TABLE_CELL))
+ return new ScXMLExternalRefCellContext(mrScImport, pAttribList, mrExternalRefInfo);
+
+ return nullptr;
+}
+
+void SAL_CALL ScXMLExternalRefRowContext::endFastElement( sal_Int32 /* nElement */ )
+{
+ ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable;
+
+ for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i)
+ {
+ // Performance: duplicates of a non-existent row will still not exist.
+ // Don't find that out for every cell.
+ // External references often are a sparse matrix.
+ if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow))
+ {
+ mrExternalRefInfo.mnRow += mnRepeatRowCount;
+ return;
+ }
+
+ for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j)
+ {
+ ScExternalRefCache::TokenRef pToken = pTab->getCell(
+ static_cast<SCCOL>(j), static_cast<SCROW>(mrExternalRefInfo.mnRow));
+
+ if (pToken)
+ {
+ pTab->setCell(static_cast<SCCOL>(j),
+ static_cast<SCROW>(mrExternalRefInfo.mnRow+i), pToken);
+ }
+ }
+ }
+ mrExternalRefInfo.mnRow += mnRepeatRowCount;
+}
+
+ScXMLExternalRefCellContext::ScXMLExternalRefCellContext(
+ ScXMLImport& rImport,
+ const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
+ ScXMLImportContext( rImport ),
+ mrScImport(rImport),
+ mrExternalRefInfo(rRefInfo),
+ mfCellValue(0.0),
+ mnRepeatCount(1),
+ mnNumberFormat(-1),
+ mnCellType(css::util::NumberFormat::UNDEFINED),
+ mbIsNumeric(false),
+ mbIsEmpty(true)
+{
+ using namespace ::xmloff::token;
+
+ for (auto &it : *rAttrList)
+ {
+ switch ( it.getToken() )
+ {
+ case XML_ELEMENT(TABLE, XML_STYLE_NAME):
+ {
+ XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles());
+ const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>(
+ pStyles->FindStyleChildContext(XmlStyleFamily::TABLE_CELL, it.toString(), true));
+ if (pStyle)
+ mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat();
+ }
+ break;
+ case XML_ELEMENT(TABLE, XML_NUMBER_COLUMNS_REPEATED):
+ {
+ mnRepeatCount = ::std::max( it.toInt32(), static_cast<sal_Int32>(1) );
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE_TYPE):
+ {
+ mnCellType = ScXMLImport::GetCellType( it.toCString(), it.getLength() );
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_VALUE):
+ {
+ if ( !it.isEmpty() )
+ {
+ mfCellValue = it.toDouble();
+ mbIsNumeric = true;
+ mbIsEmpty = false;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_DATE_VALUE):
+ {
+ if ( !it.isEmpty() && mrScImport.SetNullDateOnUnitConverter() )
+ {
+ mrScImport.GetMM100UnitConverter().convertDateTime( mfCellValue, it.toView() );
+ mbIsNumeric = true;
+ mbIsEmpty = false;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_TIME_VALUE):
+ {
+ if ( !it.isEmpty() )
+ {
+ ::sax::Converter::convertDuration( mfCellValue, it.toView() );
+ mbIsNumeric = true;
+ mbIsEmpty = false;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_STRING_VALUE):
+ {
+ if ( !it.isEmpty() )
+ {
+ maCellString = it.toString();
+ mbIsNumeric = false;
+ mbIsEmpty = false;
+ }
+ }
+ break;
+ case XML_ELEMENT(OFFICE, XML_BOOLEAN_VALUE):
+ {
+ if ( !it.isEmpty() )
+ {
+ mfCellValue = IsXMLToken( it, XML_TRUE ) ? 1.0 : 0.0;
+ mbIsNumeric = true;
+ mbIsEmpty = false;
+ }
+ }
+ break;
+ default:
+ ;
+ }
+ }
+}
+
+ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext()
+{
+}
+
+Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefCellContext::createFastChildContext(
+ sal_Int32 nElement, const Reference< XFastAttributeList >& /*xAttrList*/ )
+{
+ if (nElement == XML_ELEMENT(TEXT, XML_P))
+ return new ScXMLExternalRefCellTextContext(mrScImport, *this);
+
+ return nullptr;
+}
+
+void SAL_CALL ScXMLExternalRefCellContext::endFastElement( sal_Int32 /*nElement*/ )
+{
+ if (!maCellString.isEmpty())
+ mbIsEmpty = false;
+
+ for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol)
+ {
+ if (mbIsEmpty)
+ continue;
+
+ ScExternalRefCache::TokenRef aToken;
+ if (mbIsNumeric)
+ aToken.reset(new formula::FormulaDoubleToken(mfCellValue));
+ else
+ {
+ ScDocument& rDoc = mrScImport.GetDoc().getDoc();
+ svl::SharedString aSS = rDoc.GetSharedStringPool().intern(maCellString);
+ aToken.reset(new formula::FormulaStringToken(aSS));
+ }
+
+ sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast<sal_uInt32>(mnNumberFormat) : 0;
+ mrExternalRefInfo.mpCacheTable->setCell(
+ static_cast<SCCOL>(mrExternalRefInfo.mnCol),
+ static_cast<SCROW>(mrExternalRefInfo.mnRow),
+ aToken, nNumFmt);
+ }
+}
+
+void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr)
+{
+ maCellString = rStr;
+}
+
+ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext(
+ ScXMLImport& rImport,
+ ScXMLExternalRefCellContext& rParent ) :
+ ScXMLImportContext( rImport ),
+ mrParent(rParent)
+{
+}
+
+ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext()
+{
+}
+
+void SAL_CALL ScXMLExternalRefCellTextContext::characters( const OUString& rChars )
+{
+ maCellStrBuf.append( rChars );
+}
+
+void SAL_CALL ScXMLExternalRefCellTextContext::endFastElement( sal_Int32 /*nElement*/ )
+{
+ mrParent.SetCellString( maCellStrBuf.makeStringAndClear() );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */