LibreOffice Module sc (master) 1
addressconverter.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <addressconverter.hxx>
21
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>
29
30namespace oox::xls {
31
32using namespace ::com::sun::star::container;
33using namespace ::com::sun::star::sheet;
34using namespace ::com::sun::star::table;
35using namespace ::com::sun::star::uno;
36
37namespace {
38
40const sal_Int16 API_MAXTAB = MAXTAB;
41
42const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
43const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
44const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
45
46} // namespace
47
48
50{
51 mnRow = rStrm.readInt32();
52 mnCol = rStrm.readInt32();
53}
54
56{
57 maFirst.mnRow = rStrm.readInt32();
58 maLast.mnRow = rStrm.readInt32();
59 maFirst.mnCol = rStrm.readInt32();
60 maLast.mnCol = rStrm.readInt32();
61}
62
64{
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 );
69}
70
72 WorkbookHelper( rHelper ),
73 mbColOverflow( false ),
74 mbRowOverflow( false ),
75 mbTabOverflow( false )
76{
77 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
78}
79
81 sal_Int32& ornColumn, sal_Int32& ornRow,
82 const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
83{
84 ornColumn = ornRow = 0;
85 if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
86 return false;
87
88 const sal_Unicode* pcChar = rString.getStr() + nStart;
89 const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
90
91 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
92 while( pcChar < pcEndChar )
93 {
94 sal_Unicode cChar = *pcChar;
95 switch( eState )
96 {
97 case STATE_COL:
98 {
99 if( ('a' <= cChar) && (cChar <= 'z') )
100 cChar = (cChar - 'a') + 'A';
101 if( ('A' <= cChar) && (cChar <= 'Z') )
102 {
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);
108 }
109 else if( ornColumn > 0 )
110 {
111 --pcChar;
112 eState = STATE_ROW;
113 }
114 else
115 return false;
116 }
117 break;
118
119 case STATE_ROW:
120 {
121 if( ('0' <= cChar) && (cChar <= '9') )
122 {
123 // return, if 1-based row is already 9 digits long
124 if( ornRow >= 100000000 )
125 return false;
126 ornRow = (ornRow * 10) + (cChar - '0');
127 }
128 else
129 return false;
130 }
131 break;
132 }
133 ++pcChar;
134 }
135
136 --ornColumn;
137 --ornRow;
138 return (ornColumn >= 0) && (ornRow >= 0);
139}
140
141bool AddressConverter::parseOoxAddress2d( sal_Int32& ornColumn, sal_Int32& ornRow, std::string_view aStr )
142{
143 ornColumn = ornRow = 0;
144
145 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
146
147 const char* pStr = aStr.data();
148 while (pStr != aStr.data() + aStr.size())
149 {
150 char cChar = *pStr;
151 switch( eState )
152 {
153 case STATE_COL:
154 {
155 if( ('a' <= cChar) && (cChar <= 'z') )
156 cChar = (cChar - 'a') + 'A';
157 if( ('A' <= cChar) && (cChar <= 'Z') )
158 {
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);
164 }
165 else if( ornColumn > 0 )
166 {
167 --pStr;
168 eState = STATE_ROW;
169 }
170 else
171 return false;
172 }
173 break;
174
175 case STATE_ROW:
176 {
177 if( ('0' <= cChar) && (cChar <= '9') )
178 {
179 // return, if 1-based row is already 9 digits long
180 if( ornRow >= 100000000 )
181 return false;
182 ornRow = (ornRow * 10) + (cChar - '0');
183 }
184 else
185 return false;
186 }
187 break;
188 }
189 ++pStr;
190 }
191
192 --ornColumn;
193 --ornRow;
194 return (ornColumn >= 0) && (ornRow >= 0);
195}
196
198 sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
199 sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
200 const OUString& rString, sal_Int32 nStart )
201{
202 ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
203 if( (nStart < 0) || (nStart >= rString.getLength()) )
204 return false;
205
206 sal_Int32 nEnd = nStart + ( rString.getLength() - nStart );
207 sal_Int32 nColonPos = rString.indexOf( ':', nStart );
208 if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
209 {
210 return
211 parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
212 parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, SAL_MAX_INT32 - nColonPos - 1 );
213 }
214
215 if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart ) )
216 {
217 ornEndColumn = ornStartColumn;
218 ornEndRow = ornStartRow;
219 return true;
220 }
221
222 return false;
223}
224
225bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
226{
227 bool bValid = (0 <= nCol) && ( nCol <= maMaxPos.Col() );
228 if( !bValid && bTrackOverflow )
229 mbColOverflow = true;
230 return bValid;
231}
232
233bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
234{
235 bool bValid = (0 <= nRow) && ( nRow <= maMaxPos.Row() );
236 if( !bValid && bTrackOverflow )
237 mbRowOverflow = true;
238 return bValid;
239}
240
241bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
242{
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;
247}
248
249bool AddressConverter::checkCellAddress( const ScAddress& rAddress, bool bTrackOverflow )
250{
251 return
252 checkTab( rAddress.Tab(), bTrackOverflow ) &&
253 checkCol( rAddress.Col(), bTrackOverflow ) &&
254 checkRow( rAddress.Row(), bTrackOverflow );
255}
256
258 const OUString& rString, sal_Int16 nSheet )
259{
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);
266
267 return bRes;
268}
269
271 ScAddress& orAddress, std::string_view pStr, sal_Int16 nSheet )
272{
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);
279
280 return bRes;
281}
282
284 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
285{
286 return
287 convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
288 checkCellAddress( orAddress, bTrackOverflow );
289}
290
292 ScAddress& rAddress,
293 std::string_view pStr, sal_Int16 nSheet, bool bTrackOverflow )
294{
295 if (!convertToCellAddressUnchecked(rAddress, pStr, nSheet))
296 return false;
297
298 return checkCellAddress(rAddress, bTrackOverflow);
299}
300
302 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
303{
304 ScAddress aAddress( 0, 0, 0 );
305 if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
306 {
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() ) );
310 }
311 return aAddress;
312}
313
315 const BinAddress& rBinAddress, sal_Int16 nSheet )
316{
317 orAddress.SetTab(nSheet);
318 orAddress.SetCol(rBinAddress.mnCol);
319 orAddress.SetRow(rBinAddress.mnRow);
320}
321
323 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
324{
325 convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
326 return checkCellAddress( orAddress, bTrackOverflow );
327}
328
330 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
331{
332 ScAddress aAddress ( 0, 0, 0 );
333 if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
334 {
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() ) ) );
338 }
339 return aAddress;
340}
341
342bool AddressConverter::checkCellRange( const ScRange& rRange, bool bAllowOverflow, bool bTrackOverflow )
343{
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 );
350}
351
352bool AddressConverter::validateCellRange( ScRange& orRange, bool bAllowOverflow, bool bTrackOverflow )
353{
354 if( orRange.aStart.Col() > orRange.aEnd.Col() )
355 {
356 SCCOL nCol = orRange.aStart.Col();
357 orRange.aStart.SetCol( orRange.aEnd.Col() );
358 orRange.aEnd.SetCol( nCol );
359 }
360 if( orRange.aStart.Row() > orRange.aEnd.Row() )
361 {
362 SCROW nRow = orRange.aStart.Row();
363 orRange.aStart.SetRow( orRange.aEnd.Row() );
364 orRange.aEnd.SetRow( nRow );
365 }
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;
373}
374
376 const OUString& rString, sal_Int16 nSheet )
377{
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;
390}
391
393 const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
394{
395 return
396 convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
397 validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
398}
399
401 const BinRange& rBinRange, sal_Int16 nSheet )
402{
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 );
409}
410
412 const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
413{
414 convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
415 return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
416}
417
418void AddressConverter::validateCellRangeList( ScRangeList& orRanges, bool bTrackOverflow )
419{
420 for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
421 if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
422 orRanges.Remove( nIndex - 1 );
423}
424
426 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
427{
428 sal_Int32 nPos = 0;
429 sal_Int32 nLen = rString.getLength();
430 ScRange aRange;
431 while( (0 <= nPos) && (nPos < nLen) )
432 {
433 OUString aToken = rString.getToken( 0, ' ', nPos );
434 if( !aToken.isEmpty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
435 orRanges.push_back(aRange);
436 }
437}
438
440 const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
441{
442 ScRange aRange;
443 for( const auto& rBinRange : rBinRanges )
444 if( convertToCellRange( aRange, rBinRange, nSheet, true, bTrackOverflow ) )
445 orRanges.push_back( aRange );
446}
447
448Sequence<CellRangeAddress> AddressConverter::toApiSequence(const ScRangeList& orRanges)
449{
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)
454 {
455 ScUnoConversion::FillApiRange(pApiRanges[i], orRanges[i]);
456 }
457 return aRangeSequence;
458}
459
460// private --------------------------------------------------------------------
461
463 sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
464{
465 maMaxXlsPos.Set( nMaxXlsCol, nMaxXlsRow, nMaxXlsTab);
466
467 // maximum cell position in Calc
468 try
469 {
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 );
475 }
476 catch( Exception& )
477 {
478 OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
479 }
480}
481
482} // namespace oox
483
484/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const SCTAB MAXTAB
Definition: address.hxx:70
SCTAB Tab() const
Definition: address.hxx:283
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:403
void SetCol(SCCOL nColP)
Definition: address.hxx:291
SCROW Row() const
Definition: address.hxx:274
void SetRow(SCROW nRowP)
Definition: address.hxx:287
void SetTab(SCTAB nTabP)
Definition: address.hxx:295
SCCOL Col() const
Definition: address.hxx:279
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1137
size_t size() const
Definition: rangelst.hxx:89
void Remove(size_t nPos)
Definition: rangelst.cxx:1093
ScAddress aEnd
Definition: address.hxx:498
ScAddress aStart
Definition: address.hxx:497
static void FillApiRange(css::table::CellRangeAddress &rApiRange, const ScRange &rScRange)
Definition: convuno.hxx:87
bool isImportFilter() const
bool mbTabOverflow
Flag for "rows overflow".
ScAddress maMaxXlsPos
Maximum valid cell address in Calc.
bool convertToCellAddress(ScAddress &orAddress, const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a single cell address.
bool checkCellAddress(const ScAddress &rAddress, bool bTrackOverflow)
Checks the passed cell address if it fits into the spreadsheet limits.
static bool convertToCellRangeUnchecked(ScRange &orRange, const OUString &rString, sal_Int16 nSheet)
Converts the passed string to a cell range address, without checking any sheet limits.
bool mbColOverflow
Maximum valid cell address in Calc/Excel.
bool checkRow(sal_Int32 nRow, bool bTrackOverflow)
Checks if the passed row index is valid.
static bool parseOoxAddress2d(sal_Int32 &ornColumn, sal_Int32 &ornRow, const OUString &rString, sal_Int32 nStart=0, sal_Int32 nLength=SAL_MAX_INT32)
Tries to parse the passed string for a 2d cell address in A1 notation.
static bool parseOoxRange2d(sal_Int32 &ornStartColumn, sal_Int32 &ornStartRow, sal_Int32 &ornEndColumn, sal_Int32 &ornEndRow, const OUString &rString, sal_Int32 nStart=0)
Tries to parse the passed string for a 2d cell range in A1 notation.
bool checkCol(sal_Int32 nCol, bool bTrackOverflow)
Checks if the passed column index is valid.
bool convertToCellRange(ScRange &orRange, const OUString &rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow)
Tries to convert the passed string to a cell range address.
ScAddress maMaxPos
Maximum valid cell address in Excel.
static css::uno::Sequence< css::table::CellRangeAddress > toApiSequence(const ScRangeList &orRanges)
Converts the passed range list to a sequence of cell range addresses.
ScAddress createValidCellAddress(const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Returns a valid cell address by moving it into allowed dimensions.
bool checkCellRange(const ScRange &rRange, bool bAllowOverflow, bool bTrackOverflow)
Checks the passed cell range if it fits into the spreadsheet limits.
AddressConverter(const WorkbookHelper &rHelper)
bool mbRowOverflow
Flag for "columns overflow".
bool checkTab(sal_Int16 nSheet, bool bTrackOverflow)
Checks if the passed sheet index is valid.
void initializeMaxPos(sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow)
void validateCellRangeList(ScRangeList &orRanges, bool bTrackOverflow)
Tries to restrict the passed cell range list to current sheet limits.
void convertToCellRangeList(ScRangeList &orRanges, const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a cell range list.
bool validateCellRange(ScRange &orRange, bool bAllowOverflow, bool bTrackOverflow)
Checks the passed cell range, may try to fit it to current sheet limits.
static bool convertToCellAddressUnchecked(ScAddress &orAddress, const OUString &rString, sal_Int16 nSheet)
Converts the passed string to a single cell address, without checking any sheet limits.
A 2D cell range address list for binary filters.
void read(SequenceInputStream &rStrm)
::std::vector< BinRange > mvRanges
Helper class to provide access to global workbook data.
::oox::core::FilterBase & getBaseFilter() const
Returns the base filter object (base class of all filters).
const css::uno::Reference< css::sheet::XSpreadsheetDocument > & getDocument() const
Returns a reference to the source/target spreadsheet document model.
int nCount
sal_Int32 nIndex
sal_uInt16 nPos
aStr
@ Exception
int i
void SvStream & rStrm
A 2D cell address struct for binary filters.
void read(SequenceInputStream &rStrm)
A 2D cell range address struct for binary filters.
void read(SequenceInputStream &rStrm)
#define SAL_MAX_INT32
sal_uInt16 sal_Unicode
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
sal_Int32 nLength