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