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