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 #include "oox/xls/pivotcachebuffer.hxx"
25 
26 #include <set>
27 #include <com/sun/star/container/XIndexAccess.hpp>
28 #include <com/sun/star/container/XNameAccess.hpp>
29 #include <com/sun/star/container/XNamed.hpp>
30 #include <com/sun/star/sheet/DataPilotFieldGroupBy.hpp>
31 #include <com/sun/star/sheet/DataPilotFieldGroupInfo.hpp>
32 #include <com/sun/star/sheet/XDataPilotFieldGrouping.hpp>
33 #include <rtl/ustrbuf.hxx>
34 #include "oox/core/filterbase.hxx"
35 #include "oox/helper/attributelist.hxx"
36 #include "oox/helper/containerhelper.hxx"
37 #include "oox/helper/propertyset.hxx"
38 #include "oox/xls/biffinputstream.hxx"
39 #include "oox/xls/defnamesbuffer.hxx"
40 #include "oox/xls/excelhandlers.hxx"
41 #include "oox/xls/pivotcachefragment.hxx"
42 #include "oox/xls/sheetdatabuffer.hxx"
43 #include "oox/xls/tablebuffer.hxx"
44 #include "oox/xls/unitconverter.hxx"
45 #include "oox/xls/worksheetbuffer.hxx"
46 
47 namespace oox {
48 namespace xls {
49 
50 // ============================================================================
51 
52 using namespace ::com::sun::star::container;
53 using namespace ::com::sun::star::sheet;
54 using namespace ::com::sun::star::table;
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::util;
57 
58 using ::oox::core::Relations;
59 using ::rtl::OUString;
60 using ::rtl::OUStringBuffer;
61 
62 // ============================================================================
63 
64 namespace {
65 
66 const sal_uInt16 BIFF12_PCDFIELD_SERVERFIELD        = 0x0001;
67 const sal_uInt16 BIFF12_PCDFIELD_NOUNIQUEITEMS      = 0x0002;
68 const sal_uInt16 BIFF12_PCDFIELD_DATABASEFIELD      = 0x0004;
69 const sal_uInt16 BIFF12_PCDFIELD_HASCAPTION         = 0x0008;
70 const sal_uInt16 BIFF12_PCDFIELD_MEMBERPROPFIELD    = 0x0010;
71 const sal_uInt16 BIFF12_PCDFIELD_HASFORMULA         = 0x0100;
72 const sal_uInt16 BIFF12_PCDFIELD_HASPROPERTYNAME    = 0x0200;
73 
74 const sal_uInt16 BIFF12_PCDFSITEMS_HASSEMIMIXED     = 0x0001;
75 const sal_uInt16 BIFF12_PCDFSITEMS_HASNONDATE       = 0x0002;
76 const sal_uInt16 BIFF12_PCDFSITEMS_HASDATE          = 0x0004;
77 const sal_uInt16 BIFF12_PCDFSITEMS_HASSTRING        = 0x0008;
78 const sal_uInt16 BIFF12_PCDFSITEMS_HASBLANK         = 0x0010;
79 const sal_uInt16 BIFF12_PCDFSITEMS_HASMIXED         = 0x0020;
80 const sal_uInt16 BIFF12_PCDFSITEMS_ISNUMERIC        = 0x0040;
81 const sal_uInt16 BIFF12_PCDFSITEMS_ISINTEGER        = 0x0080;
82 const sal_uInt16 BIFF12_PCDFSITEMS_HASMINMAX        = 0x0100;
83 const sal_uInt16 BIFF12_PCDFSITEMS_HASLONGTEXT      = 0x0200;
84 
85 const sal_uInt16 BIFF12_PCITEM_ARRAY_DOUBLE         = 0x0001;
86 const sal_uInt16 BIFF12_PCITEM_ARRAY_STRING         = 0x0002;
87 const sal_uInt16 BIFF12_PCITEM_ARRAY_ERROR          = 0x0010;
88 const sal_uInt16 BIFF12_PCITEM_ARRAY_DATE           = 0x0020;
89 
90 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOSTART        = 0x01;
91 const sal_uInt8 BIFF12_PCDFRANGEPR_AUTOEND          = 0x02;
92 const sal_uInt8 BIFF12_PCDFRANGEPR_DATEGROUP        = 0x04;
93 
94 const sal_uInt8 BIFF12_PCDEFINITION_SAVEDATA        = 0x01;
95 const sal_uInt8 BIFF12_PCDEFINITION_INVALID         = 0x02;
96 const sal_uInt8 BIFF12_PCDEFINITION_REFRESHONLOAD   = 0x04;
97 const sal_uInt8 BIFF12_PCDEFINITION_OPTIMIZEMEMORY  = 0x08;
98 const sal_uInt8 BIFF12_PCDEFINITION_ENABLEREFRESH   = 0x10;
99 const sal_uInt8 BIFF12_PCDEFINITION_BACKGROUNDQUERY = 0x20;
100 const sal_uInt8 BIFF12_PCDEFINITION_UPGRADEONREFR   = 0x40;
101 const sal_uInt8 BIFF12_PCDEFINITION_TUPELCACHE      = 0x80;
102 
103 const sal_uInt8 BIFF12_PCDEFINITION_HASUSERNAME     = 0x01;
104 const sal_uInt8 BIFF12_PCDEFINITION_HASRELID        = 0x02;
105 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTSUBQUERY = 0x04;
106 const sal_uInt8 BIFF12_PCDEFINITION_SUPPORTDRILL    = 0x08;
107 
108 const sal_uInt8 BIFF12_PCDWBSOURCE_HASRELID         = 0x01;
109 const sal_uInt8 BIFF12_PCDWBSOURCE_HASSHEET         = 0x02;
110 
111 // ----------------------------------------------------------------------------
112 
113 const sal_uInt16 BIFF_PCDSOURCE_WORKSHEET           = 0x0001;
114 const sal_uInt16 BIFF_PCDSOURCE_EXTERNAL            = 0x0002;
115 const sal_uInt16 BIFF_PCDSOURCE_CONSOLIDATION       = 0x0004;
116 const sal_uInt16 BIFF_PCDSOURCE_SCENARIO            = 0x0010;
117 
118 const sal_uInt16 BIFF_PC_NOSTRING                   = 0xFFFF;
119 
120 const sal_uInt16 BIFF_PCDFIELD_HASITEMS             = 0x0001;
121 const sal_uInt16 BIFF_PCDFIELD_HASUNSHAREDITEMS     = 0x0002;
122 const sal_uInt16 BIFF_PCDFIELD_CALCULATED           = 0x0004;
123 const sal_uInt16 BIFF_PCDFIELD_HASPARENT            = 0x0008;
124 const sal_uInt16 BIFF_PCDFIELD_RANGEGROUP           = 0x0010;
125 const sal_uInt16 BIFF_PCDFIELD_ISNUMERIC            = 0x0020;
126 const sal_uInt16 BIFF_PCDFIELD_HASSEMIMIXED         = 0x0080;
127 const sal_uInt16 BIFF_PCDFIELD_HASMINMAX            = 0x0100;
128 const sal_uInt16 BIFF_PCDFIELD_HASLONGINDEX         = 0x0200;
129 const sal_uInt16 BIFF_PCDFIELD_HASNONDATE           = 0x0400;
130 const sal_uInt16 BIFF_PCDFIELD_HASDATE              = 0x0800;
131 const sal_uInt16 BIFF_PCDFIELD_SERVERFIELD          = 0x2000;
132 const sal_uInt16 BIFF_PCDFIELD_NOUNIQUEITEMS        = 0x4000;
133 
134 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOSTART         = 0x0001;
135 const sal_uInt16 BIFF_PCDFRANGEPR_AUTOEND           = 0x0002;
136 
137 const sal_uInt16 BIFF_PCDEFINITION_SAVEDATA         = 0x0001;
138 const sal_uInt16 BIFF_PCDEFINITION_INVALID          = 0x0002;
139 const sal_uInt16 BIFF_PCDEFINITION_REFRESHONLOAD    = 0x0004;
140 const sal_uInt16 BIFF_PCDEFINITION_OPTIMIZEMEMORY   = 0x0008;
141 const sal_uInt16 BIFF_PCDEFINITION_BACKGROUNDQUERY  = 0x0010;
142 const sal_uInt16 BIFF_PCDEFINITION_ENABLEREFRESH    = 0x0020;
143 
144 // ----------------------------------------------------------------------------
145 
146 /** Adjusts the weird date format read from binary streams.
147 
148     Dates before 1900-Mar-01 are stored including the non-existing leap day
149     1900-02-29. Time values (without date) are stored as times of day
150     1900-Jan-00. Nothing has to be done when the workbook is stored in 1904
151     date mode (dates before 1904-Jan-01 will not occur in this case).
152  */
lclAdjustBinDateTime(DateTime & orDateTime)153 void lclAdjustBinDateTime( DateTime& orDateTime )
154 {
155     if( (orDateTime.Year == 1900) && (orDateTime.Month <= 2) )
156     {
157         OSL_ENSURE( (orDateTime.Month == 1) || ((orDateTime.Month == 2) && (orDateTime.Day > 0)), "lclAdjustBinDateTime - invalid date" );
158         switch( orDateTime.Month )
159         {
160             case 2: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; --orDateTime.Month; }                       break;
161             case 1: if( orDateTime.Day > 1 ) --orDateTime.Day; else { orDateTime.Day += 30; orDateTime.Month = 12; --orDateTime.Year; } break;
162         }
163     }
164 }
165 
166 } // namespace
167 
168 // ============================================================================
169 
PivotCacheItem()170 PivotCacheItem::PivotCacheItem() :
171     mnType( XML_m )
172 {
173 }
174 
readString(const AttributeList & rAttribs)175 void PivotCacheItem::readString( const AttributeList& rAttribs )
176 {
177     maValue <<= rAttribs.getXString( XML_v, OUString() );
178     mnType = XML_s;
179 }
180 
readNumeric(const AttributeList & rAttribs)181 void PivotCacheItem::readNumeric( const AttributeList& rAttribs )
182 {
183     maValue <<= rAttribs.getDouble( XML_v, 0.0 );
184     mnType = XML_n;
185 }
186 
readDate(const AttributeList & rAttribs)187 void PivotCacheItem::readDate( const AttributeList& rAttribs )
188 {
189     maValue <<= rAttribs.getDateTime( XML_v, DateTime() );
190     mnType = XML_d;
191 }
192 
readBool(const AttributeList & rAttribs)193 void PivotCacheItem::readBool( const AttributeList& rAttribs )
194 {
195     maValue <<= rAttribs.getBool( XML_v, false );
196     mnType = XML_b;
197 }
198 
readError(const AttributeList & rAttribs,const UnitConverter & rUnitConverter)199 void PivotCacheItem::readError( const AttributeList& rAttribs, const UnitConverter& rUnitConverter )
200 {
201     maValue <<= static_cast< sal_Int32 >( rUnitConverter.calcBiffErrorCode( rAttribs.getXString( XML_v, OUString() ) ) );
202     mnType = XML_e;
203 }
204 
readIndex(const AttributeList & rAttribs)205 void PivotCacheItem::readIndex( const AttributeList& rAttribs )
206 {
207     maValue <<= rAttribs.getInteger( XML_v, -1 );
208     mnType = XML_x;
209 }
210 
readString(SequenceInputStream & rStrm)211 void PivotCacheItem::readString( SequenceInputStream& rStrm )
212 {
213     maValue <<= BiffHelper::readString( rStrm );
214     mnType = XML_s;
215 }
216 
readDouble(SequenceInputStream & rStrm)217 void PivotCacheItem::readDouble( SequenceInputStream& rStrm )
218 {
219     maValue <<= rStrm.readDouble();
220     mnType = XML_n;
221 }
222 
readDate(SequenceInputStream & rStrm)223 void PivotCacheItem::readDate( SequenceInputStream& rStrm )
224 {
225     DateTime aDateTime;
226     aDateTime.Year = rStrm.readuInt16();
227     aDateTime.Month = rStrm.readuInt16();
228     aDateTime.Day = rStrm.readuInt8();
229     aDateTime.Hours = rStrm.readuInt8();
230     aDateTime.Minutes = rStrm.readuInt8();
231     aDateTime.Seconds = rStrm.readuInt8();
232     lclAdjustBinDateTime( aDateTime );
233     maValue <<= aDateTime;
234     mnType = XML_d;
235 }
236 
readBool(SequenceInputStream & rStrm)237 void PivotCacheItem::readBool( SequenceInputStream& rStrm )
238 {
239     maValue <<= (rStrm.readuInt8() != 0);
240     mnType = XML_b;
241 }
242 
readError(SequenceInputStream & rStrm)243 void PivotCacheItem::readError( SequenceInputStream& rStrm )
244 {
245     maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
246     mnType = XML_e;
247 }
248 
readIndex(SequenceInputStream & rStrm)249 void PivotCacheItem::readIndex( SequenceInputStream& rStrm )
250 {
251     maValue <<= rStrm.readInt32();
252     mnType = XML_x;
253 }
254 
readString(BiffInputStream & rStrm,const WorkbookHelper & rHelper)255 void PivotCacheItem::readString( BiffInputStream& rStrm, const WorkbookHelper& rHelper )
256 {
257     maValue <<= (rHelper.getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, rHelper.getTextEncoding() );
258     mnType = XML_s;
259 }
260 
readDouble(BiffInputStream & rStrm)261 void PivotCacheItem::readDouble( BiffInputStream& rStrm )
262 {
263     maValue <<= rStrm.readDouble();
264     mnType = XML_n;
265 }
266 
readInteger(BiffInputStream & rStrm)267 void PivotCacheItem::readInteger( BiffInputStream& rStrm )
268 {
269     maValue <<= rStrm.readInt16();
270     mnType = XML_i;                 // fake, used for BIFF only
271 }
272 
readDate(BiffInputStream & rStrm)273 void PivotCacheItem::readDate( BiffInputStream& rStrm )
274 {
275     DateTime aDateTime;
276     aDateTime.Year = rStrm.readuInt16();
277     aDateTime.Month = rStrm.readuInt16();
278     aDateTime.Day = rStrm.readuInt8();
279     aDateTime.Hours = rStrm.readuInt8();
280     aDateTime.Minutes = rStrm.readuInt8();
281     aDateTime.Seconds = rStrm.readuInt8();
282     lclAdjustBinDateTime( aDateTime );
283     maValue <<= aDateTime;
284     mnType = XML_d;
285 }
286 
readBool(BiffInputStream & rStrm)287 void PivotCacheItem::readBool( BiffInputStream& rStrm )
288 {
289     maValue <<= (rStrm.readuInt8() != 0);
290     mnType = XML_b;
291 }
292 
readError(BiffInputStream & rStrm)293 void PivotCacheItem::readError( BiffInputStream& rStrm )
294 {
295     maValue <<= static_cast< sal_Int32 >( rStrm.readuInt8() );
296     mnType = XML_e;
297 }
298 
getName() const299 OUString PivotCacheItem::getName() const
300 {
301     switch( mnType )
302     {
303         case XML_m: return OUString();
304         case XML_s: return maValue.get< OUString >();
305         case XML_n: return OUString::valueOf( maValue.get< double >() );                            // !TODO
306         case XML_i: return OUString::valueOf( maValue.get< sal_Int32 >() );
307         case XML_d: return OUString();                                                              // !TODO
308         case XML_b: return OUString::valueOf( static_cast< sal_Bool >( maValue.get< bool >() ) );   // !TODO
309         case XML_e: return OUString();                                                              // !TODO
310     }
311     OSL_ENSURE( false, "PivotCacheItem::getName - invalid data type" );
312     return OUString();
313 }
314 
315 // ----------------------------------------------------------------------------
316 
PivotCacheItemList(const WorkbookHelper & rHelper)317 PivotCacheItemList::PivotCacheItemList( const WorkbookHelper& rHelper ) :
318     WorkbookHelper( rHelper )
319 {
320 }
321 
importItem(sal_Int32 nElement,const AttributeList & rAttribs)322 void PivotCacheItemList::importItem( sal_Int32 nElement, const AttributeList& rAttribs )
323 {
324     PivotCacheItem& rItem = createItem();
325     switch( nElement )
326     {
327         case XLS_TOKEN( m ):                                                        break;
328         case XLS_TOKEN( s ):    rItem.readString( rAttribs );                       break;
329         case XLS_TOKEN( n ):    rItem.readNumeric( rAttribs );                      break;
330         case XLS_TOKEN( d ):    rItem.readDate( rAttribs );                         break;
331         case XLS_TOKEN( b ):    rItem.readBool( rAttribs );                         break;
332         case XLS_TOKEN( e ):    rItem.readError( rAttribs, getUnitConverter() );    break;
333         default:    OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown element type" );
334     }
335 }
336 
importItem(sal_Int32 nRecId,SequenceInputStream & rStrm)337 void PivotCacheItemList::importItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
338 {
339     if( nRecId == BIFF12_ID_PCITEM_ARRAY )
340     {
341         importArray( rStrm );
342         return;
343     }
344 
345     PivotCacheItem& rItem = createItem();
346     switch( nRecId )
347     {
348         case BIFF12_ID_PCITEM_MISSING:
349         case BIFF12_ID_PCITEMA_MISSING:                             break;
350         case BIFF12_ID_PCITEM_STRING:
351         case BIFF12_ID_PCITEMA_STRING:  rItem.readString( rStrm );  break;
352         case BIFF12_ID_PCITEM_DOUBLE:
353         case BIFF12_ID_PCITEMA_DOUBLE:  rItem.readDouble( rStrm );  break;
354         case BIFF12_ID_PCITEM_DATE:
355         case BIFF12_ID_PCITEMA_DATE:    rItem.readDate( rStrm );    break;
356         case BIFF12_ID_PCITEM_BOOL:
357         case BIFF12_ID_PCITEMA_BOOL:    rItem.readBool( rStrm );    break;
358         case BIFF12_ID_PCITEM_ERROR:
359         case BIFF12_ID_PCITEMA_ERROR:   rItem.readError( rStrm );   break;
360         default:    OSL_ENSURE( false, "PivotCacheItemList::importItem - unknown record type" );
361     }
362 }
363 
importItemList(BiffInputStream & rStrm,sal_uInt16 nCount)364 void PivotCacheItemList::importItemList( BiffInputStream& rStrm, sal_uInt16 nCount )
365 {
366     bool bLoop = true;
367     for( sal_uInt16 nItemIdx = 0; bLoop && (nItemIdx < nCount); ++nItemIdx )
368     {
369         bLoop = rStrm.startNextRecord();
370         if( bLoop ) switch( rStrm.getRecId() )
371         {
372             case BIFF_ID_PCITEM_MISSING:    createItem();                               break;
373             case BIFF_ID_PCITEM_STRING:     createItem().readString( rStrm, *this );    break;
374             case BIFF_ID_PCITEM_DOUBLE:     createItem().readDouble( rStrm );           break;
375             case BIFF_ID_PCITEM_INTEGER:    createItem().readInteger( rStrm );          break;
376             case BIFF_ID_PCITEM_DATE:       createItem().readDate( rStrm );             break;
377             case BIFF_ID_PCITEM_BOOL:       createItem().readBool( rStrm );             break;
378             case BIFF_ID_PCITEM_ERROR:      createItem().readError( rStrm );            break;
379             default:                        rStrm.rewindRecord(); bLoop = false;
380         }
381     }
382     OSL_ENSURE( bLoop, "PivotCacheItemList::importItemList - could not read all cache item records" );
383 }
384 
getCacheItem(sal_Int32 nItemIdx) const385 const PivotCacheItem* PivotCacheItemList::getCacheItem( sal_Int32 nItemIdx ) const
386 {
387     return ContainerHelper::getVectorElement( maItems, nItemIdx );
388 }
389 
getCacheItemNames(::std::vector<OUString> & orItemNames) const390 void PivotCacheItemList::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
391 {
392     orItemNames.clear();
393     orItemNames.reserve( maItems.size() );
394     for( CacheItemVector::const_iterator aIt = maItems.begin(), aEnd = maItems.end(); aIt != aEnd; ++aIt )
395         orItemNames.push_back( aIt->getName() );
396 }
397 
398 // private --------------------------------------------------------------------
399 
createItem()400 PivotCacheItem& PivotCacheItemList::createItem()
401 {
402     maItems.resize( maItems.size() + 1 );
403     return maItems.back();
404 }
405 
importArray(SequenceInputStream & rStrm)406 void PivotCacheItemList::importArray( SequenceInputStream& rStrm )
407 {
408     sal_uInt16 nType = rStrm.readuInt16();
409     sal_Int32 nCount = rStrm.readInt32();
410     for( sal_Int32 nIdx = 0; !rStrm.isEof() && (nIdx < nCount); ++nIdx )
411     {
412         switch( nType )
413         {
414             case BIFF12_PCITEM_ARRAY_DOUBLE: createItem().readDouble( rStrm );   break;
415             case BIFF12_PCITEM_ARRAY_STRING: createItem().readString( rStrm );   break;
416             case BIFF12_PCITEM_ARRAY_ERROR:  createItem().readError( rStrm );    break;
417             case BIFF12_PCITEM_ARRAY_DATE:   createItem().readDate( rStrm );     break;
418             default:
419                 OSL_ENSURE( false, "PivotCacheItemList::importArray - unknown data type" );
420                 nIdx = nCount;
421         }
422     }
423 }
424 
425 // ============================================================================
426 
PCFieldModel()427 PCFieldModel::PCFieldModel() :
428     mnNumFmtId( 0 ),
429     mnSqlType( 0 ),
430     mnHierarchy( 0 ),
431     mnLevel( 0 ),
432     mnMappingCount( 0 ),
433     mbDatabaseField( true ),
434     mbServerField( false ),
435     mbUniqueList( true ),
436     mbMemberPropField( false )
437 {
438 }
439 
440 // ----------------------------------------------------------------------------
441 
PCSharedItemsModel()442 PCSharedItemsModel::PCSharedItemsModel() :
443     mbHasSemiMixed( true ),
444     mbHasNonDate( true ),
445     mbHasDate( false ),
446     mbHasString( true ),
447     mbHasBlank( false ),
448     mbHasMixed( false ),
449     mbIsNumeric( false ),
450     mbIsInteger( false ),
451     mbHasLongText( false ),
452     mbHasLongIndexes( false )
453 {
454 }
455 
456 // ----------------------------------------------------------------------------
457 
PCFieldGroupModel()458 PCFieldGroupModel::PCFieldGroupModel() :
459     mfStartValue( 0.0 ),
460     mfEndValue( 0.0 ),
461     mfInterval( 1.0 ),
462     mnParentField( -1 ),
463     mnBaseField( -1 ),
464     mnGroupBy( XML_range ),
465     mbRangeGroup( false ),
466     mbDateGroup( false ),
467     mbAutoStart( true ),
468     mbAutoEnd( true )
469 {
470 }
471 
setBiffGroupBy(sal_uInt8 nGroupBy)472 void PCFieldGroupModel::setBiffGroupBy( sal_uInt8 nGroupBy )
473 {
474     static const sal_Int32 spnGroupBy[] = { XML_range,
475         XML_seconds, XML_minutes, XML_hours, XML_days, XML_months, XML_quarters, XML_years };
476     mnGroupBy = STATIC_ARRAY_SELECT( spnGroupBy, nGroupBy, XML_range );
477 }
478 
479 // ----------------------------------------------------------------------------
480 
PivotCacheField(const WorkbookHelper & rHelper,bool bIsDatabaseField)481 PivotCacheField::PivotCacheField( const WorkbookHelper& rHelper, bool bIsDatabaseField ) :
482     WorkbookHelper( rHelper ),
483     maSharedItems( rHelper ),
484     maGroupItems( rHelper )
485 {
486     maFieldModel.mbDatabaseField = bIsDatabaseField;
487 }
488 
importCacheField(const AttributeList & rAttribs)489 void PivotCacheField::importCacheField( const AttributeList& rAttribs )
490 {
491     maFieldModel.maName            = rAttribs.getXString( XML_name, OUString() );
492     maFieldModel.maCaption         = rAttribs.getXString( XML_caption, OUString() );
493     maFieldModel.maPropertyName    = rAttribs.getXString( XML_propertyName, OUString() );
494     maFieldModel.maFormula         = rAttribs.getXString( XML_formula, OUString() );
495     maFieldModel.mnNumFmtId        = rAttribs.getInteger( XML_numFmtId, 0 );
496     maFieldModel.mnSqlType         = rAttribs.getInteger( XML_sqlType, 0 );
497     maFieldModel.mnHierarchy       = rAttribs.getInteger( XML_hierarchy, 0 );
498     maFieldModel.mnLevel           = rAttribs.getInteger( XML_level, 0 );
499     maFieldModel.mnMappingCount    = rAttribs.getInteger( XML_mappingCount, 0 );
500     maFieldModel.mbDatabaseField   = rAttribs.getBool( XML_databaseField, true );
501     maFieldModel.mbServerField     = rAttribs.getBool( XML_serverField, false );
502     maFieldModel.mbUniqueList      = rAttribs.getBool( XML_uniqueList, true );
503     maFieldModel.mbMemberPropField = rAttribs.getBool( XML_memberPropertyField, false );
504 }
505 
importSharedItems(const AttributeList & rAttribs)506 void PivotCacheField::importSharedItems( const AttributeList& rAttribs )
507 {
508     OSL_ENSURE( maSharedItems.empty(), "PivotCacheField::importSharedItems - multiple shared items elements" );
509     maSharedItemsModel.mbHasSemiMixed = rAttribs.getBool( XML_containsSemiMixedTypes, true );
510     maSharedItemsModel.mbHasNonDate   = rAttribs.getBool( XML_containsNonDate, true );
511     maSharedItemsModel.mbHasDate      = rAttribs.getBool( XML_containsDate, false );
512     maSharedItemsModel.mbHasString    = rAttribs.getBool( XML_containsString, true );
513     maSharedItemsModel.mbHasBlank     = rAttribs.getBool( XML_containsBlank, false );
514     maSharedItemsModel.mbHasMixed     = rAttribs.getBool( XML_containsMixedTypes, false );
515     maSharedItemsModel.mbIsNumeric    = rAttribs.getBool( XML_containsNumber, false );
516     maSharedItemsModel.mbIsInteger    = rAttribs.getBool( XML_containsInteger, false );
517     maSharedItemsModel.mbHasLongText  = rAttribs.getBool( XML_longText, false );
518 }
519 
importSharedItem(sal_Int32 nElement,const AttributeList & rAttribs)520 void PivotCacheField::importSharedItem( sal_Int32 nElement, const AttributeList& rAttribs )
521 {
522     maSharedItems.importItem( nElement, rAttribs );
523 }
524 
importFieldGroup(const AttributeList & rAttribs)525 void PivotCacheField::importFieldGroup( const AttributeList& rAttribs )
526 {
527     maFieldGroupModel.mnParentField = rAttribs.getInteger( XML_par, -1 );
528     maFieldGroupModel.mnBaseField   = rAttribs.getInteger( XML_base, -1 );
529 }
530 
importRangePr(const AttributeList & rAttribs)531 void PivotCacheField::importRangePr( const AttributeList& rAttribs )
532 {
533     maFieldGroupModel.maStartDate    = rAttribs.getDateTime( XML_startDate, DateTime() );
534     maFieldGroupModel.maEndDate      = rAttribs.getDateTime( XML_endDate, DateTime() );
535     maFieldGroupModel.mfStartValue   = rAttribs.getDouble( XML_startNum, 0.0 );
536     maFieldGroupModel.mfEndValue     = rAttribs.getDouble( XML_endNum, 0.0 );
537     maFieldGroupModel.mfInterval     = rAttribs.getDouble( XML_groupInterval, 1.0 );
538     maFieldGroupModel.mnGroupBy      = rAttribs.getToken( XML_groupBy, XML_range );
539     maFieldGroupModel.mbRangeGroup   = true;
540     maFieldGroupModel.mbDateGroup    = maFieldGroupModel.mnGroupBy != XML_range;
541     maFieldGroupModel.mbAutoStart    = rAttribs.getBool( XML_autoStart, true );
542     maFieldGroupModel.mbAutoEnd      = rAttribs.getBool( XML_autoEnd, true );
543 }
544 
importDiscretePrItem(sal_Int32 nElement,const AttributeList & rAttribs)545 void PivotCacheField::importDiscretePrItem( sal_Int32 nElement, const AttributeList& rAttribs )
546 {
547     OSL_ENSURE( nElement == XLS_TOKEN( x ), "PivotCacheField::importDiscretePrItem - unexpected element" );
548     if( nElement == XLS_TOKEN( x ) )
549         maDiscreteItems.push_back( rAttribs.getInteger( XML_v, -1 ) );
550 }
551 
importGroupItem(sal_Int32 nElement,const AttributeList & rAttribs)552 void PivotCacheField::importGroupItem( sal_Int32 nElement, const AttributeList& rAttribs )
553 {
554     maGroupItems.importItem( nElement, rAttribs );
555 }
556 
importPCDField(SequenceInputStream & rStrm)557 void PivotCacheField::importPCDField( SequenceInputStream& rStrm )
558 {
559     sal_uInt16 nFlags;
560     rStrm >> nFlags >> maFieldModel.mnNumFmtId;
561     maFieldModel.mnSqlType = rStrm.readInt16();
562     rStrm >> maFieldModel.mnHierarchy >> maFieldModel.mnLevel >> maFieldModel.mnMappingCount >> maFieldModel.maName;
563     if( getFlag( nFlags, BIFF12_PCDFIELD_HASCAPTION ) )
564         rStrm >> maFieldModel.maCaption;
565     if( getFlag( nFlags, BIFF12_PCDFIELD_HASFORMULA ) )
566         rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
567     if( maFieldModel.mnMappingCount > 0 )
568         rStrm.skip( ::std::max< sal_Int32 >( rStrm.readInt32(), 0 ) );
569     if( getFlag( nFlags, BIFF12_PCDFIELD_HASPROPERTYNAME ) )
570         rStrm >> maFieldModel.maPropertyName;
571 
572     maFieldModel.mbDatabaseField   = getFlag( nFlags, BIFF12_PCDFIELD_DATABASEFIELD );
573     maFieldModel.mbServerField     = getFlag( nFlags, BIFF12_PCDFIELD_SERVERFIELD );
574     maFieldModel.mbUniqueList      = !getFlag( nFlags, BIFF12_PCDFIELD_NOUNIQUEITEMS );
575     maFieldModel.mbMemberPropField = getFlag( nFlags, BIFF12_PCDFIELD_MEMBERPROPFIELD );
576 }
577 
importPCDFSharedItems(SequenceInputStream & rStrm)578 void PivotCacheField::importPCDFSharedItems( SequenceInputStream& rStrm )
579 {
580     sal_uInt16 nFlags;
581     rStrm >> nFlags;
582     maSharedItemsModel.mbHasSemiMixed = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSEMIMIXED );
583     maSharedItemsModel.mbHasNonDate   = getFlag( nFlags, BIFF12_PCDFSITEMS_HASNONDATE );
584     maSharedItemsModel.mbHasDate      = getFlag( nFlags, BIFF12_PCDFSITEMS_HASDATE );
585     maSharedItemsModel.mbHasString    = getFlag( nFlags, BIFF12_PCDFSITEMS_HASSTRING );
586     maSharedItemsModel.mbHasBlank     = getFlag( nFlags, BIFF12_PCDFSITEMS_HASBLANK );
587     maSharedItemsModel.mbHasMixed     = getFlag( nFlags, BIFF12_PCDFSITEMS_HASMIXED );
588     maSharedItemsModel.mbIsNumeric    = getFlag( nFlags, BIFF12_PCDFSITEMS_ISNUMERIC );
589     maSharedItemsModel.mbIsInteger    = getFlag( nFlags, BIFF12_PCDFSITEMS_ISINTEGER );
590     maSharedItemsModel.mbHasLongText  = getFlag( nFlags, BIFF12_PCDFSITEMS_HASLONGTEXT );
591 }
592 
importPCDFSharedItem(sal_Int32 nRecId,SequenceInputStream & rStrm)593 void PivotCacheField::importPCDFSharedItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
594 {
595     maSharedItems.importItem( nRecId, rStrm );
596 }
597 
importPCDFieldGroup(SequenceInputStream & rStrm)598 void PivotCacheField::importPCDFieldGroup( SequenceInputStream& rStrm )
599 {
600     rStrm >> maFieldGroupModel.mnParentField >> maFieldGroupModel.mnBaseField;
601 }
602 
importPCDFRangePr(SequenceInputStream & rStrm)603 void PivotCacheField::importPCDFRangePr( SequenceInputStream& rStrm )
604 {
605     sal_uInt8 nGroupBy, nFlags;
606     rStrm >> nGroupBy >> nFlags >> maFieldGroupModel.mfStartValue >> maFieldGroupModel.mfEndValue >> maFieldGroupModel.mfInterval;
607 
608     maFieldGroupModel.setBiffGroupBy( nGroupBy );
609     maFieldGroupModel.mbRangeGroup   = true;
610     maFieldGroupModel.mbDateGroup    = getFlag( nFlags, BIFF12_PCDFRANGEPR_DATEGROUP );
611     maFieldGroupModel.mbAutoStart    = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOSTART );
612     maFieldGroupModel.mbAutoEnd      = getFlag( nFlags, BIFF12_PCDFRANGEPR_AUTOEND );
613 
614     OSL_ENSURE( maFieldGroupModel.mbDateGroup == (maFieldGroupModel.mnGroupBy != XML_range), "PivotCacheField::importPCDFRangePr - wrong date flag" );
615     if( maFieldGroupModel.mbDateGroup )
616     {
617         maFieldGroupModel.maStartDate = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfStartValue );
618         maFieldGroupModel.maEndDate   = getUnitConverter().calcDateTimeFromSerial( maFieldGroupModel.mfEndValue );
619     }
620 }
621 
importPCDFDiscretePrItem(sal_Int32 nRecId,SequenceInputStream & rStrm)622 void PivotCacheField::importPCDFDiscretePrItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
623 {
624     OSL_ENSURE( nRecId == BIFF12_ID_PCITEM_INDEX, "PivotCacheField::importPCDFDiscretePrItem - unexpected record" );
625     if( nRecId == BIFF12_ID_PCITEM_INDEX )
626         maDiscreteItems.push_back( rStrm.readInt32() );
627 }
628 
importPCDFGroupItem(sal_Int32 nRecId,SequenceInputStream & rStrm)629 void PivotCacheField::importPCDFGroupItem( sal_Int32 nRecId, SequenceInputStream& rStrm )
630 {
631     maGroupItems.importItem( nRecId, rStrm );
632 }
633 
importPCDField(BiffInputStream & rStrm)634 void PivotCacheField::importPCDField( BiffInputStream& rStrm )
635 {
636     sal_uInt16 nFlags, nGroupItems, nBaseItems, nSharedItems;
637     rStrm >> nFlags;
638     maFieldGroupModel.mnParentField  = rStrm.readuInt16();
639     maFieldGroupModel.mnBaseField    = rStrm.readuInt16();
640     rStrm.skip( 2 );    // number of unique items (either shared or group)
641     rStrm >> nGroupItems >> nBaseItems >> nSharedItems;
642     maFieldModel.maName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( true, getTextEncoding() );
643 
644     maFieldModel.mbServerField          = getFlag( nFlags, BIFF_PCDFIELD_SERVERFIELD );
645     maFieldModel.mbUniqueList           = !getFlag( nFlags, BIFF_PCDFIELD_NOUNIQUEITEMS );
646     maSharedItemsModel.mbHasSemiMixed   = getFlag( nFlags, BIFF_PCDFIELD_HASSEMIMIXED );
647     maSharedItemsModel.mbHasNonDate     = getFlag( nFlags, BIFF_PCDFIELD_HASNONDATE );
648     maSharedItemsModel.mbHasDate        = getFlag( nFlags, BIFF_PCDFIELD_HASDATE );
649     maSharedItemsModel.mbIsNumeric      = getFlag( nFlags, BIFF_PCDFIELD_ISNUMERIC );
650     maSharedItemsModel.mbHasLongIndexes = getFlag( nFlags, BIFF_PCDFIELD_HASLONGINDEX );
651     maFieldGroupModel.mbRangeGroup      = getFlag( nFlags, BIFF_PCDFIELD_RANGEGROUP );
652 
653     // in BIFF, presence of parent group field is denoted by a flag
654     if( !getFlag( nFlags, BIFF_PCDFIELD_HASPARENT ) )
655         maFieldGroupModel.mnParentField = -1;
656 
657     // following PCDFSQLTYPE record contains SQL type
658     if( (rStrm.getNextRecId() == BIFF_ID_PCDFSQLTYPE) && rStrm.startNextRecord() )
659         maFieldModel.mnSqlType = rStrm.readInt16();
660 
661     // read group items, if any
662     if( nGroupItems > 0 )
663     {
664         OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
665         maGroupItems.importItemList( rStrm, nGroupItems );
666 
667         sal_uInt16 nNextRecId = rStrm.getNextRecId();
668         bool bHasRangePr = nNextRecId == BIFF_ID_PCDFRANGEPR;
669         bool bHasDiscretePr = nNextRecId == BIFF_ID_PCDFDISCRETEPR;
670 
671         OSL_ENSURE( bHasRangePr || bHasDiscretePr, "PivotCacheField::importPCDField - missing group properties record" );
672         OSL_ENSURE( bHasRangePr == maFieldGroupModel.mbRangeGroup, "PivotCacheField::importPCDField - invalid range grouping flag" );
673         if( bHasRangePr && rStrm.startNextRecord() )
674             importPCDFRangePr( rStrm );
675         else if( bHasDiscretePr && rStrm.startNextRecord() )
676             importPCDFDiscretePr( rStrm );
677     }
678 
679     // read the shared items, if any
680     if( nSharedItems > 0 )
681     {
682         OSL_ENSURE( getFlag( nFlags, BIFF_PCDFIELD_HASITEMS ), "PivotCacheField::importPCDField - missing items flag" );
683         maSharedItems.importItemList( rStrm, nSharedItems );
684     }
685 }
686 
importPCDFRangePr(BiffInputStream & rStrm)687 void PivotCacheField::importPCDFRangePr( BiffInputStream& rStrm )
688 {
689     sal_uInt16 nFlags;
690     rStrm >> nFlags;
691     maFieldGroupModel.setBiffGroupBy( extractValue< sal_uInt8 >( nFlags, 2, 3 ) );
692     maFieldGroupModel.mbRangeGroup = true;
693     maFieldGroupModel.mbDateGroup  = maFieldGroupModel.mnGroupBy != XML_range;
694     maFieldGroupModel.mbAutoStart  = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOSTART );
695     maFieldGroupModel.mbAutoEnd    = getFlag( nFlags, BIFF_PCDFRANGEPR_AUTOEND );
696 
697     /*  Start, end, and interval are stored in 3 separate item records. Type of
698         the items is dependent on numeric/date mode. Numeric groups expect
699         three PCITEM_DOUBLE records, date groups expect two PCITEM_DATE records
700         and one PCITEM_INT record. */
701     PivotCacheItemList aLimits( *this );
702     aLimits.importItemList( rStrm, 3 );
703     OSL_ENSURE( aLimits.size() == 3, "PivotCacheField::importPCDFRangePr - missing grouping records" );
704     const PivotCacheItem* pStartValue = aLimits.getCacheItem( 0 );
705     const PivotCacheItem* pEndValue = aLimits.getCacheItem( 1 );
706     const PivotCacheItem* pInterval = aLimits.getCacheItem( 2 );
707     if( pStartValue && pEndValue && pInterval )
708     {
709         if( maFieldGroupModel.mbDateGroup )
710         {
711             bool bHasTypes = (pStartValue->getType() == XML_d) && (pEndValue->getType() == XML_d) && (pInterval->getType() == XML_i);
712             OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
713             if( bHasTypes )
714             {
715                 maFieldGroupModel.maStartDate = pStartValue->getValue().get< DateTime >();
716                 maFieldGroupModel.maEndDate   = pEndValue->getValue().get< DateTime >();
717                 maFieldGroupModel.mfInterval  = pInterval->getValue().get< sal_Int16 >();
718             }
719         }
720         else
721         {
722             bool bHasTypes = (pStartValue->getType() == XML_n) && (pEndValue->getType() == XML_n) && (pInterval->getType() == XML_n);
723             OSL_ENSURE( bHasTypes, "PivotCacheField::importPCDFRangePr - wrong data types in grouping items" );
724             if( bHasTypes )
725             {
726                 maFieldGroupModel.mfStartValue = pStartValue->getValue().get< double >();
727                 maFieldGroupModel.mfEndValue   = pEndValue->getValue().get< double >();
728                 maFieldGroupModel.mfInterval   = pInterval->getValue().get< double >();
729             }
730         }
731     }
732 }
733 
importPCDFDiscretePr(BiffInputStream & rStrm)734 void PivotCacheField::importPCDFDiscretePr( BiffInputStream& rStrm )
735 {
736     sal_Int32 nCount = static_cast< sal_Int32 >( rStrm.size() / 2 );
737     for( sal_Int32 nIndex = 0; !rStrm.isEof() && (nIndex < nCount); ++nIndex )
738         maDiscreteItems.push_back( rStrm.readuInt16() );
739 }
740 
getCacheItem(sal_Int32 nItemIdx) const741 const PivotCacheItem* PivotCacheField::getCacheItem( sal_Int32 nItemIdx ) const
742 {
743     if( hasGroupItems() )
744         return maGroupItems.getCacheItem( nItemIdx );
745     if( hasSharedItems() )
746         return maSharedItems.getCacheItem( nItemIdx );
747     return 0;
748 }
749 
getCacheItemNames(::std::vector<OUString> & orItemNames) const750 void PivotCacheField::getCacheItemNames( ::std::vector< OUString >& orItemNames ) const
751 {
752     if( hasGroupItems() )
753         maGroupItems.getCacheItemNames( orItemNames );
754     else if( hasSharedItems() )
755         maSharedItems.getCacheItemNames( orItemNames );
756 }
757 
convertNumericGrouping(const Reference<XDataPilotField> & rxDPField) const758 void PivotCacheField::convertNumericGrouping( const Reference< XDataPilotField >& rxDPField ) const
759 {
760     OSL_ENSURE( hasGroupItems() && hasNumericGrouping(), "PivotCacheField::convertNumericGrouping - not a numeric group field" );
761     PropertySet aPropSet( rxDPField );
762     if( hasGroupItems() && hasNumericGrouping() && aPropSet.is() )
763     {
764         DataPilotFieldGroupInfo aGroupInfo;
765         aGroupInfo.HasAutoStart  = maFieldGroupModel.mbAutoStart;
766         aGroupInfo.HasAutoEnd    = maFieldGroupModel.mbAutoEnd;
767         aGroupInfo.HasDateValues = sal_False;
768         aGroupInfo.Start         = maFieldGroupModel.mfStartValue;
769         aGroupInfo.End           = maFieldGroupModel.mfEndValue;
770         aGroupInfo.Step          = maFieldGroupModel.mfInterval;
771         aGroupInfo.GroupBy       = 0;
772         aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
773     }
774 }
775 
createDateGroupField(const Reference<XDataPilotField> & rxBaseDPField) const776 OUString PivotCacheField::createDateGroupField( const Reference< XDataPilotField >& rxBaseDPField ) const
777 {
778     OSL_ENSURE( hasGroupItems() && hasDateGrouping(), "PivotCacheField::createDateGroupField - not a numeric group field" );
779     Reference< XDataPilotField > xDPGroupField;
780     PropertySet aPropSet( rxBaseDPField );
781     if( hasGroupItems() && hasDateGrouping() && aPropSet.is() )
782     {
783         bool bDayRanges = (maFieldGroupModel.mnGroupBy == XML_days) && (maFieldGroupModel.mfInterval >= 2.0);
784 
785         DataPilotFieldGroupInfo aGroupInfo;
786         aGroupInfo.HasAutoStart  = maFieldGroupModel.mbAutoStart;
787         aGroupInfo.HasAutoEnd    = maFieldGroupModel.mbAutoEnd;
788         aGroupInfo.HasDateValues = sal_True;
789         aGroupInfo.Start         = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maStartDate );
790         aGroupInfo.End           = getUnitConverter().calcSerialFromDateTime( maFieldGroupModel.maEndDate );
791         aGroupInfo.Step          = bDayRanges ? maFieldGroupModel.mfInterval : 0.0;
792 
793         using namespace ::com::sun::star::sheet::DataPilotFieldGroupBy;
794         switch( maFieldGroupModel.mnGroupBy )
795         {
796             case XML_years:     aGroupInfo.GroupBy = YEARS;     break;
797             case XML_quarters:  aGroupInfo.GroupBy = QUARTERS;  break;
798             case XML_months:    aGroupInfo.GroupBy = MONTHS;    break;
799             case XML_days:      aGroupInfo.GroupBy = DAYS;      break;
800             case XML_hours:     aGroupInfo.GroupBy = HOURS;     break;
801             case XML_minutes:   aGroupInfo.GroupBy = MINUTES;   break;
802             case XML_seconds:   aGroupInfo.GroupBy = SECONDS;   break;
803             default:    OSL_ENSURE( false, "PivotCacheField::convertRangeGrouping - unknown date/time interval" );
804         }
805 
806         try
807         {
808             Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY_THROW );
809             xDPGroupField = xDPGrouping->createDateGroup( aGroupInfo );
810         }
811         catch( Exception& )
812         {
813         }
814     }
815 
816     Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
817     return xFieldName.is() ? xFieldName->getName() : OUString();
818 }
819 
createParentGroupField(const Reference<XDataPilotField> & rxBaseDPField,PivotCacheGroupItemVector & orItemNames) const820 OUString PivotCacheField::createParentGroupField( const Reference< XDataPilotField >& rxBaseDPField, PivotCacheGroupItemVector& orItemNames ) const
821 {
822     OSL_ENSURE( hasGroupItems() && !maDiscreteItems.empty(), "PivotCacheField::createParentGroupField - not a group field" );
823     OSL_ENSURE( maDiscreteItems.size() == orItemNames.size(), "PivotCacheField::createParentGroupField - number of item names does not match grouping info" );
824     Reference< XDataPilotFieldGrouping > xDPGrouping( rxBaseDPField, UNO_QUERY );
825     if( !xDPGrouping.is() ) return OUString();
826 
827     // map the group item indexes from maGroupItems to all item indexes from maDiscreteItems
828     typedef ::std::vector< sal_Int32 > GroupItemList;
829     typedef ::std::vector< GroupItemList > GroupItemMap;
830     GroupItemMap aItemMap( maGroupItems.size() );
831     for( IndexVector::const_iterator aBeg = maDiscreteItems.begin(), aIt = aBeg, aEnd = maDiscreteItems.end(); aIt != aEnd; ++aIt )
832         if( GroupItemList* pItems = ContainerHelper::getVectorElementAccess( aItemMap, *aIt ) )
833             pItems->push_back( static_cast< sal_Int32 >( aIt - aBeg ) );
834 
835     // process all groups
836     Reference< XDataPilotField > xDPGroupField;
837     for( GroupItemMap::iterator aBeg = aItemMap.begin(), aIt = aBeg, aEnd = aItemMap.end(); aIt != aEnd; ++aIt )
838     {
839         OSL_ENSURE( !aIt->empty(), "PivotCacheField::createParentGroupField - item/group should not be empty" );
840         // if the item count is greater than 1, the item is a group of items
841         if( aIt->size() > 1 )
842         {
843             /*  Insert the names of the items that are part of this group. Calc
844                 expects the names of the members of the field whose members are
845                 grouped (which may be the names of groups too). Excel provides
846                 the names of the base field items instead (no group names
847                 involved). Therefore, the passed collection of current item
848                 names as they are already grouped is used here to resolve the
849                 item names. */
850             ::std::vector< OUString > aMembers;
851             for( GroupItemList::iterator aBeg2 = aIt->begin(), aIt2 = aBeg2, aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
852                 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, *aIt2 ) )
853                     if( ::std::find( aMembers.begin(), aMembers.end(), pName->maGroupName ) == aMembers.end() )
854                         aMembers.push_back( pName->maGroupName );
855 
856             /*  Check again, that this is not just a group that is not grouped
857                 further with other items. */
858             if( aMembers.size() > 1 ) try
859             {
860                 // only the first call of createNameGroup() returns the new field
861                 Reference< XDataPilotField > xDPNewField = xDPGrouping->createNameGroup( ContainerHelper::vectorToSequence( aMembers ) );
862                 OSL_ENSURE( xDPGroupField.is() != xDPNewField.is(), "PivotCacheField::createParentGroupField - missing group field" );
863                 if( !xDPGroupField.is() )
864                     xDPGroupField = xDPNewField;
865 
866                 // get current grouping info
867                 DataPilotFieldGroupInfo aGroupInfo;
868                 PropertySet aPropSet( xDPGroupField );
869                 aPropSet.getProperty( aGroupInfo, PROP_GroupInfo );
870 
871                 /*  Find the group object and the auto-generated group name.
872                     The returned field contains all groups derived from the
873                     previous field if that is grouped too. To find the correct
874                     group, the first item used to create the group is serached.
875                     Calc provides the original item names of the base field
876                     when the group is querried for its members. Its does not
877                     provide the names of members that are already groups in the
878                     field used to create the new groups. (Is this a bug?)
879                     Therefore, a name from the passed list of original item
880                     names is used to find the correct group. */
881                 OUString aFirstItem;
882                 if( const PivotCacheGroupItem* pName = ContainerHelper::getVectorElement( orItemNames, aIt->front() ) )
883                     aFirstItem = pName->maOrigName;
884                 Reference< XNamed > xGroupName;
885                 OUString aAutoName;
886                 Reference< XIndexAccess > xGroupsIA( aGroupInfo.Groups, UNO_QUERY_THROW );
887                 for( sal_Int32 nIdx = 0, nCount = xGroupsIA->getCount(); (nIdx < nCount) && (aAutoName.getLength() == 0); ++nIdx ) try
888                 {
889                     Reference< XNameAccess > xItemsNA( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
890                     if( xItemsNA->hasByName( aFirstItem ) )
891                     {
892                         xGroupName.set( xGroupsIA->getByIndex( nIdx ), UNO_QUERY_THROW );
893                         aAutoName = xGroupName->getName();
894                     }
895                 }
896                 catch( Exception& )
897                 {
898                 }
899                 OSL_ENSURE( aAutoName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find auto-generated group name" );
900 
901                 // get the real group name from the list of group items
902                 OUString aGroupName;
903                 if( const PivotCacheItem* pGroupItem = maGroupItems.getCacheItem( static_cast< sal_Int32 >( aIt - aBeg ) ) )
904                     aGroupName = pGroupItem->getName();
905                 OSL_ENSURE( aGroupName.getLength() > 0, "PivotCacheField::createParentGroupField - cannot find group name" );
906                 if( aGroupName.getLength() == 0 )
907                     aGroupName = aAutoName;
908 
909                 if( xGroupName.is() && (aGroupName.getLength() > 0) )
910                 {
911                     // replace the auto-generated group name with the real name
912                     if( aAutoName != aGroupName )
913                     {
914                         xGroupName->setName( aGroupName );
915                         aPropSet.setProperty( PROP_GroupInfo, aGroupInfo );
916                     }
917                     // replace original item names in passed vector with group name
918                     for( GroupItemList::iterator aIt2 = aIt->begin(), aEnd2 = aIt->end(); aIt2 != aEnd2; ++aIt2 )
919                         if( PivotCacheGroupItem* pName = ContainerHelper::getVectorElementAccess( orItemNames, *aIt2 ) )
920                             pName->maGroupName = aGroupName;
921                 }
922             }
923             catch( Exception& )
924             {
925             }
926         }
927     }
928 
929     Reference< XNamed > xFieldName( xDPGroupField, UNO_QUERY );
930     return xFieldName.is() ? xFieldName->getName() : OUString();
931 }
932 
writeSourceHeaderCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const933 void PivotCacheField::writeSourceHeaderCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
934 {
935     CellModel aModel;
936     aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
937     rSheetHelper.getSheetData().setStringCell( aModel, maFieldModel.maName );
938 }
939 
writeSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,const PivotCacheItem & rItem) const940 void PivotCacheField::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
941 {
942     bool bHasIndex = rItem.getType() == XML_x;
943     OSL_ENSURE( bHasIndex != maSharedItems.empty(), "PivotCacheField::writeSourceDataCell - shared items missing or not expected" );
944     if( bHasIndex )
945         writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem.getValue().get< sal_Int32 >() );
946     else
947         writeItemToSourceDataCell( rSheetHelper, nCol, nRow, rItem );
948 }
949 
importPCRecordItem(SequenceInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const950 void PivotCacheField::importPCRecordItem( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
951 {
952     if( hasSharedItems() )
953     {
954         writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, rStrm.readInt32() );
955     }
956     else
957     {
958         PivotCacheItem aItem;
959         if( maSharedItemsModel.mbIsNumeric )
960            aItem.readDouble( rStrm );
961         else if( maSharedItemsModel.mbHasDate && !maSharedItemsModel.mbHasString )
962            aItem.readDate( rStrm );
963         else
964            aItem.readString( rStrm );
965         writeItemToSourceDataCell( rSheetHelper, nCol, nRow, aItem );
966     }
967 }
968 
importPCItemIndex(BiffInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow) const969 void PivotCacheField::importPCItemIndex( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow ) const
970 {
971     OSL_ENSURE( hasSharedItems(), "PivotCacheField::importPCItemIndex - invalid call, no shared items found" );
972     sal_Int32 nIndex = maSharedItemsModel.mbHasLongIndexes ? rStrm.readuInt16() : rStrm.readuInt8();
973     writeSharedItemToSourceDataCell( rSheetHelper, nCol, nRow, nIndex );
974 }
975 
976 // private --------------------------------------------------------------------
977 
writeItemToSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,const PivotCacheItem & rItem) const978 void PivotCacheField::writeItemToSourceDataCell( WorksheetHelper& rSheetHelper,
979         sal_Int32 nCol, sal_Int32 nRow, const PivotCacheItem& rItem ) const
980 {
981     if( rItem.getType() != XML_m )
982     {
983         CellModel aModel;
984         aModel.maCellAddr = CellAddress( rSheetHelper.getSheetIndex(), nCol, nRow );
985         SheetDataBuffer& rSheetData = rSheetHelper.getSheetData();
986         switch( rItem.getType() )
987         {
988             case XML_s: rSheetData.setStringCell( aModel, rItem.getValue().get< OUString >() );                             break;
989             case XML_n: rSheetData.setValueCell( aModel, rItem.getValue().get< double >() );                                break;
990             case XML_i: rSheetData.setValueCell( aModel, rItem.getValue().get< sal_Int16 >() );                             break;
991             case XML_d: rSheetData.setDateTimeCell( aModel, rItem.getValue().get< DateTime >() );                           break;
992             case XML_b: rSheetData.setBooleanCell( aModel, rItem.getValue().get< bool >() );                                break;
993             case XML_e: rSheetData.setErrorCell( aModel, static_cast< sal_uInt8 >( rItem.getValue().get< sal_Int32 >() ) ); break;
994             default:    OSL_ENSURE( false, "PivotCacheField::writeItemToSourceDataCell - unexpected item data type" );
995         }
996     }
997 }
998 
writeSharedItemToSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nCol,sal_Int32 nRow,sal_Int32 nItemIdx) const999 void PivotCacheField::writeSharedItemToSourceDataCell(
1000         WorksheetHelper& rSheetHelper, sal_Int32 nCol, sal_Int32 nRow, sal_Int32 nItemIdx ) const
1001 {
1002     if( const PivotCacheItem* pCacheItem = maSharedItems.getCacheItem( nItemIdx ) )
1003         writeItemToSourceDataCell( rSheetHelper, nCol, nRow, *pCacheItem );
1004 }
1005 
1006 // ============================================================================
1007 
PCDefinitionModel()1008 PCDefinitionModel::PCDefinitionModel() :
1009     mfRefreshedDate( 0.0 ),
1010     mnRecords( 0 ),
1011     mnMissItemsLimit( 0 ),
1012     mnDatabaseFields( 0 ),
1013     mbInvalid( false ),
1014     mbSaveData( true ),
1015     mbRefreshOnLoad( false ),
1016     mbOptimizeMemory( false ),
1017     mbEnableRefresh( true ),
1018     mbBackgroundQuery( false ),
1019     mbUpgradeOnRefresh( false ),
1020     mbTupleCache( false ),
1021     mbSupportSubquery( false ),
1022     mbSupportDrill( false )
1023 {
1024 }
1025 
1026 // ----------------------------------------------------------------------------
1027 
PCSourceModel()1028 PCSourceModel::PCSourceModel() :
1029     mnSourceType( XML_TOKEN_INVALID ),
1030     mnConnectionId( 0 )
1031 {
1032 }
1033 
1034 // ----------------------------------------------------------------------------
1035 
PCWorksheetSourceModel()1036 PCWorksheetSourceModel::PCWorksheetSourceModel()
1037 {
1038     maRange.StartColumn = maRange.StartRow = maRange.EndColumn = maRange.EndRow = -1;
1039 }
1040 
1041 // ----------------------------------------------------------------------------
1042 
PivotCache(const WorkbookHelper & rHelper)1043 PivotCache::PivotCache( const WorkbookHelper& rHelper ) :
1044     WorkbookHelper( rHelper ),
1045     mnCurrRow( -1 ),
1046     mbValidSource( false ),
1047     mbDummySheet( false )
1048 {
1049 }
1050 
importPivotCacheDefinition(const AttributeList & rAttribs)1051 void PivotCache::importPivotCacheDefinition( const AttributeList& rAttribs )
1052 {
1053     maDefModel.maRelId            = rAttribs.getString( R_TOKEN( id ), OUString() );
1054     maDefModel.maRefreshedBy      = rAttribs.getXString( XML_refreshedBy, OUString() );
1055     maDefModel.mfRefreshedDate    = rAttribs.getDouble( XML_refreshedDate, 0.0 );
1056     maDefModel.mnRecords          = rAttribs.getInteger( XML_recordCount, 0 );
1057     maDefModel.mnMissItemsLimit   = rAttribs.getInteger( XML_missingItemsLimit, 0 );
1058     maDefModel.mbInvalid          = rAttribs.getBool( XML_invalid, false );
1059     maDefModel.mbSaveData         = rAttribs.getBool( XML_saveData, true );
1060     maDefModel.mbRefreshOnLoad    = rAttribs.getBool( XML_refreshOnLoad, false );
1061     maDefModel.mbOptimizeMemory   = rAttribs.getBool( XML_optimizeMemory, false );
1062     maDefModel.mbEnableRefresh    = rAttribs.getBool( XML_enableRefresh, true );
1063     maDefModel.mbBackgroundQuery  = rAttribs.getBool( XML_backgroundQuery, false );
1064     maDefModel.mbUpgradeOnRefresh = rAttribs.getBool( XML_upgradeOnRefresh, false );
1065     maDefModel.mbTupleCache       = rAttribs.getBool( XML_tupleCache, false );
1066     maDefModel.mbSupportSubquery  = rAttribs.getBool( XML_supportSubquery, false );
1067     maDefModel.mbSupportDrill     = rAttribs.getBool( XML_supportAdvancedDrill, false );
1068 }
1069 
importCacheSource(const AttributeList & rAttribs)1070 void PivotCache::importCacheSource( const AttributeList& rAttribs )
1071 {
1072     maSourceModel.mnSourceType   = rAttribs.getToken( XML_type, XML_TOKEN_INVALID );
1073     maSourceModel.mnConnectionId = rAttribs.getInteger( XML_connectionId, 0 );
1074 }
1075 
importWorksheetSource(const AttributeList & rAttribs,const Relations & rRelations)1076 void PivotCache::importWorksheetSource( const AttributeList& rAttribs, const Relations& rRelations )
1077 {
1078     maSheetSrcModel.maRelId   = rAttribs.getString( R_TOKEN( id ), OUString() );
1079     maSheetSrcModel.maSheet   = rAttribs.getXString( XML_sheet, OUString() );
1080     maSheetSrcModel.maDefName = rAttribs.getXString( XML_name, OUString() );
1081 
1082     // resolve URL of external document
1083     maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1084     // store range address unchecked with sheet index 0, will be resolved/checked later
1085     getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, rAttribs.getString( XML_ref, OUString() ), 0 );
1086 }
1087 
importPCDefinition(SequenceInputStream & rStrm)1088 void PivotCache::importPCDefinition( SequenceInputStream& rStrm )
1089 {
1090     sal_uInt8 nFlags1, nFlags2;
1091     rStrm.skip( 3 );    // create/refresh version id's
1092     rStrm >> nFlags1 >> maDefModel.mnMissItemsLimit >> maDefModel.mfRefreshedDate >> nFlags2 >> maDefModel.mnRecords;
1093     if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASUSERNAME ) )
1094         rStrm >> maDefModel.maRefreshedBy;
1095     if( getFlag( nFlags2, BIFF12_PCDEFINITION_HASRELID ) )
1096         rStrm >> maDefModel.maRelId;
1097 
1098     maDefModel.mbInvalid          = getFlag( nFlags1, BIFF12_PCDEFINITION_INVALID );
1099     maDefModel.mbSaveData         = getFlag( nFlags1, BIFF12_PCDEFINITION_SAVEDATA );
1100     maDefModel.mbRefreshOnLoad    = getFlag( nFlags1, BIFF12_PCDEFINITION_REFRESHONLOAD );
1101     maDefModel.mbOptimizeMemory   = getFlag( nFlags1, BIFF12_PCDEFINITION_OPTIMIZEMEMORY );
1102     maDefModel.mbEnableRefresh    = getFlag( nFlags1, BIFF12_PCDEFINITION_ENABLEREFRESH );
1103     maDefModel.mbBackgroundQuery  = getFlag( nFlags1, BIFF12_PCDEFINITION_BACKGROUNDQUERY );
1104     maDefModel.mbUpgradeOnRefresh = getFlag( nFlags1, BIFF12_PCDEFINITION_UPGRADEONREFR );
1105     maDefModel.mbTupleCache       = getFlag( nFlags1, BIFF12_PCDEFINITION_TUPELCACHE );
1106     maDefModel.mbSupportSubquery  = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTSUBQUERY );
1107     maDefModel.mbSupportDrill     = getFlag( nFlags2, BIFF12_PCDEFINITION_SUPPORTDRILL );
1108 }
1109 
importPCDSource(SequenceInputStream & rStrm)1110 void PivotCache::importPCDSource( SequenceInputStream& rStrm )
1111 {
1112     sal_Int32 nSourceType;
1113     rStrm >> nSourceType >> maSourceModel.mnConnectionId;
1114     static const sal_Int32 spnSourceTypes[] = { XML_worksheet, XML_external, XML_consolidation, XML_scenario };
1115     maSourceModel.mnSourceType = STATIC_ARRAY_SELECT( spnSourceTypes, nSourceType, XML_TOKEN_INVALID );
1116 }
1117 
importPCDSheetSource(SequenceInputStream & rStrm,const Relations & rRelations)1118 void PivotCache::importPCDSheetSource( SequenceInputStream& rStrm, const Relations& rRelations )
1119 {
1120     sal_uInt8 nIsDefName, nIsBuiltinName, nFlags;
1121     rStrm >> nIsDefName >> nIsBuiltinName >> nFlags;
1122     if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASSHEET ) )
1123         rStrm >> maSheetSrcModel.maSheet;
1124     if( getFlag( nFlags, BIFF12_PCDWBSOURCE_HASRELID ) )
1125         rStrm >> maSheetSrcModel.maRelId;
1126 
1127     // read cell range or defined name
1128     if( nIsDefName == 0 )
1129     {
1130         BinRange aBinRange;
1131         rStrm >> aBinRange;
1132         // store range address unchecked with sheet index 0, will be resolved/checked later
1133         getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
1134     }
1135     else
1136     {
1137         rStrm >> maSheetSrcModel.maDefName;
1138         if( nIsBuiltinName != 0 )
1139             maSheetSrcModel.maDefName = CREATE_OUSTRING( "_xlnm." ) + maSheetSrcModel.maDefName;
1140     }
1141 
1142     // resolve URL of external document
1143     maTargetUrl = rRelations.getExternalTargetFromRelId( maSheetSrcModel.maRelId );
1144 }
1145 
importPCDSource(BiffInputStream & rStrm)1146 void PivotCache::importPCDSource( BiffInputStream& rStrm )
1147 {
1148     switch( rStrm.readuInt16() )
1149     {
1150         case BIFF_PCDSOURCE_WORKSHEET:
1151         {
1152             maSourceModel.mnSourceType = XML_worksheet;
1153             sal_uInt16 nNextRecId = rStrm.getNextRecId();
1154             switch( nNextRecId )
1155             {
1156                 case BIFF_ID_DCONREF:       if( rStrm.startNextRecord() ) importDConRef( rStrm );       break;
1157                 case BIFF_ID_DCONNAME:      if( rStrm.startNextRecord() ) importDConName( rStrm );      break;
1158                 case BIFF_ID_DCONBINAME:    if( rStrm.startNextRecord() ) importDConBIName( rStrm );    break;
1159             }
1160         }
1161         break;
1162         case BIFF_PCDSOURCE_EXTERNAL:
1163             maSourceModel.mnSourceType = XML_external;
1164         break;
1165         case BIFF_PCDSOURCE_CONSOLIDATION:
1166             maSourceModel.mnSourceType = XML_consolidation;
1167         break;
1168         case BIFF_PCDSOURCE_SCENARIO:
1169             maSourceModel.mnSourceType = XML_scenario;
1170         break;
1171         default:
1172             maSourceModel.mnSourceType = XML_TOKEN_INVALID;
1173     }
1174 }
1175 
importPCDefinition(BiffInputStream & rStrm)1176 void PivotCache::importPCDefinition( BiffInputStream& rStrm )
1177 {
1178     sal_uInt16 nFlags, nUserNameLen;
1179     rStrm >> maDefModel.mnRecords;
1180     rStrm.skip( 2 );    // repeated cache ID
1181     rStrm >> nFlags;
1182     rStrm.skip( 2 );    // unused
1183     rStrm >> maDefModel.mnDatabaseFields;
1184     rStrm.skip( 6 );    // total field count, report record count, (repeated) cache type
1185     rStrm >> nUserNameLen;
1186     if( nUserNameLen != BIFF_PC_NOSTRING )
1187         maDefModel.maRefreshedBy = (getBiff() == BIFF8) ?
1188             rStrm.readUniString( nUserNameLen ) :
1189             rStrm.readCharArrayUC( nUserNameLen, getTextEncoding() );
1190 
1191     maDefModel.mbInvalid          = getFlag( nFlags, BIFF_PCDEFINITION_INVALID );
1192     maDefModel.mbSaveData         = getFlag( nFlags, BIFF_PCDEFINITION_SAVEDATA );
1193     maDefModel.mbRefreshOnLoad    = getFlag( nFlags, BIFF_PCDEFINITION_REFRESHONLOAD );
1194     maDefModel.mbOptimizeMemory   = getFlag( nFlags, BIFF_PCDEFINITION_OPTIMIZEMEMORY );
1195     maDefModel.mbEnableRefresh    = getFlag( nFlags, BIFF_PCDEFINITION_ENABLEREFRESH );
1196     maDefModel.mbBackgroundQuery  = getFlag( nFlags, BIFF_PCDEFINITION_BACKGROUNDQUERY );
1197 
1198     if( (rStrm.getNextRecId() == BIFF_ID_PCDEFINITION2) && rStrm.startNextRecord() )
1199         rStrm >> maDefModel.mfRefreshedDate;
1200 }
1201 
createCacheField(bool bInitDatabaseField)1202 PivotCacheField& PivotCache::createCacheField( bool bInitDatabaseField )
1203 {
1204     bool bIsDatabaseField = !bInitDatabaseField || (maFields.size() < maDefModel.mnDatabaseFields);
1205     PivotCacheFieldVector::value_type xCacheField( new PivotCacheField( *this, bIsDatabaseField ) );
1206     maFields.push_back( xCacheField );
1207     return *xCacheField;
1208 }
1209 
finalizeImport()1210 void PivotCache::finalizeImport()
1211 {
1212     // collect all fields that are based on source data (needed to finalize source data below)
1213     OSL_ENSURE( !maFields.empty(), "PivotCache::finalizeImport - no pivot cache fields found" );
1214     for( PivotCacheFieldVector::const_iterator aIt = maFields.begin(), aEnd = maFields.end(); aIt != aEnd; ++aIt )
1215     {
1216         if( (*aIt)->isDatabaseField() )
1217         {
1218             OSL_ENSURE( (aIt == maFields.begin()) || (*(aIt - 1))->isDatabaseField(),
1219                 "PivotCache::finalizeImport - database field follows a calculated field" );
1220             maDatabaseIndexes.push_back( static_cast< sal_Int32 >( maDatabaseFields.size() ) );
1221             maDatabaseFields.push_back( *aIt );
1222         }
1223         else
1224         {
1225             maDatabaseIndexes.push_back( -1 );
1226         }
1227     }
1228     OSL_ENSURE( !maDatabaseFields.empty(), "PivotCache::finalizeImport - no pivot cache source fields found" );
1229 
1230     // finalize source data depending on source type
1231     switch( maSourceModel.mnSourceType )
1232     {
1233         case XML_worksheet:
1234         {
1235             // decide whether an external document is used
1236             bool bInternal = (maTargetUrl.getLength() == 0) && (maSheetSrcModel.maRelId.getLength() == 0);
1237             bool bExternal = maTargetUrl.getLength() > 0;   // relation ID may be empty, e.g. BIFF import
1238             OSL_ENSURE( bInternal || bExternal, "PivotCache::finalizeImport - invalid external document URL" );
1239             if( bInternal )
1240                 finalizeInternalSheetSource();
1241             else if( bExternal )
1242                 finalizeExternalSheetSource();
1243         }
1244         break;
1245 
1246         // currently, we only support worksheet data sources
1247         case XML_external:
1248         break;
1249         case XML_consolidation:
1250         break;
1251         case XML_scenario:
1252         break;
1253     }
1254 }
1255 
getCacheFieldCount() const1256 sal_Int32 PivotCache::getCacheFieldCount() const
1257 {
1258     return static_cast< sal_Int32 >( maFields.size() );
1259 }
1260 
getCacheField(sal_Int32 nFieldIdx) const1261 const PivotCacheField* PivotCache::getCacheField( sal_Int32 nFieldIdx ) const
1262 {
1263     return maFields.get( nFieldIdx ).get();
1264 }
1265 
getCacheDatabaseIndex(sal_Int32 nFieldIdx) const1266 sal_Int32 PivotCache::getCacheDatabaseIndex( sal_Int32 nFieldIdx ) const
1267 {
1268     return ContainerHelper::getVectorElement( maDatabaseIndexes, nFieldIdx, -1 );
1269 }
1270 
writeSourceHeaderCells(WorksheetHelper & rSheetHelper) const1271 void PivotCache::writeSourceHeaderCells( WorksheetHelper& rSheetHelper ) const
1272 {
1273     OSL_ENSURE( static_cast< size_t >( maSheetSrcModel.maRange.EndColumn - maSheetSrcModel.maRange.StartColumn + 1 ) == maDatabaseFields.size(),
1274         "PivotCache::writeSourceHeaderCells - source cell range width does not match number of source fields" );
1275     sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1276     sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1277     sal_Int32 nRow = maSheetSrcModel.maRange.StartRow;
1278     mnCurrRow = -1;
1279     updateSourceDataRow( rSheetHelper, nRow );
1280     for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1281         (*aIt)->writeSourceHeaderCell( rSheetHelper, nCol, nRow );
1282 }
1283 
writeSourceDataCell(WorksheetHelper & rSheetHelper,sal_Int32 nColIdx,sal_Int32 nRowIdx,const PivotCacheItem & rItem) const1284 void PivotCache::writeSourceDataCell( WorksheetHelper& rSheetHelper, sal_Int32 nColIdx, sal_Int32 nRowIdx, const PivotCacheItem& rItem ) const
1285 {
1286     sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn + nColIdx;
1287     OSL_ENSURE( (maSheetSrcModel.maRange.StartColumn <= nCol) && (nCol <= maSheetSrcModel.maRange.EndColumn), "PivotCache::writeSourceDataCell - invalid column index" );
1288     sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1289     OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::writeSourceDataCell - invalid row index" );
1290     updateSourceDataRow( rSheetHelper, nRow );
1291     if( const PivotCacheField* pCacheField = maDatabaseFields.get( nColIdx ).get() )
1292         pCacheField->writeSourceDataCell( rSheetHelper, nCol, nRow, rItem );
1293 }
1294 
importPCRecord(SequenceInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nRowIdx) const1295 void PivotCache::importPCRecord( SequenceInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1296 {
1297     sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1298     OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCRecord - invalid row index" );
1299     sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1300     sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1301     for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1302         (*aIt)->importPCRecordItem( rStrm, rSheetHelper, nCol, nRow );
1303 }
1304 
importPCItemIndexList(BiffInputStream & rStrm,WorksheetHelper & rSheetHelper,sal_Int32 nRowIdx) const1305 void PivotCache::importPCItemIndexList( BiffInputStream& rStrm, WorksheetHelper& rSheetHelper, sal_Int32 nRowIdx ) const
1306 {
1307     sal_Int32 nRow = maSheetSrcModel.maRange.StartRow + nRowIdx;
1308     OSL_ENSURE( (maSheetSrcModel.maRange.StartRow < nRow) && (nRow <= maSheetSrcModel.maRange.EndRow), "PivotCache::importPCItemIndexList - invalid row index" );
1309     sal_Int32 nCol = maSheetSrcModel.maRange.StartColumn;
1310     sal_Int32 nMaxCol = getAddressConverter().getMaxApiAddress().Column;
1311     for( PivotCacheFieldVector::const_iterator aIt = maDatabaseFields.begin(), aEnd = maDatabaseFields.end(); !rStrm.isEof() && (aIt != aEnd) && (nCol <= nMaxCol); ++aIt, ++nCol )
1312         if( (*aIt)->hasSharedItems() )
1313             (*aIt)->importPCItemIndex( rStrm, rSheetHelper, nCol, nRow );
1314 }
1315 
1316 // private --------------------------------------------------------------------
1317 
importDConRef(BiffInputStream & rStrm)1318 void PivotCache::importDConRef( BiffInputStream& rStrm )
1319 {
1320     BinRange aBinRange;
1321     aBinRange.read( rStrm, false );     // always 8-bit column indexes
1322     // store range address unchecked with sheet index 0, will be resolved/checked later
1323     getAddressConverter().convertToCellRangeUnchecked( maSheetSrcModel.maRange, aBinRange, 0 );
1324 
1325     // the URL with (required) sheet name and optional URL of an external document
1326     importDConUrl( rStrm );
1327     OSL_ENSURE( maSheetSrcModel.maSheet.getLength() > 0, "PivotCache::importDConRef - missing sheet name" );
1328 }
1329 
importDConName(BiffInputStream & rStrm)1330 void PivotCache::importDConName( BiffInputStream& rStrm )
1331 {
1332     maSheetSrcModel.maDefName = (getBiff() == BIFF8) ? rStrm.readUniString() : rStrm.readByteStringUC( false, getTextEncoding() );
1333     OSL_ENSURE( maSheetSrcModel.maDefName.getLength() > 0, "PivotCache::importDConName - missing defined name" );
1334     importDConUrl( rStrm );
1335 }
1336 
importDConBIName(BiffInputStream & rStrm)1337 void PivotCache::importDConBIName( BiffInputStream& rStrm )
1338 {
1339     sal_uInt8 nNameId = rStrm.readuInt8();
1340     rStrm.skip( 3 );
1341     maSheetSrcModel.maDefName = OUString( sal_Unicode( nNameId ) );
1342     importDConUrl( rStrm );
1343 }
1344 
importDConUrl(BiffInputStream & rStrm)1345 void PivotCache::importDConUrl( BiffInputStream& rStrm )
1346 {
1347     // the URL with sheet name and optional URL of an external document
1348     OUString aEncodedUrl;
1349     if( getBiff() == BIFF8 )
1350     {
1351         // empty string does not contain a flags byte, cannot use simple readUniString() here...
1352         sal_uInt16 nChars = rStrm.readuInt16();
1353         if( nChars > 0 )
1354             aEncodedUrl = rStrm.readUniString( nChars );
1355     }
1356     else
1357     {
1358         aEncodedUrl = rStrm.readByteStringUC( false, getTextEncoding() );
1359     }
1360 
1361     if( aEncodedUrl.getLength() > 0 )
1362     {
1363         OUString aClassName;
1364         getAddressConverter().parseBiffTargetUrl( aClassName, maTargetUrl, maSheetSrcModel.maSheet, aEncodedUrl, true );
1365     }
1366 }
1367 
finalizeInternalSheetSource()1368 void PivotCache::finalizeInternalSheetSource()
1369 {
1370     // resolve sheet name to sheet index
1371     sal_Int16 nSheet = getWorksheets().getCalcSheetIndex( maSheetSrcModel.maSheet );
1372 
1373     // if cache is based on a defined name or table, try to resolve to cell range
1374     if( maSheetSrcModel.maDefName.getLength() > 0 )
1375     {
1376         // local or global defined name
1377         if( const DefinedName* pDefName = getDefinedNames().getByModelName( maSheetSrcModel.maDefName, nSheet ).get() )
1378         {
1379             mbValidSource = pDefName->getAbsoluteRange( maSheetSrcModel.maRange );
1380         }
1381         // table
1382         else if( const Table* pTable = getTables().getTable( maSheetSrcModel.maDefName ).get() )
1383         {
1384             // get original range from table, but exclude the totals row(s)
1385             maSheetSrcModel.maRange = pTable->getOriginalRange();
1386             mbValidSource = (pTable->getHeight() - pTable->getTotalsRows()) > 1;
1387             if( mbValidSource )
1388                 maSheetSrcModel.maRange.EndRow -= pTable->getTotalsRows();
1389         }
1390     }
1391     // else try the cell range (if the sheet exists)
1392     else if( nSheet >= 0 )
1393     {
1394         // insert sheet index into the range, range address will be checked below
1395         maSheetSrcModel.maRange.Sheet = nSheet;
1396         mbValidSource = true;
1397     }
1398     // else sheet has been deleted, generate the source data from cache
1399     else if( maSheetSrcModel.maSheet.getLength() > 0 )
1400     {
1401         prepareSourceDataSheet();
1402         // return here to skip the source range check below
1403         return;
1404     }
1405 
1406     // check range location, do not allow ranges that overflow the sheet partly
1407     mbValidSource = mbValidSource &&
1408         getAddressConverter().checkCellRange( maSheetSrcModel.maRange, false, true ) &&
1409         (maSheetSrcModel.maRange.StartRow < maSheetSrcModel.maRange.EndRow);
1410 }
1411 
finalizeExternalSheetSource()1412 void PivotCache::finalizeExternalSheetSource()
1413 {
1414     /*  If pivot cache is based on external sheet data, try to restore sheet
1415         data from cache records. No support for external defined names or tables,
1416         sheet name and path to cache records fragment (OOXML only) are required. */
1417     bool bHasRelation = (getFilterType() == FILTER_BIFF) || (maDefModel.maRelId.getLength() > 0);
1418     if( bHasRelation && (maSheetSrcModel.maDefName.getLength() == 0) && (maSheetSrcModel.maSheet.getLength() > 0) )
1419         prepareSourceDataSheet();
1420 }
1421 
prepareSourceDataSheet()1422 void PivotCache::prepareSourceDataSheet()
1423 {
1424     CellRangeAddress& rRange = maSheetSrcModel.maRange;
1425     // data will be inserted in top-left cell, sheet index is still set to 0 (will be set below)
1426     rRange.EndColumn -= rRange.StartColumn;
1427     rRange.StartColumn = 0;
1428     rRange.EndRow -= rRange.StartRow;
1429     rRange.StartRow = 0;
1430     // check range location, do not allow ranges that overflow the sheet partly
1431     if( getAddressConverter().checkCellRange( rRange, false, true ) )
1432     {
1433         maColSpans.insert( ValueRange( rRange.StartColumn, rRange.EndColumn ) );
1434         OUString aSheetName = CREATE_OUSTRING( "DPCache_" ) + maSheetSrcModel.maSheet;
1435         rRange.Sheet = getWorksheets().insertEmptySheet( aSheetName, false );
1436         mbValidSource = mbDummySheet = rRange.Sheet >= 0;
1437     }
1438 }
1439 
updateSourceDataRow(WorksheetHelper & rSheetHelper,sal_Int32 nRow) const1440 void PivotCache::updateSourceDataRow( WorksheetHelper& rSheetHelper, sal_Int32 nRow ) const
1441 {
1442     if( mnCurrRow != nRow )
1443     {
1444         rSheetHelper.getSheetData().setColSpans( nRow, maColSpans );
1445         mnCurrRow = nRow;
1446     }
1447 }
1448 
1449 // ============================================================================
1450 
PivotCacheBuffer(const WorkbookHelper & rHelper)1451 PivotCacheBuffer::PivotCacheBuffer( const WorkbookHelper& rHelper ) :
1452     WorkbookHelper( rHelper )
1453 {
1454 }
1455 
registerPivotCacheFragment(sal_Int32 nCacheId,const OUString & rFragmentPath)1456 void PivotCacheBuffer::registerPivotCacheFragment( sal_Int32 nCacheId, const OUString& rFragmentPath )
1457 {
1458     OSL_ENSURE( nCacheId >= 0, "PivotCacheBuffer::registerPivotCacheFragment - invalid pivot cache identifier" );
1459     OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::registerPivotCacheFragment - fragment path exists already" );
1460     if( (nCacheId >= 0) && (rFragmentPath.getLength() > 0) )
1461         maFragmentPaths[ nCacheId ] = rFragmentPath;
1462 }
1463 
importPivotCacheRef(BiffInputStream & rStrm)1464 void PivotCacheBuffer::importPivotCacheRef( BiffInputStream& rStrm )
1465 {
1466     // read the PIVOTCACHE record that contains the stream ID
1467     sal_Int32 nCacheId = rStrm.readuInt16();
1468     OSL_ENSURE( maFragmentPaths.count( nCacheId ) == 0, "PivotCacheBuffer::importPivotCacheRef - cache stream exists already" );
1469     OUStringBuffer aStrmName;
1470     static const sal_Unicode spcHexChars[] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
1471     for( sal_uInt8 nBit = 0; nBit < 16; nBit += 4 )
1472         aStrmName.insert( 0, spcHexChars[ extractValue< size_t >( nCacheId, nBit, 4 ) ] );
1473     aStrmName.insert( 0, (getBiff() == BIFF8) ? CREATE_OUSTRING( "_SX_DB_CUR/" ) : CREATE_OUSTRING( "_SX_DB/" ) );
1474     maFragmentPaths[ nCacheId ] = aStrmName.makeStringAndClear();
1475 
1476     // try to read PCDSOURCE record (will read following data location records too)
1477     sal_uInt16 nNextRecId = rStrm.getNextRecId();
1478     OSL_ENSURE( nNextRecId == BIFF_ID_PCDSOURCE, "PivotCacheBuffer::importPivotCacheRef - PCDSOURCE record expected" );
1479     if( (nNextRecId == BIFF_ID_PCDSOURCE) && rStrm.startNextRecord() )
1480         createPivotCache( nCacheId ).importPCDSource( rStrm );
1481 }
1482 
importPivotCacheFragment(sal_Int32 nCacheId)1483 PivotCache* PivotCacheBuffer::importPivotCacheFragment( sal_Int32 nCacheId )
1484 {
1485     switch( getFilterType() )
1486     {
1487         /*  OOXML/BIFF12 filter: On first call for the cache ID, the pivot
1488             cache object is created and inserted into maCaches. Then, the cache
1489             definition fragment is read and the cache is returned. On
1490             subsequent calls, the created cache will be found in maCaches and
1491             returned immediately. */
1492         case FILTER_OOXML:
1493         {
1494             // try to find an imported pivot cache
1495             if( PivotCache* pCache = maCaches.get( nCacheId ).get() )
1496                 return pCache;
1497 
1498             // check if a fragment path exists for the passed cache identifier
1499             FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1500             if( aIt == maFragmentPaths.end() )
1501                 return 0;
1502 
1503             /*  Import the cache fragment. This may create a dummy data sheet
1504                 for external sheet sources. */
1505             PivotCache& rCache = createPivotCache( nCacheId );
1506             importOoxFragment( new PivotCacheDefinitionFragment( *this, aIt->second, rCache ) );
1507             return &rCache;
1508         }
1509 
1510         /*  BIFF filter: Pivot table provides 0-based index into list of pivot
1511             cache source links (PIVOTCACHE/PCDSOURCE/... record blocks in
1512             workbook stream). First, this index has to be resolved to the cache
1513             identifier that is used to manage the cache stream names (the
1514             maFragmentPaths member). The cache object itself exists already
1515             before the first call for the cache source index (see
1516             PivotCacheBuffer::importPivotCacheRef() above), because source data
1517             link is part of workbook data, not of the cache stream. To detect
1518             subsequent calls with an already initialized cache, the entry in
1519             maFragmentPaths will be removed after reading the cache stream. */
1520         case FILTER_BIFF:
1521         {
1522             /*  Resolve cache index to cache identifier and try to find pivot
1523                 cache. Cache must exist already for a valid cache index. */
1524             nCacheId = ContainerHelper::getVectorElement( maCacheIds, nCacheId, -1 );
1525             PivotCache* pCache = maCaches.get( nCacheId ).get();
1526             if( !pCache )
1527                 return 0;
1528 
1529             /*  Try to find fragment path entry (stream name). If missing, the
1530                 stream has been read already, and the cache can be returned. */
1531             FragmentPathMap::iterator aIt = maFragmentPaths.find( nCacheId );
1532             if( aIt != maFragmentPaths.end() )
1533             {
1534                 /*  Import the cache stream. This may create a dummy data sheet
1535                     for external sheet sources. */
1536                 BiffPivotCacheFragment( *this, aIt->second, *pCache ).importFragment();
1537                 // remove the fragment entry to mark that the cache is initialized
1538                 maFragmentPaths.erase( aIt );
1539             }
1540             return pCache;
1541         }
1542 
1543         case FILTER_UNKNOWN:
1544             OSL_ENSURE( false, "PivotCacheBuffer::importPivotCacheFragment - unknown filter type" );
1545     }
1546     return 0;
1547 }
1548 
createPivotCache(sal_Int32 nCacheId)1549 PivotCache& PivotCacheBuffer::createPivotCache( sal_Int32 nCacheId )
1550 {
1551     maCacheIds.push_back( nCacheId );
1552     PivotCacheMap::mapped_type& rxCache = maCaches[ nCacheId ];
1553     rxCache.reset( new PivotCache( *this ) );
1554     return *rxCache;
1555 }
1556 
1557 // ============================================================================
1558 
1559 } // namespace xls
1560 } // namespace oox
1561