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