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