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/defnamesbuffer.hxx"
25
26 #include <com/sun/star/sheet/ComplexReference.hpp>
27 #include <com/sun/star/sheet/ExternalReference.hpp>
28 #include <com/sun/star/sheet/NamedRangeFlag.hpp>
29 #include <com/sun/star/sheet/ReferenceFlags.hpp>
30 #include <com/sun/star/sheet/SingleReference.hpp>
31 #include <com/sun/star/sheet/XFormulaTokens.hpp>
32 #include <com/sun/star/sheet/XPrintAreas.hpp>
33 #include <rtl/ustrbuf.hxx>
34 #include "oox/helper/attributelist.hxx"
35 #include "oox/helper/containerhelper.hxx"
36 #include "oox/helper/propertyset.hxx"
37 #include "oox/xls/addressconverter.hxx"
38 #include "oox/xls/biffinputstream.hxx"
39 #include "oox/xls/externallinkbuffer.hxx"
40 #include "oox/xls/formulaparser.hxx"
41 #include "oox/xls/worksheetbuffer.hxx"
42
43 namespace oox {
44 namespace xls {
45
46 // ============================================================================
47
48 using namespace ::com::sun::star::sheet;
49 using namespace ::com::sun::star::table;
50 using namespace ::com::sun::star::uno;
51
52 using ::rtl::OUString;
53 using ::rtl::OUStringBuffer;
54
55 // ============================================================================
56
57 namespace {
58
59 const sal_uInt32 BIFF12_DEFNAME_HIDDEN = 0x00000001;
60 const sal_uInt32 BIFF12_DEFNAME_FUNC = 0x00000002;
61 const sal_uInt32 BIFF12_DEFNAME_VBNAME = 0x00000004;
62 const sal_uInt32 BIFF12_DEFNAME_MACRO = 0x00000008;
63 const sal_uInt32 BIFF12_DEFNAME_CALCEXP = 0x00000010;
64 const sal_uInt32 BIFF12_DEFNAME_BUILTIN = 0x00000020;
65 const sal_uInt32 BIFF12_DEFNAME_PUBLISHED = 0x00008000;
66 const sal_uInt32 BIFF12_DEFNAME_WBPARAM = 0x00010000;
67
68 const sal_uInt16 BIFF_DEFNAME_HIDDEN = 0x0001;
69 const sal_uInt16 BIFF_DEFNAME_FUNC = 0x0002;
70 const sal_uInt16 BIFF_DEFNAME_VBNAME = 0x0004;
71 const sal_uInt16 BIFF_DEFNAME_MACRO = 0x0008;
72 const sal_uInt16 BIFF_DEFNAME_CALCEXP = 0x0010;
73 const sal_uInt16 BIFF_DEFNAME_BUILTIN = 0x0020;
74 const sal_uInt16 BIFF_DEFNAME_BIG = 0x1000;
75
76 const sal_uInt8 BIFF2_DEFNAME_FUNC = 0x02; /// BIFF2 function/command flag.
77
78 const sal_uInt16 BIFF_DEFNAME_GLOBAL = 0; /// 0 = Globally defined name.
79
80 const sal_uInt16 BIFF_REFFLAG_COL1REL = 0x0001;
81 const sal_uInt16 BIFF_REFFLAG_ROW1REL = 0x0002;
82 const sal_uInt16 BIFF_REFFLAG_COL2REL = 0x0004;
83 const sal_uInt16 BIFF_REFFLAG_ROW2REL = 0x0008;
84
85 // ----------------------------------------------------------------------------
86
87 const sal_Char* const spcLegacyPrefix = "Excel_BuiltIn_";
88 const sal_Char* const spcOoxPrefix = "_xlnm.";
89
90 const sal_Char* const sppcBaseNames[] =
91 {
92 "Consolidate_Area",
93 "Auto_Open",
94 "Auto_Close",
95 "Extract",
96 "Database",
97 "Criteria",
98 "Print_Area",
99 "Print_Titles",
100 "Recorder",
101 "Data_Form",
102 "Auto_Activate",
103 "Auto_Deactivate",
104 "Sheet_Title",
105 "_FilterDatabase"
106 };
107
108 /** Localized names for _xlnm._FilterDatabase as used in BIFF5. */
109 const sal_Char* const sppcFilterDbNames[] =
110 {
111 "_FilterDatabase", // English
112 "_FilterDatenbank" // German
113 };
114
lclGetBaseName(sal_Unicode cBuiltinId)115 OUString lclGetBaseName( sal_Unicode cBuiltinId )
116 {
117 OSL_ENSURE( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ), "lclGetBaseName - unsupported built-in identifier" );
118 OUStringBuffer aBuffer;
119 if( cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ) )
120 aBuffer.appendAscii( sppcBaseNames[ cBuiltinId ] );
121 else
122 aBuffer.append( static_cast< sal_Int32 >( cBuiltinId ) );
123 return aBuffer.makeStringAndClear();
124 }
125
lclGetPrefixedName(sal_Unicode cBuiltinId)126 OUString lclGetPrefixedName( sal_Unicode cBuiltinId )
127 {
128 return OUStringBuffer().appendAscii( spcOoxPrefix ).append( lclGetBaseName( cBuiltinId ) ).makeStringAndClear();
129 }
130
131 /** returns the built-in name identifier from a perfixed built-in name, e.g. '_xlnm.Print_Area'. */
lclGetBuiltinIdFromPrefixedName(const OUString & rModelName)132 sal_Unicode lclGetBuiltinIdFromPrefixedName( const OUString& rModelName )
133 {
134 OUString aPrefix = OUString::createFromAscii( spcOoxPrefix );
135 sal_Int32 nPrefixLen = aPrefix.getLength();
136 if( rModelName.matchIgnoreAsciiCase( aPrefix ) )
137 {
138 for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
139 {
140 OUString aBaseName = lclGetBaseName( cBuiltinId );
141 sal_Int32 nBaseNameLen = aBaseName.getLength();
142 if( (rModelName.getLength() == nPrefixLen + nBaseNameLen) && rModelName.matchIgnoreAsciiCase( aBaseName, nPrefixLen ) )
143 return cBuiltinId;
144 }
145 }
146 return BIFF_DEFNAME_UNKNOWN;
147 }
148
149 /** returns the built-in name identifier from a built-in base name, e.g. 'Print_Area'. */
lclGetBuiltinIdFromBaseName(const OUString & rModelName)150 sal_Unicode lclGetBuiltinIdFromBaseName( const OUString& rModelName )
151 {
152 for( sal_Unicode cBuiltinId = 0; cBuiltinId < STATIC_ARRAY_SIZE( sppcBaseNames ); ++cBuiltinId )
153 if( rModelName.equalsIgnoreAsciiCaseAscii( sppcBaseNames[ cBuiltinId ] ) )
154 return cBuiltinId;
155 return BIFF_DEFNAME_UNKNOWN;
156 }
157
lclIsFilterDatabaseName(const OUString & rModelName)158 bool lclIsFilterDatabaseName( const OUString& rModelName )
159 {
160 for( const sal_Char* const* ppcName = sppcFilterDbNames; ppcName < STATIC_ARRAY_END( sppcFilterDbNames ); ++ppcName )
161 if( rModelName.equalsIgnoreAsciiCaseAscii( *ppcName ) )
162 return true;
163 return false;
164 }
165
lclGetUpcaseModelName(const OUString & rModelName)166 OUString lclGetUpcaseModelName( const OUString& rModelName )
167 {
168 // TODO: i18n?
169 return rModelName.toAsciiUpperCase();
170 }
171
lclConvertRefFlags(sal_Int32 & ornFlags,sal_Int32 & ornAbsPos,sal_Int32 & ornRelPos,sal_Int32 nBasePos,sal_Int32 nApiRelFlag,bool bRel)172 void lclConvertRefFlags( sal_Int32& ornFlags, sal_Int32& ornAbsPos, sal_Int32& ornRelPos, sal_Int32 nBasePos, sal_Int32 nApiRelFlag, bool bRel )
173 {
174 if( getFlag( ornFlags, nApiRelFlag ) && !bRel )
175 {
176 // convert relative to absolute
177 setFlag( ornFlags, nApiRelFlag, false );
178 ornAbsPos = nBasePos + ornRelPos;
179 }
180 else if( !getFlag( ornFlags, nApiRelFlag ) && bRel )
181 {
182 // convert absolute to relative
183 setFlag( ornFlags, nApiRelFlag, true );
184 ornRelPos = ornAbsPos - nBasePos;
185 }
186 }
187
lclConvertSingleRefFlags(SingleReference & orApiRef,const CellAddress & rBaseAddr,bool bColRel,bool bRowRel)188 void lclConvertSingleRefFlags( SingleReference& orApiRef, const CellAddress& rBaseAddr, bool bColRel, bool bRowRel )
189 {
190 using namespace ::com::sun::star::sheet::ReferenceFlags;
191 lclConvertRefFlags(
192 orApiRef.Flags, orApiRef.Column, orApiRef.RelativeColumn,
193 rBaseAddr.Column, COLUMN_RELATIVE, bColRel );
194 lclConvertRefFlags(
195 orApiRef.Flags, orApiRef.Row, orApiRef.RelativeRow,
196 rBaseAddr.Row, ROW_RELATIVE, bRowRel );
197 }
198
lclConvertReference(const Any & rRefAny,const CellAddress & rBaseAddr,sal_uInt16 nRelFlags)199 Any lclConvertReference( const Any& rRefAny, const CellAddress& rBaseAddr, sal_uInt16 nRelFlags )
200 {
201 if( rRefAny.has< SingleReference >() && !getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ) && !getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) )
202 {
203 SingleReference aApiRef;
204 rRefAny >>= aApiRef;
205 lclConvertSingleRefFlags( aApiRef, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
206 return Any( aApiRef );
207 }
208 if( rRefAny.has< ComplexReference >() )
209 {
210 ComplexReference aApiRef;
211 rRefAny >>= aApiRef;
212 lclConvertSingleRefFlags( aApiRef.Reference1, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL1REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW1REL ) );
213 lclConvertSingleRefFlags( aApiRef.Reference2, rBaseAddr, getFlag( nRelFlags, BIFF_REFFLAG_COL2REL ), getFlag( nRelFlags, BIFF_REFFLAG_ROW2REL ) );
214 return Any( aApiRef );
215 }
216 return Any();
217 }
218
219 } // namespace
220
221 // ============================================================================
222
DefinedNameModel()223 DefinedNameModel::DefinedNameModel() :
224 mnSheet( -1 ),
225 mnFuncGroupId( -1 ),
226 mbMacro( false ),
227 mbFunction( false ),
228 mbVBName( false ),
229 mbHidden( false )
230 {
231 }
232
233 // ============================================================================
234
DefinedNameBase(const WorkbookHelper & rHelper)235 DefinedNameBase::DefinedNameBase( const WorkbookHelper& rHelper ) :
236 WorkbookHelper( rHelper )
237 {
238 }
239
getUpcaseModelName() const240 const OUString& DefinedNameBase::getUpcaseModelName() const
241 {
242 if( maUpModelName.getLength() == 0 )
243 maUpModelName = lclGetUpcaseModelName( maModel.maName );
244 return maUpModelName;
245 }
246
getReference(const CellAddress & rBaseAddr) const247 Any DefinedNameBase::getReference( const CellAddress& rBaseAddr ) const
248 {
249 if( maRefAny.hasValue() && (maModel.maName.getLength() >= 2) && (maModel.maName[ 0 ] == '\x01') )
250 {
251 sal_Unicode cFlagsChar = getUpcaseModelName()[ 1 ];
252 if( ('A' <= cFlagsChar) && (cFlagsChar <= 'P') )
253 {
254 sal_uInt16 nRelFlags = static_cast< sal_uInt16 >( cFlagsChar - 'A' );
255 if( maRefAny.has< ExternalReference >() )
256 {
257 ExternalReference aApiExtRef;
258 maRefAny >>= aApiExtRef;
259 Any aRefAny = lclConvertReference( aApiExtRef.Reference, rBaseAddr, nRelFlags );
260 if( aRefAny.hasValue() )
261 {
262 aApiExtRef.Reference <<= aRefAny;
263 return Any( aApiExtRef );
264 }
265 }
266 else
267 {
268 return lclConvertReference( maRefAny, rBaseAddr, nRelFlags );
269 }
270 }
271 }
272 return Any();
273 }
274
importOoxFormula(sal_Int16 nBaseSheet)275 ApiTokenSequence DefinedNameBase::importOoxFormula( sal_Int16 nBaseSheet )
276 {
277 return (maModel.maFormula.getLength() > 0) ?
278 getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), maModel.maFormula ) :
279 getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME );
280 }
281
importBiff12Formula(sal_Int16 nBaseSheet,SequenceInputStream & rStrm)282 ApiTokenSequence DefinedNameBase::importBiff12Formula( sal_Int16 nBaseSheet, SequenceInputStream& rStrm )
283 {
284 return getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm );
285 }
286
importBiffFormula(sal_Int16 nBaseSheet,BiffInputStream & rStrm,const sal_uInt16 * pnFmlaSize)287 ApiTokenSequence DefinedNameBase::importBiffFormula( sal_Int16 nBaseSheet, BiffInputStream& rStrm, const sal_uInt16* pnFmlaSize )
288 {
289 return (!pnFmlaSize || (*pnFmlaSize > 0)) ?
290 getFormulaParser().importFormula( CellAddress( nBaseSheet, 0, 0 ), FORMULATYPE_DEFINEDNAME, rStrm, pnFmlaSize ) :
291 getFormulaParser().convertErrorToFormula( BIFF_ERR_NAME );
292 }
293
extractReference(const ApiTokenSequence & rTokens)294 void DefinedNameBase::extractReference( const ApiTokenSequence& rTokens )
295 {
296 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4), "DefinedNameBase::extractReference - unexpected call" );
297 maRefAny = getFormulaParser().extractReference( rTokens );
298 }
299
300 // ============================================================================
301
DefinedName(const WorkbookHelper & rHelper)302 DefinedName::DefinedName( const WorkbookHelper& rHelper ) :
303 DefinedNameBase( rHelper ),
304 mnTokenIndex( -1 ),
305 mcBuiltinId( BIFF_DEFNAME_UNKNOWN ),
306 mnFmlaSize( 0 )
307 {
308 }
309
importDefinedName(const AttributeList & rAttribs)310 void DefinedName::importDefinedName( const AttributeList& rAttribs )
311 {
312 maModel.maName = rAttribs.getXString( XML_name, OUString() );
313 maModel.mnSheet = rAttribs.getInteger( XML_localSheetId, -1 );
314 maModel.mnFuncGroupId = rAttribs.getInteger( XML_functionGroupId, -1 );
315 maModel.mbMacro = rAttribs.getBool( XML_xlm, false );
316 maModel.mbFunction = rAttribs.getBool( XML_function, false );
317 maModel.mbVBName = rAttribs.getBool( XML_vbProcedure, false );
318 maModel.mbHidden = rAttribs.getBool( XML_hidden, false );
319 mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
320
321 /* Detect built-in state from name itself, there is no built-in flag.
322 Built-in names are prexixed with '_xlnm.' instead. */
323 mcBuiltinId = lclGetBuiltinIdFromPrefixedName( maModel.maName );
324 }
325
setFormula(const OUString & rFormula)326 void DefinedName::setFormula( const OUString& rFormula )
327 {
328 maModel.maFormula = rFormula;
329 }
330
importDefinedName(SequenceInputStream & rStrm)331 void DefinedName::importDefinedName( SequenceInputStream& rStrm )
332 {
333 sal_uInt32 nFlags;
334 rStrm >> nFlags;
335 rStrm.skip( 1 ); // keyboard shortcut
336 rStrm >> maModel.mnSheet >> maModel.maName;
337 mnCalcSheet = (maModel.mnSheet >= 0) ? getWorksheets().getCalcSheetIndex( maModel.mnSheet ) : -1;
338
339 // macro function/command, hidden flag
340 maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 9 );
341 maModel.mbMacro = getFlag( nFlags, BIFF12_DEFNAME_MACRO );
342 maModel.mbFunction = getFlag( nFlags, BIFF12_DEFNAME_FUNC );
343 maModel.mbVBName = getFlag( nFlags, BIFF12_DEFNAME_VBNAME );
344 maModel.mbHidden = getFlag( nFlags, BIFF12_DEFNAME_HIDDEN );
345
346 // get built-in name index from name
347 if( getFlag( nFlags, BIFF12_DEFNAME_BUILTIN ) )
348 mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
349
350 // store token array data
351 sal_Int64 nRecPos = rStrm.tell();
352 sal_Int32 nFmlaSize = rStrm.readInt32();
353 rStrm.skip( nFmlaSize );
354 sal_Int32 nAddDataSize = rStrm.readInt32();
355 if( !rStrm.isEof() && (nFmlaSize > 0) && (nAddDataSize >= 0) && (rStrm.getRemaining() >= nAddDataSize) )
356 {
357 sal_Int32 nTotalSize = 8 + nFmlaSize + nAddDataSize;
358 mxFormula.reset( new StreamDataSequence );
359 rStrm.seek( nRecPos );
360 rStrm.readData( *mxFormula, nTotalSize );
361 }
362 }
363
importDefinedName(BiffInputStream & rStrm,sal_Int16 nCalcSheet)364 void DefinedName::importDefinedName( BiffInputStream& rStrm, sal_Int16 nCalcSheet )
365 {
366 BiffType eBiff = getBiff();
367 sal_uInt16 nFlags = 0;
368 sal_Int16 nRefId = BIFF_DEFNAME_GLOBAL;
369 sal_Int16 nTabId = BIFF_DEFNAME_GLOBAL;
370 sal_uInt8 nNameLen = 0, nShortCut = 0;
371
372 switch( eBiff )
373 {
374 case BIFF2:
375 {
376 sal_uInt8 nFlagsBiff2;
377 rStrm >> nFlagsBiff2;
378 rStrm.skip( 1 );
379 rStrm >> nShortCut >> nNameLen;
380 mnFmlaSize = rStrm.readuInt8();
381 setFlag( nFlags, BIFF_DEFNAME_FUNC, getFlag( nFlagsBiff2, BIFF2_DEFNAME_FUNC ) );
382 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
383 }
384 break;
385 case BIFF3:
386 case BIFF4:
387 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize;
388 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
389 break;
390 case BIFF5:
391 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
392 rStrm.skip( 4 );
393 maModel.maName = rStrm.readCharArrayUC( nNameLen, getTextEncoding(), true );
394 break;
395 case BIFF8:
396 rStrm >> nFlags >> nShortCut >> nNameLen >> mnFmlaSize >> nRefId >> nTabId;
397 rStrm.skip( 4 );
398 maModel.maName = rStrm.readUniStringBody( nNameLen, true );
399 break;
400 case BIFF_UNKNOWN: break;
401 }
402
403 // macro function/command, hidden flag
404 maModel.mnFuncGroupId = extractValue< sal_Int32 >( nFlags, 6, 6 );
405 maModel.mbMacro = getFlag( nFlags, BIFF_DEFNAME_MACRO );
406 maModel.mbFunction = getFlag( nFlags, BIFF_DEFNAME_FUNC );
407 maModel.mbVBName = getFlag( nFlags, BIFF_DEFNAME_VBNAME );
408 maModel.mbHidden = getFlag( nFlags, BIFF_DEFNAME_HIDDEN );
409
410 // get built-in name index from name
411 if( getFlag( nFlags, BIFF_DEFNAME_BUILTIN ) )
412 {
413 // name may be the built-in identifier or the built-in base name
414 if( maModel.maName.getLength() == 1 )
415 mcBuiltinId = maModel.maName[ 0 ];
416 else
417 mcBuiltinId = lclGetBuiltinIdFromBaseName( maModel.maName );
418 }
419 /* In BIFF5, '_FilterDatabase' appears as hidden user name without
420 built-in flag, and even worse, localized. */
421 else if( (eBiff == BIFF5) && lclIsFilterDatabaseName( maModel.maName ) )
422 {
423 mcBuiltinId = BIFF_DEFNAME_FILTERDATABASE;
424 }
425
426 // get sheet index for sheet-local names in BIFF5-BIFF8
427 switch( getBiff() )
428 {
429 case BIFF2:
430 case BIFF3:
431 case BIFF4:
432 // BIFF2-BIFF4: all defined names are sheet-local
433 mnCalcSheet = nCalcSheet;
434 break;
435 case BIFF5:
436 // #i44019# nTabId may be invalid, resolve nRefId to sheet index
437 if( nRefId != BIFF_DEFNAME_GLOBAL )
438 if( const ExternalLink* pExtLink = getExternalLinks().getExternalLink( nRefId ).get() )
439 if( pExtLink->getLinkType() == LINKTYPE_INTERNAL )
440 mnCalcSheet = pExtLink->getCalcSheetIndex();
441 break;
442 case BIFF8:
443 // convert one-based worksheet index to zero-based Calc sheet index
444 OSL_ENSURE( nTabId >= 0, "DefinedName::importDefinedName - invalid local sheet index" );
445 if( nTabId != BIFF_DEFNAME_GLOBAL )
446 mnCalcSheet = getWorksheets().getCalcSheetIndex( nTabId - 1 );
447 break;
448 case BIFF_UNKNOWN:
449 break;
450 }
451
452 if( (getBiff() <= BIFF4) && maModel.mbHidden && (maModel.maName.getLength() > 1) && (maModel.maName[ 0 ] == '\x01') )
453 {
454 /* Read the token array of special internal names containing addresses
455 for BIFF3-BIFF4 3D references immediately. It is expected that
456 these names contain a simple cell reference or range reference.
457 Other regular defined names and external names rely on existence of
458 this reference. */
459 ApiTokenSequence aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
460 extractReference( aTokens );
461 }
462 else
463 {
464 /* Store record position of other defined names to be able to import
465 token array later. This is needed to correctly resolve references
466 to names that are stored later in the defined names list following
467 this name. */
468 mxBiffStrm.reset( new BiffInputStreamPos( rStrm ) );
469 }
470 }
471
createNameObject()472 void DefinedName::createNameObject()
473 {
474 // do not create names for (macro) functions or VBA procedures
475 // #163146# do not ignore hidden names (may be regular names created by VBA scripts)
476 if( /*maModel.mbHidden ||*/ maModel.mbFunction || maModel.mbVBName )
477 return;
478
479 // skip BIFF names without stream position (e.g. BIFF3-BIFF4 internal 3D references)
480 if( (getFilterType() == FILTER_BIFF) && !mxBiffStrm.get() )
481 return;
482
483 // convert original name to final Calc name (TODO: filter invalid characters from model name)
484 maCalcName = isBuiltinName() ? lclGetPrefixedName( mcBuiltinId ) : maModel.maName;
485
486 // #163146# do not rename sheet-local names by default, this breaks VBA scripts
487 #if 0
488 // append sheet index for local names in multi-sheet documents
489 if( isWorkbookFile() && !isGlobalName() )
490 maCalcName = OUStringBuffer( maCalcName ).append( sal_Unicode( '_' ) ).
491 append( static_cast< sal_Int32 >( mnCalcSheet + 1 ) ).makeStringAndClear();
492 #endif
493
494 // special flags for this name
495 sal_Int32 nNameFlags = 0;
496 using namespace ::com::sun::star::sheet::NamedRangeFlag;
497 if( !isGlobalName() ) switch( mcBuiltinId )
498 {
499 case BIFF_DEFNAME_CRITERIA: nNameFlags = FILTER_CRITERIA; break;
500 case BIFF_DEFNAME_PRINTAREA: nNameFlags = PRINT_AREA; break;
501 case BIFF_DEFNAME_PRINTTITLES: nNameFlags = COLUMN_HEADER | ROW_HEADER; break;
502 }
503
504 // create the name and insert it into the document, maCalcName will be changed to the resulting name
505 mxNamedRange = createNamedRangeObject( maCalcName, maModel.mnSheet, nNameFlags );
506 // index of this defined name used in formula token arrays
507 PropertySet aPropSet( mxNamedRange );
508 aPropSet.getProperty( mnTokenIndex, PROP_TokenIndex );
509 }
510
convertFormula()511 void DefinedName::convertFormula()
512 {
513 Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
514 if( !xTokens.is() )
515 return;
516
517 // convert and set formula of the defined name
518 ApiTokenSequence aTokens;
519 switch( getFilterType() )
520 {
521 case FILTER_OOXML:
522 {
523 if( mxFormula.get() )
524 {
525 SequenceInputStream aStrm( *mxFormula );
526 aTokens = importBiff12Formula( mnCalcSheet, aStrm );
527 }
528 else
529 aTokens = importOoxFormula( mnCalcSheet );
530 }
531 break;
532 case FILTER_BIFF:
533 {
534 OSL_ENSURE( mxBiffStrm.get(), "DefinedName::convertFormula - missing BIFF stream" );
535 if( mxBiffStrm.get() )
536 {
537 BiffInputStream& rStrm = mxBiffStrm->getStream();
538 BiffInputStreamPosGuard aStrmGuard( rStrm );
539 if( mxBiffStrm->restorePosition() )
540 aTokens = importBiffFormula( mnCalcSheet, rStrm, &mnFmlaSize );
541 }
542 }
543 break;
544 case FILTER_UNKNOWN:
545 break;
546 }
547 xTokens->setTokens( aTokens );
548
549 // set built-in names (print ranges, repeated titles, filter ranges)
550 if( !isGlobalName() ) switch( mcBuiltinId )
551 {
552 case BIFF_DEFNAME_PRINTAREA:
553 {
554 Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
555 ApiCellRangeList aPrintRanges;
556 getFormulaParser().extractCellRangeList( aPrintRanges, xTokens->getTokens(), false, mnCalcSheet );
557 if( xPrintAreas.is() && !aPrintRanges.empty() )
558 xPrintAreas->setPrintAreas( ContainerHelper::vectorToSequence( aPrintRanges ) );
559 }
560 break;
561 case BIFF_DEFNAME_PRINTTITLES:
562 {
563 Reference< XPrintAreas > xPrintAreas( getSheetFromDoc( mnCalcSheet ), UNO_QUERY );
564 ApiCellRangeList aTitleRanges;
565 getFormulaParser().extractCellRangeList( aTitleRanges, xTokens->getTokens(), false, mnCalcSheet );
566 if( xPrintAreas.is() && !aTitleRanges.empty() )
567 {
568 bool bHasRowTitles = false;
569 bool bHasColTitles = false;
570 const CellAddress& rMaxPos = getAddressConverter().getMaxAddress();
571 for( ApiCellRangeList::const_iterator aIt = aTitleRanges.begin(), aEnd = aTitleRanges.end(); (aIt != aEnd) && (!bHasRowTitles || !bHasColTitles); ++aIt )
572 {
573 bool bFullRow = (aIt->StartColumn == 0) && (aIt->EndColumn >= rMaxPos.Column);
574 bool bFullCol = (aIt->StartRow == 0) && (aIt->EndRow >= rMaxPos.Row);
575 if( !bHasRowTitles && bFullRow && !bFullCol )
576 {
577 xPrintAreas->setTitleRows( *aIt );
578 xPrintAreas->setPrintTitleRows( sal_True );
579 bHasRowTitles = true;
580 }
581 else if( !bHasColTitles && bFullCol && !bFullRow )
582 {
583 xPrintAreas->setTitleColumns( *aIt );
584 xPrintAreas->setPrintTitleColumns( sal_True );
585 bHasColTitles = true;
586 }
587 }
588 }
589 }
590 break;
591 }
592 }
593
getAbsoluteRange(CellRangeAddress & orRange) const594 bool DefinedName::getAbsoluteRange( CellRangeAddress& orRange ) const
595 {
596 /* ScNamedRangeObj::XCellRangeReferrer::getReferredCells is buggy with
597 relative references, so we extract an absolute reference by hand. */
598 Reference< XFormulaTokens > xTokens( mxNamedRange, UNO_QUERY );
599 return xTokens.is() && getFormulaParser().extractCellRange( orRange, xTokens->getTokens(), false );
600 }
601
602 // ============================================================================
603
DefinedNamesBuffer(const WorkbookHelper & rHelper)604 DefinedNamesBuffer::DefinedNamesBuffer( const WorkbookHelper& rHelper ) :
605 WorkbookHelper( rHelper ),
606 mnCalcSheet( -1 )
607 {
608 }
609
setLocalCalcSheet(sal_Int16 nCalcSheet)610 void DefinedNamesBuffer::setLocalCalcSheet( sal_Int16 nCalcSheet )
611 {
612 OSL_ENSURE( (getFilterType() == FILTER_BIFF) && (getBiff() <= BIFF4),
613 "DefinedNamesBuffer::setLocalCalcSheet - invalid call" );
614 mnCalcSheet = nCalcSheet;
615 }
616
importDefinedName(const AttributeList & rAttribs)617 DefinedNameRef DefinedNamesBuffer::importDefinedName( const AttributeList& rAttribs )
618 {
619 DefinedNameRef xDefName = createDefinedName();
620 xDefName->importDefinedName( rAttribs );
621 return xDefName;
622 }
623
importDefinedName(SequenceInputStream & rStrm)624 void DefinedNamesBuffer::importDefinedName( SequenceInputStream& rStrm )
625 {
626 createDefinedName()->importDefinedName( rStrm );
627 }
628
importDefinedName(BiffInputStream & rStrm)629 void DefinedNamesBuffer::importDefinedName( BiffInputStream& rStrm )
630 {
631 createDefinedName()->importDefinedName( rStrm, mnCalcSheet );
632 }
633
finalizeImport()634 void DefinedNamesBuffer::finalizeImport()
635 {
636 // first insert all names without formula definition into the document, and insert them into the maps
637 for( DefNameVector::iterator aIt = maDefNames.begin(), aEnd = maDefNames.end(); aIt != aEnd; ++aIt )
638 {
639 DefinedNameRef xDefName = *aIt;
640 xDefName->createNameObject();
641 // map by sheet index and original model name
642 maModelNameMap[ SheetNameKey( xDefName->getLocalCalcSheet(), xDefName->getUpcaseModelName() ) ] = xDefName;
643 // map by sheet index and built-in identifier
644 if( !xDefName->isGlobalName() && xDefName->isBuiltinName() )
645 maBuiltinMap[ BuiltinKey( xDefName->getLocalCalcSheet(), xDefName->getBuiltinId() ) ] = xDefName;
646 // map by API formula token identifier
647 sal_Int32 nTokenIndex = xDefName->getTokenIndex();
648 if( nTokenIndex >= 0 )
649 maTokenIdMap[ nTokenIndex ] = xDefName;
650 }
651
652 /* Now convert all name formulas, so that the formula parser can find all
653 names in case of circular dependencies. */
654 maDefNames.forEachMem( &DefinedName::convertFormula );
655 }
656
getByIndex(sal_Int32 nIndex) const657 DefinedNameRef DefinedNamesBuffer::getByIndex( sal_Int32 nIndex ) const
658 {
659 return maDefNames.get( nIndex );
660 }
661
getByTokenIndex(sal_Int32 nIndex) const662 DefinedNameRef DefinedNamesBuffer::getByTokenIndex( sal_Int32 nIndex ) const
663 {
664 return maTokenIdMap.get( nIndex );
665 }
666
getByModelName(const OUString & rModelName,sal_Int16 nCalcSheet) const667 DefinedNameRef DefinedNamesBuffer::getByModelName( const OUString& rModelName, sal_Int16 nCalcSheet ) const
668 {
669 OUString aUpcaseName = lclGetUpcaseModelName( rModelName );
670 DefinedNameRef xDefName = maModelNameMap.get( SheetNameKey( nCalcSheet, aUpcaseName ) );
671 // lookup global name, if no local name exists
672 if( !xDefName && (nCalcSheet >= 0) )
673 xDefName = maModelNameMap.get( SheetNameKey( -1, aUpcaseName ) );
674 return xDefName;
675 }
676
getByBuiltinId(sal_Unicode cBuiltinId,sal_Int16 nCalcSheet) const677 DefinedNameRef DefinedNamesBuffer::getByBuiltinId( sal_Unicode cBuiltinId, sal_Int16 nCalcSheet ) const
678 {
679 return maBuiltinMap.get( BuiltinKey( nCalcSheet, cBuiltinId ) );
680 }
681
createDefinedName()682 DefinedNameRef DefinedNamesBuffer::createDefinedName()
683 {
684 DefinedNameRef xDefName( new DefinedName( *this ) );
685 maDefNames.push_back( xDefName );
686 return xDefName;
687 }
688
689 // ============================================================================
690
691 } // namespace xls
692 } // namespace oox
693