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