1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "addressconverter.hxx"
22 #include <com/sun/star/container/XIndexAccess.hpp>
23 #include <com/sun/star/sheet/XCellRangeAddressable.hpp>
24 #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
25 #include <osl/diagnose.h>
26 #include <rtl/strbuf.hxx>
27 #include <rtl/ustrbuf.hxx>
28 #include <oox/core/filterbase.hxx>
29 #include <oox/helper/containerhelper.hxx>
30 #include "biffinputstream.hxx"
35 using namespace ::com::sun::star::container
;
36 using namespace ::com::sun::star::sheet
;
37 using namespace ::com::sun::star::table
;
38 using namespace ::com::sun::star::uno
;
42 //! TODO: this limit may change, is there a way to obtain it via API?
43 const sal_Int16 API_MAXTAB
= MAXTAB
;
45 const sal_Int32 OOX_MAXCOL
= static_cast< sal_Int32
>( (1 << 14) - 1 );
46 const sal_Int32 OOX_MAXROW
= static_cast< sal_Int32
>( (1 << 20) - 1 );
47 const sal_Int16 OOX_MAXTAB
= static_cast< sal_Int16
>( (1 << 15) - 1 );
49 const sal_Int32 BIFF2_MAXCOL
= 255;
50 const sal_Int32 BIFF2_MAXROW
= 16383;
51 const sal_Int16 BIFF2_MAXTAB
= 0;
53 const sal_Int32 BIFF3_MAXCOL
= BIFF2_MAXCOL
;
54 const sal_Int32 BIFF3_MAXROW
= BIFF2_MAXROW
;
55 const sal_Int16 BIFF3_MAXTAB
= BIFF2_MAXTAB
;
57 const sal_Int32 BIFF4_MAXCOL
= BIFF3_MAXCOL
;
58 const sal_Int32 BIFF4_MAXROW
= BIFF3_MAXROW
;
59 const sal_Int16 BIFF4_MAXTAB
= 32767;
61 const sal_Int32 BIFF5_MAXCOL
= BIFF4_MAXCOL
;
62 const sal_Int32 BIFF5_MAXROW
= BIFF4_MAXROW
;
63 const sal_Int16 BIFF5_MAXTAB
= BIFF4_MAXTAB
;
65 const sal_Int32 BIFF8_MAXCOL
= BIFF5_MAXCOL
;
66 const sal_Int32 BIFF8_MAXROW
= 65535;
67 const sal_Int16 BIFF8_MAXTAB
= BIFF5_MAXTAB
;
71 CellAddress
ApiCellRangeList::getBaseAddress() const
73 if( mvAddresses
.empty() )
75 return CellAddress( mvAddresses
.front().Sheet
, mvAddresses
.front().StartColumn
, mvAddresses
.front().StartRow
);
78 com::sun::star::uno::Sequence
< CellRangeAddress
> ApiCellRangeList::toSequence() const
80 return ContainerHelper::vectorToSequence( mvAddresses
);
83 void BinAddress::read( SequenceInputStream
& rStrm
)
85 mnRow
= rStrm
.readInt32();
86 mnCol
= rStrm
.readInt32();
89 void BinAddress::read( BiffInputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
)
91 mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
92 mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
95 void BinRange::read( SequenceInputStream
& rStrm
)
97 maFirst
.mnRow
= rStrm
.readInt32();
98 maLast
.mnRow
= rStrm
.readInt32();
99 maFirst
.mnCol
= rStrm
.readInt32();
100 maLast
.mnCol
= rStrm
.readInt32();
103 void BinRange::read( BiffInputStream
& rStrm
, bool bCol16Bit
, bool bRow32Bit
)
105 maFirst
.mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
106 maLast
.mnRow
= bRow32Bit
? rStrm
.readInt32() : rStrm
.readuInt16();
107 maFirst
.mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
108 maLast
.mnCol
= bCol16Bit
? rStrm
.readuInt16() : rStrm
.readuInt8();
111 void BinRangeList::read( SequenceInputStream
& rStrm
)
113 sal_Int32 nCount
= rStrm
.readInt32();
114 mvRanges
.resize( getLimitedValue
< size_t, sal_Int64
>( nCount
, 0, rStrm
.getRemaining() / 16 ) );
115 for( ::std::vector
< BinRange
>::iterator aIt
= mvRanges
.begin(), aEnd
= mvRanges
.end(); aIt
!= aEnd
; ++aIt
)
119 AddressConverter::AddressConverter( const WorkbookHelper
& rHelper
) :
120 WorkbookHelper( rHelper
),
121 mbColOverflow( false ),
122 mbRowOverflow( false ),
123 mbTabOverflow( false )
125 maDConChars
.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
126 switch( getFilterType() )
129 initializeMaxPos( OOX_MAXTAB
, OOX_MAXCOL
, OOX_MAXROW
);
130 maLinkChars
.set( 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF );
132 case FILTER_BIFF
: switch( getBiff() )
135 initializeMaxPos( BIFF2_MAXTAB
, BIFF2_MAXCOL
, BIFF2_MAXROW
);
136 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
139 initializeMaxPos( BIFF3_MAXTAB
, BIFF3_MAXCOL
, BIFF3_MAXROW
);
140 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
143 initializeMaxPos( BIFF4_MAXTAB
, BIFF4_MAXCOL
, BIFF4_MAXROW
);
144 maLinkChars
.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
147 initializeMaxPos( BIFF5_MAXTAB
, BIFF5_MAXCOL
, BIFF5_MAXROW
);
148 maLinkChars
.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
151 initializeMaxPos( BIFF8_MAXTAB
, BIFF8_MAXCOL
, BIFF8_MAXROW
);
152 maLinkChars
.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
155 initializeMaxPos( 0, 0, 0 );
156 maLinkChars
.set( 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF );
161 initializeMaxPos( 0, 0, 0 );
162 maLinkChars
.set( 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF );
167 bool AddressConverter::parseOoxAddress2d(
168 sal_Int32
& ornColumn
, sal_Int32
& ornRow
,
169 const OUString
& rString
, sal_Int32 nStart
, sal_Int32 nLength
)
171 ornColumn
= ornRow
= 0;
172 if( (nStart
< 0) || (nStart
>= rString
.getLength()) || (nLength
< 2) )
175 const sal_Unicode
* pcChar
= rString
.getStr() + nStart
;
176 const sal_Unicode
* pcEndChar
= pcChar
+ ::std::min( nLength
, rString
.getLength() - nStart
);
178 enum { STATE_COL
, STATE_ROW
} eState
= STATE_COL
;
179 while( pcChar
< pcEndChar
)
181 sal_Unicode cChar
= *pcChar
;
186 if( ('a' <= cChar
) && (cChar
<= 'z') )
187 (cChar
-= 'a') += 'A';
188 if( ('A' <= cChar
) && (cChar
<= 'Z') )
190 /* Return, if 1-based column index is already 6 characters
191 long (12356631 is column index for column AAAAAA). */
192 if( ornColumn
>= 12356631 )
194 (ornColumn
*= 26) += (cChar
- 'A' + 1);
196 else if( ornColumn
> 0 )
208 if( ('0' <= cChar
) && (cChar
<= '9') )
210 // return, if 1-based row is already 9 digits long
211 if( ornRow
>= 100000000 )
213 (ornRow
*= 10) += (cChar
- '0');
225 return (ornColumn
>= 0) && (ornRow
>= 0);
228 bool AddressConverter::parseOoxAddress2d( sal_Int32
& ornColumn
, sal_Int32
& ornRow
, const char* pStr
)
230 ornColumn
= ornRow
= 0;
232 enum { STATE_COL
, STATE_ROW
} eState
= STATE_COL
;
241 if( ('a' <= cChar
) && (cChar
<= 'z') )
242 (cChar
-= 'a') += 'A';
243 if( ('A' <= cChar
) && (cChar
<= 'Z') )
245 /* Return, if 1-based column index is already 6 characters
246 long (12356631 is column index for column AAAAAA). */
247 if( ornColumn
>= 12356631 )
249 (ornColumn
*= 26) += (cChar
- 'A' + 1);
251 else if( ornColumn
> 0 )
263 if( ('0' <= cChar
) && (cChar
<= '9') )
265 // return, if 1-based row is already 9 digits long
266 if( ornRow
>= 100000000 )
268 (ornRow
*= 10) += (cChar
- '0');
280 return (ornColumn
>= 0) && (ornRow
>= 0);
283 bool AddressConverter::parseOoxRange2d(
284 sal_Int32
& ornStartColumn
, sal_Int32
& ornStartRow
,
285 sal_Int32
& ornEndColumn
, sal_Int32
& ornEndRow
,
286 const OUString
& rString
, sal_Int32 nStart
, sal_Int32 nLength
)
288 ornStartColumn
= ornStartRow
= ornEndColumn
= ornEndRow
= 0;
289 if( (nStart
< 0) || (nStart
>= rString
.getLength()) || (nLength
< 2) )
292 sal_Int32 nEnd
= nStart
+ ::std::min( nLength
, rString
.getLength() - nStart
);
293 sal_Int32 nColonPos
= rString
.indexOf( ':', nStart
);
294 if( (nStart
< nColonPos
) && (nColonPos
+ 1 < nEnd
) )
297 parseOoxAddress2d( ornStartColumn
, ornStartRow
, rString
, nStart
, nColonPos
- nStart
) &&
298 parseOoxAddress2d( ornEndColumn
, ornEndRow
, rString
, nColonPos
+ 1, nLength
- nColonPos
- 1 );
301 if( parseOoxAddress2d( ornStartColumn
, ornStartRow
, rString
, nStart
, nLength
) )
303 ornEndColumn
= ornStartColumn
;
304 ornEndRow
= ornStartRow
;
311 bool AddressConverter::checkCol( sal_Int32 nCol
, bool bTrackOverflow
)
313 bool bValid
= (0 <= nCol
) && (nCol
<= maMaxPos
.Column
);
314 if( !bValid
&& bTrackOverflow
)
315 mbColOverflow
= true;
319 bool AddressConverter::checkRow( sal_Int32 nRow
, bool bTrackOverflow
)
321 bool bValid
= (0 <= nRow
) && (nRow
<= maMaxPos
.Row
);
322 if( !bValid
&& bTrackOverflow
)
323 mbRowOverflow
= true;
327 bool AddressConverter::checkTab( sal_Int16 nSheet
, bool bTrackOverflow
)
329 bool bValid
= (0 <= nSheet
) && (nSheet
<= maMaxPos
.Sheet
);
330 if( !bValid
&& bTrackOverflow
)
331 mbTabOverflow
|= (nSheet
> maMaxPos
.Sheet
); // do not warn for deleted refs (-1)
335 bool AddressConverter::checkCellAddress( const CellAddress
& rAddress
, bool bTrackOverflow
)
338 checkTab( rAddress
.Sheet
, bTrackOverflow
) &&
339 checkCol( rAddress
.Column
, bTrackOverflow
) &&
340 checkRow( rAddress
.Row
, bTrackOverflow
);
343 bool AddressConverter::convertToCellAddressUnchecked( CellAddress
& orAddress
,
344 const OUString
& rString
, sal_Int16 nSheet
)
346 orAddress
.Sheet
= nSheet
;
347 return parseOoxAddress2d( orAddress
.Column
, orAddress
.Row
, rString
);
350 bool AddressConverter::convertToCellAddressUnchecked(
351 com::sun::star::table::CellAddress
& orAddress
, const char* pStr
, sal_Int16 nSheet
)
353 orAddress
.Sheet
= nSheet
;
354 return parseOoxAddress2d(orAddress
.Column
, orAddress
.Row
, pStr
);
357 bool AddressConverter::convertToCellAddress( CellAddress
& orAddress
,
358 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
361 convertToCellAddressUnchecked( orAddress
, rString
, nSheet
) &&
362 checkCellAddress( orAddress
, bTrackOverflow
);
365 bool AddressConverter::convertToCellAddress(
366 com::sun::star::table::CellAddress
& rAddress
,
367 const char* pStr
, sal_Int16 nSheet
, bool bTrackOverflow
)
369 if (!convertToCellAddressUnchecked(rAddress
, pStr
, nSheet
))
372 return checkCellAddress(rAddress
, bTrackOverflow
);
375 CellAddress
AddressConverter::createValidCellAddress(
376 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
378 CellAddress aAddress
;
379 if( !convertToCellAddress( aAddress
, rString
, nSheet
, bTrackOverflow
) )
381 aAddress
.Sheet
= getLimitedValue
< sal_Int16
, sal_Int16
>( nSheet
, 0, maMaxPos
.Sheet
);
382 aAddress
.Column
= ::std::min( aAddress
.Column
, maMaxPos
.Column
);
383 aAddress
.Row
= ::std::min( aAddress
.Row
, maMaxPos
.Row
);
388 void AddressConverter::convertToCellAddressUnchecked( CellAddress
& orAddress
,
389 const BinAddress
& rBinAddress
, sal_Int16 nSheet
)
391 orAddress
.Sheet
= nSheet
;
392 orAddress
.Column
= rBinAddress
.mnCol
;
393 orAddress
.Row
= rBinAddress
.mnRow
;
396 bool AddressConverter::convertToCellAddress( CellAddress
& orAddress
,
397 const BinAddress
& rBinAddress
, sal_Int16 nSheet
, bool bTrackOverflow
)
399 convertToCellAddressUnchecked( orAddress
, rBinAddress
, nSheet
);
400 return checkCellAddress( orAddress
, bTrackOverflow
);
403 CellAddress
AddressConverter::createValidCellAddress(
404 const BinAddress
& rBinAddress
, sal_Int16 nSheet
, bool bTrackOverflow
)
406 CellAddress aAddress
;
407 if( !convertToCellAddress( aAddress
, rBinAddress
, nSheet
, bTrackOverflow
) )
409 aAddress
.Sheet
= getLimitedValue
< sal_Int16
, sal_Int16
>( nSheet
, 0, maMaxPos
.Sheet
);
410 aAddress
.Column
= getLimitedValue
< sal_Int32
, sal_Int32
>( rBinAddress
.mnCol
, 0, maMaxPos
.Column
);
411 aAddress
.Row
= getLimitedValue
< sal_Int32
, sal_Int32
>( rBinAddress
.mnRow
, 0, maMaxPos
.Row
);
416 bool AddressConverter::checkCellRange( const CellRangeAddress
& rRange
, bool bAllowOverflow
, bool bTrackOverflow
)
419 (checkCol( rRange
.EndColumn
, bTrackOverflow
) || bAllowOverflow
) && // bAllowOverflow after checkCol to track overflow!
420 (checkRow( rRange
.EndRow
, bTrackOverflow
) || bAllowOverflow
) && // bAllowOverflow after checkRow to track overflow!
421 checkTab( rRange
.Sheet
, bTrackOverflow
) &&
422 checkCol( rRange
.StartColumn
, bTrackOverflow
) &&
423 checkRow( rRange
.StartRow
, bTrackOverflow
);
426 bool AddressConverter::validateCellRange( CellRangeAddress
& orRange
, bool bAllowOverflow
, bool bTrackOverflow
)
428 if( orRange
.StartColumn
> orRange
.EndColumn
)
429 ::std::swap( orRange
.StartColumn
, orRange
.EndColumn
);
430 if( orRange
.StartRow
> orRange
.EndRow
)
431 ::std::swap( orRange
.StartRow
, orRange
.EndRow
);
432 if( !checkCellRange( orRange
, bAllowOverflow
, bTrackOverflow
) )
434 if( orRange
.EndColumn
> maMaxPos
.Column
)
435 orRange
.EndColumn
= maMaxPos
.Column
;
436 if( orRange
.EndRow
> maMaxPos
.Row
)
437 orRange
.EndRow
= maMaxPos
.Row
;
441 bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress
& orRange
,
442 const OUString
& rString
, sal_Int16 nSheet
)
444 orRange
.Sheet
= nSheet
;
445 return parseOoxRange2d( orRange
.StartColumn
, orRange
.StartRow
, orRange
.EndColumn
, orRange
.EndRow
, rString
);
448 bool AddressConverter::convertToCellRange( CellRangeAddress
& orRange
,
449 const OUString
& rString
, sal_Int16 nSheet
, bool bAllowOverflow
, bool bTrackOverflow
)
452 convertToCellRangeUnchecked( orRange
, rString
, nSheet
) &&
453 validateCellRange( orRange
, bAllowOverflow
, bTrackOverflow
);
456 void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress
& orRange
,
457 const BinRange
& rBinRange
, sal_Int16 nSheet
)
459 orRange
.Sheet
= nSheet
;
460 orRange
.StartColumn
= rBinRange
.maFirst
.mnCol
;
461 orRange
.StartRow
= rBinRange
.maFirst
.mnRow
;
462 orRange
.EndColumn
= rBinRange
.maLast
.mnCol
;
463 orRange
.EndRow
= rBinRange
.maLast
.mnRow
;
466 bool AddressConverter::convertToCellRange( CellRangeAddress
& orRange
,
467 const BinRange
& rBinRange
, sal_Int16 nSheet
, bool bAllowOverflow
, bool bTrackOverflow
)
469 convertToCellRangeUnchecked( orRange
, rBinRange
, nSheet
);
470 return validateCellRange( orRange
, bAllowOverflow
, bTrackOverflow
);
473 void AddressConverter::validateCellRangeList( ApiCellRangeList
& orRanges
, bool bTrackOverflow
)
475 for( size_t nIndex
= orRanges
.size(); nIndex
> 0; --nIndex
)
476 if( !validateCellRange( orRanges
[ nIndex
- 1 ], true, bTrackOverflow
) )
477 orRanges
.erase( orRanges
.begin() + nIndex
- 1 );
480 void AddressConverter::convertToCellRangeList( ApiCellRangeList
& orRanges
,
481 const OUString
& rString
, sal_Int16 nSheet
, bool bTrackOverflow
)
484 sal_Int32 nLen
= rString
.getLength();
485 CellRangeAddress aRange
;
486 while( (0 <= nPos
) && (nPos
< nLen
) )
488 OUString aToken
= rString
.getToken( 0, ' ', nPos
);
489 if( !aToken
.isEmpty() && convertToCellRange( aRange
, aToken
, nSheet
, true, bTrackOverflow
) )
490 orRanges
.push_back( aRange
);
494 void AddressConverter::convertToCellRangeList( ApiCellRangeList
& orRanges
,
495 const BinRangeList
& rBinRanges
, sal_Int16 nSheet
, bool bTrackOverflow
)
497 CellRangeAddress aRange
;
498 for( ::std::vector
< BinRange
>::const_iterator aIt
= rBinRanges
.begin(), aEnd
= rBinRanges
.end(); aIt
!= aEnd
; ++aIt
)
499 if( convertToCellRange( aRange
, *aIt
, nSheet
, true, bTrackOverflow
) )
500 orRanges
.push_back( aRange
);
503 // private --------------------------------------------------------------------
505 void AddressConverter::ControlCharacters::set(
506 sal_Unicode cThisWorkbook
, sal_Unicode cExternal
,
507 sal_Unicode cThisSheet
, sal_Unicode cInternal
, sal_Unicode cSameSheet
)
509 mcThisWorkbook
= cThisWorkbook
;
510 mcExternal
= cExternal
;
511 mcThisSheet
= cThisSheet
;
512 mcInternal
= cInternal
;
513 mcSameSheet
= cSameSheet
;
516 void AddressConverter::initializeMaxPos(
517 sal_Int16 nMaxXlsTab
, sal_Int32 nMaxXlsCol
, sal_Int32 nMaxXlsRow
)
519 maMaxXlsPos
.Sheet
= nMaxXlsTab
;
520 maMaxXlsPos
.Column
= nMaxXlsCol
;
521 maMaxXlsPos
.Row
= nMaxXlsRow
;
523 // maximum cell position in Calc
526 Reference
< XIndexAccess
> xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW
);
527 Reference
< XCellRangeAddressable
> xAddressable( xSheetsIA
->getByIndex( 0 ), UNO_QUERY_THROW
);
528 CellRangeAddress aRange
= xAddressable
->getRangeAddress();
529 maMaxApiPos
= CellAddress( API_MAXTAB
, aRange
.EndColumn
, aRange
.EndRow
);
530 maMaxPos
= getBaseFilter().isImportFilter() ? maMaxApiPos
: maMaxXlsPos
;
534 OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
541 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */