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 "xmltabi.hxx"
21 #include "xmlimprt.hxx"
22 #include "xmlrowi.hxx"
23 #include "xmlcoli.hxx"
24 #include "xmlsceni.hxx"
25 #include "xmlexternaltabi.hxx"
26 #include "xmlnexpi.hxx"
27 #include <document.hxx>
28 #include <docuno.hxx>
29 #include <olinetab.hxx>
30 #include "XMLTableShapesContext.hxx"
31 #include "XMLTableSourceContext.hxx"
32 #include "XMLStylesImportHelper.hxx"
33 #include <rangeutl.hxx>
34 #include <externalrefmgr.hxx>
35 #include <sheetdata.hxx>
36 #include "xmlcondformat.hxx"
37 
38 #include <xmloff/xmltkmap.hxx>
39 #include <xmloff/xmltoken.hxx>
40 #include <xmloff/xmlnmspe.hxx>
41 #include <xmloff/XMLEventsImportContext.hxx>
42 #include <sal/log.hxx>
43 
44 #include <tools/urlobj.hxx>
45 #include <sax/fastattribs.hxx>
46 #include <comphelper/servicehelper.hxx>
47 
48 using namespace com::sun::star;
49 using namespace xmloff::token;
50 using ::com::sun::star::uno::Reference;
51 using ::com::sun::star::uno::UNO_QUERY;
52 using ::com::sun::star::xml::sax::XAttributeList;
53 
54 /**
55  * Determine whether this table is an external reference cache from its
56  * name.  There is currently no way of determining whether a table is a
57  * regular table or an external reference cache other than examining the
58  * name itself.  We should probably introduce a new boolean value for
59  * table:table element and use it instead of doing this, to make it more
60  * reliable and future-proof.
61  *
62  * @param rName
63  *
64  * @return
65  */
lcl_isExternalRefCache(const OUString & rName,OUString & rUrl,OUString & rExtTabName)66 static bool lcl_isExternalRefCache(const OUString& rName, OUString& rUrl, OUString& rExtTabName)
67 {
68     // 'file:///path/to/file.ods'#MySheet
69     // 'file:///path/to/file.ods'#MySheet with space
70     // 'file:///path/to/file's.ods'#Sheet (Notice the quote in the file name.
71     //  That's allowed.)
72 
73     if ( rName.toChar() != '\'' )       // initial quote
74         return false;
75 
76     // #i114504# Other schemes besides "file:" are also allowed.
77     // CompareProtocolScheme is quick, only looks at the start of the string.
78     INetProtocol eProt = INetURLObject::CompareProtocolScheme( rName.copy(1) );
79     if ( eProt == INetProtocol::NotValid )
80         return false;
81 
82     OUString aPrefix = INetURLObject::GetScheme( eProt );
83     sal_Int32 nPrefLen = aPrefix.getLength();
84 
85     OUStringBuffer aUrlBuf, aTabNameBuf;
86     aUrlBuf.append( aPrefix );
87     sal_Int32 n = rName.getLength();
88     const sal_Unicode* p = rName.getStr();
89 
90     bool bInUrl = true;
91     sal_Unicode cPrev = 0;
92     for (sal_Int32 i = nPrefLen+1; i < n; ++i)      // start the loop after quote and prefix
93     {
94         const sal_Unicode c = p[i];
95         if (bInUrl)
96         {
97             // parsing file URL
98             if (c == '#')
99             {
100                 if (cPrev != '\'')
101                     return false;
102 
103                 rUrl = aUrlBuf.makeStringAndClear();
104                 rUrl = rUrl.copy(0, rUrl.getLength()-1); // remove the trailing single-quote.
105                 bInUrl = false;
106             }
107             else
108                 aUrlBuf.append(c);
109         }
110         else
111             // parsing sheet name.
112             aTabNameBuf.append(c);
113 
114         cPrev = c;
115     }
116 
117     if (bInUrl)
118         return false;
119 
120     if (aTabNameBuf.isEmpty())
121         return false;
122 
123     rExtTabName = aTabNameBuf.makeStringAndClear();
124 
125     return true;
126 }
127 
ScXMLExternalTabData()128 ScXMLExternalTabData::ScXMLExternalTabData() :
129     mpCacheTable(), mnRow(0), mnCol(0), mnFileId(0)
130 {
131 }
132 
ScXMLTableContext(ScXMLImport & rImport,const rtl::Reference<sax_fastparser::FastAttributeList> & rAttrList)133 ScXMLTableContext::ScXMLTableContext( ScXMLImport& rImport,
134                                       const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
135     ScXMLImportContext( rImport ),
136     nStartOffset(-1),
137     bStartFormPage(false),
138     bPrintEntireSheet(true)
139 {
140     // get start offset in file (if available)
141     nStartOffset = GetScImport().GetByteOffset();
142 
143     ScXMLTabProtectionData aProtectData;
144     OUString sName;
145     OUString sStyleName;
146 
147     if ( rAttrList.is() )
148     {
149         for (auto &it : *rAttrList)
150         {
151             switch (it.getToken())
152             {
153                 case XML_ELEMENT( TABLE, XML_NAME ):
154                         sName = it.toString();
155                     break;
156                 case XML_ELEMENT( TABLE, XML_STYLE_NAME ):
157                         sStyleName = it.toString();
158                     break;
159                 case XML_ELEMENT( TABLE, XML_PROTECTED ):
160                     aProtectData.mbProtected = IsXMLToken( it, XML_TRUE );
161                 break;
162                 case XML_ELEMENT( TABLE, XML_PRINT_RANGES ):
163                         sPrintRanges = it.toString();
164                     break;
165                 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY ):
166                     aProtectData.maPassword = it.toString();
167                 break;
168                 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM ):
169                     aProtectData.meHash1 = ScPassHashHelper::getHashTypeFromURI( it.toString() );
170                 break;
171                 case XML_ELEMENT( TABLE, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2 ):
172                 case XML_ELEMENT( LO_EXT, XML_PROTECTION_KEY_DIGEST_ALGORITHM_2 ):
173                     aProtectData.meHash2 = ScPassHashHelper::getHashTypeFromURI( it.toString() );
174                 break;
175                 case XML_ELEMENT( TABLE, XML_PRINT ):
176                     {
177                         if ( IsXMLToken( it, XML_FALSE) )
178                             bPrintEntireSheet = false;
179                     }
180                     break;
181             }
182 
183         }
184     }
185 
186     OUString aExtUrl, aExtTabName;
187     if (lcl_isExternalRefCache(sName, aExtUrl, aExtTabName))
188     {
189         // This is an external ref cache table.
190         pExternalRefInfo.reset(new ScXMLExternalTabData);
191         ScDocument* pDoc = GetScImport().GetDocument();
192         if (pDoc)
193         {
194             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
195             pExternalRefInfo->mnFileId = pRefMgr->getExternalFileId(aExtUrl);
196             pExternalRefInfo->mpCacheTable = pRefMgr->getCacheTable(pExternalRefInfo->mnFileId, aExtTabName, true,
197                     nullptr, &aExtUrl);
198             pExternalRefInfo->mpCacheTable->setWholeTableCached();
199         }
200     }
201     else
202     {
203         // This is a regular table.
204         GetScImport().GetTables().NewSheet(sName, sStyleName, aProtectData);
205     }
206 }
207 
~ScXMLTableContext()208 ScXMLTableContext::~ScXMLTableContext()
209 {
210 }
211 
CreateChildContext(sal_uInt16 nPrefix,const OUString & rLName,const css::uno::Reference<css::xml::sax::XAttributeList> &)212 SvXMLImportContextRef ScXMLTableContext::CreateChildContext( sal_uInt16 nPrefix,
213                                             const OUString& rLName,
214                                             const css::uno::Reference<css::xml::sax::XAttributeList>& /*xAttrList*/ )
215 {
216     const SvXMLTokenMap& rTokenMap(GetScImport().GetTableElemTokenMap());
217     sal_uInt16 nToken = rTokenMap.Get(nPrefix, rLName);
218     if (pExternalRefInfo)
219     {
220         return new SvXMLImportContext(GetImport(), nPrefix, rLName);
221     }
222 
223     SvXMLImportContext *pContext(nullptr);
224 
225     switch (nToken)
226     {
227     case XML_TOK_TABLE_FORMS:
228         {
229             GetScImport().GetFormImport()->startPage(GetScImport().GetTables().GetCurrentXDrawPage());
230             bStartFormPage = true;
231             pContext = xmloff::OFormLayerXMLImport::createOfficeFormsContext( GetScImport(), nPrefix, rLName );
232         }
233         break;
234     case XML_TOK_TABLE_EVENT_LISTENERS:
235     case XML_TOK_TABLE_EVENT_LISTENERS_EXT:
236         {
237             // use XEventsSupplier interface of the sheet
238             uno::Reference<document::XEventsSupplier> xSupplier( GetScImport().GetTables().GetCurrentXSheet(), uno::UNO_QUERY );
239             pContext = new XMLEventsImportContext( GetImport(), nPrefix, rLName, xSupplier );
240         }
241         break;
242     default:
243         ;
244     }
245 
246     if( !pContext )
247         pContext = new SvXMLImportContext( GetImport(), nPrefix, rLName );
248 
249     return pContext;
250 }
251 
252 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
createFastChildContext(sal_Int32 nElement,const uno::Reference<xml::sax::XFastAttributeList> & xAttrList)253         ScXMLTableContext::createFastChildContext( sal_Int32 nElement,
254         const uno::Reference< xml::sax::XFastAttributeList > & xAttrList )
255 {
256     sax_fastparser::FastAttributeList *pAttribList =
257         sax_fastparser::FastAttributeList::castToFastAttributeList( xAttrList );
258 
259     if (pExternalRefInfo)
260     {
261         // We only care about the table-row and table-source elements for
262         // external cache data.
263         switch ( nElement )
264         {
265             case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
266             case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
267             case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
268                 // #i101319# don't discard rows in groups or header (repeat range)
269                 return new ScXMLExternalRefRowsContext(
270                     GetScImport(), *pExternalRefInfo);
271             case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
272                 return new ScXMLExternalRefRowContext(
273                     GetScImport(), pAttribList, *pExternalRefInfo);
274             case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
275                 return new ScXMLExternalRefTabSourceContext(
276                     GetScImport(), pAttribList, *pExternalRefInfo);
277             default:
278                 ;
279         }
280         return new SvXMLImportContext( GetImport() );
281     }
282 
283     SvXMLImportContext *pContext(nullptr);
284 
285     switch ( nElement )
286     {
287     case XML_ELEMENT( TABLE, XML_NAMED_EXPRESSIONS ):
288     {
289         SCTAB nTab = GetScImport().GetTables().GetCurrentSheet();
290         pContext = new ScXMLNamedExpressionsContext(
291             GetScImport(),
292             new ScXMLNamedExpressionsContext::SheetLocalInserter(GetScImport(), nTab));
293     }
294         break;
295     case XML_ELEMENT( TABLE, XML_TABLE_COLUMN_GROUP ):
296         pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
297                                                    false, true );
298         break;
299     case XML_ELEMENT( TABLE, XML_TABLE_HEADER_COLUMNS ):
300         pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
301                                                    true, false );
302         break;
303     case XML_ELEMENT( TABLE, XML_TABLE_COLUMNS ):
304         pContext = new ScXMLTableColsContext( GetScImport(), pAttribList,
305                                                    false, false );
306         break;
307     case XML_ELEMENT( TABLE, XML_TABLE_COLUMN ):
308         pContext = new ScXMLTableColContext( GetScImport(), pAttribList );
309         break;
310     case XML_ELEMENT( TABLE, XML_TABLE_PROTECTION ):
311     case XML_ELEMENT( LO_EXT, XML_TABLE_PROTECTION ):
312     case XML_ELEMENT( OFFICE_EXT, XML_TABLE_PROTECTION ):
313         pContext = new ScXMLTableProtectionContext( GetScImport(), pAttribList );
314         break;
315     case XML_ELEMENT( TABLE, XML_TABLE_ROW_GROUP ):
316         pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
317                                                    false, true );
318         break;
319     case XML_ELEMENT( TABLE, XML_TABLE_HEADER_ROWS ):
320         pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
321                                                    true, false );
322         break;
323     case XML_ELEMENT( TABLE, XML_TABLE_ROWS ):
324         pContext = new ScXMLTableRowsContext( GetScImport(), pAttribList,
325                                                    false, false );
326         break;
327     case XML_ELEMENT( TABLE, XML_TABLE_ROW ):
328             pContext = new ScXMLTableRowContext( GetScImport(), pAttribList );
329         break;
330     case XML_ELEMENT( TABLE, XML_TABLE_SOURCE ):
331         pContext = new ScXMLTableSourceContext( GetScImport(), pAttribList);
332         break;
333     case XML_ELEMENT( TABLE, XML_SCENARIO ):
334         pContext = new ScXMLTableScenarioContext( GetScImport(), pAttribList);
335         break;
336     case XML_ELEMENT( TABLE, XML_SHAPES ):
337         pContext = new ScXMLTableShapesContext( GetScImport() );
338         break;
339     case XML_ELEMENT( CALC_EXT, XML_CONDITIONAL_FORMATS ):
340         pContext = new ScXMLConditionalFormatsContext( GetScImport() );
341         break;
342     default:
343         pContext = new SvXMLImportContext( GetImport() );
344     }
345 
346     assert(pContext);
347 
348     return pContext;
349 }
350 
endFastElement(sal_Int32)351 void SAL_CALL ScXMLTableContext::endFastElement(sal_Int32 /*nElement*/)
352 {
353     ScXMLImport::MutexGuard aMutexGuard(GetScImport());
354     ScXMLImport& rImport = GetScImport();
355     rImport.GetStylesImportHelper()->EndTable();
356     ScDocument* pDoc(rImport.GetDocument());
357     if (!pDoc)
358         return;
359 
360     ScMyTables& rTables = rImport.GetTables();
361     SCTAB nCurTab = rTables.GetCurrentSheet();
362     if (!sPrintRanges.isEmpty())
363     {
364         ScRangeList aRangeList;
365         ScRangeStringConverter::GetRangeListFromString( aRangeList, sPrintRanges, pDoc, ::formula::FormulaGrammar::CONV_OOO );
366         size_t nCount = aRangeList.size();
367         for (size_t i=0; i< nCount; i++ )
368         {
369             pDoc->AddPrintRange( nCurTab, aRangeList[i] );
370         }
371     }
372     else if (!bPrintEntireSheet)
373         // Sheet has "print entire sheet" option by default.  Remove it.
374         pDoc->ClearPrintRanges(nCurTab);
375 
376     ScOutlineTable* pOutlineTable(pDoc->GetOutlineTable(nCurTab));
377     if (pOutlineTable)
378     {
379         ScOutlineArray& rColArray(pOutlineTable->GetColArray());
380         size_t nDepth = rColArray.GetDepth();
381         for (size_t i = 0; i < nDepth; ++i)
382         {
383             size_t nCount = rColArray.GetCount(i);
384             for (size_t j = 0; j < nCount; ++j)
385             {
386                 const ScOutlineEntry* pEntry = rColArray.GetEntry(i, j);
387                 if (pEntry->IsHidden())
388                     rColArray.SetVisibleBelow(i, j, false);
389             }
390         }
391         ScOutlineArray& rRowArray(pOutlineTable->GetRowArray());
392         nDepth = rRowArray.GetDepth();
393         for (size_t i = 0; i < nDepth; ++i)
394         {
395             size_t nCount = rRowArray.GetCount(i);
396             for (size_t j = 0; j < nCount; ++j)
397             {
398                 const ScOutlineEntry* pEntry = rRowArray.GetEntry(i, j);
399                 if (pEntry->IsHidden())
400                     rRowArray.SetVisibleBelow(i, j, false);
401             }
402         }
403     }
404     if (rTables.HasDrawPage())
405     {
406         if (rTables.HasXShapes())
407         {
408             rImport.GetShapeImport()->popGroupAndPostProcess();
409             uno::Reference < drawing::XShapes > xTempShapes(rTables.GetCurrentXShapes());
410             rImport.GetShapeImport()->endPage(xTempShapes);
411         }
412         if (bStartFormPage)
413             rImport.GetFormImport()->endPage();
414     }
415 
416     rTables.DeleteTable();
417     rImport.ProgressBarIncrement();
418 
419     // store stream positions
420     if (!pExternalRefInfo && nStartOffset >= 0 /* && nEndOffset >= 0 */)
421     {
422         ScSheetSaveData* pSheetData = comphelper::getUnoTunnelImplementation<ScModelObj>(rImport.GetModel())->GetSheetSaveData();
423         SCTAB nTab = rTables.GetCurrentSheet();
424         // pSheetData->AddStreamPos( nTab, nStartOffset, nEndOffset );
425         pSheetData->StartStreamPos( nTab, nStartOffset );
426     }
427 }
428 
ScXMLTableProtectionContext(ScXMLImport & rImport,const rtl::Reference<sax_fastparser::FastAttributeList> & rAttrList)429 ScXMLTableProtectionContext::ScXMLTableProtectionContext(
430     ScXMLImport& rImport,
431     const rtl::Reference<sax_fastparser::FastAttributeList>& rAttrList ) :
432     ScXMLImportContext( rImport )
433 {
434     bool bSelectProtectedCells = false;
435     bool bSelectUnprotectedCells = false;
436     bool bInsertColumns = false;
437     bool bInsertRows = false;
438     bool bDeleteColumns = false;
439     bool bDeleteRows = false;
440 
441     if ( rAttrList.is() )
442     {
443         for (auto &aIter : *rAttrList)
444         {
445             sal_Int32 nToken = aIter.getToken();
446             switch (nToken)
447             {
448             case XML_ELEMENT( TABLE, XML_SELECT_PROTECTED_CELLS ):
449             case XML_ELEMENT( OFFICE_EXT, XML_SELECT_PROTECTED_CELLS ):
450             case XML_ELEMENT( LO_EXT, XML_SELECT_PROTECTED_CELLS ):
451                 bSelectProtectedCells = IsXMLToken(aIter, XML_TRUE);
452                 break;
453             case XML_ELEMENT( TABLE, XML_SELECT_UNPROTECTED_CELLS ):
454             case XML_ELEMENT( OFFICE_EXT, XML_SELECT_UNPROTECTED_CELLS ):
455             case XML_ELEMENT( LO_EXT, XML_SELECT_UNPROTECTED_CELLS ):
456                 bSelectUnprotectedCells = IsXMLToken(aIter, XML_TRUE);
457                 break;
458             case XML_ELEMENT( LO_EXT, XML_INSERT_COLUMNS ):
459                 bInsertColumns = IsXMLToken(aIter, XML_TRUE);
460                 break;
461             case XML_ELEMENT( LO_EXT,  XML_INSERT_ROWS ):
462                 bInsertRows = IsXMLToken(aIter, XML_TRUE);
463                 break;
464             case XML_ELEMENT( LO_EXT, XML_DELETE_COLUMNS ):
465                 bDeleteColumns = IsXMLToken(aIter, XML_TRUE);
466                 break;
467             case XML_ELEMENT( LO_EXT, XML_DELETE_ROWS ):
468                 bDeleteRows = IsXMLToken(aIter, XML_TRUE);
469                 break;
470             default:
471                 SAL_WARN("sc", "unknown attribute: " << nToken);
472             }
473         }
474     }
475 
476     ScXMLTabProtectionData& rProtectData = GetScImport().GetTables().GetCurrentProtectionData();
477     rProtectData.mbSelectProtectedCells   = bSelectProtectedCells;
478     rProtectData.mbSelectUnprotectedCells = bSelectUnprotectedCells;
479     rProtectData.mbInsertColumns = bInsertColumns;
480     rProtectData.mbInsertRows = bInsertRows;
481     rProtectData.mbDeleteColumns = bDeleteColumns;
482     rProtectData.mbDeleteRows = bDeleteRows;
483 }
484 
~ScXMLTableProtectionContext()485 ScXMLTableProtectionContext::~ScXMLTableProtectionContext()
486 {
487 }
488 
createFastChildContext(sal_Int32,const uno::Reference<xml::sax::XFastAttributeList> &)489 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL ScXMLTableProtectionContext::createFastChildContext(
490     sal_Int32 /*nElement*/, const uno::Reference< xml::sax::XFastAttributeList >& /*xAttrList*/ )
491 {
492     return nullptr;
493 }
494 
495 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
496