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 4 : 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 4 : mrExternalRefInfo(rRefInfo)
50 : {
51 : using namespace ::xmloff::token;
52 :
53 4 : sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
54 24 : for (sal_Int16 i = 0; i < nAttrCount; ++i)
55 : {
56 20 : const OUString& sAttrName = xAttrList->getNameByIndex(i);
57 40 : OUString aLocalName;
58 20 : sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
59 40 : const OUString& sValue = xAttrList->getValueByIndex(i);
60 20 : if (nAttrPrefix == XML_NAMESPACE_XLINK)
61 : {
62 8 : if (IsXMLToken(aLocalName, XML_HREF))
63 4 : maRelativeUrl = sValue;
64 : }
65 12 : else if (nAttrPrefix == XML_NAMESPACE_TABLE)
66 : {
67 12 : if (IsXMLToken(aLocalName, XML_TABLE_NAME))
68 4 : maTableName = sValue;
69 8 : else if (IsXMLToken(aLocalName, XML_FILTER_NAME))
70 4 : maFilterName = sValue;
71 4 : else if (IsXMLToken(aLocalName, XML_FILTER_OPTIONS))
72 0 : maFilterOptions = sValue;
73 : }
74 20 : }
75 4 : }
76 :
77 8 : ScXMLExternalRefTabSourceContext::~ScXMLExternalRefTabSourceContext()
78 : {
79 8 : }
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 4 : static bool lcl_isValidRelativeURL(const OUString& rUrl)
95 : {
96 4 : sal_Int32 n = ::std::min( rUrl.getLength(), static_cast<sal_Int32>(3));
97 4 : if (n < 3)
98 0 : return false;
99 4 : const sal_Unicode* p = rUrl.getStr();
100 16 : for (sal_Int32 i = 0; i < n; ++i)
101 : {
102 12 : sal_Unicode c = p[i];
103 12 : if (i < 2 && c != '.')
104 : // the path must begin with '..'
105 0 : return false;
106 12 : else if (i == 2 && c != '/')
107 : // a '/' path separator must follow
108 0 : return false;
109 : }
110 4 : return true;
111 : }
112 :
113 4 : void ScXMLExternalRefTabSourceContext::EndElement()
114 : {
115 4 : ScDocument* pDoc = mrScImport.GetDocument();
116 4 : if (!pDoc)
117 4 : return;
118 :
119 4 : ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
120 4 : if (lcl_isValidRelativeURL(maRelativeUrl))
121 4 : pRefMgr->setRelativeFileName(mrExternalRefInfo.mnFileId, maRelativeUrl);
122 4 : 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 88 : 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 88 : mnRepeatRowCount(1)
173 : {
174 88 : mrExternalRefInfo.mnCol = 0;
175 :
176 88 : sal_Int16 nAttrCount(xAttrList.is() ? xAttrList->getLength() : 0);
177 88 : const SvXMLTokenMap& rAttrTokenMap = mrScImport.GetTableRowAttrTokenMap();
178 90 : for( sal_Int16 i=0; i < nAttrCount; ++i )
179 : {
180 2 : const OUString& sAttrName = xAttrList->getNameByIndex(i);
181 4 : OUString aLocalName;
182 2 : sal_uInt16 nAttrPrefix = mrScImport.GetNamespaceMap().GetKeyByAttrName(sAttrName, &aLocalName);
183 4 : const OUString& sValue = xAttrList->getValueByIndex(i);
184 :
185 2 : switch (rAttrTokenMap.Get(nAttrPrefix, aLocalName))
186 : {
187 : case XML_TOK_TABLE_ROW_ATTR_REPEATED:
188 : {
189 2 : mnRepeatRowCount = std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
190 : }
191 2 : break;
192 : }
193 2 : }
194 88 : }
195 :
196 176 : ScXMLExternalRefRowContext::~ScXMLExternalRefRowContext()
197 : {
198 176 : }
199 :
200 242 : SvXMLImportContext* ScXMLExternalRefRowContext::CreateChildContext(
201 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
202 : {
203 242 : const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowElemTokenMap();
204 242 : sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
205 242 : if (nToken == XML_TOK_TABLE_ROW_CELL || nToken == XML_TOK_TABLE_ROW_COVERED_CELL)
206 242 : return new ScXMLExternalRefCellContext(mrScImport, nPrefix, rLocalName, xAttrList, mrExternalRefInfo);
207 :
208 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
209 : }
210 :
211 88 : void ScXMLExternalRefRowContext::EndElement()
212 : {
213 88 : ScExternalRefCache::TableTypeRef pTab = mrExternalRefInfo.mpCacheTable;
214 :
215 88 : 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 2 : if (i == 1 && !pTab->hasRow( mrExternalRefInfo.mnRow))
221 : {
222 2 : mrExternalRefInfo.mnRow += mnRepeatRowCount;
223 90 : 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 86 : mrExternalRefInfo.mnRow += mnRepeatRowCount;
239 : }
240 :
241 242 : 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 242 : mbIsEmpty(true)
253 : {
254 : using namespace ::xmloff::token;
255 :
256 242 : sal_Int16 nAttrCount = xAttrList.is() ? xAttrList->getLength() : 0;
257 242 : const SvXMLTokenMap& rTokenMap = rImport.GetTableRowCellAttrTokenMap();
258 790 : for (sal_Int16 i = 0; i < nAttrCount; ++i)
259 : {
260 548 : OUString aLocalName;
261 548 : sal_uInt16 nAttrPrefix = rImport.GetNamespaceMap().GetKeyByAttrName(
262 1096 : xAttrList->getNameByIndex(i), &aLocalName);
263 :
264 1096 : const OUString& sValue = xAttrList->getValueByIndex(i);
265 548 : sal_uInt16 nToken = rTokenMap.Get(nAttrPrefix, aLocalName);
266 :
267 548 : switch (nToken)
268 : {
269 : case XML_TOK_TABLE_ROW_CELL_ATTR_STYLE_NAME:
270 : {
271 238 : XMLTableStylesContext* pStyles = static_cast<XMLTableStylesContext*>(mrScImport.GetAutoStyles());
272 : const XMLTableStyleContext* pStyle = static_cast<const XMLTableStyleContext*>(
273 238 : pStyles->FindStyleChildContext(XML_STYLE_FAMILY_TABLE_CELL, sValue, true));
274 238 : if (pStyle)
275 238 : mnNumberFormat = const_cast<XMLTableStyleContext*>(pStyle)->GetNumberFormat();
276 : }
277 238 : break;
278 : case XML_TOK_TABLE_ROW_CELL_ATTR_REPEATED:
279 : {
280 2 : mnRepeatCount = ::std::max(sValue.toInt32(), static_cast<sal_Int32>(1));
281 : }
282 2 : break;
283 : case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE_TYPE:
284 : {
285 228 : mnCellType = mrScImport.GetCellType(sValue);
286 : }
287 228 : break;
288 : case XML_TOK_TABLE_ROW_CELL_ATTR_VALUE:
289 : {
290 80 : if (!sValue.isEmpty())
291 : {
292 80 : ::sax::Converter::convertDouble(mfCellValue, sValue);
293 80 : mbIsNumeric = true;
294 80 : mbIsEmpty = false;
295 : }
296 : }
297 80 : 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 548 : }
342 242 : }
343 :
344 484 : ScXMLExternalRefCellContext::~ScXMLExternalRefCellContext()
345 : {
346 484 : }
347 :
348 238 : SvXMLImportContext* ScXMLExternalRefCellContext::CreateChildContext(
349 : sal_uInt16 nPrefix, const OUString& rLocalName, const Reference<XAttributeList>& xAttrList )
350 : {
351 238 : const SvXMLTokenMap& rTokenMap = mrScImport.GetTableRowCellElemTokenMap();
352 238 : sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLocalName);
353 238 : if (nToken == XML_TOK_TABLE_ROW_CELL_P)
354 238 : return new ScXMLExternalRefCellTextContext(mrScImport, nPrefix, rLocalName, xAttrList, *this);
355 :
356 0 : return new SvXMLImportContext(GetImport(), nPrefix, rLocalName);
357 : }
358 :
359 242 : void ScXMLExternalRefCellContext::EndElement()
360 : {
361 242 : if (!maCellString.isEmpty())
362 228 : mbIsEmpty = false;
363 :
364 494 : for (sal_Int32 i = 0; i < mnRepeatCount; ++i, ++mrExternalRefInfo.mnCol)
365 : {
366 252 : if (mbIsEmpty)
367 24 : continue;
368 :
369 228 : ScExternalRefCache::TokenRef aToken;
370 228 : if (mbIsNumeric)
371 80 : aToken.reset(new formula::FormulaDoubleToken(mfCellValue));
372 : else
373 : {
374 148 : ScDocument& rDoc = mrScImport.GetDoc().getDoc();
375 148 : svl::SharedString aSS = rDoc.GetSharedStringPool().intern(maCellString);
376 148 : aToken.reset(new formula::FormulaStringToken(aSS));
377 : }
378 :
379 228 : 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 228 : aToken, nNumFmt);
384 228 : }
385 242 : }
386 :
387 238 : void ScXMLExternalRefCellContext::SetCellString(const OUString& rStr)
388 : {
389 238 : maCellString = rStr;
390 238 : }
391 :
392 238 : 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 238 : mrParent(rParent)
398 : {
399 238 : }
400 :
401 476 : ScXMLExternalRefCellTextContext::~ScXMLExternalRefCellTextContext()
402 : {
403 476 : }
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 228 : void ScXMLExternalRefCellTextContext::Characters(const OUString& rChar)
412 : {
413 228 : maCellStrBuf.append(rChar);
414 228 : }
415 :
416 238 : void ScXMLExternalRefCellTextContext::EndElement()
417 : {
418 238 : mrParent.SetCellString(maCellStrBuf.makeStringAndClear());
419 466 : }
420 :
421 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|