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