xref: /aoo42x/main/sc/source/core/tool/address.cxx (revision b3f79822)
1*b3f79822SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*b3f79822SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*b3f79822SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*b3f79822SAndrew Rist  * distributed with this work for additional information
6*b3f79822SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*b3f79822SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*b3f79822SAndrew Rist  * "License"); you may not use this file except in compliance
9*b3f79822SAndrew Rist  * with the License.  You may obtain a copy of the License at
10*b3f79822SAndrew Rist  *
11*b3f79822SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*b3f79822SAndrew Rist  *
13*b3f79822SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*b3f79822SAndrew Rist  * software distributed under the License is distributed on an
15*b3f79822SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*b3f79822SAndrew Rist  * KIND, either express or implied.  See the License for the
17*b3f79822SAndrew Rist  * specific language governing permissions and limitations
18*b3f79822SAndrew Rist  * under the License.
19*b3f79822SAndrew Rist  *
20*b3f79822SAndrew Rist  *************************************************************/
21*b3f79822SAndrew Rist 
22*b3f79822SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_sc.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include "address.hxx"
28cdf0e10cSrcweir #include "global.hxx"
29cdf0e10cSrcweir #include "compiler.hxx"
30cdf0e10cSrcweir #include "document.hxx"
31cdf0e10cSrcweir #include "externalrefmgr.hxx"
32cdf0e10cSrcweir 
33cdf0e10cSrcweir #include "globstr.hrc"
34cdf0e10cSrcweir #include <sal/alloca.h>
35cdf0e10cSrcweir 
36cdf0e10cSrcweir #include <com/sun/star/frame/XModel.hpp>
37cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp>
38cdf0e10cSrcweir #include <com/sun/star/sheet/ExternalLinkInfo.hpp>
39cdf0e10cSrcweir #include <com/sun/star/sheet/ExternalLinkType.hpp>
40cdf0e10cSrcweir #include <sfx2/objsh.hxx>
41cdf0e10cSrcweir #include <tools/urlobj.hxx>
42cdf0e10cSrcweir using namespace ::com::sun::star;
43cdf0e10cSrcweir 
44cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////
45cdf0e10cSrcweir const ScAddress::Details ScAddress::detailsOOOa1( formula::FormulaGrammar::CONV_OOO, 0, 0 );
46cdf0e10cSrcweir 
Details(const ScDocument * pDoc,const ScAddress & rAddr)47cdf0e10cSrcweir ScAddress::Details::Details ( const ScDocument* pDoc,
48cdf0e10cSrcweir                               const ScAddress & rAddr ) :
49cdf0e10cSrcweir     eConv( pDoc->GetAddressConvention() ),
50cdf0e10cSrcweir     nRow( rAddr.Row() ),
51cdf0e10cSrcweir     nCol( rAddr.Col() )
52cdf0e10cSrcweir {
53cdf0e10cSrcweir }
54cdf0e10cSrcweir 
55cdf0e10cSrcweir //UNUSED2009-05 void ScAddress::Details::SetPos ( const ScDocument* pDoc,
56cdf0e10cSrcweir //UNUSED2009-05                                   const ScAddress & rAddr )
57cdf0e10cSrcweir //UNUSED2009-05 {
58cdf0e10cSrcweir //UNUSED2009-05     nRow  = rAddr.Row();
59cdf0e10cSrcweir //UNUSED2009-05     nCol  = rAddr.Col();
60cdf0e10cSrcweir //UNUSED2009-05     eConv = pDoc->GetAddressConvention();
61cdf0e10cSrcweir //UNUSED2009-05 }
62cdf0e10cSrcweir 
63cdf0e10cSrcweir ////////////////////////////////////////////////////////////////////////////
64cdf0e10cSrcweir 
65cdf0e10cSrcweir #include <iostream>
66cdf0e10cSrcweir 
67cdf0e10cSrcweir /**
68cdf0e10cSrcweir  * Parse from the opening single quote to the closing single quote.  Inside
69cdf0e10cSrcweir  * the quotes, a single quote character is encoded by double single-quote
70cdf0e10cSrcweir  * characters.
71cdf0e10cSrcweir  *
72cdf0e10cSrcweir  * @param p pointer to the first character to begin parsing.
73cdf0e10cSrcweir  * @param rName (reference) parsed name within the quotes.  If the name is
74cdf0e10cSrcweir  *              empty, either the parsing failed or it's an empty quote.
75cdf0e10cSrcweir  *
76cdf0e10cSrcweir  * @return pointer to the character immediately after the closing single
77cdf0e10cSrcweir  *         quote.
78cdf0e10cSrcweir  */
lcl_ParseQuotedName(const sal_Unicode * p,String & rName)79cdf0e10cSrcweir static const sal_Unicode* lcl_ParseQuotedName( const sal_Unicode* p, String& rName )
80cdf0e10cSrcweir {
81cdf0e10cSrcweir     rName.Erase();
82cdf0e10cSrcweir     if (*p != '\'')
83cdf0e10cSrcweir         return p;
84cdf0e10cSrcweir 
85cdf0e10cSrcweir     const sal_Unicode* pStart = p;
86cdf0e10cSrcweir     sal_Unicode cPrev = 0;
87cdf0e10cSrcweir     for (++p; *p; ++p)
88cdf0e10cSrcweir     {
89cdf0e10cSrcweir         if (*p == '\'')
90cdf0e10cSrcweir         {
91cdf0e10cSrcweir             if (cPrev == '\'')
92cdf0e10cSrcweir             {
93cdf0e10cSrcweir                 // double single-quote equals one single quote.
94cdf0e10cSrcweir                 rName += *p;
95cdf0e10cSrcweir                 cPrev = 0;
96cdf0e10cSrcweir                 continue;
97cdf0e10cSrcweir             }
98cdf0e10cSrcweir         }
99cdf0e10cSrcweir         else if (cPrev == '\'')
100cdf0e10cSrcweir             // We are past the closing quote.  We're done!
101cdf0e10cSrcweir             return p;
102cdf0e10cSrcweir         else
103cdf0e10cSrcweir             rName += *p;
104cdf0e10cSrcweir         cPrev = *p;
105cdf0e10cSrcweir     }
106cdf0e10cSrcweir     rName.Erase();
107cdf0e10cSrcweir     return pStart;
108cdf0e10cSrcweir }
109cdf0e10cSrcweir 
110cdf0e10cSrcweir static long int
sal_Unicode_strtol(const sal_Unicode * p,const sal_Unicode ** pEnd)111cdf0e10cSrcweir sal_Unicode_strtol ( const sal_Unicode*  p,
112cdf0e10cSrcweir                      const sal_Unicode** pEnd )
113cdf0e10cSrcweir {
114cdf0e10cSrcweir     long int accum = 0, prev = 0;
115cdf0e10cSrcweir     bool is_neg = false;
116cdf0e10cSrcweir 
117cdf0e10cSrcweir     if( *p == '-' )
118cdf0e10cSrcweir     {
119cdf0e10cSrcweir         is_neg = true;
120cdf0e10cSrcweir         p++;
121cdf0e10cSrcweir     }
122cdf0e10cSrcweir     else if( *p == '+' )
123cdf0e10cSrcweir         p++;
124cdf0e10cSrcweir 
125cdf0e10cSrcweir     while (CharClass::isAsciiDigit( *p ))
126cdf0e10cSrcweir     {
127cdf0e10cSrcweir         accum = accum * 10 + *p - '0';
128cdf0e10cSrcweir         if( accum < prev )
129cdf0e10cSrcweir         {
130cdf0e10cSrcweir             *pEnd = NULL;
131cdf0e10cSrcweir             return 0;
132cdf0e10cSrcweir         }
133cdf0e10cSrcweir         prev = accum;
134cdf0e10cSrcweir         p++;
135cdf0e10cSrcweir     }
136cdf0e10cSrcweir 
137cdf0e10cSrcweir     *pEnd = p;
138cdf0e10cSrcweir     return is_neg ? -accum : accum;
139cdf0e10cSrcweir }
140cdf0e10cSrcweir 
lcl_eatWhiteSpace(const sal_Unicode * p)141cdf0e10cSrcweir const sal_Unicode* lcl_eatWhiteSpace( const sal_Unicode* p )
142cdf0e10cSrcweir {
143cdf0e10cSrcweir     if ( p )
144cdf0e10cSrcweir     {
145cdf0e10cSrcweir         while(  *p == ' ' )
146cdf0e10cSrcweir             ++p;
147cdf0e10cSrcweir     }
148cdf0e10cSrcweir     return p;
149cdf0e10cSrcweir }
150cdf0e10cSrcweir 
151cdf0e10cSrcweir /** Determines the number of sheets an external reference spans and sets
152cdf0e10cSrcweir     rRange.aEnd.nTab accordingly. If a sheet is not found, the corresponding
153cdf0e10cSrcweir     bits in rFlags are cleared. pExtInfo is filled if it wasn't already. If in
154cdf0e10cSrcweir     cached order rStartTabName comes after rEndTabName, pExtInfo->maTabName
155cdf0e10cSrcweir     is set to rEndTabName.
156cdf0e10cSrcweir     @returns <FALSE/> if pExtInfo is already filled and rExternDocName does not
157cdf0e10cSrcweir              result in the identical file ID. Else <TRUE/>.
158cdf0e10cSrcweir  */
lcl_ScRange_External_TabSpan(ScRange & rRange,sal_uInt16 & rFlags,ScAddress::ExternalInfo * pExtInfo,const String & rExternDocName,const String & rStartTabName,const String & rEndTabName,ScDocument * pDoc)159cdf0e10cSrcweir static bool lcl_ScRange_External_TabSpan(
160cdf0e10cSrcweir         ScRange & rRange,
161cdf0e10cSrcweir         sal_uInt16 & rFlags,
162cdf0e10cSrcweir         ScAddress::ExternalInfo* pExtInfo,
163cdf0e10cSrcweir         const String & rExternDocName,
164cdf0e10cSrcweir         const String & rStartTabName,
165cdf0e10cSrcweir         const String & rEndTabName,
166cdf0e10cSrcweir         ScDocument* pDoc )
167cdf0e10cSrcweir {
168cdf0e10cSrcweir     if (!rExternDocName.Len())
169cdf0e10cSrcweir         return !pExtInfo || !pExtInfo->mbExternal;
170cdf0e10cSrcweir 
171cdf0e10cSrcweir     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
172cdf0e10cSrcweir     if (pRefMgr->isOwnDocument( rExternDocName))
173cdf0e10cSrcweir         return !pExtInfo || !pExtInfo->mbExternal;
174cdf0e10cSrcweir 
175cdf0e10cSrcweir     sal_uInt16 nFileId = pRefMgr->getExternalFileId( rExternDocName);
176cdf0e10cSrcweir 
177cdf0e10cSrcweir     if (pExtInfo)
178cdf0e10cSrcweir     {
179cdf0e10cSrcweir         if (pExtInfo->mbExternal)
180cdf0e10cSrcweir         {
181cdf0e10cSrcweir             if (pExtInfo->mnFileId != nFileId)
182cdf0e10cSrcweir                 return false;
183cdf0e10cSrcweir         }
184cdf0e10cSrcweir         else
185cdf0e10cSrcweir         {
186cdf0e10cSrcweir             pExtInfo->mbExternal = true;
187cdf0e10cSrcweir             pExtInfo->maTabName = rStartTabName;
188cdf0e10cSrcweir             pExtInfo->mnFileId = nFileId;
189cdf0e10cSrcweir         }
190cdf0e10cSrcweir     }
191cdf0e10cSrcweir 
192cdf0e10cSrcweir     if (!rEndTabName.Len() || rStartTabName == rEndTabName)
193cdf0e10cSrcweir     {
194cdf0e10cSrcweir         rRange.aEnd.SetTab( rRange.aStart.Tab());
195cdf0e10cSrcweir         return true;
196cdf0e10cSrcweir     }
197cdf0e10cSrcweir 
198cdf0e10cSrcweir     SCsTAB nSpan = pRefMgr->getCachedTabSpan( nFileId, rStartTabName, rEndTabName);
199cdf0e10cSrcweir     if (nSpan == -1)
200cdf0e10cSrcweir         rFlags &= ~(SCA_VALID_TAB | SCA_VALID_TAB2);
201cdf0e10cSrcweir     else if (nSpan == 0)
202cdf0e10cSrcweir         rFlags &= ~SCA_VALID_TAB2;
203cdf0e10cSrcweir     else if (nSpan >= 1)
204cdf0e10cSrcweir         rRange.aEnd.SetTab( rRange.aStart.Tab() + nSpan - 1);
205cdf0e10cSrcweir     else // (nSpan < -1)
206cdf0e10cSrcweir     {
207cdf0e10cSrcweir         rRange.aEnd.SetTab( rRange.aStart.Tab() - nSpan - 1);
208cdf0e10cSrcweir         if (pExtInfo)
209cdf0e10cSrcweir             pExtInfo->maTabName = rEndTabName;
210cdf0e10cSrcweir     }
211cdf0e10cSrcweir     return true;
212cdf0e10cSrcweir }
213cdf0e10cSrcweir 
214cdf0e10cSrcweir /** Returns NULL if the string should be a sheet name, but is invalid.
215cdf0e10cSrcweir     Returns a pointer to the first character after the sheet name, if there was
216cdf0e10cSrcweir     any, else pointer to start.
217cdf0e10cSrcweir     @param pMsoxlQuoteStop
218cdf0e10cSrcweir         Starting _within_ a quoted name, but still may be 3D; quoted name stops
219cdf0e10cSrcweir         at pMsoxlQuoteStop
220cdf0e10cSrcweir  */
221cdf0e10cSrcweir static const sal_Unicode *
lcl_XL_ParseSheetRef(const sal_Unicode * start,String & rExternTabName,bool allow_3d,const sal_Unicode * pMsoxlQuoteStop)222cdf0e10cSrcweir lcl_XL_ParseSheetRef( const sal_Unicode* start,
223cdf0e10cSrcweir                       String& rExternTabName,
224cdf0e10cSrcweir                       bool allow_3d,
225cdf0e10cSrcweir                       const sal_Unicode* pMsoxlQuoteStop )
226cdf0e10cSrcweir {
227cdf0e10cSrcweir     String aTabName;
228cdf0e10cSrcweir     const sal_Unicode *p = start;
229cdf0e10cSrcweir 
230cdf0e10cSrcweir     // XL only seems to use single quotes for sheet names.
231cdf0e10cSrcweir     if (pMsoxlQuoteStop)
232cdf0e10cSrcweir     {
233cdf0e10cSrcweir         const sal_Unicode* pCurrentStart = p;
234cdf0e10cSrcweir         while (p < pMsoxlQuoteStop)
235cdf0e10cSrcweir         {
236cdf0e10cSrcweir             if (*p == '\'')
237cdf0e10cSrcweir             {
238cdf0e10cSrcweir                 // We pre-analyzed the quoting, no checks needed here.
239cdf0e10cSrcweir                 if (*++p == '\'')
240cdf0e10cSrcweir                 {
241cdf0e10cSrcweir                     aTabName.Append( pCurrentStart,
242cdf0e10cSrcweir                             sal::static_int_cast<xub_StrLen>( p - pCurrentStart));
243cdf0e10cSrcweir                     pCurrentStart = ++p;
244cdf0e10cSrcweir                 }
245cdf0e10cSrcweir             }
246cdf0e10cSrcweir             else if (*p == ':')
247cdf0e10cSrcweir             {
248cdf0e10cSrcweir                 break;  // while
249cdf0e10cSrcweir             }
250cdf0e10cSrcweir             else
251cdf0e10cSrcweir                 ++p;
252cdf0e10cSrcweir         }
253cdf0e10cSrcweir         if (pCurrentStart < p)
254cdf0e10cSrcweir             aTabName.Append( pCurrentStart, sal::static_int_cast<xub_StrLen>( p - pCurrentStart));
255cdf0e10cSrcweir         if (!aTabName.Len())
256cdf0e10cSrcweir             return NULL;
257cdf0e10cSrcweir         if (p == pMsoxlQuoteStop)
258cdf0e10cSrcweir             ++p;    // position on ! of ...'!...
259cdf0e10cSrcweir         if( *p != '!' && ( !allow_3d || *p != ':' ) )
260cdf0e10cSrcweir             return (!allow_3d && *p == ':') ? p : start;
261cdf0e10cSrcweir     }
262cdf0e10cSrcweir     else if( *p == '\'')
263cdf0e10cSrcweir     {
264cdf0e10cSrcweir         p = lcl_ParseQuotedName(p, aTabName);
265cdf0e10cSrcweir         if (!aTabName.Len())
266cdf0e10cSrcweir             return NULL;
267cdf0e10cSrcweir     }
268cdf0e10cSrcweir     else
269cdf0e10cSrcweir     {
270cdf0e10cSrcweir         bool only_digits = sal_True;
271cdf0e10cSrcweir 
272cdf0e10cSrcweir         /*
273cdf0e10cSrcweir          * Valid: Normal!a1
274cdf0e10cSrcweir          * Valid: x.y!a1
275cdf0e10cSrcweir          * Invalid: .y!a1
276cdf0e10cSrcweir          *
277cdf0e10cSrcweir          * Some names starting with digits are actually valid, but
278cdf0e10cSrcweir          * unparse quoted. Things are quite tricky: most sheet names
279cdf0e10cSrcweir          * starting with a digit are ok, but not those starting with
280cdf0e10cSrcweir          * "[0-9]*\." or "[0-9]+[eE]".
281cdf0e10cSrcweir          *
282cdf0e10cSrcweir          * Valid: 42!a1
283cdf0e10cSrcweir          * Valid: 4x!a1
284cdf0e10cSrcweir          * Invalid: 1.!a1
285cdf0e10cSrcweir          * Invalid: 1e!a1
286cdf0e10cSrcweir          */
287cdf0e10cSrcweir         while( 1 )
288cdf0e10cSrcweir         {
289cdf0e10cSrcweir             const sal_Unicode uc = *p;
290cdf0e10cSrcweir             if( CharClass::isAsciiAlpha( uc ) || uc == '_' )
291cdf0e10cSrcweir             {
292cdf0e10cSrcweir                 if( only_digits && p != start &&
293cdf0e10cSrcweir                    (uc == 'e' || uc == 'E' ) )
294cdf0e10cSrcweir                 {
295cdf0e10cSrcweir                     p = start;
296cdf0e10cSrcweir                     break;
297cdf0e10cSrcweir                 }
298cdf0e10cSrcweir                 only_digits = sal_False;
299cdf0e10cSrcweir                 p++;
300cdf0e10cSrcweir             }
301cdf0e10cSrcweir             else if( CharClass::isAsciiDigit( uc ))
302cdf0e10cSrcweir             {
303cdf0e10cSrcweir                 p++;
304cdf0e10cSrcweir             }
305cdf0e10cSrcweir             else if( uc == '.' )
306cdf0e10cSrcweir             {
307cdf0e10cSrcweir                 if( only_digits ) // Valid, except after only digits.
308cdf0e10cSrcweir                 {
309cdf0e10cSrcweir                     p = start;
310cdf0e10cSrcweir                     break;
311cdf0e10cSrcweir                 }
312cdf0e10cSrcweir                 p++;
313cdf0e10cSrcweir             }
314cdf0e10cSrcweir             else if (uc > 127)
315cdf0e10cSrcweir             {
316cdf0e10cSrcweir                 // non ASCII character is allowed.
317cdf0e10cSrcweir                 ++p;
318cdf0e10cSrcweir             }
319cdf0e10cSrcweir             else
320cdf0e10cSrcweir                 break;
321cdf0e10cSrcweir         }
322cdf0e10cSrcweir 
323cdf0e10cSrcweir         if( *p != '!' && ( !allow_3d || *p != ':' ) )
324cdf0e10cSrcweir             return (!allow_3d && *p == ':') ? p : start;
325cdf0e10cSrcweir 
326cdf0e10cSrcweir         aTabName.Append( start, sal::static_int_cast<xub_StrLen>( p - start ) );
327cdf0e10cSrcweir     }
328cdf0e10cSrcweir 
329cdf0e10cSrcweir     rExternTabName = aTabName;
330cdf0e10cSrcweir     return p;
331cdf0e10cSrcweir }
332cdf0e10cSrcweir 
333cdf0e10cSrcweir 
Parse_XL_Header(const sal_Unicode * p,const ScDocument * pDoc,String & rExternDocName,String & rStartTabName,String & rEndTabName,sal_uInt16 & nFlags,bool bOnlyAcceptSingle,const uno::Sequence<const sheet::ExternalLinkInfo> * pExternalLinks)334cdf0e10cSrcweir const sal_Unicode* ScRange::Parse_XL_Header(
335cdf0e10cSrcweir         const sal_Unicode* p,
336cdf0e10cSrcweir         const ScDocument* pDoc,
337cdf0e10cSrcweir         String& rExternDocName,
338cdf0e10cSrcweir         String& rStartTabName,
339cdf0e10cSrcweir         String& rEndTabName,
340cdf0e10cSrcweir         sal_uInt16& nFlags,
341cdf0e10cSrcweir         bool bOnlyAcceptSingle,
342cdf0e10cSrcweir         const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
343cdf0e10cSrcweir {
344cdf0e10cSrcweir     const sal_Unicode* startTabs, *start = p;
345cdf0e10cSrcweir     sal_uInt16 nSaveFlags = nFlags;
346cdf0e10cSrcweir 
347cdf0e10cSrcweir     // Is this an external reference ?
348cdf0e10cSrcweir     rStartTabName.Erase();
349cdf0e10cSrcweir     rEndTabName.Erase();
350cdf0e10cSrcweir     rExternDocName.Erase();
351cdf0e10cSrcweir     const sal_Unicode* pMsoxlQuoteStop = NULL;
352cdf0e10cSrcweir     if (*p == '[')
353cdf0e10cSrcweir     {
354cdf0e10cSrcweir         ++p;
355cdf0e10cSrcweir         // Only single quotes are correct, and a double single quote escapes a
356cdf0e10cSrcweir         // single quote text inside the quoted text.
357cdf0e10cSrcweir         if (*p == '\'')
358cdf0e10cSrcweir         {
359cdf0e10cSrcweir             p = lcl_ParseQuotedName(p, rExternDocName);
360cdf0e10cSrcweir             if (!*p || *p != ']' || !rExternDocName.Len())
361cdf0e10cSrcweir             {
362cdf0e10cSrcweir                 rExternDocName.Erase();
363cdf0e10cSrcweir                 return start;
364cdf0e10cSrcweir             }
365cdf0e10cSrcweir         }
366cdf0e10cSrcweir         else
367cdf0e10cSrcweir         {
368cdf0e10cSrcweir             // non-quoted file name.
369cdf0e10cSrcweir             p = ScGlobal::UnicodeStrChr( start+1, ']' );
370cdf0e10cSrcweir             if( p == NULL )
371cdf0e10cSrcweir                 return start;
372cdf0e10cSrcweir             rExternDocName.Append( start+1, sal::static_int_cast<xub_StrLen>( p-(start+1) ) );
373cdf0e10cSrcweir         }
374cdf0e10cSrcweir         ++p;
375cdf0e10cSrcweir 
376cdf0e10cSrcweir         if (pExternalLinks && pExternalLinks->hasElements())
377cdf0e10cSrcweir         {
378cdf0e10cSrcweir             // A numeric "document name" is an index into the sequence.
379cdf0e10cSrcweir             if (CharClass::isAsciiNumeric( rExternDocName))
380cdf0e10cSrcweir             {
381cdf0e10cSrcweir                 sal_Int32 i = rExternDocName.ToInt32();
382cdf0e10cSrcweir                 if (i < 0 || i >= pExternalLinks->getLength())
383cdf0e10cSrcweir                     return start;
384cdf0e10cSrcweir                 const sheet::ExternalLinkInfo & rInfo = (*pExternalLinks)[i];
385cdf0e10cSrcweir                 switch (rInfo.Type)
386cdf0e10cSrcweir                 {
387cdf0e10cSrcweir                     case sheet::ExternalLinkType::DOCUMENT :
388cdf0e10cSrcweir                         {
389cdf0e10cSrcweir                             rtl::OUString aStr;
390cdf0e10cSrcweir                             if (!(rInfo.Data >>= aStr))
391cdf0e10cSrcweir                             {
392cdf0e10cSrcweir                                 DBG_ERROR1( "ScRange::Parse_XL_Header: Data type mismatch for ExternalLinkInfo %d", i);
393cdf0e10cSrcweir                                 return NULL;
394cdf0e10cSrcweir                             }
395cdf0e10cSrcweir                             rExternDocName = aStr;
396cdf0e10cSrcweir                         }
397cdf0e10cSrcweir                         break;
398cdf0e10cSrcweir                     case sheet::ExternalLinkType::SELF :
399cdf0e10cSrcweir                         return start;   // ???
400cdf0e10cSrcweir                     case sheet::ExternalLinkType::SPECIAL :
401cdf0e10cSrcweir                         // silently return nothing (do not assert), caller has to handle this
402cdf0e10cSrcweir                         return NULL;
403cdf0e10cSrcweir                     default:
404cdf0e10cSrcweir                         DBG_ERROR2( "ScRange::Parse_XL_Header: unhandled ExternalLinkType %d for index %d",
405cdf0e10cSrcweir                                 rInfo.Type, i);
406cdf0e10cSrcweir                         return NULL;
407cdf0e10cSrcweir                 }
408cdf0e10cSrcweir             }
409cdf0e10cSrcweir         }
410cdf0e10cSrcweir         rExternDocName = ScGlobal::GetAbsDocName(rExternDocName, pDoc->GetDocumentShell());
411cdf0e10cSrcweir     }
412cdf0e10cSrcweir     else if (*p == '\'')
413cdf0e10cSrcweir     {
414cdf0e10cSrcweir         // Sickness in Excel's ODF msoxl namespace:
415cdf0e10cSrcweir         // 'E:\[EXTDATA8.XLS]Sheet1'!$A$7  or
416cdf0e10cSrcweir         // 'E:\[EXTDATA12B.XLSB]Sheet1:Sheet3'!$A$11
417cdf0e10cSrcweir         // But, 'Sheet1'!B3 would also be a valid!
418cdf0e10cSrcweir         // Excel does not allow [ and ] characters in sheet names though.
419cdf0e10cSrcweir         p = lcl_ParseQuotedName(p, rExternDocName);
420cdf0e10cSrcweir         if (!*p || *p != '!')
421cdf0e10cSrcweir         {
422cdf0e10cSrcweir             rExternDocName.Erase();
423cdf0e10cSrcweir             return start;
424cdf0e10cSrcweir         }
425cdf0e10cSrcweir         if (rExternDocName.Len())
426cdf0e10cSrcweir         {
427cdf0e10cSrcweir             xub_StrLen nOpen = rExternDocName.Search( '[');
428cdf0e10cSrcweir             if (nOpen == STRING_NOTFOUND)
429cdf0e10cSrcweir                 rExternDocName.Erase();
430cdf0e10cSrcweir             else
431cdf0e10cSrcweir             {
432cdf0e10cSrcweir                 xub_StrLen nClose = rExternDocName.Search( ']', nOpen+1);
433cdf0e10cSrcweir                 if (nClose == STRING_NOTFOUND)
434cdf0e10cSrcweir                     rExternDocName.Erase();
435cdf0e10cSrcweir                 else
436cdf0e10cSrcweir                 {
437cdf0e10cSrcweir                     rExternDocName.Erase( nClose);
438cdf0e10cSrcweir                     rExternDocName.Erase( nOpen, 1);
439cdf0e10cSrcweir                     pMsoxlQuoteStop = p - 1;    // the ' quote char
440cdf0e10cSrcweir                     // There may be embedded escaped quotes, just matching the
441cdf0e10cSrcweir                     // doc name's length may not work.
442cdf0e10cSrcweir                     for (p = start; *p != '['; ++p)
443cdf0e10cSrcweir                         ;
444cdf0e10cSrcweir                     for ( ; *p != ']'; ++p)
445cdf0e10cSrcweir                         ;
446cdf0e10cSrcweir                     ++p;
447cdf0e10cSrcweir                 }
448cdf0e10cSrcweir             }
449cdf0e10cSrcweir         }
450cdf0e10cSrcweir         if (!rExternDocName.Len())
451cdf0e10cSrcweir             p = start;
452cdf0e10cSrcweir     }
453cdf0e10cSrcweir 
454cdf0e10cSrcweir     startTabs = p;
455cdf0e10cSrcweir     p = lcl_XL_ParseSheetRef( p, rStartTabName, !bOnlyAcceptSingle, pMsoxlQuoteStop);
456cdf0e10cSrcweir     if( NULL == p )
457cdf0e10cSrcweir         return start;       // invalid tab
458cdf0e10cSrcweir     if (bOnlyAcceptSingle && *p == ':')
459cdf0e10cSrcweir         return NULL;        // 3D
460cdf0e10cSrcweir     if( p != startTabs )
461cdf0e10cSrcweir     {
462cdf0e10cSrcweir         nFlags |= SCA_VALID_TAB | SCA_TAB_3D | SCA_TAB_ABSOLUTE;
463cdf0e10cSrcweir         if( *p == ':' ) // 3d ref
464cdf0e10cSrcweir         {
465cdf0e10cSrcweir             p = lcl_XL_ParseSheetRef( p+1, rEndTabName, false, pMsoxlQuoteStop);
466cdf0e10cSrcweir             if( p == NULL )
467cdf0e10cSrcweir             {
468cdf0e10cSrcweir                 nFlags = nSaveFlags;
469cdf0e10cSrcweir                 return start; // invalid tab
470cdf0e10cSrcweir             }
471cdf0e10cSrcweir             nFlags |= SCA_VALID_TAB2 | SCA_TAB2_3D | SCA_TAB2_ABSOLUTE;
472cdf0e10cSrcweir         }
473cdf0e10cSrcweir         else
474cdf0e10cSrcweir         {
475cdf0e10cSrcweir             // If only one sheet is given, the full reference is still valid,
476cdf0e10cSrcweir             // only the second 3D flag is not set.
477cdf0e10cSrcweir             nFlags |= SCA_VALID_TAB2 | SCA_TAB2_ABSOLUTE;
478cdf0e10cSrcweir             aEnd.SetTab( aStart.Tab() );
479cdf0e10cSrcweir         }
480cdf0e10cSrcweir 
481cdf0e10cSrcweir         if( *p++ != '!' )
482cdf0e10cSrcweir         {
483cdf0e10cSrcweir             nFlags = nSaveFlags;
484cdf0e10cSrcweir             return start;   // syntax error
485cdf0e10cSrcweir         }
486cdf0e10cSrcweir         else
487cdf0e10cSrcweir             p = lcl_eatWhiteSpace( p );
488cdf0e10cSrcweir     }
489cdf0e10cSrcweir     else
490cdf0e10cSrcweir     {
491cdf0e10cSrcweir         nFlags |= SCA_VALID_TAB | SCA_VALID_TAB2;
492cdf0e10cSrcweir         // Use the current tab, it needs to be passed in. : aEnd.SetTab( .. );
493cdf0e10cSrcweir     }
494cdf0e10cSrcweir 
495cdf0e10cSrcweir     if (rExternDocName.Len())
496cdf0e10cSrcweir     {
497cdf0e10cSrcweir         ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
498cdf0e10cSrcweir         pRefMgr->convertToAbsName( rExternDocName);
499cdf0e10cSrcweir     }
500cdf0e10cSrcweir     else
501cdf0e10cSrcweir     {
502cdf0e10cSrcweir         // Internal reference.
503cdf0e10cSrcweir         if (!rStartTabName.Len())
504cdf0e10cSrcweir         {
505cdf0e10cSrcweir             nFlags = nSaveFlags;
506cdf0e10cSrcweir             return start;
507cdf0e10cSrcweir         }
508cdf0e10cSrcweir 
509cdf0e10cSrcweir         SCTAB nTab;
510cdf0e10cSrcweir         if (!pDoc->GetTable(rStartTabName, nTab))
511cdf0e10cSrcweir         {
512cdf0e10cSrcweir             // invalid table name.
513cdf0e10cSrcweir             nFlags &= ~SCA_VALID_TAB;
514cdf0e10cSrcweir             nTab = -1;
515cdf0e10cSrcweir         }
516cdf0e10cSrcweir 
517cdf0e10cSrcweir         aStart.SetTab(nTab);
518cdf0e10cSrcweir         aEnd.SetTab(nTab);
519cdf0e10cSrcweir 
520cdf0e10cSrcweir         if (rEndTabName.Len())
521cdf0e10cSrcweir         {
522cdf0e10cSrcweir             if (!pDoc->GetTable(rEndTabName, nTab))
523cdf0e10cSrcweir             {
524cdf0e10cSrcweir                 // invalid table name.
525cdf0e10cSrcweir                 nFlags &= ~SCA_VALID_TAB2;
526cdf0e10cSrcweir                 nTab = -1;
527cdf0e10cSrcweir             }
528cdf0e10cSrcweir 
529cdf0e10cSrcweir             aEnd.SetTab(nTab);
530cdf0e10cSrcweir         }
531cdf0e10cSrcweir     }
532cdf0e10cSrcweir     return p;
533cdf0e10cSrcweir }
534cdf0e10cSrcweir 
535cdf0e10cSrcweir 
536cdf0e10cSrcweir static const sal_Unicode*
lcl_r1c1_get_col(const sal_Unicode * p,const ScAddress::Details & rDetails,ScAddress * pAddr,sal_uInt16 * nFlags)537cdf0e10cSrcweir lcl_r1c1_get_col( const sal_Unicode* p,
538cdf0e10cSrcweir                   const ScAddress::Details& rDetails,
539cdf0e10cSrcweir                   ScAddress* pAddr, sal_uInt16* nFlags )
540cdf0e10cSrcweir {
541cdf0e10cSrcweir     const sal_Unicode *pEnd;
542cdf0e10cSrcweir     long int n;
543cdf0e10cSrcweir     bool isRelative;
544cdf0e10cSrcweir 
545cdf0e10cSrcweir     if( p[0] == '\0' )
546cdf0e10cSrcweir         return NULL;
547cdf0e10cSrcweir 
548cdf0e10cSrcweir     p++;
549cdf0e10cSrcweir     if( (isRelative = (*p == '[') ) != false )
550cdf0e10cSrcweir         p++;
551cdf0e10cSrcweir     n = sal_Unicode_strtol( p, &pEnd );
552cdf0e10cSrcweir     if( NULL == pEnd )
553cdf0e10cSrcweir         return NULL;
554cdf0e10cSrcweir 
555cdf0e10cSrcweir     if( p == pEnd ) // C is a relative ref with offset 0
556cdf0e10cSrcweir     {
557cdf0e10cSrcweir         if( isRelative )
558cdf0e10cSrcweir             return NULL;
559cdf0e10cSrcweir         n = rDetails.nCol;
560cdf0e10cSrcweir     }
561cdf0e10cSrcweir     else if( isRelative )
562cdf0e10cSrcweir     {
563cdf0e10cSrcweir         if( *pEnd != ']' )
564cdf0e10cSrcweir             return NULL;
565cdf0e10cSrcweir         n += rDetails.nCol;
566cdf0e10cSrcweir         pEnd++;
567cdf0e10cSrcweir     }
568cdf0e10cSrcweir     else
569cdf0e10cSrcweir     {
570cdf0e10cSrcweir         *nFlags |= SCA_COL_ABSOLUTE;
571cdf0e10cSrcweir         n--;
572cdf0e10cSrcweir     }
573cdf0e10cSrcweir 
574cdf0e10cSrcweir     if( n < 0 || n >= MAXCOLCOUNT )
575cdf0e10cSrcweir         return NULL;
576cdf0e10cSrcweir     pAddr->SetCol( static_cast<SCCOL>( n ) );
577cdf0e10cSrcweir     *nFlags |= SCA_VALID_COL;
578cdf0e10cSrcweir 
579cdf0e10cSrcweir     return pEnd;
580cdf0e10cSrcweir }
581cdf0e10cSrcweir static inline const sal_Unicode*
lcl_r1c1_get_row(const sal_Unicode * p,const ScAddress::Details & rDetails,ScAddress * pAddr,sal_uInt16 * nFlags)582cdf0e10cSrcweir lcl_r1c1_get_row( const sal_Unicode* p,
583cdf0e10cSrcweir                   const ScAddress::Details& rDetails,
584cdf0e10cSrcweir                   ScAddress* pAddr, sal_uInt16* nFlags )
585cdf0e10cSrcweir {
586cdf0e10cSrcweir     const sal_Unicode *pEnd;
587cdf0e10cSrcweir     long int n;
588cdf0e10cSrcweir     bool isRelative;
589cdf0e10cSrcweir 
590cdf0e10cSrcweir     if( p[0] == '\0' )
591cdf0e10cSrcweir         return NULL;
592cdf0e10cSrcweir 
593cdf0e10cSrcweir     p++;
594cdf0e10cSrcweir     if( (isRelative = (*p == '[') ) != false )
595cdf0e10cSrcweir         p++;
596cdf0e10cSrcweir     n = sal_Unicode_strtol( p, &pEnd );
597cdf0e10cSrcweir     if( NULL == pEnd )
598cdf0e10cSrcweir         return NULL;
599cdf0e10cSrcweir 
600cdf0e10cSrcweir     if( p == pEnd ) // R is a relative ref with offset 0
601cdf0e10cSrcweir     {
602cdf0e10cSrcweir         if( isRelative )
603cdf0e10cSrcweir             return NULL;
604cdf0e10cSrcweir         n = rDetails.nRow;
605cdf0e10cSrcweir     }
606cdf0e10cSrcweir     else if( isRelative )
607cdf0e10cSrcweir     {
608cdf0e10cSrcweir         if( *pEnd != ']' )
609cdf0e10cSrcweir             return NULL;
610cdf0e10cSrcweir         n += rDetails.nRow;
611cdf0e10cSrcweir         pEnd++;
612cdf0e10cSrcweir     }
613cdf0e10cSrcweir     else
614cdf0e10cSrcweir     {
615cdf0e10cSrcweir         *nFlags |= SCA_ROW_ABSOLUTE;
616cdf0e10cSrcweir         n--;
617cdf0e10cSrcweir     }
618cdf0e10cSrcweir 
619cdf0e10cSrcweir     if( n < 0 || n >= MAXROWCOUNT )
620cdf0e10cSrcweir         return NULL;
621cdf0e10cSrcweir     pAddr->SetRow( static_cast<SCROW>( n ) );
622cdf0e10cSrcweir     *nFlags |= SCA_VALID_ROW;
623cdf0e10cSrcweir 
624cdf0e10cSrcweir     return pEnd;
625cdf0e10cSrcweir }
626cdf0e10cSrcweir 
627cdf0e10cSrcweir static sal_uInt16
lcl_ScRange_Parse_XL_R1C1(ScRange & r,const sal_Unicode * p,ScDocument * pDoc,const ScAddress::Details & rDetails,bool bOnlyAcceptSingle,ScAddress::ExternalInfo * pExtInfo)628cdf0e10cSrcweir lcl_ScRange_Parse_XL_R1C1( ScRange& r,
629cdf0e10cSrcweir                            const sal_Unicode* p,
630cdf0e10cSrcweir                            ScDocument* pDoc,
631cdf0e10cSrcweir                            const ScAddress::Details& rDetails,
632cdf0e10cSrcweir                            bool bOnlyAcceptSingle,
633cdf0e10cSrcweir                            ScAddress::ExternalInfo* pExtInfo )
634cdf0e10cSrcweir {
635cdf0e10cSrcweir     const sal_Unicode* pTmp = NULL;
636cdf0e10cSrcweir     String aExternDocName, aStartTabName, aEndTabName;
637cdf0e10cSrcweir     sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB;
638cdf0e10cSrcweir     // Keep in mind that nFlags2 gets left-shifted by 4 bits before being merged.
639cdf0e10cSrcweir     sal_uInt16 nFlags2 = SCA_VALID_TAB;
640cdf0e10cSrcweir 
641cdf0e10cSrcweir #if 0
642cdf0e10cSrcweir     {
643cdf0e10cSrcweir         ByteString  aStr(p, RTL_TEXTENCODING_UTF8);
644cdf0e10cSrcweir         aStr.Append(static_cast< char >(0));
645cdf0e10cSrcweir         std::cerr << "parse::XL::R1C1 \'" << aStr.GetBuffer() << '\'' << std::endl;
646cdf0e10cSrcweir     }
647cdf0e10cSrcweir #endif
648cdf0e10cSrcweir     p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
649cdf0e10cSrcweir             aEndTabName, nFlags, bOnlyAcceptSingle, NULL );
650cdf0e10cSrcweir 
651cdf0e10cSrcweir     if (aExternDocName.Len() > 0)
652cdf0e10cSrcweir         lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
653cdf0e10cSrcweir                 aStartTabName, aEndTabName, pDoc);
654cdf0e10cSrcweir 
655cdf0e10cSrcweir     if( NULL == p )
656cdf0e10cSrcweir         return 0;
657cdf0e10cSrcweir 
658cdf0e10cSrcweir     if( *p == 'R' || *p == 'r' )
659cdf0e10cSrcweir     {
660cdf0e10cSrcweir         if( NULL == (p = lcl_r1c1_get_row( p, rDetails, &r.aStart, &nFlags )) )
661cdf0e10cSrcweir             goto failed;
662cdf0e10cSrcweir 
663cdf0e10cSrcweir         if( *p != 'C' && *p != 'c' )    // full row R#
664cdf0e10cSrcweir         {
665cdf0e10cSrcweir             if( p[0] != ':' || (p[1] != 'R' && p[1] != 'r' ) ||
666cdf0e10cSrcweir                 NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )))
667cdf0e10cSrcweir             {
668cdf0e10cSrcweir                 // Only the initial row number is given, or the second row
669cdf0e10cSrcweir                 // number is invalid. Fallback to just the initial R
670cdf0e10cSrcweir                 nFlags |= (nFlags << 4);
671cdf0e10cSrcweir                 r.aEnd.SetRow( r.aStart.Row() );
672cdf0e10cSrcweir             }
673cdf0e10cSrcweir             else
674cdf0e10cSrcweir             {
675cdf0e10cSrcweir                 // Full row range successfully parsed.
676cdf0e10cSrcweir                 nFlags |= (nFlags2 << 4);
677cdf0e10cSrcweir                 p = pTmp;
678cdf0e10cSrcweir             }
679cdf0e10cSrcweir 
680cdf0e10cSrcweir             if (p && p[0] != 0)
681cdf0e10cSrcweir             {
682cdf0e10cSrcweir                 // any trailing invalid character must invalidate the whole address.
683cdf0e10cSrcweir                 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
684cdf0e10cSrcweir                             SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
685cdf0e10cSrcweir                 return nFlags;
686cdf0e10cSrcweir             }
687cdf0e10cSrcweir 
688cdf0e10cSrcweir             nFlags |=
689cdf0e10cSrcweir                 SCA_VALID_COL | SCA_VALID_COL2 |
690cdf0e10cSrcweir                 SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE;
691cdf0e10cSrcweir             r.aStart.SetCol( 0 );
692cdf0e10cSrcweir             r.aEnd.SetCol( MAXCOL );
693cdf0e10cSrcweir 
694cdf0e10cSrcweir             return bOnlyAcceptSingle ? 0 : nFlags;
695cdf0e10cSrcweir         }
696cdf0e10cSrcweir         else if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
697cdf0e10cSrcweir             goto failed;
698cdf0e10cSrcweir 
699cdf0e10cSrcweir         if( p[0] != ':' ||
700cdf0e10cSrcweir             (p[1] != 'R' && p[1] != 'r') ||
701cdf0e10cSrcweir             NULL == (pTmp = lcl_r1c1_get_row( p+1, rDetails, &r.aEnd, &nFlags2 )) ||
702cdf0e10cSrcweir             (*pTmp != 'C' && *pTmp != 'c') ||
703cdf0e10cSrcweir             NULL == (pTmp = lcl_r1c1_get_col( pTmp, rDetails, &r.aEnd, &nFlags2 )))
704cdf0e10cSrcweir         {
705cdf0e10cSrcweir             // single cell reference
706cdf0e10cSrcweir 
707cdf0e10cSrcweir             if (p && p[0] != 0)
708cdf0e10cSrcweir             {
709cdf0e10cSrcweir                 // any trailing invalid character must invalidate the whole address.
710cdf0e10cSrcweir                 nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB);
711cdf0e10cSrcweir                 return nFlags;
712cdf0e10cSrcweir             }
713cdf0e10cSrcweir 
714cdf0e10cSrcweir             return bOnlyAcceptSingle ? nFlags : 0;
715cdf0e10cSrcweir         }
716cdf0e10cSrcweir         p = pTmp;
717cdf0e10cSrcweir 
718cdf0e10cSrcweir         // double reference
719cdf0e10cSrcweir 
720cdf0e10cSrcweir         if (p && p[0] != 0)
721cdf0e10cSrcweir         {
722cdf0e10cSrcweir             // any trailing invalid character must invalidate the whole range.
723cdf0e10cSrcweir             nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
724cdf0e10cSrcweir                         SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
725cdf0e10cSrcweir             return nFlags;
726cdf0e10cSrcweir         }
727cdf0e10cSrcweir 
728cdf0e10cSrcweir         nFlags |= (nFlags2 << 4);
729cdf0e10cSrcweir         return bOnlyAcceptSingle ? 0 : nFlags;
730cdf0e10cSrcweir     }
731cdf0e10cSrcweir     else if( *p == 'C' || *p == 'c' )   // full col C#
732cdf0e10cSrcweir     {
733cdf0e10cSrcweir         if( NULL == (p = lcl_r1c1_get_col( p, rDetails, &r.aStart, &nFlags )))
734cdf0e10cSrcweir             goto failed;
735cdf0e10cSrcweir 
736cdf0e10cSrcweir         if( p[0] != ':' || (p[1] != 'C' && p[1] != 'c') ||
737cdf0e10cSrcweir             NULL == (pTmp = lcl_r1c1_get_col( p+1, rDetails, &r.aEnd, &nFlags2 )))
738cdf0e10cSrcweir         {    // Fallback to just the initial C
739cdf0e10cSrcweir             nFlags |= (nFlags << 4);
740cdf0e10cSrcweir             r.aEnd.SetCol( r.aStart.Col() );
741cdf0e10cSrcweir         }
742cdf0e10cSrcweir         else
743cdf0e10cSrcweir         {
744cdf0e10cSrcweir             nFlags |= (nFlags2 << 4);
745cdf0e10cSrcweir             p = pTmp;
746cdf0e10cSrcweir         }
747cdf0e10cSrcweir 
748cdf0e10cSrcweir         if (p && p[0] != 0)
749cdf0e10cSrcweir         {
750cdf0e10cSrcweir             // any trailing invalid character must invalidate the whole address.
751cdf0e10cSrcweir             nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
752cdf0e10cSrcweir                         SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
753cdf0e10cSrcweir             return nFlags;
754cdf0e10cSrcweir         }
755cdf0e10cSrcweir 
756cdf0e10cSrcweir         nFlags |=
757cdf0e10cSrcweir             SCA_VALID_ROW | SCA_VALID_ROW2 |
758cdf0e10cSrcweir             SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE;
759cdf0e10cSrcweir         r.aStart.SetRow( 0 );
760cdf0e10cSrcweir         r.aEnd.SetRow( MAXROW );
761cdf0e10cSrcweir 
762cdf0e10cSrcweir         return bOnlyAcceptSingle ? 0 : nFlags;
763cdf0e10cSrcweir     }
764cdf0e10cSrcweir 
765cdf0e10cSrcweir failed :
766cdf0e10cSrcweir     return 0;
767cdf0e10cSrcweir }
768cdf0e10cSrcweir 
769cdf0e10cSrcweir static inline const sal_Unicode*
lcl_a1_get_col(const sal_Unicode * p,ScAddress * pAddr,sal_uInt16 * nFlags)770cdf0e10cSrcweir lcl_a1_get_col( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags )
771cdf0e10cSrcweir {
772cdf0e10cSrcweir     SCCOL nCol;
773cdf0e10cSrcweir 
774cdf0e10cSrcweir     if( *p == '$' )
775cdf0e10cSrcweir         *nFlags |= SCA_COL_ABSOLUTE, p++;
776cdf0e10cSrcweir 
777cdf0e10cSrcweir     if( !CharClass::isAsciiAlpha( *p ) )
778cdf0e10cSrcweir         return NULL;
779cdf0e10cSrcweir 
780cdf0e10cSrcweir     nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' );
781cdf0e10cSrcweir     while (nCol <= MAXCOL && CharClass::isAsciiAlpha(*p))
782cdf0e10cSrcweir         nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' );
783cdf0e10cSrcweir     if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) )
784cdf0e10cSrcweir         return NULL;
785cdf0e10cSrcweir 
786cdf0e10cSrcweir     *nFlags |= SCA_VALID_COL;
787cdf0e10cSrcweir     pAddr->SetCol( nCol );
788cdf0e10cSrcweir 
789cdf0e10cSrcweir     return p;
790cdf0e10cSrcweir }
791cdf0e10cSrcweir 
792cdf0e10cSrcweir static inline const sal_Unicode*
lcl_a1_get_row(const sal_Unicode * p,ScAddress * pAddr,sal_uInt16 * nFlags)793cdf0e10cSrcweir lcl_a1_get_row( const sal_Unicode* p, ScAddress* pAddr, sal_uInt16* nFlags )
794cdf0e10cSrcweir {
795cdf0e10cSrcweir     const sal_Unicode *pEnd;
796cdf0e10cSrcweir     long int n;
797cdf0e10cSrcweir 
798cdf0e10cSrcweir     if( *p == '$' )
799cdf0e10cSrcweir         *nFlags |= SCA_ROW_ABSOLUTE, p++;
800cdf0e10cSrcweir 
801cdf0e10cSrcweir     n = sal_Unicode_strtol( p, &pEnd ) - 1;
802cdf0e10cSrcweir     if( NULL == pEnd || p == pEnd || n < 0 || n > MAXROW )
803cdf0e10cSrcweir         return NULL;
804cdf0e10cSrcweir 
805cdf0e10cSrcweir     *nFlags |= SCA_VALID_ROW;
806cdf0e10cSrcweir     pAddr->SetRow( static_cast<SCROW>(n) );
807cdf0e10cSrcweir 
808cdf0e10cSrcweir     return pEnd;
809cdf0e10cSrcweir }
810cdf0e10cSrcweir 
811cdf0e10cSrcweir static sal_uInt16
lcl_ScRange_Parse_XL_A1(ScRange & r,const sal_Unicode * p,ScDocument * pDoc,bool bOnlyAcceptSingle,ScAddress::ExternalInfo * pExtInfo,const uno::Sequence<const sheet::ExternalLinkInfo> * pExternalLinks)812cdf0e10cSrcweir lcl_ScRange_Parse_XL_A1( ScRange& r,
813cdf0e10cSrcweir                          const sal_Unicode* p,
814cdf0e10cSrcweir                          ScDocument* pDoc,
815cdf0e10cSrcweir                          bool bOnlyAcceptSingle,
816cdf0e10cSrcweir                          ScAddress::ExternalInfo* pExtInfo,
817cdf0e10cSrcweir                          const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
818cdf0e10cSrcweir {
819cdf0e10cSrcweir     const sal_Unicode* tmp1, *tmp2;
820cdf0e10cSrcweir     String aExternDocName, aStartTabName, aEndTabName; // for external link table
821cdf0e10cSrcweir     sal_uInt16 nFlags = SCA_VALID | SCA_VALID_TAB, nFlags2 = SCA_VALID_TAB;
822cdf0e10cSrcweir 
823cdf0e10cSrcweir #if 0
824cdf0e10cSrcweir     {
825cdf0e10cSrcweir         ByteString  aStr(p, RTL_TEXTENCODING_UTF8);
826cdf0e10cSrcweir         aStr.Append(static_cast< char >(0));
827cdf0e10cSrcweir         std::cerr << "parse::XL::A1 \'" << aStr.GetBuffer() << '\'' << std::endl;
828cdf0e10cSrcweir     }
829cdf0e10cSrcweir #endif
830cdf0e10cSrcweir     p = r.Parse_XL_Header( p, pDoc, aExternDocName, aStartTabName,
831cdf0e10cSrcweir             aEndTabName, nFlags, bOnlyAcceptSingle, pExternalLinks );
832cdf0e10cSrcweir 
833cdf0e10cSrcweir     if (aExternDocName.Len() > 0)
834cdf0e10cSrcweir         lcl_ScRange_External_TabSpan( r, nFlags, pExtInfo, aExternDocName,
835cdf0e10cSrcweir                 aStartTabName, aEndTabName, pDoc);
836cdf0e10cSrcweir 
837cdf0e10cSrcweir     if( NULL == p )
838cdf0e10cSrcweir         return 0;
839cdf0e10cSrcweir 
840cdf0e10cSrcweir     tmp1 = lcl_a1_get_col( p, &r.aStart, &nFlags );
841cdf0e10cSrcweir     if( tmp1 == NULL )          // Is it a row only reference 3:5
842cdf0e10cSrcweir     {
843cdf0e10cSrcweir         if( bOnlyAcceptSingle ) // by definition full row refs are ranges
844cdf0e10cSrcweir             return 0;
845cdf0e10cSrcweir 
846cdf0e10cSrcweir         tmp1 = lcl_a1_get_row( p, &r.aStart, &nFlags );
847cdf0e10cSrcweir 
848cdf0e10cSrcweir         tmp1 = lcl_eatWhiteSpace( tmp1 );
849cdf0e10cSrcweir         if( !tmp1 || *tmp1++ != ':' ) // Even a singleton requires ':' (eg 2:2)
850cdf0e10cSrcweir             return 0;
851cdf0e10cSrcweir 
852cdf0e10cSrcweir         tmp1 = lcl_eatWhiteSpace( tmp1 );
853cdf0e10cSrcweir         tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
854cdf0e10cSrcweir         if( !tmp2 )
855cdf0e10cSrcweir             return 0;
856cdf0e10cSrcweir 
857cdf0e10cSrcweir         r.aStart.SetCol( 0 ); r.aEnd.SetCol( MAXCOL );
858cdf0e10cSrcweir         nFlags |=
859cdf0e10cSrcweir             SCA_VALID_COL | SCA_VALID_COL2 |
860cdf0e10cSrcweir             SCA_COL_ABSOLUTE | SCA_COL2_ABSOLUTE;
861cdf0e10cSrcweir         nFlags |= (nFlags2 << 4);
862cdf0e10cSrcweir         return nFlags;
863cdf0e10cSrcweir     }
864cdf0e10cSrcweir 
865cdf0e10cSrcweir     tmp2 = lcl_a1_get_row( tmp1, &r.aStart, &nFlags );
866cdf0e10cSrcweir     if( tmp2 == NULL )          // check for col only reference F:H
867cdf0e10cSrcweir     {
868cdf0e10cSrcweir         if( bOnlyAcceptSingle ) // by definition full col refs are ranges
869cdf0e10cSrcweir             return 0;
870cdf0e10cSrcweir 
871cdf0e10cSrcweir         tmp1 = lcl_eatWhiteSpace( tmp1 );
872cdf0e10cSrcweir         if( *tmp1++ != ':' )    // Even a singleton requires ':' (eg F:F)
873cdf0e10cSrcweir             return 0;
874cdf0e10cSrcweir 
875cdf0e10cSrcweir         tmp1 = lcl_eatWhiteSpace( tmp1 );
876cdf0e10cSrcweir         tmp2 = lcl_a1_get_col( tmp1, &r.aEnd, &nFlags2 );
877cdf0e10cSrcweir         if( !tmp2 )
878cdf0e10cSrcweir             return 0;
879cdf0e10cSrcweir 
880cdf0e10cSrcweir         r.aStart.SetRow( 0 ); r.aEnd.SetRow( MAXROW );
881cdf0e10cSrcweir         nFlags |=
882cdf0e10cSrcweir             SCA_VALID_ROW | SCA_VALID_ROW2 |
883cdf0e10cSrcweir             SCA_ROW_ABSOLUTE | SCA_ROW2_ABSOLUTE;
884cdf0e10cSrcweir         nFlags |= (nFlags2 << 4);
885cdf0e10cSrcweir         return nFlags;
886cdf0e10cSrcweir     }
887cdf0e10cSrcweir 
888cdf0e10cSrcweir     // prepare as if it's a singleton, in case we want to fall back */
889cdf0e10cSrcweir     r.aEnd.SetCol( r.aStart.Col() );
890cdf0e10cSrcweir     r.aEnd.SetRow( r.aStart.Row() );    // don't overwrite sheet number as parsed in Parse_XL_Header()
891cdf0e10cSrcweir 
892cdf0e10cSrcweir     if ( bOnlyAcceptSingle )
893cdf0e10cSrcweir     {
894cdf0e10cSrcweir         if ( *tmp2 == 0 )
895cdf0e10cSrcweir             return nFlags;
896cdf0e10cSrcweir         else
897cdf0e10cSrcweir         {
898cdf0e10cSrcweir             // any trailing invalid character must invalidate the address.
899cdf0e10cSrcweir             nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB);
900cdf0e10cSrcweir             return nFlags;
901cdf0e10cSrcweir         }
902cdf0e10cSrcweir     }
903cdf0e10cSrcweir 
904cdf0e10cSrcweir     tmp2 = lcl_eatWhiteSpace( tmp2 );
905cdf0e10cSrcweir     if( *tmp2 != ':' )
906cdf0e10cSrcweir     {
907cdf0e10cSrcweir         // Sheet1:Sheet2!C4 is a valid range, without a second sheet it is
908cdf0e10cSrcweir         // not. Any trailing invalid character invalidates the range.
909cdf0e10cSrcweir         if (*tmp2 == 0 && (nFlags & SCA_TAB2_3D))
910cdf0e10cSrcweir         {
911cdf0e10cSrcweir             if (nFlags & SCA_COL_ABSOLUTE)
912cdf0e10cSrcweir                 nFlags |= SCA_COL2_ABSOLUTE;
913cdf0e10cSrcweir             if (nFlags & SCA_ROW_ABSOLUTE)
914cdf0e10cSrcweir                 nFlags |= SCA_ROW2_ABSOLUTE;
915cdf0e10cSrcweir         }
916cdf0e10cSrcweir         else
917cdf0e10cSrcweir             nFlags &= ~(SCA_VALID |
918cdf0e10cSrcweir                     SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
919cdf0e10cSrcweir                     SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
920cdf0e10cSrcweir         return nFlags;
921cdf0e10cSrcweir     }
922cdf0e10cSrcweir 
923cdf0e10cSrcweir     p = tmp2;
924cdf0e10cSrcweir     p = lcl_eatWhiteSpace( p+1 );
925cdf0e10cSrcweir     tmp1 = lcl_a1_get_col( p, &r.aEnd, &nFlags2 );
926cdf0e10cSrcweir     if( !tmp1 ) // strange, but valid singleton
927cdf0e10cSrcweir         return nFlags;
928cdf0e10cSrcweir 
929cdf0e10cSrcweir     tmp2 = lcl_a1_get_row( tmp1, &r.aEnd, &nFlags2 );
930cdf0e10cSrcweir     if( !tmp2 ) // strange, but valid singleton
931cdf0e10cSrcweir         return nFlags;
932cdf0e10cSrcweir 
933cdf0e10cSrcweir     if ( *tmp2 != 0 )
934cdf0e10cSrcweir     {
935cdf0e10cSrcweir         // any trailing invalid character must invalidate the range.
936cdf0e10cSrcweir         nFlags &= ~(SCA_VALID | SCA_VALID_COL | SCA_VALID_ROW | SCA_VALID_TAB |
937cdf0e10cSrcweir                     SCA_VALID_COL2 | SCA_VALID_ROW2 | SCA_VALID_TAB2);
938cdf0e10cSrcweir         return nFlags;
939cdf0e10cSrcweir     }
940cdf0e10cSrcweir 
941cdf0e10cSrcweir     nFlags |= (nFlags2 << 4);
942cdf0e10cSrcweir     return nFlags;
943cdf0e10cSrcweir }
944cdf0e10cSrcweir 
945cdf0e10cSrcweir /**
946cdf0e10cSrcweir     @param pRange   pointer to range where rAddr effectively is *pRange->aEnd,
947cdf0e10cSrcweir                     used in conjunction with pExtInfo to determine the tab span
948cdf0e10cSrcweir                     of a 3D reference.
949cdf0e10cSrcweir  */
950cdf0e10cSrcweir static sal_uInt16
lcl_ScAddress_Parse_OOo(const sal_Unicode * p,ScDocument * pDoc,ScAddress & rAddr,ScAddress::ExternalInfo * pExtInfo=NULL,ScRange * pRange=NULL)951cdf0e10cSrcweir lcl_ScAddress_Parse_OOo( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
952cdf0e10cSrcweir                          ScAddress::ExternalInfo* pExtInfo = NULL, ScRange* pRange = NULL )
953cdf0e10cSrcweir {
954cdf0e10cSrcweir     sal_uInt16  nRes = 0;
955cdf0e10cSrcweir     String  aDocName;       // der pure Dokumentenname
956cdf0e10cSrcweir     String  aTab;
957cdf0e10cSrcweir     bool    bExtDoc = false;
958cdf0e10cSrcweir     bool    bExtDocInherited = false;
959cdf0e10cSrcweir     const ScAddress aCurPos(rAddr);
960cdf0e10cSrcweir 
961cdf0e10cSrcweir     // Lets see if this is a reference to something in an external file.  A
962cdf0e10cSrcweir     // document name is always quoted and has a trailing #.
963cdf0e10cSrcweir     if (*p == '\'')
964cdf0e10cSrcweir     {
965cdf0e10cSrcweir         const sal_Unicode* pStart = p;
966cdf0e10cSrcweir         p = lcl_ParseQuotedName(p, aDocName);
967cdf0e10cSrcweir         if (*p++ == SC_COMPILER_FILE_TAB_SEP)
968cdf0e10cSrcweir             bExtDoc = true;
969cdf0e10cSrcweir         else
970cdf0e10cSrcweir             // This is not a document name.  Perhaps a quoted relative table
971cdf0e10cSrcweir             // name.
972cdf0e10cSrcweir             p = pStart;
973cdf0e10cSrcweir     }
974cdf0e10cSrcweir     else if (pExtInfo && pExtInfo->mbExternal)
975cdf0e10cSrcweir     {
976cdf0e10cSrcweir         // This is an external reference.
977cdf0e10cSrcweir         bExtDoc = bExtDocInherited = true;
978cdf0e10cSrcweir     }
979cdf0e10cSrcweir 
980cdf0e10cSrcweir     SCCOL   nCol = 0;
981cdf0e10cSrcweir     SCROW   nRow = 0;
982cdf0e10cSrcweir     SCTAB   nTab = 0;
983cdf0e10cSrcweir     sal_uInt16  nBits = SCA_VALID_TAB;
984cdf0e10cSrcweir     const sal_Unicode* q;
985cdf0e10cSrcweir     if ( ScGlobal::FindUnquoted( p, '.') )
986cdf0e10cSrcweir     {
987cdf0e10cSrcweir         nRes |= SCA_TAB_3D;
988cdf0e10cSrcweir         if ( bExtDoc )
989cdf0e10cSrcweir             nRes |= SCA_TAB_ABSOLUTE;
990cdf0e10cSrcweir         if (*p == '$')
991cdf0e10cSrcweir             nRes |= SCA_TAB_ABSOLUTE, p++;
992cdf0e10cSrcweir 
993cdf0e10cSrcweir         if (*p == '\'')
994cdf0e10cSrcweir         {
995cdf0e10cSrcweir             // Tokens that start at ' can have anything in them until a final
996cdf0e10cSrcweir             // ' but '' marks an escaped '.  We've earlier guaranteed that a
997cdf0e10cSrcweir             // string containing '' will be surrounded by '.
998cdf0e10cSrcweir             p = lcl_ParseQuotedName(p, aTab);
999cdf0e10cSrcweir         }
1000cdf0e10cSrcweir         else
1001cdf0e10cSrcweir         {
1002cdf0e10cSrcweir             while (*p)
1003cdf0e10cSrcweir             {
1004cdf0e10cSrcweir                 if( *p == '.')
1005cdf0e10cSrcweir                     break;
1006cdf0e10cSrcweir 
1007cdf0e10cSrcweir                 if( *p == '\'' )
1008cdf0e10cSrcweir                 {
1009cdf0e10cSrcweir                     p++; break;
1010cdf0e10cSrcweir                 }
1011cdf0e10cSrcweir                 aTab += *p++;
1012cdf0e10cSrcweir             }
1013cdf0e10cSrcweir         }
1014cdf0e10cSrcweir         if( *p++ != '.' )
1015cdf0e10cSrcweir             nBits = 0;
1016cdf0e10cSrcweir 
1017cdf0e10cSrcweir         if (!bExtDoc && (!pDoc || !pDoc->GetTable( aTab, nTab )))
1018cdf0e10cSrcweir             nBits = 0;
1019cdf0e10cSrcweir     }
1020cdf0e10cSrcweir     else
1021cdf0e10cSrcweir     {
1022cdf0e10cSrcweir         if (bExtDoc && !bExtDocInherited)
1023cdf0e10cSrcweir             return nRes;        // After a document a sheet must follow.
1024cdf0e10cSrcweir         nTab = rAddr.Tab();
1025cdf0e10cSrcweir     }
1026cdf0e10cSrcweir     nRes |= nBits;
1027cdf0e10cSrcweir 
1028cdf0e10cSrcweir     q = p;
1029cdf0e10cSrcweir     if (*p)
1030cdf0e10cSrcweir     {
1031cdf0e10cSrcweir         nBits = SCA_VALID_COL;
1032cdf0e10cSrcweir         if (*p == '$')
1033cdf0e10cSrcweir             nBits |= SCA_COL_ABSOLUTE, p++;
1034cdf0e10cSrcweir 
1035cdf0e10cSrcweir         if (CharClass::isAsciiAlpha( *p ))
1036cdf0e10cSrcweir         {
1037cdf0e10cSrcweir             nCol = sal::static_int_cast<SCCOL>( toupper( char(*p++) ) - 'A' );
1038cdf0e10cSrcweir             while (nCol < MAXCOL && CharClass::isAsciiAlpha(*p))
1039cdf0e10cSrcweir                 nCol = sal::static_int_cast<SCCOL>( ((nCol + 1) * 26) + toupper( char(*p++) ) - 'A' );
1040cdf0e10cSrcweir         }
1041cdf0e10cSrcweir         else
1042cdf0e10cSrcweir             nBits = 0;
1043cdf0e10cSrcweir 
1044cdf0e10cSrcweir         if( nCol > MAXCOL || CharClass::isAsciiAlpha( *p ) )
1045cdf0e10cSrcweir             nBits = 0;
1046cdf0e10cSrcweir         nRes |= nBits;
1047cdf0e10cSrcweir         if( !nBits )
1048cdf0e10cSrcweir             p = q;
1049cdf0e10cSrcweir     }
1050cdf0e10cSrcweir 
1051cdf0e10cSrcweir     q = p;
1052cdf0e10cSrcweir     if (*p)
1053cdf0e10cSrcweir     {
1054cdf0e10cSrcweir         nBits = SCA_VALID_ROW;
1055cdf0e10cSrcweir         if (*p == '$')
1056cdf0e10cSrcweir             nBits |= SCA_ROW_ABSOLUTE, p++;
1057cdf0e10cSrcweir         if( !CharClass::isAsciiDigit( *p ) )
1058cdf0e10cSrcweir         {
1059cdf0e10cSrcweir             nBits = 0;
1060cdf0e10cSrcweir             nRow = SCROW(-1);
1061cdf0e10cSrcweir         }
1062cdf0e10cSrcweir         else
1063cdf0e10cSrcweir         {
1064cdf0e10cSrcweir             String aTmp( p );
1065cdf0e10cSrcweir             long n = aTmp.ToInt32() - 1;
1066cdf0e10cSrcweir             while (CharClass::isAsciiDigit( *p ))
1067cdf0e10cSrcweir                 p++;
1068cdf0e10cSrcweir             if( n < 0 || n > MAXROW )
1069cdf0e10cSrcweir                 nBits = 0;
1070cdf0e10cSrcweir             nRow = static_cast<SCROW>(n);
1071cdf0e10cSrcweir         }
1072cdf0e10cSrcweir         nRes |= nBits;
1073cdf0e10cSrcweir         if( !nBits )
1074cdf0e10cSrcweir             p = q;
1075cdf0e10cSrcweir     }
1076cdf0e10cSrcweir 
1077cdf0e10cSrcweir     rAddr.Set( nCol, nRow, nTab );
1078cdf0e10cSrcweir 
1079cdf0e10cSrcweir     if (!*p && bExtDoc)
1080cdf0e10cSrcweir     {
1081cdf0e10cSrcweir         if (!pDoc)
1082cdf0e10cSrcweir             nRes = 0;
1083cdf0e10cSrcweir         else
1084cdf0e10cSrcweir         {
1085cdf0e10cSrcweir             ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
1086cdf0e10cSrcweir 
1087cdf0e10cSrcweir             // Need document name if inherited.
1088cdf0e10cSrcweir             if (bExtDocInherited)
1089cdf0e10cSrcweir             {
1090cdf0e10cSrcweir                 const String* pFileName = pRefMgr->getExternalFileName( pExtInfo->mnFileId);
1091cdf0e10cSrcweir                 if (pFileName)
1092cdf0e10cSrcweir                     aDocName = *pFileName;
1093cdf0e10cSrcweir                 else
1094cdf0e10cSrcweir                     nRes = 0;
1095cdf0e10cSrcweir             }
1096cdf0e10cSrcweir             pRefMgr->convertToAbsName(aDocName);
1097cdf0e10cSrcweir 
1098cdf0e10cSrcweir             if ((!pExtInfo || !pExtInfo->mbExternal) && pRefMgr->isOwnDocument(aDocName))
1099cdf0e10cSrcweir             {
1100cdf0e10cSrcweir                 if (!pDoc->GetTable( aTab, nTab ))
1101cdf0e10cSrcweir                     nRes = 0;
1102cdf0e10cSrcweir                 else
1103cdf0e10cSrcweir                 {
1104cdf0e10cSrcweir                     rAddr.SetTab( nTab);
1105cdf0e10cSrcweir                     nRes |= SCA_VALID_TAB;
1106cdf0e10cSrcweir                 }
1107cdf0e10cSrcweir             }
1108cdf0e10cSrcweir             else
1109cdf0e10cSrcweir             {
1110cdf0e10cSrcweir                 if (!pExtInfo)
1111cdf0e10cSrcweir                     nRes = 0;
1112cdf0e10cSrcweir                 else
1113cdf0e10cSrcweir                 {
1114cdf0e10cSrcweir                     if (!pExtInfo->mbExternal)
1115cdf0e10cSrcweir                     {
1116cdf0e10cSrcweir                         sal_uInt16 nFileId = pRefMgr->getExternalFileId(aDocName);
1117cdf0e10cSrcweir 
1118cdf0e10cSrcweir                         pExtInfo->mbExternal = true;
1119cdf0e10cSrcweir                         pExtInfo->maTabName = aTab;
1120cdf0e10cSrcweir                         pExtInfo->mnFileId = nFileId;
1121cdf0e10cSrcweir 
1122cdf0e10cSrcweir                         if (pRefMgr->getSingleRefToken(nFileId, aTab,
1123cdf0e10cSrcweir                                     ScAddress(nCol, nRow, 0), NULL,
1124cdf0e10cSrcweir                                     &nTab).get())
1125cdf0e10cSrcweir                         {
1126cdf0e10cSrcweir                             rAddr.SetTab( nTab);
1127cdf0e10cSrcweir                             nRes |= SCA_VALID_TAB;
1128cdf0e10cSrcweir                         }
1129cdf0e10cSrcweir                         else
1130cdf0e10cSrcweir                             nRes = 0;
1131cdf0e10cSrcweir                     }
1132cdf0e10cSrcweir                     else
1133cdf0e10cSrcweir                     {
1134cdf0e10cSrcweir                         // This is a call for the second part of the reference,
1135cdf0e10cSrcweir                         // we must have the range to adapt tab span.
1136cdf0e10cSrcweir                         if (!pRange)
1137cdf0e10cSrcweir                             nRes = 0;
1138cdf0e10cSrcweir                         else
1139cdf0e10cSrcweir                         {
1140cdf0e10cSrcweir                             sal_uInt16 nFlags = nRes | SCA_VALID_TAB2;
1141cdf0e10cSrcweir                             if (!lcl_ScRange_External_TabSpan( *pRange, nFlags,
1142cdf0e10cSrcweir                                         pExtInfo, aDocName,
1143cdf0e10cSrcweir                                         pExtInfo->maTabName, aTab, pDoc))
1144cdf0e10cSrcweir                                 nRes &= ~SCA_VALID_TAB;
1145cdf0e10cSrcweir                             else
1146cdf0e10cSrcweir                             {
1147cdf0e10cSrcweir                                 if (nFlags & SCA_VALID_TAB2)
1148cdf0e10cSrcweir                                 {
1149cdf0e10cSrcweir                                     rAddr.SetTab( pRange->aEnd.Tab());
1150cdf0e10cSrcweir                                     nRes |= SCA_VALID_TAB;
1151cdf0e10cSrcweir                                 }
1152cdf0e10cSrcweir                                 else
1153cdf0e10cSrcweir                                     nRes &= ~SCA_VALID_TAB;
1154cdf0e10cSrcweir                             }
1155cdf0e10cSrcweir                         }
1156cdf0e10cSrcweir                     }
1157cdf0e10cSrcweir                 }
1158cdf0e10cSrcweir             }
1159cdf0e10cSrcweir         }
1160cdf0e10cSrcweir     }
1161cdf0e10cSrcweir 
1162cdf0e10cSrcweir     if ( !(nRes & SCA_VALID_ROW) && (nRes & SCA_VALID_COL)
1163cdf0e10cSrcweir             && !( (nRes & SCA_TAB_3D) && (nRes & SCA_VALID_TAB)) )
1164cdf0e10cSrcweir     {   // no Row, no Tab, but Col => DM (...), B (...) et al
1165cdf0e10cSrcweir         nRes = 0;
1166cdf0e10cSrcweir     }
1167cdf0e10cSrcweir     if( !*p )
1168cdf0e10cSrcweir     {
1169cdf0e10cSrcweir         sal_uInt16 nMask = nRes & ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB );
1170cdf0e10cSrcweir         if( nMask == ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB ) )
1171cdf0e10cSrcweir             nRes |= SCA_VALID;
1172cdf0e10cSrcweir     }
1173cdf0e10cSrcweir     else
1174cdf0e10cSrcweir         nRes = 0;
1175cdf0e10cSrcweir     return nRes;
1176cdf0e10cSrcweir }
1177cdf0e10cSrcweir 
1178cdf0e10cSrcweir static sal_uInt16
lcl_ScAddress_Parse(const sal_Unicode * p,ScDocument * pDoc,ScAddress & rAddr,const ScAddress::Details & rDetails,ScAddress::ExternalInfo * pExtInfo=NULL,const uno::Sequence<const sheet::ExternalLinkInfo> * pExternalLinks=NULL)1179cdf0e10cSrcweir lcl_ScAddress_Parse ( const sal_Unicode* p, ScDocument* pDoc, ScAddress& rAddr,
1180cdf0e10cSrcweir                       const ScAddress::Details& rDetails,
1181cdf0e10cSrcweir                       ScAddress::ExternalInfo* pExtInfo = NULL,
1182cdf0e10cSrcweir                       const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks = NULL )
1183cdf0e10cSrcweir {
1184cdf0e10cSrcweir     if( !*p )
1185cdf0e10cSrcweir         return 0;
1186cdf0e10cSrcweir 
1187cdf0e10cSrcweir     switch (rDetails.eConv)
1188cdf0e10cSrcweir     {
1189cdf0e10cSrcweir     default :
1190cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO:
1191cdf0e10cSrcweir         {
1192cdf0e10cSrcweir             return lcl_ScAddress_Parse_OOo( p, pDoc, rAddr, pExtInfo, NULL );
1193cdf0e10cSrcweir         }
1194cdf0e10cSrcweir 
1195cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1196cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1197cdf0e10cSrcweir         {
1198cdf0e10cSrcweir             ScRange r = rAddr;
1199cdf0e10cSrcweir             sal_uInt16 nFlags = lcl_ScRange_Parse_XL_A1( r, p, pDoc, true, pExtInfo,
1200cdf0e10cSrcweir                     (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) );
1201cdf0e10cSrcweir             rAddr = r.aStart;
1202cdf0e10cSrcweir             return nFlags;
1203cdf0e10cSrcweir         }
1204cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1205cdf0e10cSrcweir         {
1206cdf0e10cSrcweir             ScRange r = rAddr;
1207cdf0e10cSrcweir             sal_uInt16 nFlags = lcl_ScRange_Parse_XL_R1C1( r, p, pDoc, rDetails, true, pExtInfo );
1208cdf0e10cSrcweir             rAddr = r.aStart;
1209cdf0e10cSrcweir             return nFlags;
1210cdf0e10cSrcweir         }
1211cdf0e10cSrcweir     }
1212cdf0e10cSrcweir }
1213cdf0e10cSrcweir 
1214cdf0e10cSrcweir 
ConvertSingleRef(ScDocument * pDoc,const String & rRefString,SCTAB nDefTab,ScRefAddress & rRefAddress,const ScAddress::Details & rDetails,ScAddress::ExternalInfo * pExtInfo)1215cdf0e10cSrcweir bool ConvertSingleRef( ScDocument* pDoc, const String& rRefString,
1216cdf0e10cSrcweir                        SCTAB nDefTab, ScRefAddress& rRefAddress,
1217cdf0e10cSrcweir                        const ScAddress::Details& rDetails,
1218cdf0e10cSrcweir                        ScAddress::ExternalInfo* pExtInfo /* = NULL */ )
1219cdf0e10cSrcweir {
1220cdf0e10cSrcweir     bool bRet = false;
1221cdf0e10cSrcweir     if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND))
1222cdf0e10cSrcweir     {
1223cdf0e10cSrcweir         ScAddress aAddr( 0, 0, nDefTab );
1224cdf0e10cSrcweir         sal_uInt16 nRes = aAddr.Parse( rRefString, pDoc, rDetails, pExtInfo);
1225cdf0e10cSrcweir         if ( nRes & SCA_VALID )
1226cdf0e10cSrcweir         {
1227cdf0e10cSrcweir             rRefAddress.Set( aAddr,
1228cdf0e10cSrcweir                     ((nRes & SCA_COL_ABSOLUTE) == 0),
1229cdf0e10cSrcweir                     ((nRes & SCA_ROW_ABSOLUTE) == 0),
1230cdf0e10cSrcweir                     ((nRes & SCA_TAB_ABSOLUTE) == 0));
1231cdf0e10cSrcweir             bRet = true;
1232cdf0e10cSrcweir         }
1233cdf0e10cSrcweir     }
1234cdf0e10cSrcweir     return bRet;
1235cdf0e10cSrcweir }
1236cdf0e10cSrcweir 
1237cdf0e10cSrcweir 
ConvertDoubleRef(ScDocument * pDoc,const String & rRefString,SCTAB nDefTab,ScRefAddress & rStartRefAddress,ScRefAddress & rEndRefAddress,const ScAddress::Details & rDetails,ScAddress::ExternalInfo * pExtInfo)1238cdf0e10cSrcweir bool ConvertDoubleRef( ScDocument* pDoc, const String& rRefString, SCTAB nDefTab,
1239cdf0e10cSrcweir                        ScRefAddress& rStartRefAddress, ScRefAddress& rEndRefAddress,
1240cdf0e10cSrcweir                        const ScAddress::Details& rDetails,
1241cdf0e10cSrcweir                        ScAddress::ExternalInfo* pExtInfo /* = NULL */ )
1242cdf0e10cSrcweir {
1243cdf0e10cSrcweir     bool bRet = false;
1244cdf0e10cSrcweir     if (pExtInfo || (ScGlobal::FindUnquoted( rRefString, SC_COMPILER_FILE_TAB_SEP) == STRING_NOTFOUND))
1245cdf0e10cSrcweir     {
1246cdf0e10cSrcweir         ScRange aRange( ScAddress( 0, 0, nDefTab));
1247cdf0e10cSrcweir         sal_uInt16 nRes = aRange.Parse( rRefString, pDoc, rDetails, pExtInfo);
1248cdf0e10cSrcweir         if ( nRes & SCA_VALID )
1249cdf0e10cSrcweir         {
1250cdf0e10cSrcweir             rStartRefAddress.Set( aRange.aStart,
1251cdf0e10cSrcweir                     ((nRes & SCA_COL_ABSOLUTE) == 0),
1252cdf0e10cSrcweir                     ((nRes & SCA_ROW_ABSOLUTE) == 0),
1253cdf0e10cSrcweir                     ((nRes & SCA_TAB_ABSOLUTE) == 0));
1254cdf0e10cSrcweir             rEndRefAddress.Set( aRange.aEnd,
1255cdf0e10cSrcweir                     ((nRes & SCA_COL2_ABSOLUTE) == 0),
1256cdf0e10cSrcweir                     ((nRes & SCA_ROW2_ABSOLUTE) == 0),
1257cdf0e10cSrcweir                     ((nRes & SCA_TAB2_ABSOLUTE) == 0));
1258cdf0e10cSrcweir             bRet = true;
1259cdf0e10cSrcweir         }
1260cdf0e10cSrcweir     }
1261cdf0e10cSrcweir     return bRet;
1262cdf0e10cSrcweir }
1263cdf0e10cSrcweir 
1264cdf0e10cSrcweir 
Parse(const String & r,ScDocument * pDoc,const Details & rDetails,ExternalInfo * pExtInfo,const uno::Sequence<const sheet::ExternalLinkInfo> * pExternalLinks)1265cdf0e10cSrcweir sal_uInt16 ScAddress::Parse( const String& r, ScDocument* pDoc,
1266cdf0e10cSrcweir                          const Details& rDetails,
1267cdf0e10cSrcweir                          ExternalInfo* pExtInfo,
1268cdf0e10cSrcweir                          const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
1269cdf0e10cSrcweir {
1270cdf0e10cSrcweir     return lcl_ScAddress_Parse( r.GetBuffer(), pDoc, *this, rDetails, pExtInfo, pExternalLinks );
1271cdf0e10cSrcweir }
1272cdf0e10cSrcweir 
1273cdf0e10cSrcweir 
Intersects(const ScRange & r) const1274cdf0e10cSrcweir bool ScRange::Intersects( const ScRange& r ) const
1275cdf0e10cSrcweir {
1276cdf0e10cSrcweir     return !(
1277cdf0e10cSrcweir         Min( aEnd.Col(), r.aEnd.Col() ) < Max( aStart.Col(), r.aStart.Col() )
1278cdf0e10cSrcweir      || Min( aEnd.Row(), r.aEnd.Row() ) < Max( aStart.Row(), r.aStart.Row() )
1279cdf0e10cSrcweir      || Min( aEnd.Tab(), r.aEnd.Tab() ) < Max( aStart.Tab(), r.aStart.Tab() )
1280cdf0e10cSrcweir         );
1281cdf0e10cSrcweir }
1282cdf0e10cSrcweir 
1283cdf0e10cSrcweir 
Justify()1284cdf0e10cSrcweir void ScRange::Justify()
1285cdf0e10cSrcweir {
1286cdf0e10cSrcweir     SCCOL nTempCol;
1287cdf0e10cSrcweir     if ( aEnd.Col() < (nTempCol = aStart.Col()) )
1288cdf0e10cSrcweir     {
1289cdf0e10cSrcweir         aStart.SetCol(aEnd.Col()); aEnd.SetCol(nTempCol);
1290cdf0e10cSrcweir     }
1291cdf0e10cSrcweir     SCROW nTempRow;
1292cdf0e10cSrcweir     if ( aEnd.Row() < (nTempRow = aStart.Row()) )
1293cdf0e10cSrcweir     {
1294cdf0e10cSrcweir         aStart.SetRow(aEnd.Row()); aEnd.SetRow(nTempRow);
1295cdf0e10cSrcweir     }
1296cdf0e10cSrcweir     SCTAB nTempTab;
1297cdf0e10cSrcweir     if ( aEnd.Tab() < (nTempTab = aStart.Tab()) )
1298cdf0e10cSrcweir     {
1299cdf0e10cSrcweir         aStart.SetTab(aEnd.Tab()); aEnd.SetTab(nTempTab);
1300cdf0e10cSrcweir     }
1301cdf0e10cSrcweir }
1302cdf0e10cSrcweir 
ExtendTo(const ScRange & rRange)1303cdf0e10cSrcweir void ScRange::ExtendTo( const ScRange& rRange )
1304cdf0e10cSrcweir {
1305cdf0e10cSrcweir     DBG_ASSERT( rRange.IsValid(), "ScRange::ExtendTo - cannot extend to invalid range" );
1306cdf0e10cSrcweir     if( IsValid() )
1307cdf0e10cSrcweir     {
1308cdf0e10cSrcweir         aStart.SetCol( ::std::min( aStart.Col(), rRange.aStart.Col() ) );
1309cdf0e10cSrcweir         aStart.SetRow( ::std::min( aStart.Row(), rRange.aStart.Row() ) );
1310cdf0e10cSrcweir         aStart.SetTab( ::std::min( aStart.Tab(), rRange.aStart.Tab() ) );
1311cdf0e10cSrcweir         aEnd.SetCol(   ::std::max( aEnd.Col(),   rRange.aEnd.Col() ) );
1312cdf0e10cSrcweir         aEnd.SetRow(   ::std::max( aEnd.Row(),   rRange.aEnd.Row() ) );
1313cdf0e10cSrcweir         aEnd.SetTab(   ::std::max( aEnd.Tab(),   rRange.aEnd.Tab() ) );
1314cdf0e10cSrcweir     }
1315cdf0e10cSrcweir     else
1316cdf0e10cSrcweir         *this = rRange;
1317cdf0e10cSrcweir }
1318cdf0e10cSrcweir 
1319cdf0e10cSrcweir static sal_uInt16
lcl_ScRange_Parse_OOo(ScRange & aRange,const String & r,ScDocument * pDoc,ScAddress::ExternalInfo * pExtInfo=NULL)1320cdf0e10cSrcweir lcl_ScRange_Parse_OOo( ScRange &aRange, const String& r, ScDocument* pDoc, ScAddress::ExternalInfo* pExtInfo = NULL )
1321cdf0e10cSrcweir {
1322cdf0e10cSrcweir     sal_uInt16 nRes1 = 0, nRes2 = 0;
1323cdf0e10cSrcweir     xub_StrLen nPos = ScGlobal::FindUnquoted( r, ':');
1324cdf0e10cSrcweir     if (nPos != STRING_NOTFOUND)
1325cdf0e10cSrcweir     {
1326cdf0e10cSrcweir         String aTmp( r );
1327cdf0e10cSrcweir         sal_Unicode* p = aTmp.GetBufferAccess();
1328cdf0e10cSrcweir         p[ nPos ] = 0;
1329cdf0e10cSrcweir         if( (nRes1 = lcl_ScAddress_Parse_OOo( p, pDoc, aRange.aStart, pExtInfo, NULL ) ) != 0 )
1330cdf0e10cSrcweir         {
1331cdf0e10cSrcweir             aRange.aEnd = aRange.aStart;  // sheet must be initialized identical to first sheet
1332cdf0e10cSrcweir             if ( (nRes2 = lcl_ScAddress_Parse_OOo( p + nPos+ 1, pDoc, aRange.aEnd, pExtInfo, &aRange ) ) != 0 )
1333cdf0e10cSrcweir             {
1334cdf0e10cSrcweir                 // PutInOrder / Justify
1335cdf0e10cSrcweir                 sal_uInt16 nMask, nBits1, nBits2;
1336cdf0e10cSrcweir                 SCCOL nTempCol;
1337cdf0e10cSrcweir                 if ( aRange.aEnd.Col() < (nTempCol = aRange.aStart.Col()) )
1338cdf0e10cSrcweir                 {
1339cdf0e10cSrcweir                     aRange.aStart.SetCol(aRange.aEnd.Col()); aRange.aEnd.SetCol(nTempCol);
1340cdf0e10cSrcweir                     nMask = (SCA_VALID_COL | SCA_COL_ABSOLUTE);
1341cdf0e10cSrcweir                     nBits1 = nRes1 & nMask;
1342cdf0e10cSrcweir                     nBits2 = nRes2 & nMask;
1343cdf0e10cSrcweir                     nRes1 = (nRes1 & ~nMask) | nBits2;
1344cdf0e10cSrcweir                     nRes2 = (nRes2 & ~nMask) | nBits1;
1345cdf0e10cSrcweir                 }
1346cdf0e10cSrcweir                 SCROW nTempRow;
1347cdf0e10cSrcweir                 if ( aRange.aEnd.Row() < (nTempRow = aRange.aStart.Row()) )
1348cdf0e10cSrcweir                 {
1349cdf0e10cSrcweir                     aRange.aStart.SetRow(aRange.aEnd.Row()); aRange.aEnd.SetRow(nTempRow);
1350cdf0e10cSrcweir                     nMask = (SCA_VALID_ROW | SCA_ROW_ABSOLUTE);
1351cdf0e10cSrcweir                     nBits1 = nRes1 & nMask;
1352cdf0e10cSrcweir                     nBits2 = nRes2 & nMask;
1353cdf0e10cSrcweir                     nRes1 = (nRes1 & ~nMask) | nBits2;
1354cdf0e10cSrcweir                     nRes2 = (nRes2 & ~nMask) | nBits1;
1355cdf0e10cSrcweir                 }
1356cdf0e10cSrcweir                 SCTAB nTempTab;
1357cdf0e10cSrcweir                 if ( aRange.aEnd.Tab() < (nTempTab = aRange.aStart.Tab()) )
1358cdf0e10cSrcweir                 {
1359cdf0e10cSrcweir                     aRange.aStart.SetTab(aRange.aEnd.Tab()); aRange.aEnd.SetTab(nTempTab);
1360cdf0e10cSrcweir                     nMask = (SCA_VALID_TAB | SCA_TAB_ABSOLUTE | SCA_TAB_3D);
1361cdf0e10cSrcweir                     nBits1 = nRes1 & nMask;
1362cdf0e10cSrcweir                     nBits2 = nRes2 & nMask;
1363cdf0e10cSrcweir                     nRes1 = (nRes1 & ~nMask) | nBits2;
1364cdf0e10cSrcweir                     nRes2 = (nRes2 & ~nMask) | nBits1;
1365cdf0e10cSrcweir                 }
1366cdf0e10cSrcweir                 if ( ((nRes1 & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ))
1367cdf0e10cSrcweir                         == ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ))
1368cdf0e10cSrcweir                         && !(nRes2 & SCA_TAB_3D) )
1369cdf0e10cSrcweir                     nRes2 |= SCA_TAB_ABSOLUTE;
1370cdf0e10cSrcweir             }
1371cdf0e10cSrcweir             else
1372cdf0e10cSrcweir                 nRes1 = 0;      // #38840# keine Tokens aus halben Sachen
1373cdf0e10cSrcweir         }
1374cdf0e10cSrcweir     }
1375cdf0e10cSrcweir     nRes1 = ( ( nRes1 | nRes2 ) & SCA_VALID )
1376cdf0e10cSrcweir           | nRes1
1377cdf0e10cSrcweir           | ( ( nRes2 & 0x070F ) << 4 );
1378cdf0e10cSrcweir     return nRes1;
1379cdf0e10cSrcweir }
1380cdf0e10cSrcweir 
Parse(const String & r,ScDocument * pDoc,const ScAddress::Details & rDetails,ScAddress::ExternalInfo * pExtInfo,const uno::Sequence<const sheet::ExternalLinkInfo> * pExternalLinks)1381cdf0e10cSrcweir sal_uInt16 ScRange::Parse( const String& r, ScDocument* pDoc,
1382cdf0e10cSrcweir                        const ScAddress::Details& rDetails,
1383cdf0e10cSrcweir                        ScAddress::ExternalInfo* pExtInfo,
1384cdf0e10cSrcweir                        const uno::Sequence< const sheet::ExternalLinkInfo > * pExternalLinks )
1385cdf0e10cSrcweir {
1386cdf0e10cSrcweir     if ( r.Len() <= 0 )
1387cdf0e10cSrcweir         return 0;
1388cdf0e10cSrcweir 
1389cdf0e10cSrcweir     switch (rDetails.eConv)
1390cdf0e10cSrcweir     {
1391cdf0e10cSrcweir     default :
1392cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO:
1393cdf0e10cSrcweir         return lcl_ScRange_Parse_OOo( *this, r, pDoc, pExtInfo );
1394cdf0e10cSrcweir 
1395cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1396cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1397cdf0e10cSrcweir         return lcl_ScRange_Parse_XL_A1( *this, r.GetBuffer(), pDoc, false, pExtInfo,
1398cdf0e10cSrcweir                 (rDetails.eConv == formula::FormulaGrammar::CONV_XL_OOX ? pExternalLinks : NULL) );
1399cdf0e10cSrcweir 
1400cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1401cdf0e10cSrcweir         return lcl_ScRange_Parse_XL_R1C1( *this, r.GetBuffer(), pDoc, rDetails, false, pExtInfo );
1402cdf0e10cSrcweir     }
1403cdf0e10cSrcweir }
1404cdf0e10cSrcweir 
1405cdf0e10cSrcweir 
1406cdf0e10cSrcweir // Accept a full range, or an address
ParseAny(const String & r,ScDocument * pDoc,const ScAddress::Details & rDetails)1407cdf0e10cSrcweir sal_uInt16 ScRange::ParseAny( const String& r, ScDocument* pDoc,
1408cdf0e10cSrcweir                           const ScAddress::Details& rDetails )
1409cdf0e10cSrcweir {
1410cdf0e10cSrcweir     sal_uInt16 nRet = Parse( r, pDoc, rDetails );
1411cdf0e10cSrcweir     const sal_uInt16 nValid = SCA_VALID | SCA_VALID_COL2 | SCA_VALID_ROW2 |
1412cdf0e10cSrcweir         SCA_VALID_TAB2;
1413cdf0e10cSrcweir 
1414cdf0e10cSrcweir     if ( (nRet & nValid) != nValid )
1415cdf0e10cSrcweir     {
1416cdf0e10cSrcweir         ScAddress aAdr;
1417cdf0e10cSrcweir         nRet = aAdr.Parse( r, pDoc, rDetails );
1418cdf0e10cSrcweir         if ( nRet & SCA_VALID )
1419cdf0e10cSrcweir             aStart = aEnd = aAdr;
1420cdf0e10cSrcweir     }
1421cdf0e10cSrcweir     return nRet;
1422cdf0e10cSrcweir }
1423cdf0e10cSrcweir 
1424cdf0e10cSrcweir // Parse only full row references
ParseCols(const String & rStr,ScDocument * pDoc,const ScAddress::Details & rDetails)1425cdf0e10cSrcweir sal_uInt16 ScRange::ParseCols( const String& rStr, ScDocument* pDoc,
1426cdf0e10cSrcweir                            const ScAddress::Details& rDetails )
1427cdf0e10cSrcweir {
1428cdf0e10cSrcweir     const sal_Unicode* p = rStr.GetBuffer();
1429cdf0e10cSrcweir     sal_uInt16 nRes = 0, ignored = 0;
1430cdf0e10cSrcweir 
1431cdf0e10cSrcweir     if( NULL == p )
1432cdf0e10cSrcweir         return 0;
1433cdf0e10cSrcweir 
1434cdf0e10cSrcweir     pDoc = NULL; // make compiler shutup we may need this later
1435cdf0e10cSrcweir 
1436cdf0e10cSrcweir     switch (rDetails.eConv)
1437cdf0e10cSrcweir     {
1438cdf0e10cSrcweir     default :
1439cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO: // No full col refs in OOO yet, assume XL notation
1440cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1441cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1442cdf0e10cSrcweir         if (NULL != (p = lcl_a1_get_col( p, &aStart, &ignored ) ) )
1443cdf0e10cSrcweir         {
1444cdf0e10cSrcweir             if( p[0] == ':')
1445cdf0e10cSrcweir             {
1446cdf0e10cSrcweir                 if( NULL != (p = lcl_a1_get_col( p+1, &aEnd, &ignored )))
1447cdf0e10cSrcweir                 {
1448cdf0e10cSrcweir                     nRes = SCA_VALID_COL;
1449cdf0e10cSrcweir                 }
1450cdf0e10cSrcweir             }
1451cdf0e10cSrcweir             else
1452cdf0e10cSrcweir             {
1453cdf0e10cSrcweir                 aEnd = aStart;
1454cdf0e10cSrcweir                 nRes = SCA_VALID_COL;
1455cdf0e10cSrcweir             }
1456cdf0e10cSrcweir         }
1457cdf0e10cSrcweir         break;
1458cdf0e10cSrcweir 
1459cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1460cdf0e10cSrcweir         if ((p[0] == 'C' || p[0] != 'c') &&
1461cdf0e10cSrcweir             NULL != (p = lcl_r1c1_get_col( p, rDetails, &aStart, &ignored )))
1462cdf0e10cSrcweir         {
1463cdf0e10cSrcweir             if( p[0] == ':')
1464cdf0e10cSrcweir             {
1465cdf0e10cSrcweir                 if( (p[1] == 'C' || p[1] == 'c') &&
1466cdf0e10cSrcweir                     NULL != (p = lcl_r1c1_get_col( p+1, rDetails, &aEnd, &ignored )))
1467cdf0e10cSrcweir                 {
1468cdf0e10cSrcweir                     nRes = SCA_VALID_COL;
1469cdf0e10cSrcweir                 }
1470cdf0e10cSrcweir             }
1471cdf0e10cSrcweir             else
1472cdf0e10cSrcweir             {
1473cdf0e10cSrcweir                 aEnd = aStart;
1474cdf0e10cSrcweir                 nRes = SCA_VALID_COL;
1475cdf0e10cSrcweir             }
1476cdf0e10cSrcweir         }
1477cdf0e10cSrcweir         break;
1478cdf0e10cSrcweir     }
1479cdf0e10cSrcweir 
1480cdf0e10cSrcweir     return (p != NULL && *p == '\0') ? nRes : 0;
1481cdf0e10cSrcweir }
1482cdf0e10cSrcweir 
1483cdf0e10cSrcweir // Parse only full row references
ParseRows(const String & rStr,ScDocument * pDoc,const ScAddress::Details & rDetails)1484cdf0e10cSrcweir sal_uInt16 ScRange::ParseRows( const String& rStr, ScDocument* pDoc,
1485cdf0e10cSrcweir                            const ScAddress::Details& rDetails )
1486cdf0e10cSrcweir {
1487cdf0e10cSrcweir     const sal_Unicode* p = rStr.GetBuffer();
1488cdf0e10cSrcweir     sal_uInt16 nRes = 0, ignored = 0;
1489cdf0e10cSrcweir 
1490cdf0e10cSrcweir     if( NULL == p )
1491cdf0e10cSrcweir         return 0;
1492cdf0e10cSrcweir 
1493cdf0e10cSrcweir     pDoc = NULL; // make compiler shutup we may need this later
1494cdf0e10cSrcweir 
1495cdf0e10cSrcweir     switch (rDetails.eConv)
1496cdf0e10cSrcweir     {
1497cdf0e10cSrcweir     default :
1498cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO: // No full row refs in OOO yet, assume XL notation
1499cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1500cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1501cdf0e10cSrcweir         if (NULL != (p = lcl_a1_get_row( p, &aStart, &ignored ) ) )
1502cdf0e10cSrcweir         {
1503cdf0e10cSrcweir             if( p[0] == ':')
1504cdf0e10cSrcweir             {
1505cdf0e10cSrcweir                 if( NULL != (p = lcl_a1_get_row( p+1, &aEnd, &ignored )))
1506cdf0e10cSrcweir                 {
1507cdf0e10cSrcweir                     nRes = SCA_VALID_COL;
1508cdf0e10cSrcweir                 }
1509cdf0e10cSrcweir             }
1510cdf0e10cSrcweir             else
1511cdf0e10cSrcweir             {
1512cdf0e10cSrcweir                 aEnd = aStart;
1513cdf0e10cSrcweir                 nRes = SCA_VALID_COL;
1514cdf0e10cSrcweir             }
1515cdf0e10cSrcweir         }
1516cdf0e10cSrcweir         break;
1517cdf0e10cSrcweir 
1518cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1519cdf0e10cSrcweir         if ((p[0] == 'R' || p[0] != 'r') &&
1520cdf0e10cSrcweir             NULL != (p = lcl_r1c1_get_row( p, rDetails, &aStart, &ignored )))
1521cdf0e10cSrcweir         {
1522cdf0e10cSrcweir             if( p[0] == ':')
1523cdf0e10cSrcweir             {
1524cdf0e10cSrcweir                 if( (p[1] == 'R' || p[1] == 'r') &&
1525cdf0e10cSrcweir                     NULL != (p = lcl_r1c1_get_row( p+1, rDetails, &aEnd, &ignored )))
1526cdf0e10cSrcweir                 {
1527cdf0e10cSrcweir                     nRes = SCA_VALID_COL;
1528cdf0e10cSrcweir                 }
1529cdf0e10cSrcweir             }
1530cdf0e10cSrcweir             else
1531cdf0e10cSrcweir             {
1532cdf0e10cSrcweir                 aEnd = aStart;
1533cdf0e10cSrcweir                 nRes = SCA_VALID_COL;
1534cdf0e10cSrcweir             }
1535cdf0e10cSrcweir         }
1536cdf0e10cSrcweir         break;
1537cdf0e10cSrcweir     }
1538cdf0e10cSrcweir 
1539cdf0e10cSrcweir     return (p != NULL && *p == '\0') ? nRes : 0;
1540cdf0e10cSrcweir }
1541cdf0e10cSrcweir 
1542cdf0e10cSrcweir static inline void
lcl_a1_append_c(String & r,int nCol,bool bIsAbs)1543cdf0e10cSrcweir lcl_a1_append_c ( String &r, int nCol, bool bIsAbs )
1544cdf0e10cSrcweir {
1545cdf0e10cSrcweir     if( bIsAbs )
1546cdf0e10cSrcweir         r += '$';
1547cdf0e10cSrcweir     ScColToAlpha( r, sal::static_int_cast<SCCOL>(nCol) );
1548cdf0e10cSrcweir }
1549cdf0e10cSrcweir 
1550cdf0e10cSrcweir static inline void
lcl_a1_append_r(String & r,int nRow,bool bIsAbs)1551cdf0e10cSrcweir lcl_a1_append_r ( String &r, int nRow, bool bIsAbs )
1552cdf0e10cSrcweir {
1553cdf0e10cSrcweir     if ( bIsAbs )
1554cdf0e10cSrcweir         r += '$';
1555cdf0e10cSrcweir     r += String::CreateFromInt32( nRow+1 );
1556cdf0e10cSrcweir }
1557cdf0e10cSrcweir 
1558cdf0e10cSrcweir static inline void
lcl_r1c1_append_c(String & r,int nCol,bool bIsAbs,const ScAddress::Details & rDetails)1559cdf0e10cSrcweir lcl_r1c1_append_c ( String &r, int nCol, bool bIsAbs,
1560cdf0e10cSrcweir                     const ScAddress::Details& rDetails )
1561cdf0e10cSrcweir {
1562cdf0e10cSrcweir     r += 'C';
1563cdf0e10cSrcweir     if (bIsAbs)
1564cdf0e10cSrcweir     {
1565cdf0e10cSrcweir         r += String::CreateFromInt32( nCol + 1 );
1566cdf0e10cSrcweir     }
1567cdf0e10cSrcweir     else
1568cdf0e10cSrcweir     {
1569cdf0e10cSrcweir         nCol -= rDetails.nCol;
1570cdf0e10cSrcweir         if (nCol != 0) {
1571cdf0e10cSrcweir             r += '[';
1572cdf0e10cSrcweir             r += String::CreateFromInt32( nCol );
1573cdf0e10cSrcweir             r += ']';
1574cdf0e10cSrcweir         }
1575cdf0e10cSrcweir     }
1576cdf0e10cSrcweir }
1577cdf0e10cSrcweir static inline void
lcl_r1c1_append_r(String & r,int nRow,bool bIsAbs,const ScAddress::Details & rDetails)1578cdf0e10cSrcweir lcl_r1c1_append_r ( String &r, int nRow, bool bIsAbs,
1579cdf0e10cSrcweir                     const ScAddress::Details& rDetails )
1580cdf0e10cSrcweir {
1581cdf0e10cSrcweir     r += 'R';
1582cdf0e10cSrcweir     if (bIsAbs)
1583cdf0e10cSrcweir     {
1584cdf0e10cSrcweir         r += String::CreateFromInt32( nRow + 1 );
1585cdf0e10cSrcweir     }
1586cdf0e10cSrcweir     else
1587cdf0e10cSrcweir     {
1588cdf0e10cSrcweir         nRow -= rDetails.nRow;
1589cdf0e10cSrcweir         if (nRow != 0) {
1590cdf0e10cSrcweir             r += '[';
1591cdf0e10cSrcweir             r += String::CreateFromInt32( nRow );
1592cdf0e10cSrcweir             r += ']';
1593cdf0e10cSrcweir         }
1594cdf0e10cSrcweir     }
1595cdf0e10cSrcweir }
1596cdf0e10cSrcweir 
1597cdf0e10cSrcweir static String
getFileNameFromDoc(const ScDocument * pDoc)1598cdf0e10cSrcweir getFileNameFromDoc( const ScDocument* pDoc )
1599cdf0e10cSrcweir {
1600cdf0e10cSrcweir     // TODO : er points at ScGlobal::GetAbsDocName()
1601cdf0e10cSrcweir     // as a better template.  Look into it
1602cdf0e10cSrcweir     String sFileName;
1603cdf0e10cSrcweir     SfxObjectShell* pShell;
1604cdf0e10cSrcweir 
1605cdf0e10cSrcweir     if( NULL != pDoc &&
1606cdf0e10cSrcweir         NULL != (pShell = pDoc->GetDocumentShell() ) )
1607cdf0e10cSrcweir     {
1608cdf0e10cSrcweir         uno::Reference< frame::XModel > xModel( pShell->GetModel(), uno::UNO_QUERY );
1609cdf0e10cSrcweir         if( xModel.is() )
1610cdf0e10cSrcweir         {
1611cdf0e10cSrcweir             if( xModel->getURL().getLength() )
1612cdf0e10cSrcweir             {
1613cdf0e10cSrcweir                 INetURLObject aURL( xModel->getURL() );
1614cdf0e10cSrcweir                 sFileName = aURL.GetLastName();
1615cdf0e10cSrcweir             }
1616cdf0e10cSrcweir             else
1617cdf0e10cSrcweir                 sFileName = pShell->GetTitle();
1618cdf0e10cSrcweir         }
1619cdf0e10cSrcweir     }
1620cdf0e10cSrcweir #if 0
1621cdf0e10cSrcweir         {
1622cdf0e10cSrcweir             ByteString  aStr( sFileName, RTL_TEXTENCODING_UTF8 );
1623cdf0e10cSrcweir             aStr.Append(static_cast< char >(0));
1624cdf0e10cSrcweir             std::cerr << "docname \'" << aStr.GetBuffer() << '\'' << std::endl;
1625cdf0e10cSrcweir         }
1626cdf0e10cSrcweir #endif
1627cdf0e10cSrcweir     return sFileName;
1628cdf0e10cSrcweir }
1629cdf0e10cSrcweir 
Format(String & r,sal_uInt16 nFlags,ScDocument * pDoc,const Details & rDetails) const1630cdf0e10cSrcweir void ScAddress::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc,
1631cdf0e10cSrcweir                         const Details& rDetails) const
1632cdf0e10cSrcweir {
1633cdf0e10cSrcweir     r.Erase();
1634cdf0e10cSrcweir     if( nFlags & SCA_VALID )
1635cdf0e10cSrcweir         nFlags |= ( SCA_VALID_ROW | SCA_VALID_COL | SCA_VALID_TAB );
1636cdf0e10cSrcweir     if( pDoc && (nFlags & SCA_VALID_TAB ) )
1637cdf0e10cSrcweir     {
1638cdf0e10cSrcweir         if ( nTab >= pDoc->GetTableCount() )
1639cdf0e10cSrcweir         {
1640cdf0e10cSrcweir             r = ScGlobal::GetRscString( STR_NOREF_STR );
1641cdf0e10cSrcweir             return;
1642cdf0e10cSrcweir         }
1643cdf0e10cSrcweir //      if( nFlags & ( SCA_TAB_ABSOLUTE | SCA_TAB_3D ) )
1644cdf0e10cSrcweir         if( nFlags & SCA_TAB_3D )
1645cdf0e10cSrcweir         {
1646cdf0e10cSrcweir             String aTabName, aDocName;
1647cdf0e10cSrcweir             pDoc->GetName( nTab, aTabName );
1648cdf0e10cSrcweir             // External Reference, same as in ScCompiler::MakeTabStr()
1649cdf0e10cSrcweir             if( aTabName.GetChar(0) == '\'' )
1650cdf0e10cSrcweir             {   // "'Doc'#Tab"
1651cdf0e10cSrcweir                 xub_StrLen nPos = ScCompiler::GetDocTabPos( aTabName);
1652cdf0e10cSrcweir                 if (nPos != STRING_NOTFOUND)
1653cdf0e10cSrcweir                 {
1654cdf0e10cSrcweir                     aDocName = aTabName.Copy( 0, nPos + 1 );
1655cdf0e10cSrcweir                     aTabName.Erase( 0, nPos + 1 );
1656cdf0e10cSrcweir                 }
1657cdf0e10cSrcweir             }
1658cdf0e10cSrcweir             else if( nFlags & SCA_FORCE_DOC )
1659cdf0e10cSrcweir             {
1660cdf0e10cSrcweir                 // VBA has an 'external' flag that forces the addition of the
1661cdf0e10cSrcweir                 // tab name _and_ the doc name.  The VBA code would be
1662cdf0e10cSrcweir                 // needlessly complicated if it constructed an actual external
1663cdf0e10cSrcweir                 // reference so we add this somewhat cheesy kludge to force the
1664cdf0e10cSrcweir                 // addition of the document name even for non-external references
1665cdf0e10cSrcweir                 aDocName = getFileNameFromDoc( pDoc );
1666cdf0e10cSrcweir             }
1667cdf0e10cSrcweir             ScCompiler::CheckTabQuotes( aTabName, rDetails.eConv);
1668cdf0e10cSrcweir 
1669cdf0e10cSrcweir             switch( rDetails.eConv )
1670cdf0e10cSrcweir             {
1671cdf0e10cSrcweir             default :
1672cdf0e10cSrcweir             case formula::FormulaGrammar::CONV_OOO:
1673cdf0e10cSrcweir                 r += aDocName;
1674cdf0e10cSrcweir                 if( nFlags & SCA_TAB_ABSOLUTE )
1675cdf0e10cSrcweir                     r += '$';
1676cdf0e10cSrcweir                 r += aTabName;
1677cdf0e10cSrcweir                 r += '.';
1678cdf0e10cSrcweir                 break;
1679cdf0e10cSrcweir 
1680cdf0e10cSrcweir             case formula::FormulaGrammar::CONV_XL_A1:
1681cdf0e10cSrcweir             case formula::FormulaGrammar::CONV_XL_R1C1:
1682cdf0e10cSrcweir             case formula::FormulaGrammar::CONV_XL_OOX:
1683cdf0e10cSrcweir                 if (aDocName.Len() > 0)
1684cdf0e10cSrcweir                 {
1685cdf0e10cSrcweir                     r += '[';
1686cdf0e10cSrcweir                     r += aDocName;
1687cdf0e10cSrcweir                     r += ']';
1688cdf0e10cSrcweir                 }
1689cdf0e10cSrcweir                 r += aTabName;
1690cdf0e10cSrcweir                 r += '!';
1691cdf0e10cSrcweir                 break;
1692cdf0e10cSrcweir             }
1693cdf0e10cSrcweir         }
1694cdf0e10cSrcweir     }
1695cdf0e10cSrcweir     switch( rDetails.eConv )
1696cdf0e10cSrcweir     {
1697cdf0e10cSrcweir     default :
1698cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO:
1699cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1700cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1701cdf0e10cSrcweir         if( nFlags & SCA_VALID_COL )
1702cdf0e10cSrcweir             lcl_a1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE );
1703cdf0e10cSrcweir         if( nFlags & SCA_VALID_ROW )
1704cdf0e10cSrcweir             lcl_a1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE );
1705cdf0e10cSrcweir         break;
1706cdf0e10cSrcweir 
1707cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1708cdf0e10cSrcweir         if( nFlags & SCA_VALID_ROW )
1709cdf0e10cSrcweir             lcl_r1c1_append_r ( r, nRow, nFlags & SCA_ROW_ABSOLUTE, rDetails );
1710cdf0e10cSrcweir         if( nFlags & SCA_VALID_COL )
1711cdf0e10cSrcweir             lcl_r1c1_append_c ( r, nCol, nFlags & SCA_COL_ABSOLUTE, rDetails );
1712cdf0e10cSrcweir         break;
1713cdf0e10cSrcweir     }
1714cdf0e10cSrcweir }
1715cdf0e10cSrcweir 
1716cdf0e10cSrcweir static void
lcl_Split_DocTab(const ScDocument * pDoc,SCTAB nTab,const ScAddress::Details & rDetails,sal_uInt16 nFlags,String & rTabName,String & rDocName)1717cdf0e10cSrcweir lcl_Split_DocTab( const ScDocument* pDoc,  SCTAB nTab,
1718cdf0e10cSrcweir                   const ScAddress::Details& rDetails,
1719cdf0e10cSrcweir                   sal_uInt16 nFlags,
1720cdf0e10cSrcweir                   String& rTabName, String& rDocName )
1721cdf0e10cSrcweir {
1722cdf0e10cSrcweir     pDoc->GetName( nTab, rTabName );
1723cdf0e10cSrcweir     rDocName.Erase();
1724cdf0e10cSrcweir #if 0
1725cdf0e10cSrcweir     {
1726cdf0e10cSrcweir         ByteString  aStr(rTabName, RTL_TEXTENCODING_UTF8);
1727cdf0e10cSrcweir         aStr.Append(static_cast< char >(0));
1728cdf0e10cSrcweir         std::cerr << "tabname \'" << aStr.GetBuffer() << '\'' << std::endl;
1729cdf0e10cSrcweir     }
1730cdf0e10cSrcweir #endif
1731cdf0e10cSrcweir     // External reference, same as in ScCompiler::MakeTabStr()
1732cdf0e10cSrcweir     if ( rTabName.GetChar(0) == '\'' )
1733cdf0e10cSrcweir     {   // "'Doc'#Tab"
1734cdf0e10cSrcweir         xub_StrLen nPos = ScCompiler::GetDocTabPos( rTabName);
1735cdf0e10cSrcweir         if (nPos != STRING_NOTFOUND)
1736cdf0e10cSrcweir         {
1737cdf0e10cSrcweir             rDocName = rTabName.Copy( 0, nPos + 1 );
1738cdf0e10cSrcweir             rTabName.Erase( 0, nPos + 1 );
1739cdf0e10cSrcweir         }
1740cdf0e10cSrcweir     }
1741cdf0e10cSrcweir     else if( nFlags & SCA_FORCE_DOC )
1742cdf0e10cSrcweir     {
1743cdf0e10cSrcweir         // VBA has an 'external' flag that forces the addition of the
1744cdf0e10cSrcweir         // tab name _and_ the doc name.  The VBA code would be
1745cdf0e10cSrcweir         // needlessly complicated if it constructed an actual external
1746cdf0e10cSrcweir         // reference so we add this somewhat cheesy kludge to force the
1747cdf0e10cSrcweir         // addition of the document name even for non-external references
1748cdf0e10cSrcweir         rDocName = getFileNameFromDoc( pDoc );
1749cdf0e10cSrcweir     }
1750cdf0e10cSrcweir     ScCompiler::CheckTabQuotes( rTabName, rDetails.eConv);
1751cdf0e10cSrcweir }
1752cdf0e10cSrcweir 
1753cdf0e10cSrcweir static void
lcl_ScRange_Format_XL_Header(String & r,const ScRange & rRange,sal_uInt16 nFlags,ScDocument * pDoc,const ScAddress::Details & rDetails)1754cdf0e10cSrcweir lcl_ScRange_Format_XL_Header( String& r, const ScRange& rRange,
1755cdf0e10cSrcweir                               sal_uInt16 nFlags, ScDocument* pDoc,
1756cdf0e10cSrcweir                               const ScAddress::Details& rDetails )
1757cdf0e10cSrcweir {
1758cdf0e10cSrcweir     if( nFlags & SCA_TAB_3D )
1759cdf0e10cSrcweir     {
1760cdf0e10cSrcweir         String aTabName, aDocName;
1761cdf0e10cSrcweir         lcl_Split_DocTab( pDoc, rRange.aStart.Tab(), rDetails, nFlags,
1762cdf0e10cSrcweir                           aTabName, aDocName );
1763cdf0e10cSrcweir         if( aDocName.Len() > 0 )
1764cdf0e10cSrcweir         {
1765cdf0e10cSrcweir             r += '[';
1766cdf0e10cSrcweir             r += aDocName;
1767cdf0e10cSrcweir             r += ']';
1768cdf0e10cSrcweir         }
1769cdf0e10cSrcweir         r += aTabName;
1770cdf0e10cSrcweir 
1771cdf0e10cSrcweir         if( nFlags & SCA_TAB2_3D )
1772cdf0e10cSrcweir         {
1773cdf0e10cSrcweir             lcl_Split_DocTab( pDoc, rRange.aEnd.Tab(), rDetails, nFlags,
1774cdf0e10cSrcweir                               aTabName, aDocName );
1775cdf0e10cSrcweir             r += ':';
1776cdf0e10cSrcweir             r += aTabName;
1777cdf0e10cSrcweir         }
1778cdf0e10cSrcweir         r += '!';
1779cdf0e10cSrcweir     }
1780cdf0e10cSrcweir }
1781cdf0e10cSrcweir 
Format(String & r,sal_uInt16 nFlags,ScDocument * pDoc,const ScAddress::Details & rDetails) const1782cdf0e10cSrcweir void ScRange::Format( String& r, sal_uInt16 nFlags, ScDocument* pDoc,
1783cdf0e10cSrcweir                       const ScAddress::Details& rDetails ) const
1784cdf0e10cSrcweir {
1785cdf0e10cSrcweir     r.Erase();
1786cdf0e10cSrcweir     if( !( nFlags & SCA_VALID ) )
1787cdf0e10cSrcweir     {
1788cdf0e10cSrcweir         r = ScGlobal::GetRscString( STR_NOREF_STR );
1789cdf0e10cSrcweir         return;
1790cdf0e10cSrcweir     }
1791cdf0e10cSrcweir 
1792cdf0e10cSrcweir #define absrel_differ(nFlags, mask) (((nFlags) & (mask)) ^ (((nFlags) >> 4) & (mask)))
1793cdf0e10cSrcweir     switch( rDetails.eConv ) {
1794cdf0e10cSrcweir     default :
1795cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO: {
1796cdf0e10cSrcweir         sal_Bool bOneTab = (aStart.Tab() == aEnd.Tab());
1797cdf0e10cSrcweir         if ( !bOneTab )
1798cdf0e10cSrcweir             nFlags |= SCA_TAB_3D;
1799cdf0e10cSrcweir         aStart.Format( r, nFlags, pDoc, rDetails );
1800cdf0e10cSrcweir         if( aStart != aEnd ||
1801cdf0e10cSrcweir             absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
1802cdf0e10cSrcweir             absrel_differ( nFlags, SCA_ROW_ABSOLUTE ))
1803cdf0e10cSrcweir         {
1804cdf0e10cSrcweir             String aName;
1805cdf0e10cSrcweir             nFlags = ( nFlags & SCA_VALID ) | ( ( nFlags >> 4 ) & 0x070F );
1806cdf0e10cSrcweir             if ( bOneTab )
1807cdf0e10cSrcweir                 pDoc = NULL;
1808cdf0e10cSrcweir             else
1809cdf0e10cSrcweir                 nFlags |= SCA_TAB_3D;
1810cdf0e10cSrcweir             aEnd.Format( aName, nFlags, pDoc, rDetails );
1811cdf0e10cSrcweir             r += ':';
1812cdf0e10cSrcweir             r += aName;
1813cdf0e10cSrcweir         }
1814cdf0e10cSrcweir     }
1815cdf0e10cSrcweir     break;
1816cdf0e10cSrcweir 
1817cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1818cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1819cdf0e10cSrcweir         lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails );
1820cdf0e10cSrcweir         if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL )
1821cdf0e10cSrcweir         {
1822cdf0e10cSrcweir             // Full col refs always require 2 rows (2:2)
1823cdf0e10cSrcweir             lcl_a1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE );
1824cdf0e10cSrcweir             r += ':';
1825cdf0e10cSrcweir             lcl_a1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE );
1826cdf0e10cSrcweir         }
1827cdf0e10cSrcweir         else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW )
1828cdf0e10cSrcweir         {
1829cdf0e10cSrcweir             // Full row refs always require 2 cols (A:A)
1830cdf0e10cSrcweir             lcl_a1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE );
1831cdf0e10cSrcweir             r += ':';
1832cdf0e10cSrcweir             lcl_a1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE );
1833cdf0e10cSrcweir         }
1834cdf0e10cSrcweir         else
1835cdf0e10cSrcweir         {
1836cdf0e10cSrcweir             lcl_a1_append_c ( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE );
1837cdf0e10cSrcweir             lcl_a1_append_r ( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE );
1838cdf0e10cSrcweir             if( aStart.Col() != aEnd.Col() ||
1839cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
1840cdf0e10cSrcweir                 aStart.Row() != aEnd.Row() ||
1841cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
1842cdf0e10cSrcweir                 r += ':';
1843cdf0e10cSrcweir                 lcl_a1_append_c ( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE );
1844cdf0e10cSrcweir                 lcl_a1_append_r ( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE );
1845cdf0e10cSrcweir             }
1846cdf0e10cSrcweir         }
1847cdf0e10cSrcweir     break;
1848cdf0e10cSrcweir 
1849cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1850cdf0e10cSrcweir         lcl_ScRange_Format_XL_Header( r, *this, nFlags, pDoc, rDetails );
1851cdf0e10cSrcweir         if( aStart.Col() == 0 && aEnd.Col() >= MAXCOL )
1852cdf0e10cSrcweir         {
1853cdf0e10cSrcweir             lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails );
1854cdf0e10cSrcweir             if( aStart.Row() != aEnd.Row() ||
1855cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
1856cdf0e10cSrcweir                 r += ':';
1857cdf0e10cSrcweir                 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails );
1858cdf0e10cSrcweir             }
1859cdf0e10cSrcweir         }
1860cdf0e10cSrcweir         else if( aStart.Row() == 0 && aEnd.Row() >= MAXROW )
1861cdf0e10cSrcweir         {
1862cdf0e10cSrcweir             lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails );
1863cdf0e10cSrcweir             if( aStart.Col() != aEnd.Col() ||
1864cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_COL_ABSOLUTE )) {
1865cdf0e10cSrcweir                 r += ':';
1866cdf0e10cSrcweir                 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails );
1867cdf0e10cSrcweir             }
1868cdf0e10cSrcweir         }
1869cdf0e10cSrcweir         else
1870cdf0e10cSrcweir         {
1871cdf0e10cSrcweir             lcl_r1c1_append_r( r, aStart.Row(), nFlags & SCA_ROW_ABSOLUTE, rDetails );
1872cdf0e10cSrcweir             lcl_r1c1_append_c( r, aStart.Col(), nFlags & SCA_COL_ABSOLUTE, rDetails );
1873cdf0e10cSrcweir             if( aStart.Col() != aEnd.Col() ||
1874cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_COL_ABSOLUTE ) ||
1875cdf0e10cSrcweir                 aStart.Row() != aEnd.Row() ||
1876cdf0e10cSrcweir                 absrel_differ( nFlags, SCA_ROW_ABSOLUTE )) {
1877cdf0e10cSrcweir                 r += ':';
1878cdf0e10cSrcweir                 lcl_r1c1_append_r( r, aEnd.Row(), nFlags & SCA_ROW2_ABSOLUTE, rDetails );
1879cdf0e10cSrcweir                 lcl_r1c1_append_c( r, aEnd.Col(), nFlags & SCA_COL2_ABSOLUTE, rDetails );
1880cdf0e10cSrcweir             }
1881cdf0e10cSrcweir         }
1882cdf0e10cSrcweir     }
1883cdf0e10cSrcweir #undef  absrel_differ
1884cdf0e10cSrcweir }
1885cdf0e10cSrcweir 
Move(SCsCOL dx,SCsROW dy,SCsTAB dz,ScDocument * pDoc)1886cdf0e10cSrcweir bool ScAddress::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
1887cdf0e10cSrcweir {
1888cdf0e10cSrcweir     SCsTAB nMaxTab = pDoc ? pDoc->GetTableCount() : MAXTAB+1;
1889cdf0e10cSrcweir     dx = Col() + dx;
1890cdf0e10cSrcweir     dy = Row() + dy;
1891cdf0e10cSrcweir     dz = Tab() + dz;
1892cdf0e10cSrcweir     sal_Bool bValid = sal_True;
1893cdf0e10cSrcweir     if( dx < 0 )
1894cdf0e10cSrcweir         dx = 0, bValid = sal_False;
1895cdf0e10cSrcweir     else if( dx > MAXCOL )
1896cdf0e10cSrcweir         dx = MAXCOL, bValid =sal_False;
1897cdf0e10cSrcweir     if( dy < 0 )
1898cdf0e10cSrcweir         dy = 0, bValid = sal_False;
1899cdf0e10cSrcweir     else if( dy > MAXROW )
1900cdf0e10cSrcweir         dy = MAXROW, bValid =sal_False;
1901cdf0e10cSrcweir     if( dz < 0 )
1902cdf0e10cSrcweir         dz = 0, bValid = sal_False;
1903cdf0e10cSrcweir     else if( dz >= nMaxTab )
1904cdf0e10cSrcweir         dz = nMaxTab-1, bValid =sal_False;
1905cdf0e10cSrcweir     Set( dx, dy, dz );
1906cdf0e10cSrcweir     return bValid;
1907cdf0e10cSrcweir }
1908cdf0e10cSrcweir 
1909cdf0e10cSrcweir 
Move(SCsCOL dx,SCsROW dy,SCsTAB dz,ScDocument * pDoc)1910cdf0e10cSrcweir bool ScRange::Move( SCsCOL dx, SCsROW dy, SCsTAB dz, ScDocument* pDoc )
1911cdf0e10cSrcweir {
1912cdf0e10cSrcweir     // Einfahces &, damit beides ausgefuehrt wird!!
1913cdf0e10cSrcweir     return aStart.Move( dx, dy, dz, pDoc ) & aEnd.Move( dx, dy, dz, pDoc );
1914cdf0e10cSrcweir }
1915cdf0e10cSrcweir 
1916cdf0e10cSrcweir 
GetColRowString(bool bAbsolute,const Details & rDetails) const1917cdf0e10cSrcweir String ScAddress::GetColRowString( bool bAbsolute,
1918cdf0e10cSrcweir                                    const Details& rDetails ) const
1919cdf0e10cSrcweir {
1920cdf0e10cSrcweir     String aString;
1921cdf0e10cSrcweir 
1922cdf0e10cSrcweir     switch( rDetails.eConv )
1923cdf0e10cSrcweir     {
1924cdf0e10cSrcweir     default :
1925cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_OOO:
1926cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_A1:
1927cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_OOX:
1928cdf0e10cSrcweir     if (bAbsolute)
1929cdf0e10cSrcweir         aString.Append( '$' );
1930cdf0e10cSrcweir 
1931cdf0e10cSrcweir     ScColToAlpha( aString, nCol);
1932cdf0e10cSrcweir 
1933cdf0e10cSrcweir     if ( bAbsolute )
1934cdf0e10cSrcweir         aString.Append( '$' );
1935cdf0e10cSrcweir 
1936cdf0e10cSrcweir     aString += String::CreateFromInt32(nRow+1);
1937cdf0e10cSrcweir         break;
1938cdf0e10cSrcweir 
1939cdf0e10cSrcweir     case formula::FormulaGrammar::CONV_XL_R1C1:
1940cdf0e10cSrcweir         lcl_r1c1_append_r ( aString, nRow, bAbsolute, rDetails );
1941cdf0e10cSrcweir         lcl_r1c1_append_c ( aString, nCol, bAbsolute, rDetails );
1942cdf0e10cSrcweir         break;
1943cdf0e10cSrcweir     }
1944cdf0e10cSrcweir 
1945cdf0e10cSrcweir     return aString;
1946cdf0e10cSrcweir }
1947cdf0e10cSrcweir 
1948cdf0e10cSrcweir 
GetRefString(ScDocument * pDoc,SCTAB nActTab,const ScAddress::Details & rDetails) const1949cdf0e10cSrcweir String ScRefAddress::GetRefString( ScDocument* pDoc, SCTAB nActTab,
1950cdf0e10cSrcweir                                    const ScAddress::Details& rDetails ) const
1951cdf0e10cSrcweir {
1952cdf0e10cSrcweir     if ( !pDoc )
1953cdf0e10cSrcweir         return EMPTY_STRING;
1954cdf0e10cSrcweir     if ( Tab()+1 > pDoc->GetTableCount() )
1955cdf0e10cSrcweir         return ScGlobal::GetRscString( STR_NOREF_STR );
1956cdf0e10cSrcweir 
1957cdf0e10cSrcweir     String aString;
1958cdf0e10cSrcweir     sal_uInt16 nFlags = SCA_VALID;
1959cdf0e10cSrcweir     if ( nActTab != Tab() )
1960cdf0e10cSrcweir     {
1961cdf0e10cSrcweir         nFlags |= SCA_TAB_3D;
1962cdf0e10cSrcweir         if ( !bRelTab )
1963cdf0e10cSrcweir             nFlags |= SCA_TAB_ABSOLUTE;
1964cdf0e10cSrcweir     }
1965cdf0e10cSrcweir     if ( !bRelCol )
1966cdf0e10cSrcweir         nFlags |= SCA_COL_ABSOLUTE;
1967cdf0e10cSrcweir     if ( !bRelRow )
1968cdf0e10cSrcweir         nFlags |= SCA_ROW_ABSOLUTE;
1969cdf0e10cSrcweir 
1970cdf0e10cSrcweir     aAdr.Format( aString, nFlags, pDoc, rDetails );
1971cdf0e10cSrcweir 
1972cdf0e10cSrcweir     return aString;
1973cdf0e10cSrcweir }
1974cdf0e10cSrcweir 
1975cdf0e10cSrcweir //------------------------------------------------------------------------
1976cdf0e10cSrcweir 
ScColToAlpha(rtl::OUStringBuffer & rBuf,SCCOL nCol)1977cdf0e10cSrcweir void ScColToAlpha( rtl::OUStringBuffer& rBuf, SCCOL nCol )
1978cdf0e10cSrcweir {
1979cdf0e10cSrcweir     if (nCol < 26*26)
1980cdf0e10cSrcweir     {
1981cdf0e10cSrcweir         if (nCol < 26)
1982cdf0e10cSrcweir             rBuf.append( static_cast<sal_Unicode>( 'A' +
1983cdf0e10cSrcweir                         static_cast<sal_uInt16>(nCol)));
1984cdf0e10cSrcweir         else
1985cdf0e10cSrcweir         {
1986cdf0e10cSrcweir             rBuf.append( static_cast<sal_Unicode>( 'A' +
1987cdf0e10cSrcweir                         (static_cast<sal_uInt16>(nCol) / 26) - 1));
1988cdf0e10cSrcweir             rBuf.append( static_cast<sal_Unicode>( 'A' +
1989cdf0e10cSrcweir                         (static_cast<sal_uInt16>(nCol) % 26)));
1990cdf0e10cSrcweir         }
1991cdf0e10cSrcweir     }
1992cdf0e10cSrcweir     else
1993cdf0e10cSrcweir     {
1994cdf0e10cSrcweir         String aStr;
1995cdf0e10cSrcweir         while (nCol >= 26)
1996cdf0e10cSrcweir         {
1997cdf0e10cSrcweir             SCCOL nC = nCol % 26;
1998cdf0e10cSrcweir             aStr += static_cast<sal_Unicode>( 'A' +
1999cdf0e10cSrcweir                     static_cast<sal_uInt16>(nC));
2000cdf0e10cSrcweir             nCol = sal::static_int_cast<SCCOL>( nCol - nC );
2001cdf0e10cSrcweir             nCol = nCol / 26 - 1;
2002cdf0e10cSrcweir         }
2003cdf0e10cSrcweir         aStr += static_cast<sal_Unicode>( 'A' +
2004cdf0e10cSrcweir                 static_cast<sal_uInt16>(nCol));
2005cdf0e10cSrcweir         aStr.Reverse();
2006cdf0e10cSrcweir         rBuf.append( aStr);
2007cdf0e10cSrcweir     }
2008cdf0e10cSrcweir }
2009cdf0e10cSrcweir 
2010cdf0e10cSrcweir 
AlphaToCol(SCCOL & rCol,const String & rStr)2011cdf0e10cSrcweir bool AlphaToCol( SCCOL& rCol, const String& rStr)
2012cdf0e10cSrcweir {
2013cdf0e10cSrcweir     SCCOL nResult = 0;
2014cdf0e10cSrcweir     xub_StrLen nStop = rStr.Len();
2015cdf0e10cSrcweir     xub_StrLen nPos = 0;
2016cdf0e10cSrcweir     sal_Unicode c;
2017cdf0e10cSrcweir     while (nResult <= MAXCOL && nPos < nStop && (c = rStr.GetChar( nPos)) != 0 &&
2018cdf0e10cSrcweir             CharClass::isAsciiAlpha(c))
2019cdf0e10cSrcweir     {
2020cdf0e10cSrcweir         if (nPos > 0)
2021cdf0e10cSrcweir             nResult = (nResult + 1) * 26;
2022cdf0e10cSrcweir         nResult += ScGlobal::ToUpperAlpha(c) - 'A';
2023cdf0e10cSrcweir         ++nPos;
2024cdf0e10cSrcweir     }
2025cdf0e10cSrcweir     bool bOk = (ValidCol(nResult) && nPos > 0);
2026cdf0e10cSrcweir     if (bOk)
2027cdf0e10cSrcweir         rCol = nResult;
2028cdf0e10cSrcweir     return bOk;
2029cdf0e10cSrcweir }
2030