1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
22 #include <rangenam.hxx>
23 #include <xistream.hxx>
24 #include <excform.hxx>
25 #include <excimp8.hxx>
26 #include <scextopt.hxx>
27 #include <document.hxx>
29 // *** Implementation ***
31 XclImpName::TokenStrmData::TokenStrmData( XclImpStream
& rStrm
) :
32 mrStrm(rStrm
), mnStrmPos(0), mnStrmSize(0) {}
34 XclImpName::XclImpName( XclImpStream
& rStrm
, sal_uInt16 nXclNameIdx
) :
35 XclImpRoot( rStrm
.GetRoot() ),
38 meNameType( ScRangeData::Type::Name
),
39 mnXclTab( EXC_NAME_GLOBAL
),
40 mnNameIndex( nXclNameIdx
),
44 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
46 // 1) *** read data from stream *** ---------------------------------------
48 sal_uInt16 nFlags
= 0, nFmlaSize
= 0, nExtSheet
= EXC_NAME_GLOBAL
;
49 sal_uInt8 nNameLen
= 0;
50 sal_Unicode
cBuiltIn(EXC_BUILTIN_UNKNOWN
); /// Excel built-in name index.
56 sal_uInt8 nFlagsBiff2
;
57 nFlagsBiff2
= rStrm
.ReaduInt8();
59 rStrm
.Ignore( 1 ); //nShortCut
60 nNameLen
= rStrm
.ReaduInt8();
61 nFmlaSize
= rStrm
.ReaduInt8();
62 ::set_flag( nFlags
, EXC_NAME_FUNC
, ::get_flag( nFlagsBiff2
, EXC_NAME2_FUNC
) );
69 nFlags
= rStrm
.ReaduInt16();
70 rStrm
.Ignore( 1 ); //nShortCut
71 nNameLen
= rStrm
.ReaduInt8();
72 nFmlaSize
= rStrm
.ReaduInt16();
79 nFlags
= rStrm
.ReaduInt16();
80 rStrm
.Ignore( 1 ); //nShortCut
81 nNameLen
= rStrm
.ReaduInt8();
82 nFmlaSize
= rStrm
.ReaduInt16();
83 nExtSheet
= rStrm
.ReaduInt16();
84 mnXclTab
= rStrm
.ReaduInt16();
89 default: DBG_ERROR_BIFF();
92 if( GetBiff() <= EXC_BIFF5
)
93 maXclName
= rStrm
.ReadRawByteString( nNameLen
);
95 maXclName
= rStrm
.ReadUniString( nNameLen
);
97 // 2) *** convert sheet index and name *** --------------------------------
100 bool bFunction
= ::get_flag( nFlags
, EXC_NAME_FUNC
);
101 mbVBName
= ::get_flag( nFlags
, EXC_NAME_VB
);
102 mbMacro
= ::get_flag( nFlags
, EXC_NAME_PROC
);
104 // get built-in name, or convert characters invalid in Calc
105 bool bBuiltIn
= ::get_flag( nFlags
, EXC_NAME_BUILTIN
);
107 // special case for BIFF5 filter range - name appears as plain text without built-in flag
108 if( (GetBiff() == EXC_BIFF5
) && (maXclName
== XclTools::GetXclBuiltInDefName(EXC_BUILTIN_FILTERDATABASE
)) )
111 maXclName
= OUStringChar(EXC_BUILTIN_FILTERDATABASE
);
114 // convert Excel name to Calc name
118 maScName
= maXclName
;
123 if( !maXclName
.isEmpty() )
124 cBuiltIn
= maXclName
[0];
125 if( cBuiltIn
== '?' ) // NUL character is imported as '?'
127 maScName
= XclTools::GetBuiltInDefName( cBuiltIn
);
132 maScName
= ScfTools::ConvertToScDefinedName( maXclName
);
135 // add index for local names
136 if( mnXclTab
!= EXC_NAME_GLOBAL
)
138 sal_uInt16 nUsedTab
= (GetBiff() == EXC_BIFF8
) ? mnXclTab
: nExtSheet
;
139 // TODO: may not work for BIFF5, handle skipped sheets (all BIFF)
140 mnScTab
= static_cast< SCTAB
>( nUsedTab
- 1 );
143 // 3) *** convert the name definition formula *** -------------------------
146 std::unique_ptr
<ScTokenArray
> pTokArr
;
148 if( ::get_flag( nFlags
, EXC_NAME_BIG
) )
150 // special, unsupported name
151 pTokArr
= rFmlaConv
.GetDummy();
155 SCTAB
const nLocalTab
= (mnXclTab
== EXC_NAME_GLOBAL
) ? SCTAB_MAX
: (mnXclTab
- 1);
157 // --- print ranges or title ranges ---
158 rStrm
.PushPosition();
161 case EXC_BUILTIN_PRINTAREA
:
162 if( rFmlaConv
.Convert( GetPrintAreaBuffer(), rStrm
, nFmlaSize
, nLocalTab
, FT_RangeName
) == ConvErr::OK
)
163 meNameType
|= ScRangeData::Type::PrintArea
;
165 case EXC_BUILTIN_PRINTTITLES
:
166 if( rFmlaConv
.Convert( GetTitleAreaBuffer(), rStrm
, nFmlaSize
, nLocalTab
, FT_RangeName
) == ConvErr::OK
)
167 meNameType
|= ScRangeData::Type::ColHeader
| ScRangeData::Type::RowHeader
;
172 // --- name formula ---
173 // JEG : double check this. It is clearly false for normal names
174 // but some of the builtins (sheettitle?) might be able to handle arrays
175 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize
, false, FT_RangeName
);
177 // --- auto or advanced filter ---
178 if ((GetBiff() == EXC_BIFF8
) && pTokArr
)
181 if (pTokArr
->IsReference(aRange
, ScAddress()))
185 case EXC_BUILTIN_FILTERDATABASE
:
186 GetFilterManager().Insert( &GetOldRoot(), aRange
);
188 case EXC_BUILTIN_CRITERIA
:
189 GetFilterManager().AddAdvancedRange( aRange
);
190 meNameType
|= ScRangeData::Type::Criteria
;
192 case EXC_BUILTIN_EXTRACT
:
193 if (pTokArr
->IsValidReference(aRange
, ScAddress()))
194 GetFilterManager().AddExtractPos( aRange
);
200 else if( nFmlaSize
> 0 )
202 // Regular defined name. We need to convert the tokens after all the
203 // names have been registered (for cross-referenced names).
204 mpTokensData
.reset(new TokenStrmData(rStrm
));
205 mpTokensData
->mnStrmPos
= rStrm
.GetSvStreamPos();
206 rStrm
.StorePosition(mpTokensData
->maStrmPos
);
207 mpTokensData
->mnStrmSize
= nFmlaSize
;
210 if (pTokArr
&& !bFunction
&& !mbVBName
)
211 InsertName(pTokArr
.get());
214 void XclImpName::ConvertTokens()
219 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
221 std::unique_ptr
<ScTokenArray
> pArray
;
223 XclImpStreamPos aOldPos
;
224 XclImpStream
& rStrm
= mpTokensData
->mrStrm
;
225 rStrm
.StorePosition(aOldPos
);
226 rStrm
.RestorePosition(mpTokensData
->maStrmPos
);
227 rFmlaConv
.Convert(pArray
, rStrm
, mpTokensData
->mnStrmSize
, true, FT_RangeName
);
228 rStrm
.RestorePosition(aOldPos
);
231 InsertName(pArray
.get());
233 mpTokensData
.reset();
236 void XclImpName::InsertName(const ScTokenArray
* pArray
)
238 // create the Calc name data
239 ScRangeData
* pData
= new ScRangeData(GetDoc(), maScName
, *pArray
, ScAddress(), meNameType
);
240 pData
->GuessPosition(); // calculate base position for relative refs
241 pData
->SetIndex( mnNameIndex
); // used as unique identifier in formulas
242 if (mnXclTab
== EXC_NAME_GLOBAL
)
244 if (!GetDoc().GetRangeName()->insert(pData
))
249 ScRangeName
* pLocalNames
= GetDoc().GetRangeName(mnScTab
);
252 if (!pLocalNames
->insert(pData
))
261 if (GetBiff() == EXC_BIFF8
&& pData
)
264 // discard deleted ranges ( for the moment at least )
265 if ( pData
->IsValidReference( aRange
) )
267 GetExtDocOptions().GetOrCreateTabSettings( mnXclTab
);
273 GetDoc().CheckLinkFormulaNeedingCheck( *pData
->GetCode());
274 mpScData
= pData
; // cache for later use
278 XclImpNameManager::XclImpNameManager( const XclImpRoot
& rRoot
) :
283 void XclImpNameManager::ReadName( XclImpStream
& rStrm
)
285 size_t nCount
= maNameList
.size();
286 if( nCount
< 0xFFFF )
287 maNameList
.push_back( std::make_unique
<XclImpName
>( rStrm
, static_cast< sal_uInt16
>( nCount
+ 1 ) ) );
290 const XclImpName
* XclImpNameManager::FindName( std::u16string_view rXclName
, SCTAB nScTab
) const
292 const XclImpName
* pGlobalName
= nullptr; // a found global name
293 const XclImpName
* pLocalName
= nullptr; // a found local name
294 // If a duplicate name is seen by ScRangeName::insert then the existing
295 // name is erased and the new one inserted, so in the case of duplicates
296 // the last one seen is valid and the others invalid. So do this lookup in
297 // reverse in order to return the XclImpName* that references the valid
298 // entry (see tdf#44831 for the insert behavior and 'forum-mso-en4-30276.xls'
299 // for an example of this problem)
300 for (auto itName
= maNameList
.rbegin(); itName
!= maNameList
.rend(); ++itName
)
302 const auto& rxName
= *itName
;
303 if( rxName
->GetXclName() == rXclName
)
305 if( rxName
->GetScTab() == nScTab
)
306 pLocalName
= rxName
.get();
307 else if( rxName
->IsGlobal() )
308 pGlobalName
= rxName
.get();
314 return pLocalName
? pLocalName
: pGlobalName
;
317 const XclImpName
* XclImpNameManager::GetName( sal_uInt16 nXclNameIdx
) const
319 OSL_ENSURE( nXclNameIdx
> 0, "XclImpNameManager::GetName - index must be >0" );
320 return ( nXclNameIdx
<= 0 || nXclNameIdx
> maNameList
.size() ) ? nullptr : maNameList
.at( nXclNameIdx
- 1 ).get();
323 void XclImpNameManager::ConvertAllTokens()
325 for (auto& rxName
: maNameList
)
326 rxName
->ConvertTokens();
329 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */