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 <pivotcachefragment.hxx>
21 
22 #include <osl/diagnose.h>
23 #include <oox/token/namespaces.hxx>
24 #include <biffhelper.hxx>
25 #include <formulabuffer.hxx>
26 #include <pivotcachebuffer.hxx>
27 #include <worksheetbuffer.hxx>
28 
29 namespace oox::xls {
30 
31 using namespace ::com::sun::star::uno;
32 using namespace ::oox::core;
33 
PivotCacheFieldContext(WorkbookFragmentBase & rFragment,PivotCacheField & rCacheField)34 PivotCacheFieldContext::PivotCacheFieldContext( WorkbookFragmentBase& rFragment, PivotCacheField& rCacheField ) :
35     WorkbookContextBase( rFragment ),
36     mrCacheField( rCacheField )
37 {
38 }
39 
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)40 ContextHandlerRef PivotCacheFieldContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
41 {
42     switch( getCurrentElement() )
43     {
44         case XLS_TOKEN( cacheField ):
45             if( nElement == XLS_TOKEN( sharedItems ) )  { mrCacheField.importSharedItems( rAttribs );   return this; }
46             if( nElement == XLS_TOKEN( fieldGroup ) )   { mrCacheField.importFieldGroup( rAttribs );    return this; }
47         break;
48 
49         case XLS_TOKEN( fieldGroup ):
50             switch( nElement )
51             {
52                 case XLS_TOKEN( rangePr ):      mrCacheField.importRangePr( rAttribs );     break;
53                 case XLS_TOKEN( discretePr ):   return this;
54                 case XLS_TOKEN( groupItems ):   return this;
55             }
56         break;
57 
58         case XLS_TOKEN( sharedItems ):  mrCacheField.importSharedItem( nElement, rAttribs );        break;
59         case XLS_TOKEN( discretePr ):   mrCacheField.importDiscretePrItem( nElement, rAttribs );    break;
60         case XLS_TOKEN( groupItems ):   mrCacheField.importGroupItem( nElement, rAttribs );         break;
61     }
62     return nullptr;
63 }
64 
onStartElement(const AttributeList & rAttribs)65 void PivotCacheFieldContext::onStartElement( const AttributeList& rAttribs )
66 {
67     if( isRootElement() )
68         mrCacheField.importCacheField( rAttribs );
69 }
70 
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)71 ContextHandlerRef PivotCacheFieldContext::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
72 {
73     switch( getCurrentElement() )
74     {
75         case BIFF12_ID_PCDFIELD:
76             switch( nRecId )
77             {
78                 case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItems( rStrm );  return this;
79                 case BIFF12_ID_PCDFIELDGROUP:   mrCacheField.importPCDFieldGroup( rStrm );    return this;
80             }
81         break;
82 
83         case BIFF12_ID_PCDFIELDGROUP:
84             switch( nRecId )
85             {
86                 case BIFF12_ID_PCDFRANGEPR:     mrCacheField.importPCDFRangePr( rStrm );    break;
87                 case BIFF12_ID_PCDFDISCRETEPR:  return this;
88                 case BIFF12_ID_PCDFGROUPITEMS:  return this;
89             }
90         break;
91 
92         case BIFF12_ID_PCDFSHAREDITEMS: mrCacheField.importPCDFSharedItem( nRecId, rStrm );     break;
93         case BIFF12_ID_PCDFDISCRETEPR:  mrCacheField.importPCDFDiscretePrItem( nRecId, rStrm ); break;
94         case BIFF12_ID_PCDFGROUPITEMS:  mrCacheField.importPCDFGroupItem( nRecId, rStrm );      break;
95     }
96     return nullptr;
97 }
98 
onStartRecord(SequenceInputStream & rStrm)99 void PivotCacheFieldContext::onStartRecord( SequenceInputStream& rStrm )
100 {
101     if( isRootElement() )
102         mrCacheField.importPCDField( rStrm );
103 }
104 
PivotCacheDefinitionFragment(const WorkbookHelper & rHelper,const OUString & rFragmentPath,PivotCache & rPivotCache)105 PivotCacheDefinitionFragment::PivotCacheDefinitionFragment(
106         const WorkbookHelper& rHelper, const OUString& rFragmentPath, PivotCache& rPivotCache ) :
107     WorkbookFragmentBase( rHelper, rFragmentPath ),
108     mrPivotCache( rPivotCache )
109 {
110 }
111 
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)112 ContextHandlerRef PivotCacheDefinitionFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
113 {
114     switch( getCurrentElement() )
115     {
116         case XML_ROOT_CONTEXT:
117             if( nElement == XLS_TOKEN( pivotCacheDefinition ) ) { mrPivotCache.importPivotCacheDefinition( rAttribs ); return this; }
118         break;
119 
120         case XLS_TOKEN( pivotCacheDefinition ):
121             switch( nElement )
122             {
123                 case XLS_TOKEN( cacheSource ):  mrPivotCache.importCacheSource( rAttribs ); return this;
124                 case XLS_TOKEN( cacheFields ):  return this;
125             }
126         break;
127 
128         case XLS_TOKEN( cacheSource ):
129             if( nElement == XLS_TOKEN( worksheetSource ) ) mrPivotCache.importWorksheetSource( rAttribs, getRelations() );
130         break;
131 
132         case XLS_TOKEN( cacheFields ):
133             if( nElement == XLS_TOKEN( cacheField ) ) return new PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
134         break;
135     }
136     return nullptr;
137 }
138 
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)139 ContextHandlerRef PivotCacheDefinitionFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
140 {
141     switch( getCurrentElement() )
142     {
143         case XML_ROOT_CONTEXT:
144             if( nRecId == BIFF12_ID_PCDEFINITION ) { mrPivotCache.importPCDefinition( rStrm ); return this; }
145         break;
146 
147         case BIFF12_ID_PCDEFINITION:
148             switch( nRecId )
149             {
150                 case BIFF12_ID_PCDSOURCE: mrPivotCache.importPCDSource( rStrm ); return this;
151                 case BIFF12_ID_PCDFIELDS: return this;
152             }
153         break;
154 
155         case BIFF12_ID_PCDSOURCE:
156             if( nRecId == BIFF12_ID_PCDSHEETSOURCE ) mrPivotCache.importPCDSheetSource( rStrm, getRelations() );
157         break;
158 
159         case BIFF12_ID_PCDFIELDS:
160             if( nRecId == BIFF12_ID_PCDFIELD ) return new PivotCacheFieldContext( *this, mrPivotCache.createCacheField() );
161         break;
162     }
163     return nullptr;
164 }
165 
getRecordInfos() const166 const RecordInfo* PivotCacheDefinitionFragment::getRecordInfos() const
167 {
168     static const RecordInfo spRecInfos[] =
169     {
170         { BIFF12_ID_PCDEFINITION,       BIFF12_ID_PCDEFINITION + 1      },
171         { BIFF12_ID_PCDFDISCRETEPR,     BIFF12_ID_PCDFDISCRETEPR + 1    },
172         { BIFF12_ID_PCDFGROUPITEMS,     BIFF12_ID_PCDFGROUPITEMS + 1    },
173         { BIFF12_ID_PCDFIELD,           BIFF12_ID_PCDFIELD + 1          },
174         { BIFF12_ID_PCDFIELDGROUP,      BIFF12_ID_PCDFIELDGROUP + 1     },
175         { BIFF12_ID_PCDFIELDS,          BIFF12_ID_PCDFIELDS + 1         },
176         { BIFF12_ID_PCDFRANGEPR,        BIFF12_ID_PCDFRANGEPR + 1       },
177         { BIFF12_ID_PCDFSHAREDITEMS,    BIFF12_ID_PCDFSHAREDITEMS + 1   },
178         { BIFF12_ID_PCITEM_ARRAY,       BIFF12_ID_PCITEM_ARRAY + 1      },
179         { BIFF12_ID_PCDSHEETSOURCE,     BIFF12_ID_PCDSHEETSOURCE + 1    },
180         { BIFF12_ID_PCDSOURCE,          BIFF12_ID_PCDSOURCE + 1         },
181         { -1,                           -1                              }
182     };
183     return spRecInfos;
184 }
185 
finalizeImport()186 void PivotCacheDefinitionFragment::finalizeImport()
187 {
188     // finalize the cache (check source range etc.)
189     mrPivotCache.finalizeImport();
190 
191     // load the cache records, if the cache is based on a deleted or an external worksheet
192     if( mrPivotCache.isValidDataSource() && mrPivotCache.isBasedOnDummySheet() )
193     {
194         OUString aRecFragmentPath = getRelations().getFragmentPathFromRelId( mrPivotCache.getRecordsRelId() );
195         if( !aRecFragmentPath.isEmpty() )
196         {
197             SCTAB nSheet = mrPivotCache.getSourceRange().aStart.Tab();
198             WorksheetGlobalsRef xSheetGlob = WorksheetHelper::constructGlobals( *this, ISegmentProgressBarRef(), WorksheetType::Work, nSheet );
199             if( xSheetGlob )
200                 importOoxFragment( new PivotCacheRecordsFragment( *xSheetGlob, aRecFragmentPath, mrPivotCache ) );
201         }
202     }
203 }
204 
PivotCacheRecordsFragment(const WorksheetHelper & rHelper,const OUString & rFragmentPath,const PivotCache & rPivotCache)205 PivotCacheRecordsFragment::PivotCacheRecordsFragment( const WorksheetHelper& rHelper,
206         const OUString& rFragmentPath, const PivotCache& rPivotCache ) :
207     WorksheetFragmentBase( rHelper, rFragmentPath ),
208     mrPivotCache( rPivotCache ),
209     mnColIdx( 0 ),
210     mnRowIdx( 0 ),
211     mbInRecord( false )
212 {
213     sal_Int32 nSheetCount = rPivotCache.getWorksheets().getAllSheetCount();
214 
215     // prepare sheet: insert column header names into top row
216     rPivotCache.writeSourceHeaderCells( *this );
217     // resize formula buffers since we've added a new dummy sheet
218     rHelper.getFormulaBuffer().SetSheetCount( nSheetCount );
219 }
220 
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)221 ContextHandlerRef PivotCacheRecordsFragment::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
222 {
223     switch( getCurrentElement() )
224     {
225         case XML_ROOT_CONTEXT:
226             if( nElement == XLS_TOKEN( pivotCacheRecords ) ) return this;
227         break;
228 
229         case XLS_TOKEN( pivotCacheRecords ):
230             if( nElement == XLS_TOKEN( r ) ) { startCacheRecord(); return this; }
231         break;
232 
233         case XLS_TOKEN( r ):
234         {
235             PivotCacheItem aItem;
236             switch( nElement )
237             {
238                 case XLS_TOKEN( m ):                                                        break;
239                 case XLS_TOKEN( s ):    aItem.readString( rAttribs );                       break;
240                 case XLS_TOKEN( n ):    aItem.readNumeric( rAttribs );                      break;
241                 case XLS_TOKEN( d ):    aItem.readDate( rAttribs );                         break;
242                 case XLS_TOKEN( b ):    aItem.readBool( rAttribs );                         break;
243                 case XLS_TOKEN( e ):    aItem.readError( rAttribs );                        break;
244                 case XLS_TOKEN( x ):    aItem.readIndex( rAttribs );                        break;
245                 default:    OSL_FAIL( "OoxPivotCacheRecordsFragment::onCreateContext - unexpected element" );
246             }
247             mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
248             ++mnColIdx;
249         }
250         break;
251     }
252     return nullptr;
253 }
254 
onCreateRecordContext(sal_Int32 nRecId,SequenceInputStream & rStrm)255 ContextHandlerRef PivotCacheRecordsFragment::onCreateRecordContext( sal_Int32 nRecId, SequenceInputStream& rStrm )
256 {
257     switch( getCurrentElement() )
258     {
259         case XML_ROOT_CONTEXT:
260             if( nRecId == BIFF12_ID_PCRECORDS ) return this;
261         break;
262 
263         case BIFF12_ID_PCRECORDS:
264             switch( nRecId )
265             {
266                 case BIFF12_ID_PCRECORD:    importPCRecord( rStrm );                break;
267                 case BIFF12_ID_PCRECORDDT:  startCacheRecord();                     break;
268                 default:                    importPCRecordItem( nRecId, rStrm );    break;
269             }
270         break;
271     }
272     return nullptr;
273 }
274 
getRecordInfos() const275 const RecordInfo* PivotCacheRecordsFragment::getRecordInfos() const
276 {
277     static const RecordInfo spRecInfos[] =
278     {
279         { BIFF12_ID_PCRECORDS,  BIFF12_ID_PCRECORDS + 1 },
280         { -1,                   -1                      }
281     };
282     return spRecInfos;
283 }
284 
285 // private --------------------------------------------------------------------
286 
startCacheRecord()287 void PivotCacheRecordsFragment::startCacheRecord()
288 {
289     mnColIdx = 0;
290     ++mnRowIdx;
291     mbInRecord = true;
292 }
293 
importPCRecord(SequenceInputStream & rStrm)294 void PivotCacheRecordsFragment::importPCRecord( SequenceInputStream& rStrm )
295 {
296     startCacheRecord();
297     mrPivotCache.importPCRecord( rStrm, *this, mnRowIdx );
298     mbInRecord = false;
299 }
300 
importPCRecordItem(sal_Int32 nRecId,SequenceInputStream & rStrm)301 void PivotCacheRecordsFragment::importPCRecordItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
302 {
303     if( !mbInRecord )
304         return;
305 
306     PivotCacheItem aItem;
307     switch( nRecId )
308     {
309         case BIFF12_ID_PCITEM_MISSING:                              break;
310         case BIFF12_ID_PCITEM_STRING:   aItem.readString( rStrm );  break;
311         case BIFF12_ID_PCITEM_DOUBLE:   aItem.readDouble( rStrm );  break;
312         case BIFF12_ID_PCITEM_DATE:     aItem.readDate( rStrm );    break;
313         case BIFF12_ID_PCITEM_BOOL:     aItem.readBool( rStrm );    break;
314         case BIFF12_ID_PCITEM_ERROR:    aItem.readError( rStrm );   break;
315         case BIFF12_ID_PCITEM_INDEX:    aItem.readIndex( rStrm );   break;
316         default:    OSL_FAIL( "OoxPivotCacheRecordsFragment::importPCRecordItem - unexpected record" );
317     }
318     mrPivotCache.writeSourceDataCell( *this, mnColIdx, mnRowIdx, aItem );
319     ++mnColIdx;
320 }
321 
322 
323 } // namespace oox::xls
324 
325 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
326