nss: upgrade to release 3.73
[LibreOffice.git] / sc / source / filter / oox / addressconverter.cxx
blobb3fc5b16722db39b3d359f77da7a3623718c3a7d
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::xls {
32 using namespace ::com::sun::star::container;
33 using namespace ::com::sun::star::sheet;
34 using namespace ::com::sun::star::table;
35 using namespace ::com::sun::star::uno;
37 namespace {
39 //! TODO: this limit may change, is there a way to obtain it via API?
40 const sal_Int16 API_MAXTAB = MAXTAB;
42 const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
43 const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
44 const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
46 } // namespace
49 void BinAddress::read( SequenceInputStream& rStrm )
51 mnRow = rStrm.readInt32();
52 mnCol = rStrm.readInt32();
55 void BinRange::read( SequenceInputStream& rStrm )
57 maFirst.mnRow = rStrm.readInt32();
58 maLast.mnRow = rStrm.readInt32();
59 maFirst.mnCol = rStrm.readInt32();
60 maLast.mnCol = rStrm.readInt32();
63 void BinRangeList::read( SequenceInputStream& rStrm )
65 sal_Int32 nCount = rStrm.readInt32();
66 mvRanges.resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) );
67 for( auto& rRange : mvRanges )
68 rRange.read( rStrm );
71 AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
72 WorkbookHelper( rHelper ),
73 mbColOverflow( false ),
74 mbRowOverflow( false ),
75 mbTabOverflow( false )
77 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
80 bool AddressConverter::parseOoxAddress2d(
81 sal_Int32& ornColumn, sal_Int32& ornRow,
82 const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
84 ornColumn = ornRow = 0;
85 if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
86 return false;
88 const sal_Unicode* pcChar = rString.getStr() + nStart;
89 const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
91 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
92 while( pcChar < pcEndChar )
94 sal_Unicode cChar = *pcChar;
95 switch( eState )
97 case STATE_COL:
99 if( ('a' <= cChar) && (cChar <= 'z') )
100 cChar = (cChar - 'a') + 'A';
101 if( ('A' <= cChar) && (cChar <= 'Z') )
103 /* Return, if 1-based column index is already 6 characters
104 long (12356631 is column index for column AAAAAA). */
105 if( ornColumn >= 12356631 )
106 return false;
107 ornColumn = (ornColumn * 26) + (cChar - 'A' + 1);
109 else if( ornColumn > 0 )
111 --pcChar;
112 eState = STATE_ROW;
114 else
115 return false;
117 break;
119 case STATE_ROW:
121 if( ('0' <= cChar) && (cChar <= '9') )
123 // return, if 1-based row is already 9 digits long
124 if( ornRow >= 100000000 )
125 return false;
126 ornRow = (ornRow * 10) + (cChar - '0');
128 else
129 return false;
131 break;
133 ++pcChar;
136 --ornColumn;
137 --ornRow;
138 return (ornColumn >= 0) && (ornRow >= 0);
141 bool AddressConverter::parseOoxAddress2d( sal_Int32& ornColumn, sal_Int32& ornRow, const char* pStr )
143 ornColumn = ornRow = 0;
145 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
147 while (*pStr)
149 char cChar = *pStr;
150 switch( eState )
152 case STATE_COL:
154 if( ('a' <= cChar) && (cChar <= 'z') )
155 cChar = (cChar - 'a') + 'A';
156 if( ('A' <= cChar) && (cChar <= 'Z') )
158 /* Return, if 1-based column index is already 6 characters
159 long (12356631 is column index for column AAAAAA). */
160 if( ornColumn >= 12356631 )
161 return false;
162 ornColumn = (ornColumn * 26) + (cChar - 'A' + 1);
164 else if( ornColumn > 0 )
166 --pStr;
167 eState = STATE_ROW;
169 else
170 return false;
172 break;
174 case STATE_ROW:
176 if( ('0' <= cChar) && (cChar <= '9') )
178 // return, if 1-based row is already 9 digits long
179 if( ornRow >= 100000000 )
180 return false;
181 ornRow = (ornRow * 10) + (cChar - '0');
183 else
184 return false;
186 break;
188 ++pStr;
191 --ornColumn;
192 --ornRow;
193 return (ornColumn >= 0) && (ornRow >= 0);
196 bool AddressConverter::parseOoxRange2d(
197 sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
198 sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
199 const OUString& rString, sal_Int32 nStart )
201 ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
202 if( (nStart < 0) || (nStart >= rString.getLength()) )
203 return false;
205 sal_Int32 nEnd = nStart + ( rString.getLength() - nStart );
206 sal_Int32 nColonPos = rString.indexOf( ':', nStart );
207 if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
209 return
210 parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
211 parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, SAL_MAX_INT32 - nColonPos - 1 );
214 if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart ) )
216 ornEndColumn = ornStartColumn;
217 ornEndRow = ornStartRow;
218 return true;
221 return false;
224 bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
226 bool bValid = (0 <= nCol) && ( nCol <= maMaxPos.Col() );
227 if( !bValid && bTrackOverflow )
228 mbColOverflow = true;
229 return bValid;
232 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
234 bool bValid = (0 <= nRow) && ( nRow <= maMaxPos.Row() );
235 if( !bValid && bTrackOverflow )
236 mbRowOverflow = true;
237 return bValid;
240 bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
242 bool bValid = (0 <= nSheet) && ( nSheet <= maMaxPos.Tab() );
243 if( !bValid && bTrackOverflow )
244 mbTabOverflow |= ( nSheet > maMaxPos.Tab() ); // do not warn for deleted refs (-1)
245 return bValid;
248 bool AddressConverter::checkCellAddress( const ScAddress& rAddress, bool bTrackOverflow )
250 return
251 checkTab( rAddress.Tab(), bTrackOverflow ) &&
252 checkCol( rAddress.Col(), bTrackOverflow ) &&
253 checkRow( rAddress.Row(), bTrackOverflow );
256 bool AddressConverter::convertToCellAddressUnchecked( ScAddress& orAddress,
257 const OUString& rString, sal_Int16 nSheet )
259 orAddress.SetTab(nSheet);
260 sal_Int32 nCol = 0;
261 sal_Int32 nRow = 0;
262 bool bRes = parseOoxAddress2d( nCol, nRow, rString );
263 orAddress.SetRow(nRow);
264 orAddress.SetCol(nCol);
266 return bRes;
269 bool AddressConverter::convertToCellAddressUnchecked(
270 ScAddress& orAddress, const char* pStr, sal_Int16 nSheet )
272 orAddress.SetTab(nSheet);
273 sal_Int32 nCol = 0;
274 sal_Int32 nRow = 0;
275 bool bRes = parseOoxAddress2d(nCol, nRow, pStr);
276 orAddress.SetRow(nRow);
277 orAddress.SetCol(nCol);
279 return bRes;
282 bool AddressConverter::convertToCellAddress( ScAddress& orAddress,
283 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
285 return
286 convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
287 checkCellAddress( orAddress, bTrackOverflow );
290 bool AddressConverter::convertToCellAddress(
291 ScAddress& rAddress,
292 const char* pStr, sal_Int16 nSheet, bool bTrackOverflow )
294 if (!convertToCellAddressUnchecked(rAddress, pStr, nSheet))
295 return false;
297 return checkCellAddress(rAddress, bTrackOverflow);
300 ScAddress AddressConverter::createValidCellAddress(
301 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
303 ScAddress aAddress( 0, 0, 0 );
304 if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
306 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
307 aAddress.SetCol( ::std::min( aAddress.Col(), maMaxPos.Col() ) );
308 aAddress.SetRow( ::std::min( aAddress.Row(), maMaxPos.Row() ) );
310 return aAddress;
313 void AddressConverter::convertToCellAddressUnchecked( ScAddress& orAddress,
314 const BinAddress& rBinAddress, sal_Int16 nSheet )
316 orAddress.SetTab(nSheet);
317 orAddress.SetCol(rBinAddress.mnCol);
318 orAddress.SetRow(rBinAddress.mnRow);
321 bool AddressConverter::convertToCellAddress( ScAddress& orAddress,
322 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
324 convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
325 return checkCellAddress( orAddress, bTrackOverflow );
328 ScAddress AddressConverter::createValidCellAddress(
329 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
331 ScAddress aAddress ( 0, 0, 0 );
332 if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
334 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
335 aAddress.SetCol( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, sal_Int32( maMaxPos.Col() ) ) );
336 aAddress.SetRow( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, sal_Int32( maMaxPos.Row() ) ) );
338 return aAddress;
341 bool AddressConverter::checkCellRange( const ScRange& rRange, bool bAllowOverflow, bool bTrackOverflow )
343 return
344 (checkCol( rRange.aEnd.Col(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
345 (checkRow( rRange.aEnd.Row(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
346 checkTab( rRange.aStart.Tab(), bTrackOverflow ) &&
347 checkCol( rRange.aStart.Col(), bTrackOverflow ) &&
348 checkRow( rRange.aStart.Row(), bTrackOverflow );
351 bool AddressConverter::validateCellRange( ScRange& orRange, bool bAllowOverflow, bool bTrackOverflow )
353 if( orRange.aStart.Col() > orRange.aEnd.Col() )
355 SCCOL nCol = orRange.aStart.Col();
356 orRange.aStart.SetCol( orRange.aEnd.Col() );
357 orRange.aEnd.SetCol( nCol );
359 if( orRange.aStart.Row() > orRange.aEnd.Row() )
361 SCROW nRow = orRange.aStart.Row();
362 orRange.aStart.SetRow( orRange.aEnd.Row() );
363 orRange.aEnd.SetRow( nRow );
365 if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
366 return false;
367 if( orRange.aEnd.Col() > maMaxPos.Col() )
368 orRange.aEnd.SetCol( maMaxPos.Col() );
369 if( orRange.aEnd.Row() > maMaxPos.Row() )
370 orRange.aEnd.SetRow( maMaxPos.Row() );
371 return true;
374 bool AddressConverter::convertToCellRangeUnchecked( ScRange& orRange,
375 const OUString& rString, sal_Int16 nSheet )
377 orRange.aStart.SetTab( nSheet );
378 orRange.aEnd.SetTab( nSheet );
379 sal_Int32 aStartCol = orRange.aStart.Col();
380 sal_Int32 aStartRow = orRange.aStart.Row();
381 sal_Int32 aEndCol = orRange.aEnd.Col();
382 sal_Int32 aEndRow = orRange.aEnd.Row();
383 bool bReturnValue = parseOoxRange2d( aStartCol, aStartRow, aEndCol, aEndRow, rString );
384 orRange.aStart.SetCol( aStartCol );
385 orRange.aStart.SetRow( aStartRow );
386 orRange.aEnd.SetCol( aEndCol );
387 orRange.aEnd.SetRow( aEndRow );
388 return bReturnValue;
391 bool AddressConverter::convertToCellRange( ScRange& orRange,
392 const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
394 return
395 convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
396 validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
399 void AddressConverter::convertToCellRangeUnchecked( ScRange& orRange,
400 const BinRange& rBinRange, sal_Int16 nSheet )
402 orRange.aStart.SetTab( nSheet );
403 orRange.aStart.SetCol( rBinRange.maFirst.mnCol );
404 orRange.aStart.SetRow( rBinRange.maFirst.mnRow );
405 orRange.aEnd.SetTab( nSheet );
406 orRange.aEnd.SetCol( rBinRange.maLast.mnCol );
407 orRange.aEnd.SetRow( rBinRange.maLast.mnRow );
410 bool AddressConverter::convertToCellRange( ScRange& orRange,
411 const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
413 convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
414 return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
417 void AddressConverter::validateCellRangeList( ScRangeList& orRanges, bool bTrackOverflow )
419 for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
420 if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
421 orRanges.Remove( nIndex - 1 );
424 void AddressConverter::convertToCellRangeList( ScRangeList& orRanges,
425 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
427 sal_Int32 nPos = 0;
428 sal_Int32 nLen = rString.getLength();
429 ScRange aRange;
430 while( (0 <= nPos) && (nPos < nLen) )
432 OUString aToken = rString.getToken( 0, ' ', nPos );
433 if( !aToken.isEmpty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
434 orRanges.push_back(aRange);
438 void AddressConverter::convertToCellRangeList( ScRangeList& orRanges,
439 const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
441 ScRange aRange;
442 for( const auto& rBinRange : rBinRanges )
443 if( convertToCellRange( aRange, rBinRange, nSheet, true, bTrackOverflow ) )
444 orRanges.push_back( aRange );
447 Sequence<CellRangeAddress> AddressConverter::toApiSequence(const ScRangeList& orRanges)
449 const size_t nSize = orRanges.size();
450 Sequence<CellRangeAddress> aRangeSequence(nSize);
451 CellRangeAddress* pApiRanges = aRangeSequence.getArray();
452 for (size_t i = 0; i < nSize; ++i)
454 ScUnoConversion::FillApiRange(pApiRanges[i], orRanges[i]);
456 return aRangeSequence;
459 // private --------------------------------------------------------------------
461 void AddressConverter::initializeMaxPos(
462 sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
464 maMaxXlsPos.Set( nMaxXlsCol, nMaxXlsRow, nMaxXlsTab);
466 // maximum cell position in Calc
469 Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
470 Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
471 CellRangeAddress aRange = xAddressable->getRangeAddress();
472 maMaxApiPos = ScAddress( aRange.EndColumn, aRange.EndRow, API_MAXTAB );
473 maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
475 catch( Exception& )
477 OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
481 } // namespace oox
483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */