xref: /trunk/main/oox/source/xls/defnamesbuffer.cxx (revision dffa72de)
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