Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / sc / source / filter / oox / addressconverter.cxx
blob2abc37307f9043fec6931b8e92f683c3947ddb24
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <convuno.hxx>
26 #include <osl/diagnose.h>
27 #include <oox/core/filterbase.hxx>
28 #include <oox/helper/binaryinputstream.hxx>
30 namespace oox {
31 namespace xls {
33 using namespace ::com::sun::star::container;
34 using namespace ::com::sun::star::sheet;
35 using namespace ::com::sun::star::table;
36 using namespace ::com::sun::star::uno;
38 namespace {
40 //! TODO: this limit may change, is there a way to obtain it via API?
41 const sal_Int16 API_MAXTAB = MAXTAB;
43 const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
44 const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
45 const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
47 } // namespace
50 void BinAddress::read( SequenceInputStream& rStrm )
52 mnRow = rStrm.readInt32();
53 mnCol = rStrm.readInt32();
56 void BinRange::read( SequenceInputStream& rStrm )
58 maFirst.mnRow = rStrm.readInt32();
59 maLast.mnRow = rStrm.readInt32();
60 maFirst.mnCol = rStrm.readInt32();
61 maLast.mnCol = rStrm.readInt32();
64 void BinRangeList::read( SequenceInputStream& rStrm )
66 sal_Int32 nCount = rStrm.readInt32();
67 mvRanges.resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) );
68 for( auto& rRange : mvRanges )
69 rRange.read( rStrm );
72 AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
73 WorkbookHelper( rHelper ),
74 mbColOverflow( false ),
75 mbRowOverflow( false ),
76 mbTabOverflow( false )
78 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
81 bool AddressConverter::parseOoxAddress2d(
82 sal_Int32& ornColumn, sal_Int32& ornRow,
83 const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
85 ornColumn = ornRow = 0;
86 if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
87 return false;
89 const sal_Unicode* pcChar = rString.getStr() + nStart;
90 const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
92 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
93 while( pcChar < pcEndChar )
95 sal_Unicode cChar = *pcChar;
96 switch( eState )
98 case STATE_COL:
100 if( ('a' <= cChar) && (cChar <= 'z') )
101 cChar = (cChar - 'a') + 'A';
102 if( ('A' <= cChar) && (cChar <= 'Z') )
104 /* Return, if 1-based column index is already 6 characters
105 long (12356631 is column index for column AAAAAA). */
106 if( ornColumn >= 12356631 )
107 return false;
108 ornColumn = (ornColumn * 26) + (cChar - 'A' + 1);
110 else if( ornColumn > 0 )
112 --pcChar;
113 eState = STATE_ROW;
115 else
116 return false;
118 break;
120 case STATE_ROW:
122 if( ('0' <= cChar) && (cChar <= '9') )
124 // return, if 1-based row is already 9 digits long
125 if( ornRow >= 100000000 )
126 return false;
127 ornRow = (ornRow * 10) + (cChar - '0');
129 else
130 return false;
132 break;
134 ++pcChar;
137 --ornColumn;
138 --ornRow;
139 return (ornColumn >= 0) && (ornRow >= 0);
142 bool AddressConverter::parseOoxAddress2d( sal_Int32& ornColumn, sal_Int32& ornRow, const char* pStr )
144 ornColumn = ornRow = 0;
146 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
148 while (*pStr)
150 char cChar = *pStr;
151 switch( eState )
153 case STATE_COL:
155 if( ('a' <= cChar) && (cChar <= 'z') )
156 cChar = (cChar - 'a') + 'A';
157 if( ('A' <= cChar) && (cChar <= 'Z') )
159 /* Return, if 1-based column index is already 6 characters
160 long (12356631 is column index for column AAAAAA). */
161 if( ornColumn >= 12356631 )
162 return false;
163 ornColumn = (ornColumn * 26) + (cChar - 'A' + 1);
165 else if( ornColumn > 0 )
167 --pStr;
168 eState = STATE_ROW;
170 else
171 return false;
173 break;
175 case STATE_ROW:
177 if( ('0' <= cChar) && (cChar <= '9') )
179 // return, if 1-based row is already 9 digits long
180 if( ornRow >= 100000000 )
181 return false;
182 ornRow = (ornRow * 10) + (cChar - '0');
184 else
185 return false;
187 break;
189 ++pStr;
192 --ornColumn;
193 --ornRow;
194 return (ornColumn >= 0) && (ornRow >= 0);
197 bool AddressConverter::parseOoxRange2d(
198 sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
199 sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
200 const OUString& rString, sal_Int32 nStart )
202 ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
203 if( (nStart < 0) || (nStart >= rString.getLength()) )
204 return false;
206 sal_Int32 nEnd = nStart + ( rString.getLength() - nStart );
207 sal_Int32 nColonPos = rString.indexOf( ':', nStart );
208 if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
210 return
211 parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
212 parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, SAL_MAX_INT32 - nColonPos - 1 );
215 if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart ) )
217 ornEndColumn = ornStartColumn;
218 ornEndRow = ornStartRow;
219 return true;
222 return false;
225 bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
227 bool bValid = (0 <= nCol) && ( nCol <= maMaxPos.Col() );
228 if( !bValid && bTrackOverflow )
229 mbColOverflow = true;
230 return bValid;
233 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
235 bool bValid = (0 <= nRow) && ( nRow <= maMaxPos.Row() );
236 if( !bValid && bTrackOverflow )
237 mbRowOverflow = true;
238 return bValid;
241 bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
243 bool bValid = (0 <= nSheet) && ( nSheet <= maMaxPos.Tab() );
244 if( !bValid && bTrackOverflow )
245 mbTabOverflow |= ( nSheet > maMaxPos.Tab() ); // do not warn for deleted refs (-1)
246 return bValid;
249 bool AddressConverter::checkCellAddress( const ScAddress& rAddress, bool bTrackOverflow )
251 return
252 checkTab( rAddress.Tab(), bTrackOverflow ) &&
253 checkCol( rAddress.Col(), bTrackOverflow ) &&
254 checkRow( rAddress.Row(), bTrackOverflow );
257 bool AddressConverter::convertToCellAddressUnchecked( ScAddress& orAddress,
258 const OUString& rString, sal_Int16 nSheet )
260 orAddress.SetTab(nSheet);
261 sal_Int32 nCol = 0;
262 sal_Int32 nRow = 0;
263 bool bRes = parseOoxAddress2d( nCol, nRow, rString );
264 orAddress.SetRow(nRow);
265 orAddress.SetCol(nCol);
267 return bRes;
270 bool AddressConverter::convertToCellAddressUnchecked(
271 ScAddress& orAddress, const char* pStr, sal_Int16 nSheet )
273 orAddress.SetTab(nSheet);
274 sal_Int32 nCol = 0;
275 sal_Int32 nRow = 0;
276 bool bRes = parseOoxAddress2d(nCol, nRow, pStr);
277 orAddress.SetRow(nRow);
278 orAddress.SetCol(nCol);
280 return bRes;
283 bool AddressConverter::convertToCellAddress( ScAddress& orAddress,
284 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
286 return
287 convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
288 checkCellAddress( orAddress, bTrackOverflow );
291 bool AddressConverter::convertToCellAddress(
292 ScAddress& rAddress,
293 const char* pStr, sal_Int16 nSheet, bool bTrackOverflow )
295 if (!convertToCellAddressUnchecked(rAddress, pStr, nSheet))
296 return false;
298 return checkCellAddress(rAddress, bTrackOverflow);
301 ScAddress AddressConverter::createValidCellAddress(
302 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
304 ScAddress aAddress( 0, 0, 0 );
305 if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
307 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
308 aAddress.SetCol( ::std::min( aAddress.Col(), maMaxPos.Col() ) );
309 aAddress.SetRow( ::std::min( aAddress.Row(), maMaxPos.Row() ) );
311 return aAddress;
314 void AddressConverter::convertToCellAddressUnchecked( ScAddress& orAddress,
315 const BinAddress& rBinAddress, sal_Int16 nSheet )
317 orAddress.SetTab(nSheet);
318 orAddress.SetCol(rBinAddress.mnCol);
319 orAddress.SetRow(rBinAddress.mnRow);
322 bool AddressConverter::convertToCellAddress( ScAddress& orAddress,
323 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
325 convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
326 return checkCellAddress( orAddress, bTrackOverflow );
329 ScAddress AddressConverter::createValidCellAddress(
330 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
332 ScAddress aAddress ( 0, 0, 0 );
333 if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
335 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
336 aAddress.SetCol( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, sal_Int32( maMaxPos.Col() ) ) );
337 aAddress.SetRow( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, sal_Int32( maMaxPos.Row() ) ) );
339 return aAddress;
342 bool AddressConverter::checkCellRange( const ScRange& rRange, bool bAllowOverflow, bool bTrackOverflow )
344 return
345 (checkCol( rRange.aEnd.Col(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
346 (checkRow( rRange.aEnd.Row(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
347 checkTab( rRange.aStart.Tab(), bTrackOverflow ) &&
348 checkCol( rRange.aStart.Col(), bTrackOverflow ) &&
349 checkRow( rRange.aStart.Row(), bTrackOverflow );
352 bool AddressConverter::validateCellRange( ScRange& orRange, bool bAllowOverflow, bool bTrackOverflow )
354 if( orRange.aStart.Col() > orRange.aEnd.Col() )
356 SCCOL nCol = orRange.aStart.Col();
357 orRange.aStart.SetCol( orRange.aEnd.Col() );
358 orRange.aEnd.SetCol( nCol );
360 if( orRange.aStart.Row() > orRange.aEnd.Row() )
362 SCROW nRow = orRange.aStart.Row();
363 orRange.aStart.SetRow( orRange.aEnd.Row() );
364 orRange.aEnd.SetRow( nRow );
366 if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
367 return false;
368 if( orRange.aEnd.Col() > maMaxPos.Col() )
369 orRange.aEnd.SetCol( maMaxPos.Col() );
370 if( orRange.aEnd.Row() > maMaxPos.Row() )
371 orRange.aEnd.SetRow( maMaxPos.Row() );
372 return true;
375 bool AddressConverter::convertToCellRangeUnchecked( ScRange& orRange,
376 const OUString& rString, sal_Int16 nSheet )
378 orRange.aStart.SetTab( nSheet );
379 orRange.aEnd.SetTab( nSheet );
380 sal_Int32 aStartCol = orRange.aStart.Col();
381 sal_Int32 aStartRow = orRange.aStart.Row();
382 sal_Int32 aEndCol = orRange.aEnd.Col();
383 sal_Int32 aEndRow = orRange.aEnd.Row();
384 bool bReturnValue = parseOoxRange2d( aStartCol, aStartRow, aEndCol, aEndRow, rString );
385 orRange.aStart.SetCol( aStartCol );
386 orRange.aStart.SetRow( aStartRow );
387 orRange.aEnd.SetCol( aEndCol );
388 orRange.aEnd.SetRow( aEndRow );
389 return bReturnValue;
392 bool AddressConverter::convertToCellRange( ScRange& orRange,
393 const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
395 return
396 convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
397 validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
400 void AddressConverter::convertToCellRangeUnchecked( ScRange& orRange,
401 const BinRange& rBinRange, sal_Int16 nSheet )
403 orRange.aStart.SetTab( nSheet );
404 orRange.aStart.SetCol( rBinRange.maFirst.mnCol );
405 orRange.aStart.SetRow( rBinRange.maFirst.mnRow );
406 orRange.aEnd.SetTab( nSheet );
407 orRange.aEnd.SetCol( rBinRange.maLast.mnCol );
408 orRange.aEnd.SetRow( rBinRange.maLast.mnRow );
411 bool AddressConverter::convertToCellRange( ScRange& orRange,
412 const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
414 convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
415 return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
418 void AddressConverter::validateCellRangeList( ScRangeList& orRanges, bool bTrackOverflow )
420 for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
421 if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
422 orRanges.Remove( nIndex - 1 );
425 void AddressConverter::convertToCellRangeList( ScRangeList& orRanges,
426 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
428 sal_Int32 nPos = 0;
429 sal_Int32 nLen = rString.getLength();
430 ScRange aRange;
431 while( (0 <= nPos) && (nPos < nLen) )
433 OUString aToken = rString.getToken( 0, ' ', nPos );
434 if( !aToken.isEmpty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
435 orRanges.push_back(aRange);
439 void AddressConverter::convertToCellRangeList( ScRangeList& orRanges,
440 const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
442 ScRange aRange;
443 for( const auto& rBinRange : rBinRanges )
444 if( convertToCellRange( aRange, rBinRange, nSheet, true, bTrackOverflow ) )
445 orRanges.push_back( aRange );
448 Sequence<CellRangeAddress> AddressConverter::toApiSequence(const ScRangeList& orRanges)
450 const size_t nSize = orRanges.size();
451 Sequence<CellRangeAddress> aRangeSequence(nSize);
452 CellRangeAddress* pApiRanges = aRangeSequence.getArray();
453 for (size_t i = 0; i < nSize; ++i)
455 ScUnoConversion::FillApiRange(pApiRanges[i], orRanges[i]);
457 return aRangeSequence;
460 // private --------------------------------------------------------------------
462 void AddressConverter::initializeMaxPos(
463 sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
465 maMaxXlsPos.Set( nMaxXlsCol, nMaxXlsRow, nMaxXlsTab);
467 // maximum cell position in Calc
470 Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
471 Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
472 CellRangeAddress aRange = xAddressable->getRangeAddress();
473 maMaxApiPos = ScAddress( aRange.EndColumn, aRange.EndRow, API_MAXTAB );
474 maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
476 catch( Exception& )
478 OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
482 } // namespace xls
483 } // namespace oox
485 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */