1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "oox/xls/addressconverter.hxx"
29 
30 #include <com/sun/star/container/XIndexAccess.hpp>
31 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
32 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
33 #include <osl/diagnose.h>
34 #include <rtl/strbuf.hxx>
35 #include <rtl/ustrbuf.hxx>
36 #include "oox/core/filterbase.hxx"
37 #include "oox/xls/biffinputstream.hxx"
38 #include "oox/xls/biffoutputstream.hxx"
39 
40 namespace oox {
41 namespace xls {
42 
43 // ============================================================================
44 
45 using namespace ::com::sun::star::container;
46 using namespace ::com::sun::star::sheet;
47 using namespace ::com::sun::star::table;
48 using namespace ::com::sun::star::uno;
49 
50 using ::rtl::OStringBuffer;
51 using ::rtl::OUString;
52 using ::rtl::OUStringBuffer;
53 using ::rtl::OUStringToOString;
54 
55 // ============================================================================
56 
57 namespace {
58 
59 //! TODO: this limit may change, is there a way to obtain it via API?
60 const sal_Int16 API_MAXTAB          = 255;
61 
62 const sal_Int32 OOX_MAXCOL          = static_cast< sal_Int32 >( (1 << 14) - 1 );
63 const sal_Int32 OOX_MAXROW          = static_cast< sal_Int32 >( (1 << 20) - 1 );
64 const sal_Int16 OOX_MAXTAB          = static_cast< sal_Int16 >( (1 << 15) - 1 );
65 
66 const sal_Int32 BIFF2_MAXCOL        = 255;
67 const sal_Int32 BIFF2_MAXROW        = 16383;
68 const sal_Int16 BIFF2_MAXTAB        = 0;
69 
70 const sal_Int32 BIFF3_MAXCOL        = BIFF2_MAXCOL;
71 const sal_Int32 BIFF3_MAXROW        = BIFF2_MAXROW;
72 const sal_Int16 BIFF3_MAXTAB        = BIFF2_MAXTAB;
73 
74 const sal_Int32 BIFF4_MAXCOL        = BIFF3_MAXCOL;
75 const sal_Int32 BIFF4_MAXROW        = BIFF3_MAXROW;
76 const sal_Int16 BIFF4_MAXTAB        = 32767;
77 
78 const sal_Int32 BIFF5_MAXCOL        = BIFF4_MAXCOL;
79 const sal_Int32 BIFF5_MAXROW        = BIFF4_MAXROW;
80 const sal_Int16 BIFF5_MAXTAB        = BIFF4_MAXTAB;
81 
82 const sal_Int32 BIFF8_MAXCOL        = BIFF5_MAXCOL;
83 const sal_Int32 BIFF8_MAXROW        = 65535;
84 const sal_Int16 BIFF8_MAXTAB        = BIFF5_MAXTAB;
85 
86 const sal_Unicode BIFF_URL_DRIVE    = '\x01';       /// DOS drive letter or UNC path.
87 const sal_Unicode BIFF_URL_ROOT     = '\x02';       /// Root directory of current drive.
88 const sal_Unicode BIFF_URL_SUBDIR   = '\x03';       /// Subdirectory delimiter.
89 const sal_Unicode BIFF_URL_PARENT   = '\x04';       /// Parent directory.
90 const sal_Unicode BIFF_URL_RAW      = '\x05';       /// Unencoded URL.
91 const sal_Unicode BIFF_URL_INSTALL  = '\x06';       /// Application installation directory.
92 const sal_Unicode BIFF_URL_INSTALL2 = '\x07';       /// Alternative application installation directory.
93 const sal_Unicode BIFF_URL_LIBRARY  = '\x08';       /// Library directory in application installation.
94 const sal_Unicode BIFF4_URL_SHEET   = '\x09';       /// BIFF4 internal sheet.
95 const sal_Unicode BIFF_URL_UNC      = '@';          /// UNC path root.
96 
97 const sal_Unicode BIFF_DCON_ENCODED = '\x01';       /// First character of an encoded path from DCON* records.
98 const sal_Unicode BIFF_DCON_INTERN  = '\x02';       /// First character of an encoded sheet name from DCON* records.
99 
100 
101 inline sal_uInt8 lclGetBiffAddressSize( bool bCol16Bit, bool bRow32Bit )
102 {
103     return (bCol16Bit ? 2 : 1) + (bRow32Bit ? 4 : 2);
104 }
105 
106 inline sal_uInt8 lclGetBiffRangeSize( bool bCol16Bit, bool bRow32Bit )
107 {
108     return 2 * lclGetBiffAddressSize( bCol16Bit, bRow32Bit );
109 }
110 
111 } // namespace
112 
113 // ============================================================================
114 // ============================================================================
115 
116 CellAddress ApiCellRangeList::getBaseAddress() const
117 {
118     if( empty() )
119         return CellAddress();
120     return CellAddress( front().Sheet, front().StartColumn, front().StartRow );
121 }
122 
123 // ============================================================================
124 
125 void BinAddress::read( SequenceInputStream& rStrm )
126 {
127     rStrm >> mnRow >> mnCol;
128 }
129 
130 void BinAddress::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
131 {
132     mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
133     mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
134 }
135 
136 void BinAddress::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
137 {
138     if( bRow32Bit )
139         rStrm << mnRow;
140     else
141         rStrm << static_cast< sal_uInt16 >( mnRow );
142     if( bCol16Bit )
143         rStrm << static_cast< sal_uInt16 >( mnCol );
144     else
145         rStrm << static_cast< sal_uInt8 >( mnCol );
146 }
147 
148 // ============================================================================
149 
150 bool BinRange::contains( const BinAddress& rAddr ) const
151 {
152     return  (maFirst.mnCol <= rAddr.mnCol) && (rAddr.mnCol <= maLast.mnCol) &&
153             (maFirst.mnRow <= rAddr.mnRow) && (rAddr.mnRow <= maLast.mnRow);
154 }
155 
156 void BinRange::read( SequenceInputStream& rStrm )
157 {
158     rStrm >> maFirst.mnRow >> maLast.mnRow >> maFirst.mnCol >> maLast.mnCol;
159 }
160 
161 void BinRange::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
162 {
163     maFirst.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
164     maLast.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
165     maFirst.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
166     maLast.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
167 }
168 
169 void BinRange::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
170 {
171     if( bRow32Bit )
172         rStrm << maFirst.mnRow << maLast.mnRow;
173     else
174         rStrm << static_cast< sal_uInt16 >( maFirst.mnRow ) << static_cast< sal_uInt16 >( maLast.mnRow );
175     if( bCol16Bit )
176         rStrm << static_cast< sal_uInt16 >( maFirst.mnCol ) << static_cast< sal_uInt16 >( maLast.mnCol );
177     else
178         rStrm << static_cast< sal_uInt8 >( maFirst.mnCol ) << static_cast< sal_uInt8 >( maLast.mnCol );
179 }
180 
181 // ============================================================================
182 
183 BinRange BinRangeList::getEnclosingRange() const
184 {
185     BinRange aRange;
186     if( !empty() )
187     {
188         const_iterator aIt = begin(), aEnd = end();
189         aRange = *aIt;
190         for( ++aIt; aIt != aEnd; ++aIt )
191         {
192             aRange.maFirst.mnCol = ::std::min( aRange.maFirst.mnCol, aIt->maFirst.mnCol );
193             aRange.maFirst.mnRow = ::std::min( aRange.maFirst.mnRow, aIt->maFirst.mnRow );
194             aRange.maLast.mnCol  = ::std::max( aRange.maLast.mnCol, aIt->maLast.mnCol );
195             aRange.maLast.mnRow  = ::std::max( aRange.maLast.mnRow, aIt->maLast.mnRow );
196         }
197     }
198     return aRange;
199 }
200 
201 void BinRangeList::read( SequenceInputStream& rStrm )
202 {
203     sal_Int32 nCount = rStrm.readInt32();
204     resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) );
205     for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
206         aIt->read( rStrm );
207 }
208 
209 void BinRangeList::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
210 {
211     sal_uInt16 nCount = rStrm.readuInt16();
212     resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) ) );
213     for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
214         aIt->read( rStrm, bCol16Bit, bRow32Bit );
215 }
216 
217 void BinRangeList::write( BiffOutputStream& rStrm, bool bCol16Bit, bool bRow32Bit ) const
218 {
219     writeSubList( rStrm, 0, size(), bCol16Bit, bRow32Bit );
220 }
221 
222 void BinRangeList::writeSubList( BiffOutputStream& rStrm, size_t nBegin, size_t nCount, bool bCol16Bit, bool bRow32Bit ) const
223 {
224     OSL_ENSURE( nBegin <= size(), "BiffRangeList::writeSubList - invalid start position" );
225     size_t nEnd = ::std::min< size_t >( nBegin + nCount, size() );
226     sal_uInt16 nBiffCount = getLimitedValue< sal_uInt16, size_t >( nEnd - nBegin, 0, SAL_MAX_UINT16 );
227     rStrm << nBiffCount;
228     rStrm.setPortionSize( lclGetBiffRangeSize( bCol16Bit, bRow32Bit ) );
229     for( const_iterator aIt = begin() + nBegin, aEnd = begin() + nEnd; aIt != aEnd; ++aIt )
230         aIt->write( rStrm, bCol16Bit, bRow32Bit );
231 }
232 
233 // ============================================================================
234 // ============================================================================
235 
236 AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
237     WorkbookHelper( rHelper ),
238     mbColOverflow( false ),
239     mbRowOverflow( false ),
240     mbTabOverflow( false )
241 {
242     maDConChars.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
243     switch( getFilterType() )
244     {
245         case FILTER_OOXML:
246             initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
247         break;
248         case FILTER_BIFF: switch( getBiff() )
249         {
250             case BIFF2:
251                 initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW );
252                 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
253             break;
254             case BIFF3:
255                 initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
256                 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
257             break;
258             case BIFF4:
259                 initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
260                 maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
261             break;
262             case BIFF5:
263                 initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
264                 maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
265             break;
266             case BIFF8:
267                 initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
268                 maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
269             break;
270             case BIFF_UNKNOWN: break;
271         }
272         break;
273         case FILTER_UNKNOWN: break;
274     }
275 }
276 
277 // ----------------------------------------------------------------------------
278 
279 bool AddressConverter::parseOoxAddress2d(
280         sal_Int32& ornColumn, sal_Int32& ornRow,
281         const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
282 {
283     ornColumn = ornRow = 0;
284     if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
285         return false;
286 
287     const sal_Unicode* pcChar = rString.getStr() + nStart;
288     const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
289 
290     enum { STATE_COL, STATE_ROW } eState = STATE_COL;
291     while( pcChar < pcEndChar )
292     {
293         sal_Unicode cChar = *pcChar;
294         switch( eState )
295         {
296             case STATE_COL:
297             {
298                 if( ('a' <= cChar) && (cChar <= 'z') )
299                     (cChar -= 'a') += 'A';
300                 if( ('A' <= cChar) && (cChar <= 'Z') )
301                 {
302                     /*  Return, if 1-based column index is already 6 characters
303                         long (12356631 is column index for column AAAAAA). */
304                     if( ornColumn >= 12356631 )
305                         return false;
306                     (ornColumn *= 26) += (cChar - 'A' + 1);
307                 }
308                 else if( ornColumn > 0 )
309                 {
310                     --pcChar;
311                     eState = STATE_ROW;
312                 }
313                 else
314                     return false;
315             }
316             break;
317 
318             case STATE_ROW:
319             {
320                 if( ('0' <= cChar) && (cChar <= '9') )
321                 {
322                     // return, if 1-based row is already 9 digits long
323                     if( ornRow >= 100000000 )
324                         return false;
325                     (ornRow *= 10) += (cChar - '0');
326                 }
327                 else
328                     return false;
329             }
330             break;
331         }
332         ++pcChar;
333     }
334 
335     --ornColumn;
336     --ornRow;
337     return (ornColumn >= 0) && (ornRow >= 0);
338 }
339 
340 bool AddressConverter::parseOoxRange2d(
341         sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
342         sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
343         const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
344 {
345     ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
346     if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
347         return false;
348 
349     sal_Int32 nEnd = nStart + ::std::min( nLength, rString.getLength() - nStart );
350     sal_Int32 nColonPos = rString.indexOf( ':', nStart );
351     if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
352     {
353         return
354             parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
355             parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, nLength - nColonPos - 1 );
356     }
357 
358     if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nLength ) )
359     {
360         ornEndColumn = ornStartColumn;
361         ornEndRow = ornStartRow;
362         return true;
363     }
364 
365     return false;
366 }
367 
368 namespace {
369 
370 bool lclAppendUrlChar( OUStringBuffer& orUrl, sal_Unicode cChar, bool bEncodeSpecial )
371 {
372     // #126855# encode special characters
373     if( bEncodeSpecial ) switch( cChar )
374     {
375         case '#':   orUrl.appendAscii( "%23" );  return true;
376         case '%':   orUrl.appendAscii( "%25" );  return true;
377     }
378     orUrl.append( cChar );
379     return cChar >= ' ';
380 }
381 
382 } // namespace
383 
384 BiffTargetType AddressConverter::parseBiffTargetUrl(
385         OUString& orClassName, OUString& orTargetUrl, OUString& orSheetName,
386         const OUString& rBiffTargetUrl, bool bFromDConRec )
387 {
388     OUStringBuffer aTargetUrl;
389     OUStringBuffer aSheetName;
390     // default target type: some URL with/without sheet name, may be overridden below
391     BiffTargetType eTargetType = BIFF_TARGETTYPE_URL;
392     const ControlCharacters& rCChars = bFromDConRec ? maDConChars : maLinkChars;
393 
394     enum
395     {
396         STATE_START,
397         STATE_ENCODED_PATH_START,       /// Start of encoded file path.
398         STATE_ENCODED_PATH,             /// Inside encoded file path.
399         STATE_ENCODED_DRIVE,            /// DOS drive letter or start of UNC path.
400         STATE_ENCODED_URL,              /// Encoded URL, e.g. http links.
401         STATE_UNENCODED,                /// Unencoded URL, could be DDE or OLE.
402         STATE_DDE_OLE,                  /// Second part of DDE or OLE link.
403         STATE_FILENAME,                 /// File name enclosed in brackets.
404         STATE_SHEETNAME,                /// Sheet name following enclosed file name.
405         STATE_UNSUPPORTED,              /// Unsupported special paths.
406         STATE_ERROR
407     }
408     eState = STATE_START;
409 
410     const sal_Unicode* pcChar = rBiffTargetUrl.getStr();
411     const sal_Unicode* pcEnd = pcChar + rBiffTargetUrl.getLength();
412     for( ; (eState != STATE_ERROR) && (pcChar < pcEnd); ++pcChar )
413     {
414         sal_Unicode cChar = *pcChar;
415         switch( eState )
416         {
417             case STATE_START:
418                 if( (cChar == rCChars.mcThisWorkbook) || (cChar == rCChars.mcThisSheet) || (cChar == rCChars.mcSameSheet) )
419                 {
420                     if( pcChar + 1 < pcEnd )
421                         eState = STATE_ERROR;
422                     if( cChar == rCChars.mcSameSheet )
423                         eTargetType = BIFF_TARGETTYPE_SAMESHEET;
424                 }
425                 else if( cChar == rCChars.mcExternal )
426                     eState = (pcChar + 1 < pcEnd) ? STATE_ENCODED_PATH_START : STATE_ERROR;
427                 else if( cChar == rCChars.mcInternal )
428                     eState = (pcChar + 1 < pcEnd) ? STATE_SHEETNAME : STATE_ERROR;
429                 else
430                     eState = lclAppendUrlChar( aTargetUrl, cChar, true ) ? STATE_UNENCODED : STATE_ERROR;
431             break;
432 
433             case STATE_ENCODED_PATH_START:
434                 if( cChar == BIFF_URL_DRIVE )
435                     eState = STATE_ENCODED_DRIVE;
436                 else if( cChar == BIFF_URL_ROOT )
437                 {
438                     aTargetUrl.append( sal_Unicode( '/' ) );
439                     eState = STATE_ENCODED_PATH;
440                 }
441                 else if( cChar == BIFF_URL_PARENT )
442                     aTargetUrl.appendAscii( "../" );
443                 else if( cChar == BIFF_URL_RAW )
444                     eState = STATE_ENCODED_URL;
445                 else if( cChar == BIFF_URL_INSTALL )
446                     eState = STATE_UNSUPPORTED;
447                 else if( cChar == BIFF_URL_INSTALL2 )
448                     eState = STATE_UNSUPPORTED;
449                 else if( cChar == BIFF_URL_LIBRARY )
450                 {
451                     eState = STATE_ENCODED_PATH;
452                     eTargetType = BIFF_TARGETTYPE_LIBRARY;
453                 }
454                 else if( (getBiff() == BIFF4) && (cChar == BIFF4_URL_SHEET) )
455                     eState = STATE_SHEETNAME;
456                 else if( cChar == '[' )
457                     eState = STATE_FILENAME;
458                 else if( lclAppendUrlChar( aTargetUrl, cChar, true ) )
459                     eState = STATE_ENCODED_PATH;
460                 else
461                     eState = STATE_ERROR;
462             break;
463 
464             case STATE_ENCODED_PATH:
465                 if( cChar == BIFF_URL_SUBDIR )
466                     aTargetUrl.append( sal_Unicode( '/' ) );
467                 else if( cChar == '[' )
468                     eState = STATE_FILENAME;
469                 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
470                     eState = STATE_ERROR;
471             break;
472 
473             case STATE_ENCODED_DRIVE:
474                 if( cChar == BIFF_URL_UNC )
475                 {
476                     aTargetUrl.appendAscii( "file://" );
477                     eState = STATE_ENCODED_PATH;
478                 }
479                 else
480                 {
481                     aTargetUrl.appendAscii( "file:///" );
482                     eState = lclAppendUrlChar( aTargetUrl, cChar, false ) ? STATE_ENCODED_PATH : STATE_ERROR;
483                     aTargetUrl.appendAscii( ":/" );
484                 }
485             break;
486 
487             case STATE_ENCODED_URL:
488             {
489                 sal_Int32 nLength = cChar;
490                 if( nLength + 1 == pcEnd - pcChar )
491                     aTargetUrl.append( pcChar + 1, nLength );
492                 else
493                     eState = STATE_ERROR;
494             }
495             break;
496 
497             case STATE_UNENCODED:
498                 if( cChar == BIFF_URL_SUBDIR )
499                 {
500                     orClassName = aTargetUrl.makeStringAndClear();
501                     eState = bFromDConRec ? STATE_ERROR : STATE_DDE_OLE;
502                     eTargetType = BIFF_TARGETTYPE_DDE_OLE;
503                 }
504                 else if( cChar == '[' )
505                     eState = STATE_FILENAME;
506                 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
507                     eState = STATE_ERROR;
508             break;
509 
510             case STATE_DDE_OLE:
511                 if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
512                     eState = STATE_ERROR;
513             break;
514 
515             case STATE_FILENAME:
516                 if( cChar == ']' )
517                     eState = STATE_SHEETNAME;
518                 else if( !lclAppendUrlChar( aTargetUrl, cChar, true ) )
519                     eState = STATE_ERROR;
520             break;
521 
522             case STATE_SHEETNAME:
523                 if( !lclAppendUrlChar( aSheetName, cChar, false ) )
524                     eState = STATE_ERROR;
525             break;
526 
527             case STATE_UNSUPPORTED:
528                 pcChar = pcEnd - 1;
529             break;
530 
531             case STATE_ERROR:
532             break;
533         }
534     }
535 
536     OSL_ENSURE( (eState != STATE_ERROR) && (pcChar == pcEnd),
537         OStringBuffer( "AddressConverter::parseBiffTargetUrl - parser error in target \"" ).
538         append( OUStringToOString( rBiffTargetUrl, RTL_TEXTENCODING_UTF8 ) ).append( '"' ).getStr() );
539     bool bParserOk = (eState != STATE_ERROR) && (eState != STATE_UNSUPPORTED) && (pcChar == pcEnd);
540 
541     if( bParserOk )
542     {
543         orTargetUrl = aTargetUrl.makeStringAndClear();
544         orSheetName = aSheetName.makeStringAndClear();
545     }
546     else
547     {
548         orClassName = orTargetUrl = orSheetName = OUString();
549     }
550 
551     return bParserOk ? eTargetType : BIFF_TARGETTYPE_UNKNOWN;
552 }
553 
554 // ----------------------------------------------------------------------------
555 
556 bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
557 {
558     bool bValid = (0 <= nCol) && (nCol <= maMaxPos.Column);
559     if( !bValid && bTrackOverflow )
560         mbColOverflow = true;
561     return bValid;
562 }
563 
564 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
565 {
566     bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row);
567     if( !bValid && bTrackOverflow )
568         mbRowOverflow = true;
569     return bValid;
570 }
571 
572 bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
573 {
574     bool bValid = (0 <= nSheet) && (nSheet <= maMaxPos.Sheet);
575     if( !bValid && bTrackOverflow )
576         mbTabOverflow |= (nSheet > maMaxPos.Sheet);  // do not warn for deleted refs (-1)
577     return bValid;
578 }
579 
580 // ----------------------------------------------------------------------------
581 
582 bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow )
583 {
584     return
585         checkTab( rAddress.Sheet, bTrackOverflow ) &&
586         checkCol( rAddress.Column, bTrackOverflow ) &&
587         checkRow( rAddress.Row, bTrackOverflow );
588 }
589 
590 bool AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
591         const OUString& rString, sal_Int16 nSheet )
592 {
593     orAddress.Sheet = nSheet;
594     return parseOoxAddress2d( orAddress.Column, orAddress.Row, rString );
595 }
596 
597 bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
598         const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
599 {
600     return
601         convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
602         checkCellAddress( orAddress, bTrackOverflow );
603 }
604 
605 CellAddress AddressConverter::createValidCellAddress(
606         const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
607 {
608     CellAddress aAddress;
609     if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
610     {
611         aAddress.Sheet  = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
612         aAddress.Column = ::std::min( aAddress.Column, maMaxPos.Column );
613         aAddress.Row    = ::std::min( aAddress.Row, maMaxPos.Row );
614     }
615     return aAddress;
616 }
617 
618 void AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
619         const BinAddress& rBinAddress, sal_Int16 nSheet )
620 {
621     orAddress.Sheet  = nSheet;
622     orAddress.Column = rBinAddress.mnCol;
623     orAddress.Row    = rBinAddress.mnRow;
624 }
625 
626 bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
627         const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
628 {
629     convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
630     return checkCellAddress( orAddress, bTrackOverflow );
631 }
632 
633 CellAddress AddressConverter::createValidCellAddress(
634         const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
635 {
636     CellAddress aAddress;
637     if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
638     {
639         aAddress.Sheet  = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
640         aAddress.Column = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, maMaxPos.Column );
641         aAddress.Row    = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, maMaxPos.Row );
642     }
643     return aAddress;
644 }
645 
646 // ----------------------------------------------------------------------------
647 
648 bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bAllowOverflow, bool bTrackOverflow )
649 {
650     return
651         (checkCol( rRange.EndColumn, bTrackOverflow ) || bAllowOverflow) &&     // bAllowOverflow after checkCol to track overflow!
652         (checkRow( rRange.EndRow, bTrackOverflow ) || bAllowOverflow) &&        // bAllowOverflow after checkRow to track overflow!
653         checkTab( rRange.Sheet, bTrackOverflow ) &&
654         checkCol( rRange.StartColumn, bTrackOverflow ) &&
655         checkRow( rRange.StartRow, bTrackOverflow );
656 }
657 
658 bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bAllowOverflow, bool bTrackOverflow )
659 {
660     if( orRange.StartColumn > orRange.EndColumn )
661         ::std::swap( orRange.StartColumn, orRange.EndColumn );
662     if( orRange.StartRow > orRange.EndRow )
663         ::std::swap( orRange.StartRow, orRange.EndRow );
664     if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
665         return false;
666     if( orRange.EndColumn > maMaxPos.Column )
667         orRange.EndColumn = maMaxPos.Column;
668     if( orRange.EndRow > maMaxPos.Row )
669         orRange.EndRow = maMaxPos.Row;
670     return true;
671 }
672 
673 bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
674         const OUString& rString, sal_Int16 nSheet )
675 {
676     orRange.Sheet = nSheet;
677     return parseOoxRange2d( orRange.StartColumn, orRange.StartRow, orRange.EndColumn, orRange.EndRow, rString );
678 }
679 
680 bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
681         const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
682 {
683     return
684         convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
685         validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
686 }
687 
688 void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
689         const BinRange& rBinRange, sal_Int16 nSheet )
690 {
691     orRange.Sheet       = nSheet;
692     orRange.StartColumn = rBinRange.maFirst.mnCol;
693     orRange.StartRow    = rBinRange.maFirst.mnRow;
694     orRange.EndColumn   = rBinRange.maLast.mnCol;
695     orRange.EndRow      = rBinRange.maLast.mnRow;
696 }
697 
698 bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
699         const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
700 {
701     convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
702     return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
703 }
704 
705 // ----------------------------------------------------------------------------
706 
707 bool AddressConverter::checkCellRangeList( const ApiCellRangeList& rRanges, bool bAllowOverflow, bool bTrackOverflow )
708 {
709     for( ApiCellRangeList::const_iterator aIt = rRanges.begin(), aEnd = rRanges.end(); aIt != aEnd; ++aIt )
710         if( !checkCellRange( *aIt, bAllowOverflow, bTrackOverflow ) )
711             return false;
712     return true;
713 }
714 
715 void AddressConverter::validateCellRangeList( ApiCellRangeList& orRanges, bool bTrackOverflow )
716 {
717     for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
718         if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
719             orRanges.erase( orRanges.begin() + nIndex - 1 );
720 }
721 
722 void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
723         const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
724 {
725     sal_Int32 nPos = 0;
726     sal_Int32 nLen = rString.getLength();
727     CellRangeAddress aRange;
728     while( (0 <= nPos) && (nPos < nLen) )
729     {
730         OUString aToken = rString.getToken( 0, ' ', nPos );
731         if( (aToken.getLength() > 0) && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
732             orRanges.push_back( aRange );
733     }
734 }
735 
736 void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
737         const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
738 {
739     CellRangeAddress aRange;
740     for( BinRangeList::const_iterator aIt = rBinRanges.begin(), aEnd = rBinRanges.end(); aIt != aEnd; ++aIt )
741         if( convertToCellRange( aRange, *aIt, nSheet, true, bTrackOverflow ) )
742             orRanges.push_back( aRange );
743 }
744 
745 // private --------------------------------------------------------------------
746 
747 void AddressConverter::ControlCharacters::set(
748         sal_Unicode cThisWorkbook, sal_Unicode cExternal,
749         sal_Unicode cThisSheet, sal_Unicode cInternal, sal_Unicode cSameSheet )
750 {
751     mcThisWorkbook = cThisWorkbook;
752     mcExternal     = cExternal;
753     mcThisSheet    = cThisSheet;
754     mcInternal     = cInternal;
755     mcSameSheet    = cSameSheet;
756 }
757 
758 void AddressConverter::initializeMaxPos(
759         sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
760 {
761     maMaxXlsPos.Sheet  = nMaxXlsTab;
762     maMaxXlsPos.Column = nMaxXlsCol;
763     maMaxXlsPos.Row    = nMaxXlsRow;
764 
765     // maximum cell position in Calc
766     try
767     {
768         Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
769         Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
770         CellRangeAddress aRange = xAddressable->getRangeAddress();
771         maMaxApiPos = CellAddress( API_MAXTAB, aRange.EndColumn, aRange.EndRow );
772         maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
773     }
774     catch( Exception& )
775     {
776         OSL_ENSURE( false, "AddressConverter::AddressConverter - cannot get sheet limits" );
777     }
778 }
779 
780 // ============================================================================
781 
782 } // namespace xls
783 } // namespace oox
784