Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #include "xmlexternaltabi.hxx"
21 : #include "xmlimprt.hxx"
22 : #include "xmltabi.hxx"
23 : #include "xmlstyli.hxx"
24 :
25 : #include "token.hxx"
26 : #include "document.hxx"
27 : #include <documentimport.hxx>
28 :
29 : #include <svl/sharedstringpool.hxx>
30 : #include <xmloff/nmspmap.hxx>
31 : #include <xmloff/xmlnmspe.hxx>
32 : #include <xmloff/xmltoken.hxx>
33 : #include <xmloff/xmluconv.hxx>
34 :
35 : #include <sax/tools/converter.hxx>
36 :
37 : #include <com/sun/star/util/NumberFormat.hpp>
38 :
39 : using namespace ::com::sun::star;
40 :
41 : using ::com::sun::star::uno::Reference;
42 : using ::com::sun::star::xml::sax::XAttributeList;
43 :
44 6 : ScXMLExternalRefTabSourceContext::ScXMLExternalRefTabSourceContext(
45 : ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName,
46 : const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
47 : SvXMLImportContext( rImport, nPrefix, rLName ),
48 : mrScImport(rImport),
49 6 : mrExternalRefInfo(rRefInfo)
50 : {
51 : using namespace ::xmloff::token;
52 :
53 6 : sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
54 36 : for (sal_Int16 i = 0; i < nAttrCount; ++i)
55 : {
56 30 : const OUString& sAttrName = xAttrList->getNameByIndex(i);
57 60 : OUString aLocalName;
58 30 : sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
59 60 : const OUString& sValue = xAttrList->getValueByIndex(i);
60 30 : if (nAttrPrefix == XML_NAMESPACE_XLINK)
61 : {
62 12 : if (IsXMLToken(aLocalName, XML_HREF))
63 6 : maRelativeUrl = sValue;
64 : }
65 18 : else if (nAttrPrefix == XML_NAMESPACE_TABLE)
66 : {
67 18 : if (IsXMLToken(aLocalName, XML_TABLE_NAME))
68 6 : maTableName = sValue;
69 12 : else if (IsXMLToken(aLocalName, XML_FILTER_NAME))
70 6 : maFilterName = sValue;
71 6 : else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS))
72 0 : maFilterOptions = sValue;
73 : }
74 30 : }
75 6 : }
76 :
77 12 : ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext()
78 : {
79 12 : }
80 :
81 0 : SvXMLImportContext* ScXMLExternalRefTabSourceContext::CreateChildContext(
82 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ )
83 : {
84 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
85 : }
86 :
87 : /**
88 : * Make sure the URL is a valid relative URL, mainly to avoid storing
89 : * absolute URL as relative URL by accident. For now, we only check the first
90 : * three characters which are assumed to be always '../', because the relative
91 : * URL for an external document is always in reference to the content.xml
92 : * fragment of the original document.
93 : */
94 6 : static bool lcl_isValidRelativeURL(const OUString& rUrl)
95 : {
96 6 : sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3));
97 6 : if (n < 3)
98 0 : return false;
99 6 : const sal_Unicode* p = rUrl.getStr();
100 24 : for (sal_Int32 i = 0; i < n; ++i)
101 : {
102 18 : sal_Unicode c = p[i];
103 18 : if (i < 2 && c != '.')
104 : // the path must begin with '..'
105 0 : return false;
106 18 : else if (i == 2 && c != '/')
107 : // a '/' path separator must follow
108 0 : return false;
109 : }
110 6 : return true;
111 : }
112 :
113 6 : void ScXMLExternalRefTabSourceContext::EndElement()
114 : {
115 6 : ScDocument* pDoc = mrScImport.GetDocument();
116 6 : if (!pDoc)
117 6 : return;
118 :
119 6 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
120 6 : if (lcl_isValidRelativeURL(maRelativeUrl))
121 6 : pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl);
122 6 : pRefMgr->setFilterData(mrExternalRefInfo.mnFileId, maFilterName, maFilterOptions);
123 : }
124 :
125 0 : ScXMLExternalRefRowsContext::ScXMLExternalRefRowsContext(
126 : ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName,
127 : const Reference<XAttributeList>& /* xAttrList */, ScXMLExternalTabData& rRefInfo ) :
128 : SvXMLImportContext( rImport, nPrefix, rLName ),
129 : mrScImport(rImport),
130 0 : mrExternalRefInfo(rRefInfo)
131 : {
132 0 : }
133 :
134 0 : ScXMLExternalRefRowsContext::~ScXMLExternalRefRowsContext()
135 : {
136 0 : }
137 :
138 0 : SvXMLImportContext* ScXMLExternalRefRowsContext::CreateChildContext(
139 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
140 : {
141 : // #i101319# row elements inside group, rows or header-rows
142 : // are treated like row elements directly in the table element
143 :
144 0 : const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowsElemTokenMap();
145 0 : sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
146 0 : switch (nToken)
147 : {
148 : case XML_TOK_TABLE_ROWS_ROW_GROUP:
149 : case XML_TOK_TABLE_ROWS_HEADER_ROWS:
150 : case XML_TOK_TABLE_ROWS_ROWS:
151 : return new ScXMLExternalRefRowsContext(
152 0 : mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo);
153 : case XML_TOK_TABLE_ROWS_ROW:
154 : return new ScXMLExternalRefRowContext(
155 0 : mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo);
156 : default:
157 : ;
158 : }
159 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
160 : }
161 :
162 0 : void ScXMLExternalRefRowsContext::EndElement()
163 : {
164 0 : }
165 :
166 68 : ScXMLExternalRefRowContext::ScXMLExternalRefRowContext(
167 : ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName,
168 : const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
169 : SvXMLImportContext( rImport, nPrefix, rLName ),
170 : mrScImport(rImport),
171 : mrExternalRefInfo(rRefInfo),
172 68 : mnRepeatRowCount(1)
173 : {
174 68 : mrExternalRefInfo.mnCol = 0;
175 :
176 68 : sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0);
177 68 : const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap();
178 71 : for( sal_Int16 i=0; i < nAttrCount; ++i )
179 : {
180 3 : const OUString& sAttrName = xAttrList->getNameByIndex(i);
181 6 : OUString aLocalName;
182 3 : sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
183 6 : const OUString& sValue = xAttrList->getValueByIndex(i);
184 :
185 3 : switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName))
186 : {
187 : case XML_TOK_TABLE_ROW_ATTR_REPEATED:
188 : {
189 3 : mnRepeatRowCount = std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
190 : }
191 3 : break;
192 : }
193 3 : }
194 68 : }
195 :
196 136 : ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext()
197 : {
198 136 : }
199 :
200 161 : SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext(
201 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
202 : {
203 161 : const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap();
204 161 : sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
205 161 : if (nToken == XML_TOK_TABLE_ROW_CELL || nToken == XML_TOK_TABLE_ROW_COVERED_CELL)
206 161 : return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo);
207 :
208 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
209 : }
210 :
211 68 : void ScXMLExternalRefRowContext::EndElement()
212 : {
213 68 : ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable;
214 :
215 68 : for (sal_Int32 i = 1; i < mnRepeatRowCount; ++i)
216 : {
217 : // Performance: duplicates of a non-existent row will still not exist.
218 : // Don't find that out for every cell.
219 : // External references often are a sparse matrix.
220 3 : if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow))
221 : {
222 3 : mrExternalRefInfo.mnRow += mnRepeatRowCount;
223 71 : return;
224 : }
225 :
226 0 : for (sal_Int32 j = 0; j < mrExternalRefInfo.mnCol; ++j)
227 : {
228 : ScExternalRefCache::TokenRef pToken = pTab->getCell(
229 0 : static_cast<SCCOL>(j), static_cast<SCROW>(mrExternalRefInfo.mnRow));
230 :
231 0 : if (pToken.get())
232 : {
233 : pTab->setCell(static_cast<SCCOL>(j),
234 0 : static_cast<SCROW>(mrExternalRefInfo.mnRow+i), pToken);
235 : }
236 0 : }
237 : }
238 65 : mrExternalRefInfo.mnRow += mnRepeatRowCount;
239 : }
240 :
241 161 : ScXMLExternalRefCellContext::ScXMLExternalRefCellContext(
242 : ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName,
243 : const Reference<XAttributeList>& xAttrList, ScXMLExternalTabData& rRefInfo ) :
244 : SvXMLImportContext( rImport, nPrefix, rLName ),
245 : mrScImport(rImport),
246 : mrExternalRefInfo(rRefInfo),
247 : mfCellValue(0.0),
248 : mnRepeatCount(1),
249 : mnNumberFormat(-1),
250 : mnCellType(::com::sun::star::util::NumberFormat::UNDEFINED),
251 : mbIsNumeric(false),
252 161 : mbIsEmpty(true)
253 : {
254 : using namespace ::xmloff::token;
255 :
256 161 : sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
257 161 : const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap();
258 525 : for (sal_Int16 i = 0; i < nAttrCount; ++i)
259 : {
260 364 : OUString aLocalName;
261 364 : sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(
262 728 : xAttrList->getNameByIndex(i), &aLocalName);
263 :
264 728 : const OUString& sValue = xAttrList->getValueByIndex(i);
265 364 : sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName);
266 :
267 364 : switch (nToken)
268 : {
269 : case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME:
270 : {
271 148 : XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles());
272 : const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>(
273 148 : pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, sValue, true));
274 148 : if (pStyle)
275 148 : mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat();
276 : }
277 148 : break;
278 : case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED:
279 : {
280 11 : mnRepeatCount = ::std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
281 : }
282 11 : break;
283 : case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
284 : {
285 143 : mnCellType = mrScImport.GetCellType(sValue);
286 : }
287 143 : break;
288 : case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
289 : {
290 62 : if (!sValue.isEmpty())
291 : {
292 62 : ::sax::Converter::convertDouble(mfCellValue, sValue);
293 62 : mbIsNumeric = true;
294 62 : mbIsEmpty = false;
295 : }
296 : }
297 62 : break;
298 : case XML_TOK_TABLE_ROW_CELL_ATTR_DATE_VALUE:
299 : {
300 0 : if (!sValue.isEmpty() && mrScImport.SetNullDateOnUnitConverter())
301 : {
302 0 : mrScImport.GetMM100UnitConverter().convertDateTime(mfCellValue, sValue);
303 0 : mbIsNumeric = true;
304 0 : mbIsEmpty = false;
305 : }
306 : }
307 0 : break;
308 : case XML_TOK_TABLE_ROW_CELL_ATTR_TIME_VALUE:
309 : {
310 0 : if (!sValue.isEmpty())
311 : {
312 0 : ::sax::Converter::convertDuration(mfCellValue, sValue);
313 0 : mbIsNumeric = true;
314 0 : mbIsEmpty = false;
315 : }
316 : }
317 0 : break;
318 : case XML_TOK_TABLE_ROW_CELL_ATTR_STRING_VALUE:
319 : {
320 0 : if (!sValue.isEmpty())
321 : {
322 0 : maCellString = sValue;
323 0 : mbIsNumeric = false;
324 0 : mbIsEmpty = false;
325 : }
326 : }
327 0 : break;
328 : case XML_TOK_TABLE_ROW_CELL_ATTR_BOOLEAN_VALUE:
329 : {
330 0 : if (!sValue.isEmpty())
331 : {
332 0 : mfCellValue = IsXMLToken(sValue, XML_TRUE) ? 1.0 : 0.0;
333 0 : mbIsNumeric = true;
334 0 : mbIsEmpty = false;
335 : }
336 : }
337 0 : break;
338 : default:
339 : ;
340 : }
341 364 : }
342 161 : }
343 :
344 322 : ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext()
345 : {
346 322 : }
347 :
348 148 : SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext(
349 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
350 : {
351 148 : const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap();
352 148 : sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
353 148 : if (nToken == XML_TOK_TABLE_ROW_CELL_P)
354 148 : return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, *this);
355 :
356 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
357 : }
358 :
359 161 : void ScXMLExternalRefCellContext::EndElement()
360 : {
361 161 : if (!maCellString.isEmpty())
362 143 : mbIsEmpty = false;
363 :
364 352 : for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol)
365 : {
366 191 : if (mbIsEmpty)
367 48 : continue;
368 :
369 143 : ScExternalRefCache::TokenRef aToken;
370 143 : if (mbIsNumeric)
371 62 : aToken.reset(new formula::FormulaDoubleToken(mfCellValue));
372 : else
373 : {
374 81 : ScDocument& rDoc = mrScImport.GetDoc().getDoc();
375 81 : svl::SharedString aSS = rDoc.GetSharedStringPool().intern(maCellString);
376 81 : aToken.reset(new formula::FormulaStringToken(aSS));
377 : }
378 :
379 143 : sal_uInt32 nNumFmt = mnNumberFormat >= 0 ? static_cast<sal_uInt32>(mnNumberFormat) : 0;
380 : mrExternalRefInfo.mpCacheTable->setCell(
381 : static_cast<SCCOL>(mrExternalRefInfo.mnCol),
382 : static_cast<SCROW>(mrExternalRefInfo.mnRow),
383 143 : aToken, nNumFmt);
384 143 : }
385 161 : }
386 :
387 148 : void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr)
388 : {
389 148 : maCellString = rStr;
390 148 : }
391 :
392 148 : ScXMLExternalRefCellTextContext::ScXMLExternalRefCellTextContext(
393 : ScXMLImport& rImport, sal_uInt16 nPrefix, const OUString& rLName,
394 : const Reference<XAttributeList>& /*xAttrList*/,
395 : ScXMLExternalRefCellContext& rParent ) :
396 : SvXMLImportContext( rImport, nPrefix, rLName ),
397 148 : mrParent(rParent)
398 : {
399 148 : }
400 :
401 296 : ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext()
402 : {
403 296 : }
404 :
405 0 : SvXMLImportContext* ScXMLExternalRefCellTextContext::CreateChildContext(
406 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& /*xAttrList*/ )
407 : {
408 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
409 : }
410 :
411 143 : void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar)
412 : {
413 143 : maCellStrBuf.append(rChar);
414 143 : }
415 :
416 148 : void ScXMLExternalRefCellTextContext::EndElement()
417 : {
418 148 : mrParent.SetCellString(maCellStrBuf.makeStringAndClear());
419 304 : }
420 :
421 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|