/* -*- 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 "token.hxx" #include "document.hxx" #include #include #include #include #include #include using namespace ::com::sun::star; using ::com::sun::star::uno::Reference; using ::com::sun::star::xml::sax::XAttributeList; // ============================================================================ ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext( ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, const Reference& xAttrList, ScXMLExternalTabData& rRefInfo ) : SvXMLImportContext( rImport, nPrefix, rLName ), mrScImport(rImport), mrExternalRefInfo(rRefInfo) { using namespace ::xmloff::token; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; for (sal_Int16 i = 0; i < nAttrCount; ++i) { const OUString& sAttrName = xAttrList->getNameByIndex(i); OUString aLocalName; sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); const OUString& sValue = xAttrList->getValueByIndex(i); if (nAttrPrefix == XML_NAMESPACE_XLINK) { if (IsXMLToken(aLocalName, XML_HREF)) maRelativeUrl = sValue; } else if (nAttrPrefix == XML_NAMESPACE_TABLE) { if (IsXMLToken(aLocalName, XML_TABLE_NAME)) maTableName = sValue; else if (IsXMLToken(aLocalName, XML_FILTER_NAME)) maFilterName = sValue; else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS)) maFilterOptions = sValue; } } } ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext() { } SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const Reference& /*xAttrList*/ ) { return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } /** * 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(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 ScXMLExternalRefTabSourceContext::EndElement() { ScDocument* pDoc = mrScImport.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, sal_uInt16 nPrefix, const OUString& rLName, const Reference& /* xAttrList */, ScXMLExternalTabData& rRefInfo ) : SvXMLImportContext( rImport, nPrefix, rLName ), mrScImport(rImport), mrExternalRefInfo(rRefInfo) { } ScXMLExternalRefRowsContext::~ScXMLExternalRefRowsContext() { } SvXMLImportContext* ScXMLExternalRefRowsContext::CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const Reference& xAttrList ) { // #i101319# row elements inside group, rows or header-rows // are treated like row elements directly in the table element const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowsElemTokenMap(); sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); switch (nToken) { case XML_TOK_TABLE_ROWS_ROW_GROUP: case XML_TOK_TABLE_ROWS_HEADER_ROWS: case XML_TOK_TABLE_ROWS_ROWS: return new ScXMLExternalRefRowsContext( mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); case XML_TOK_TABLE_ROWS_ROW: return new ScXMLExternalRefRowContext( mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); default: ; } return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } void ScXMLExternalRefRowsContext::EndElement() { } // ============================================================================ ScXMLExternalRefRowContext::ScXMLExternalRefRowContext( ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, const Reference& xAttrList, ScXMLExternalTabData& rRefInfo ) : SvXMLImportContext( rImport, nPrefix, rLName ), mrScImport(rImport), mrExternalRefInfo(rRefInfo), mnRepeatRowCount(1) { mrExternalRefInfo.mnCol = 0; sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0); const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap(); for( sal_Int16 i=0; i < nAttrCount; ++i ) { const OUString& sAttrName = xAttrList->getNameByIndex(i); OUString aLocalName; sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName); const OUString& sValue = xAttrList->getValueByIndex(i); switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName)) { case XML_TOK_TABLE_ROW_ATTR_REPEATED: { mnRepeatRowCount = std::max(sValue.toInt32(), static_cast(1)); } break; } } } ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext() { } SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const Reference& xAttrList ) { const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap(); sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); if (nToken == XML_TOK_TABLE_ROW_CELL || nToken == XML_TOK_TABLE_ROW_COVERED_CELL) return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo); return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } void ScXMLExternalRefRowContext::EndElement() { 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(j), static_cast(mrExternalRefInfo.mnRow)); if (pToken.get()) { pTab->setCell(static_cast(j), static_cast(mrExternalRefInfo.mnRow+i), pToken); } } } mrExternalRefInfo.mnRow += mnRepeatRowCount; } // ============================================================================ ScXMLExternalRefCellContext::ScXMLExternalRefCellContext( ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, const Reference& xAttrList, ScXMLExternalTabData& rRefInfo ) : SvXMLImportContext( rImport, nPrefix, rLName ), mrScImport(rImport), mrExternalRefInfo(rRefInfo), mfCellValue(0.0), mnRepeatCount(1), mnNumberFormat(-1), mnCellType(::com::sun::star::util::NumberFormat::UNDEFINED), mbIsNumeric(false), mbIsEmpty(true) { using namespace ::xmloff::token; sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0; const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap(); for (sal_Int16 i = 0; i < nAttrCount; ++i) { OUString aLocalName; sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName( xAttrList->getNameByIndex(i), &aLocalName); const OUString& sValue = xAttrList->getValueByIndex(i); sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName); switch (nToken) { case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME: { XMLTableStylesContext* pStyles = static_cast(mrScImport.GetAutoStyles()); const XMLTableStyleContext* pStyle = static_cast( pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, sValue, true)); if (pStyle) mnNumberFormat = const_cast(pStyle)->GetNumberFormat(); } break; case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED: { mnRepeatCount = ::std::max(sValue.toInt32(), static_cast(1)); } break; case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE: { mnCellType = mrScImport.GetCellType(sValue); } break; case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE: { if (!sValue.isEmpty()) { ::sax::Converter::convertDouble(mfCellValue, sValue); mbIsNumeric = true; mbIsEmpty = false; } } break; case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE: { if (!sValue.isEmpty() && mrScImport.SetNullDateOnUnitConverter()) { mrScImport.GetMM100UnitConverter().convertDateTime(mfCellValue, sValue); mbIsNumeric = true; mbIsEmpty = false; } } break; case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE: { if (!sValue.isEmpty()) { ::sax::Converter::convertDuration(mfCellValue, sValue); mbIsNumeric = true; mbIsEmpty = false; } } break; case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE: { if (!sValue.isEmpty()) { maCellString = sValue; mbIsNumeric = false; mbIsEmpty = false; } } break; case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE: { if (!sValue.isEmpty()) { mfCellValue = IsXMLToken(sValue, XML_TRUE) ? 1.0 : 0.0; mbIsNumeric = true; mbIsEmpty = false; } } break; default: ; } } } ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext() { } SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const Reference& xAttrList ) { const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap(); sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName); if (nToken == XML_TOK_TABLE_ROW_CELL_P) return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, *this); return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } void ScXMLExternalRefCellContext::EndElement() { 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 aToken.reset(new formula::FormulaStringToken(maCellString)); sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast(mnNumberFormat) : 0; mrExternalRefInfo.mpCacheTable->setCell( static_cast(mrExternalRefInfo.mnCol), static_cast(mrExternalRefInfo.mnRow), aToken, nNumFmt); } } void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr) { maCellString = rStr; } // ============================================================================ ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext( ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName, const Reference& /*xAttrList*/, ScXMLExternalRefCellContext& rParent ) : SvXMLImportContext( rImport, nPrefix, rLName ), mrParent(rParent) { } ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext() { } SvXMLImportContext* ScXMLExternalRefCellTextContext::CreateChildContext( sal_uInt16 nPrefix, const OUString& rLocalName, const Reference& /*xAttrList*/ ) { return new SvXMLImportContext(GetImport(), nPrefix, rLocalName); } void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar) { maCellStrBuf.append(rChar); } void ScXMLExternalRefCellTextContext::EndElement() { mrParent.SetCellString(maCellStrBuf.makeStringAndClear()); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */