Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / xml / xmlexternaltabi.cxx
blob5515fd835ba53fa29e27938dafff38eb29089efd
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "xmlexternaltabi.hxx"
21 #include "xmlimprt.hxx"
22 #include "xmltabi.hxx"
23 #include "xmlstyli.hxx"
25 #include <document.hxx>
26 #include <documentimport.hxx>
28 #include <svl/sharedstringpool.hxx>
29 #include <xmloff/xmlnmspe.hxx>
30 #include <xmloff/xmltoken.hxx>
31 #include <xmloff/xmluconv.hxx>
33 #include <sax/tools/converter.hxx>
35 #include <com/sun/star/util/NumberFormat.hpp>
37 using namespace ::com::sun::star;
38 using namespace ::com::sun::star::xml::sax;
40 using ::com::sun::star::uno::Reference;
42 ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext(
43 ScXMLImport& rImport,
44 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
45 ScXMLImportContext( rImport ),
46 mrExternalRefInfo(rRefInfo)
48 using namespace ::xmloff::token;
50 if ( rAttrList.is() )
52 for (auto &it : *rAttrList)
54 sal_Int32 nAttrToken = it.getToken();
55 if ( nAttrToken == XML_ELEMENT( XLINK, XML_HREF ) )
56 maRelativeUrl = it.toString();
57 else if ( nAttrToken == XML_ELEMENT( TABLE, XML_TABLE_NAME ) )
58 // todo
60 else if ( nAttrToken == XML_ELEMENT( TABLE, XML_FILTER_NAME ) )
61 maFilterName = it.toString();
62 else if ( nAttrToken == XML_ELEMENT( TABLE, XML_FILTER_OPTIONS ) )
63 maFilterOptions = it.toString();
68 ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext()
72 /**
73 * Make sure the URL is a valid relative URL, mainly to avoid storing
74 * absolute URL as relative URL by accident. For now, we only check the first
75 * three characters which are assumed to be always '../', because the relative
76 * URL for an external document is always in reference to the content.xml
77 * fragment of the original document.
79 static bool lcl_isValidRelativeURL(const OUString& rUrl)
81 sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3));
82 if (n < 3)
83 return false;
84 const sal_Unicode* p = rUrl.getStr();
85 for (sal_Int32 i = 0; i < n; ++i)
87 sal_Unicode c = p[i];
88 if (i < 2 && c != '.')
89 // the path must begin with '..'
90 return false;
91 else if (i == 2 && c != '/')
92 // a '/' path separator must follow
93 return false;
95 return true;
98 void SAL_CALL ScXMLExternalRefTabSourceContext::endFastElement( sal_Int32 /*nElement*/ )
100 ScDocument* pDoc = GetScImport().GetDocument();
101 if (!pDoc)
102 return;
104 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
105 if (lcl_isValidRelativeURL(maRelativeUrl))
106 pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl);
107 pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions);
110 ScXMLExternalRefRowsContext::ScXMLExternalRefRowsContext(
111 ScXMLImport& rImport, ScXMLExternalTabData& rRefInfo ) :
112 ScXMLImportContext( rImport ),
113 mrExternalRefInfo(rRefInfo)
117 ScXMLExternalRefRowsContext::~ScXMLExternalRefRowsContext()
121 Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefRowsContext::createFastChildContext(
122 sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
124 // #i101319# row elements inside group, rows or header-rows
125 // are treated like row elements directly in the table element
127 const SvXMLTokenMap& rTokenMap = GetScImport().GetTableRowsElemTokenMap();
128 sal_uInt16 nToken = rTokenMap.Get( nElement );
129 sax_fastparser::FastAttributeList *pAttribList =
130 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
132 switch (nToken)
134 case XML_TOK_TABLE_ROWS_ROW_GROUP:
135 case XML_TOK_TABLE_ROWS_HEADER_ROWS:
136 case XML_TOK_TABLE_ROWS_ROWS:
137 return new ScXMLExternalRefRowsContext(
138 GetScImport(), mrExternalRefInfo);
139 case XML_TOK_TABLE_ROWS_ROW:
140 return new ScXMLExternalRefRowContext(
141 GetScImport(), pAttribList, mrExternalRefInfo);
142 default:
145 return new SvXMLImportContext( GetImport() );
148 ScXMLExternalRefRowContext::ScXMLExternalRefRowContext(
149 ScXMLImport& rImport,
150 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
151 ScXMLImportContext( rImport ),
152 mrScImport(rImport),
153 mrExternalRefInfo(rRefInfo),
154 mnRepeatRowCount(1)
156 mrExternalRefInfo.mnCol = 0;
158 const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap();
159 if ( rAttrList.is() )
161 for (auto &it : *rAttrList)
163 switch ( rAttrTokenMap.Get( it.getToken() ) )
165 case XML_TOK_TABLE_ROW_ATTR_REPEATED:
167 mnRepeatRowCount = std::max(it.toInt32(), static_cast<sal_Int32>(1));
169 break;
175 ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext()
179 Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefRowContext::createFastChildContext(
180 sal_Int32 nElement, const Reference< XFastAttributeList >& xAttrList )
182 const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap();
183 sal_uInt16 nToken = rTokenMap.Get( nElement );
184 sax_fastparser::FastAttributeList *pAttribList =
185 sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
187 if (nToken == XML_TOK_TABLE_ROW_CELL || nToken == XML_TOK_TABLE_ROW_COVERED_CELL)
188 return new ScXMLExternalRefCellContext(mrScImport, pAttribList, mrExternalRefInfo);
190 return new SvXMLImportContext( GetImport() );
193 void SAL_CALL ScXMLExternalRefRowContext::endFastElement( sal_Int32 /* nElement */ )
195 ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable;
197 for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i)
199 // Performance: duplicates of a non-existent row will still not exist.
200 // Don't find that out for every cell.
201 // External references often are a sparse matrix.
202 if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow))
204 mrExternalRefInfo.mnRow += mnRepeatRowCount;
205 return;
208 for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j)
210 ScExternalRefCache::TokenRef pToken = pTab->getCell(
211 static_cast<SCCOL>(j), static_cast<SCROW>(mrExternalRefInfo.mnRow));
213 if (pToken.get())
215 pTab->setCell(static_cast<SCCOL>(j),
216 static_cast<SCROW>(mrExternalRefInfo.mnRow+i), pToken);
220 mrExternalRefInfo.mnRow += mnRepeatRowCount;
223 ScXMLExternalRefCellContext::ScXMLExternalRefCellContext(
224 ScXMLImport& rImport,
225 const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList, ScXMLExternalTabData& rRefInfo ) :
226 ScXMLImportContext( rImport ),
227 mrScImport(rImport),
228 mrExternalRefInfo(rRefInfo),
229 mfCellValue(0.0),
230 mnRepeatCount(1),
231 mnNumberFormat(-1),
232 mnCellType(css::util::NumberFormat::UNDEFINED),
233 mbIsNumeric(false),
234 mbIsEmpty(true)
236 using namespace ::xmloff::token;
238 const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap();
239 if ( rAttrList.is() )
241 for (auto &it : *rAttrList)
243 switch ( rTokenMap.Get( it.getToken() ) )
245 case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME:
247 XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles());
248 const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>(
249 pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, it.toString(), true));
250 if (pStyle)
251 mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat();
253 break;
254 case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED:
256 mnRepeatCount = ::std::max( it.toInt32(), static_cast<sal_Int32>(1) );
258 break;
259 case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
261 mnCellType = ScXMLImport::GetCellType( it.toCString(), it.getLength() );
263 break;
264 case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
266 if ( !it.isEmpty() )
268 mfCellValue = it.toDouble();
269 mbIsNumeric = true;
270 mbIsEmpty = false;
273 break;
274 case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE:
276 if ( !it.isEmpty() && mrScImport.SetNullDateOnUnitConverter() )
278 mrScImport.GetMM100UnitConverter().convertDateTime( mfCellValue, it.toString() );
279 mbIsNumeric = true;
280 mbIsEmpty = false;
283 break;
284 case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE:
286 if ( !it.isEmpty() )
288 ::sax::Converter::convertDuration( mfCellValue, it.toString() );
289 mbIsNumeric = true;
290 mbIsEmpty = false;
293 break;
294 case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE:
296 if ( !it.isEmpty() )
298 maCellString = it.toString();
299 mbIsNumeric = false;
300 mbIsEmpty = false;
303 break;
304 case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE:
306 if ( !it.isEmpty() )
308 mfCellValue = IsXMLToken( it, XML_TRUE ) ? 1.0 : 0.0;
309 mbIsNumeric = true;
310 mbIsEmpty = false;
313 break;
314 default:
321 ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext()
325 Reference< XFastContextHandler > SAL_CALL ScXMLExternalRefCellContext::createFastChildContext(
326 sal_Int32 nElement, const Reference< XFastAttributeList >& /*xAttrList*/ )
328 const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap();
329 sal_uInt16 nToken = rTokenMap.Get( nElement );
331 if (nToken == XML_TOK_TABLE_ROW_CELL_P)
332 return new ScXMLExternalRefCellTextContext(mrScImport, *this);
334 return new SvXMLImportContext( GetImport() );
337 void SAL_CALL ScXMLExternalRefCellContext::endFastElement( sal_Int32 /*nElement*/ )
339 if (!maCellString.isEmpty())
340 mbIsEmpty = false;
342 for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol)
344 if (mbIsEmpty)
345 continue;
347 ScExternalRefCache::TokenRef aToken;
348 if (mbIsNumeric)
349 aToken.reset(new formula::FormulaDoubleToken(mfCellValue));
350 else
352 ScDocument& rDoc = mrScImport.GetDoc().getDoc();
353 svl::SharedString aSS = rDoc.GetSharedStringPool().intern(maCellString);
354 aToken.reset(new formula::FormulaStringToken(aSS));
357 sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast<sal_uInt32>(mnNumberFormat) : 0;
358 mrExternalRefInfo.mpCacheTable->setCell(
359 static_cast<SCCOL>(mrExternalRefInfo.mnCol),
360 static_cast<SCROW>(mrExternalRefInfo.mnRow),
361 aToken, nNumFmt);
365 void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr)
367 maCellString = rStr;
370 ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext(
371 ScXMLImport& rImport,
372 ScXMLExternalRefCellContext& rParent ) :
373 ScXMLImportContext( rImport ),
374 mrParent(rParent)
378 ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext()
382 void SAL_CALL ScXMLExternalRefCellTextContext::characters( const OUString& rChars )
384 maCellStrBuf.append( rChars );
387 void SAL_CALL ScXMLExternalRefCellTextContext::endFastElement( sal_Int32 /*nElement*/ )
389 mrParent.SetCellString( maCellStrBuf.makeStringAndClear() );
392 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */