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 <o3tl/string_view.hxx>
27#include <osl/diagnose.h>
30
31namespace oox::xls {
32
33using namespace ::com::sun::star::container;
34using namespace ::com::sun::star::sheet;
35using namespace ::com::sun::star::table;
36using namespace ::com::sun::star::uno;
37
38namespace {
39
41const sal_Int16 API_MAXTAB = MAXTAB;
42
43const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
44const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
45const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
46
47} // namespace
48
49
51{
52 mnRow = rStrm.readInt32();
53 mnCol = rStrm.readInt32();
54}
55
57{
58 maFirst.mnRow = rStrm.readInt32();
59 maLast.mnRow = rStrm.readInt32();
60 maFirst.mnCol = rStrm.readInt32();
61 maLast.mnCol = rStrm.readInt32();
62}
63
65{
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 );
70}
71
73 WorkbookHelper( rHelper ),
74 mbColOverflow( false ),
75 mbRowOverflow( false ),
76 mbTabOverflow( false )
77{
78 initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
79}
80
82 sal_Int32& ornColumn, sal_Int32& ornRow,
83 std::u16string_view aString, sal_Int32 nStart, sal_Int32 nLength )
84{
85 ornColumn = ornRow = 0;
86 if( (nStart < 0) || (nStart >= sal_Int32(aString.size())) || (nLength < 2) )
87 return false;
88
89 const sal_Unicode* pcChar = aString.data() + nStart;
90 const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, sal_Int32(aString.size() - nStart) );
91
92 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
93 while( pcChar < pcEndChar )
94 {
95 sal_Unicode cChar = *pcChar;
96 switch( eState )
97 {
98 case STATE_COL:
99 {
100 if( ('a' <= cChar) && (cChar <= 'z') )
101 cChar = (cChar - 'a') + 'A';
102 if( ('A' <= cChar) && (cChar <= 'Z') )
103 {
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);
109 }
110 else if( ornColumn > 0 )
111 {
112 --pcChar;
113 eState = STATE_ROW;
114 }
115 else
116 return false;
117 }
118 break;
119
120 case STATE_ROW:
121 {
122 if( ('0' <= cChar) && (cChar <= '9') )
123 {
124 // return, if 1-based row is already 9 digits long
125 if( ornRow >= 100000000 )
126 return false;
127 ornRow = (ornRow * 10) + (cChar - '0');
128 }
129 else
130 return false;
131 }
132 break;
133 }
134 ++pcChar;
135 }
136
137 --ornColumn;
138 --ornRow;
139 return (ornColumn >= 0) && (ornRow >= 0);
140}
141
142bool AddressConverter::parseOoxAddress2d( sal_Int32& ornColumn, sal_Int32& ornRow, std::string_view aStr )
143{
144 ornColumn = ornRow = 0;
145
146 enum { STATE_COL, STATE_ROW } eState = STATE_COL;
147
148 const char* pStr = aStr.data();
149 while (pStr != aStr.data() + aStr.size())
150 {
151 char cChar = *pStr;
152 switch( eState )
153 {
154 case STATE_COL:
155 {
156 if( ('a' <= cChar) && (cChar <= 'z') )
157 cChar = (cChar - 'a') + 'A';
158 if( ('A' <= cChar) && (cChar <= 'Z') )
159 {
160 /* Return, if 1-based column index is already 6 characters
161 long (12356631 is column index for column AAAAAA). */
162 if( ornColumn >= 12356631 )
163 return false;
164 ornColumn = (ornColumn * 26) + (cChar - 'A' + 1);
165 }
166 else if( ornColumn > 0 )
167 {
168 --pStr;
169 eState = STATE_ROW;
170 }
171 else
172 return false;
173 }
174 break;
175
176 case STATE_ROW:
177 {
178 if( ('0' <= cChar) && (cChar <= '9') )
179 {
180 // return, if 1-based row is already 9 digits long
181 if( ornRow >= 100000000 )
182 return false;
183 ornRow = (ornRow * 10) + (cChar - '0');
184 }
185 else
186 return false;
187 }
188 break;
189 }
190 ++pStr;
191 }
192
193 --ornColumn;
194 --ornRow;
195 return (ornColumn >= 0) && (ornRow >= 0);
196}
197
199 sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
200 sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
201 std::u16string_view aString, sal_Int32 nStart )
202{
203 ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
204 if( (nStart < 0) || (nStart >= sal_Int32(aString.size())) )
205 return false;
206
207 sal_Int32 nEnd = nStart + ( aString.size() - nStart );
208 size_t nColonPos = aString.find( ':', nStart );
209 if( nColonPos != std::u16string_view::npos && (nStart < sal_Int32(nColonPos)) && (sal_Int32(nColonPos + 1) < nEnd) )
210 {
211 return
212 parseOoxAddress2d( ornStartColumn, ornStartRow, aString, nStart, nColonPos - nStart ) &&
213 parseOoxAddress2d( ornEndColumn, ornEndRow, aString, nColonPos + 1, SAL_MAX_INT32 - nColonPos - 1 );
214 }
215
216 if( parseOoxAddress2d( ornStartColumn, ornStartRow, aString, nStart ) )
217 {
218 ornEndColumn = ornStartColumn;
219 ornEndRow = ornStartRow;
220 return true;
221 }
222
223 return false;
224}
225
226bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
227{
228 bool bValid = (0 <= nCol) && ( nCol <= maMaxPos.Col() );
229 if( !bValid && bTrackOverflow )
230 mbColOverflow = true;
231 return bValid;
232}
233
234bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
235{
236 bool bValid = (0 <= nRow) && ( nRow <= maMaxPos.Row() );
237 if( !bValid && bTrackOverflow )
238 mbRowOverflow = true;
239 return bValid;
240}
241
242bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
243{
244 bool bValid = (0 <= nSheet) && ( nSheet <= maMaxPos.Tab() );
245 if( !bValid && bTrackOverflow )
246 mbTabOverflow |= ( nSheet > maMaxPos.Tab() ); // do not warn for deleted refs (-1)
247 return bValid;
248}
249
250bool AddressConverter::checkCellAddress( const ScAddress& rAddress, bool bTrackOverflow )
251{
252 return
253 checkTab( rAddress.Tab(), bTrackOverflow ) &&
254 checkCol( rAddress.Col(), bTrackOverflow ) &&
255 checkRow( rAddress.Row(), bTrackOverflow );
256}
257
259 const OUString& rString, sal_Int16 nSheet )
260{
261 orAddress.SetTab(nSheet);
262 sal_Int32 nCol = 0;
263 sal_Int32 nRow = 0;
264 bool bRes = parseOoxAddress2d( nCol, nRow, rString );
265 orAddress.SetRow(nRow);
266 orAddress.SetCol(nCol);
267
268 return bRes;
269}
270
272 ScAddress& orAddress, std::string_view pStr, sal_Int16 nSheet )
273{
274 orAddress.SetTab(nSheet);
275 sal_Int32 nCol = 0;
276 sal_Int32 nRow = 0;
277 bool bRes = parseOoxAddress2d(nCol, nRow, pStr);
278 orAddress.SetRow(nRow);
279 orAddress.SetCol(nCol);
280
281 return bRes;
282}
283
285 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
286{
287 return
288 convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
289 checkCellAddress( orAddress, bTrackOverflow );
290}
291
293 ScAddress& rAddress,
294 std::string_view pStr, sal_Int16 nSheet, bool bTrackOverflow )
295{
296 if (!convertToCellAddressUnchecked(rAddress, pStr, nSheet))
297 return false;
298
299 return checkCellAddress(rAddress, bTrackOverflow);
300}
301
303 const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
304{
305 ScAddress aAddress( 0, 0, 0 );
306 if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
307 {
308 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
309 aAddress.SetCol( ::std::min( aAddress.Col(), maMaxPos.Col() ) );
310 aAddress.SetRow( ::std::min( aAddress.Row(), maMaxPos.Row() ) );
311 }
312 return aAddress;
313}
314
316 const BinAddress& rBinAddress, sal_Int16 nSheet )
317{
318 orAddress.SetTab(nSheet);
319 orAddress.SetCol(rBinAddress.mnCol);
320 orAddress.SetRow(rBinAddress.mnRow);
321}
322
324 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
325{
326 convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
327 return checkCellAddress( orAddress, bTrackOverflow );
328}
329
331 const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
332{
333 ScAddress aAddress ( 0, 0, 0 );
334 if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
335 {
336 aAddress.SetTab( getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Tab() ) );
337 aAddress.SetCol( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, sal_Int32( maMaxPos.Col() ) ) );
338 aAddress.SetRow( getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, sal_Int32( maMaxPos.Row() ) ) );
339 }
340 return aAddress;
341}
342
343bool AddressConverter::checkCellRange( const ScRange& rRange, bool bAllowOverflow, bool bTrackOverflow )
344{
345 return
346 (checkCol( rRange.aEnd.Col(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
347 (checkRow( rRange.aEnd.Row(), bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
348 checkTab( rRange.aStart.Tab(), bTrackOverflow ) &&
349 checkCol( rRange.aStart.Col(), bTrackOverflow ) &&
350 checkRow( rRange.aStart.Row(), bTrackOverflow );
351}
352
353bool AddressConverter::validateCellRange( ScRange& orRange, bool bAllowOverflow, bool bTrackOverflow )
354{
355 if( orRange.aStart.Col() > orRange.aEnd.Col() )
356 {
357 SCCOL nCol = orRange.aStart.Col();
358 orRange.aStart.SetCol( orRange.aEnd.Col() );
359 orRange.aEnd.SetCol( nCol );
360 }
361 if( orRange.aStart.Row() > orRange.aEnd.Row() )
362 {
363 SCROW nRow = orRange.aStart.Row();
364 orRange.aStart.SetRow( orRange.aEnd.Row() );
365 orRange.aEnd.SetRow( nRow );
366 }
367 if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
368 return false;
369 if( orRange.aEnd.Col() > maMaxPos.Col() )
370 orRange.aEnd.SetCol( maMaxPos.Col() );
371 if( orRange.aEnd.Row() > maMaxPos.Row() )
372 orRange.aEnd.SetRow( maMaxPos.Row() );
373 return true;
374}
375
377 std::u16string_view aString, sal_Int16 nSheet )
378{
379 orRange.aStart.SetTab( nSheet );
380 orRange.aEnd.SetTab( nSheet );
381 sal_Int32 aStartCol = orRange.aStart.Col();
382 sal_Int32 aStartRow = orRange.aStart.Row();
383 sal_Int32 aEndCol = orRange.aEnd.Col();
384 sal_Int32 aEndRow = orRange.aEnd.Row();
385 bool bReturnValue = parseOoxRange2d( aStartCol, aStartRow, aEndCol, aEndRow, aString );
386 orRange.aStart.SetCol( aStartCol );
387 orRange.aStart.SetRow( aStartRow );
388 orRange.aEnd.SetCol( aEndCol );
389 orRange.aEnd.SetRow( aEndRow );
390 return bReturnValue;
391}
392
394 std::u16string_view aString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
395{
396 return
397 convertToCellRangeUnchecked( orRange, aString, nSheet ) &&
398 validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
399}
400
402 const BinRange& rBinRange, sal_Int16 nSheet )
403{
404 orRange.aStart.SetTab( nSheet );
405 orRange.aStart.SetCol( rBinRange.maFirst.mnCol );
406 orRange.aStart.SetRow( rBinRange.maFirst.mnRow );
407 orRange.aEnd.SetTab( nSheet );
408 orRange.aEnd.SetCol( rBinRange.maLast.mnCol );
409 orRange.aEnd.SetRow( rBinRange.maLast.mnRow );
410}
411
413 const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
414{
415 convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
416 return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
417}
418
419void AddressConverter::validateCellRangeList( ScRangeList& orRanges, bool bTrackOverflow )
420{
421 for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
422 if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
423 orRanges.Remove( nIndex - 1 );
424}
425
427 std::u16string_view aString, sal_Int16 nSheet, bool bTrackOverflow )
428{
429 size_t nPos = 0;
430 size_t nLen = aString.size();
431 ScRange aRange;
432 while( nPos != std::u16string_view::npos && (nPos < nLen) )
433 {
434 std::u16string_view aToken = o3tl::getToken(aString, u' ', nPos );
435 if( !aToken.empty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
436 orRanges.push_back(aRange);
437 }
438}
439
441 const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
442{
443 ScRange aRange;
444 for( const auto& rBinRange : rBinRanges )
445 if( convertToCellRange( aRange, rBinRange, nSheet, true, bTrackOverflow ) )
446 orRanges.push_back( aRange );
447}
448
449Sequence<CellRangeAddress> AddressConverter::toApiSequence(const ScRangeList& orRanges)
450{
451 const size_t nSize = orRanges.size();
452 Sequence<CellRangeAddress> aRangeSequence(nSize);
453 CellRangeAddress* pApiRanges = aRangeSequence.getArray();
454 for (size_t i = 0; i < nSize; ++i)
455 {
456 ScUnoConversion::FillApiRange(pApiRanges[i], orRanges[i]);
457 }
458 return aRangeSequence;
459}
460
461// private --------------------------------------------------------------------
462
464 sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
465{
466 maMaxXlsPos.Set( nMaxXlsCol, nMaxXlsRow, nMaxXlsTab);
467
468 // maximum cell position in Calc
469 try
470 {
471 Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
472 Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
473 CellRangeAddress aRange = xAddressable->getRangeAddress();
474 maMaxApiPos = ScAddress( aRange.EndColumn, aRange.EndRow, API_MAXTAB );
476 }
477 catch( Exception& )
478 {
479 OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
480 }
481}
482
483} // namespace oox
484
485/* 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.
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 parseOoxRange2d(sal_Int32 &ornStartColumn, sal_Int32 &ornStartRow, sal_Int32 &ornEndColumn, sal_Int32 &ornEndRow, std::u16string_view aString, 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.
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.
static bool parseOoxAddress2d(sal_Int32 &ornColumn, sal_Int32 &ornRow, std::u16string_view aString, sal_Int32 nStart=0, sal_Int32 nLength=SAL_MAX_INT32)
Tries to parse the passed string for a 2d cell address in A1 notation.
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.
bool convertToCellRange(ScRange &orRange, std::u16string_view aString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow)
Tries to convert the passed string to a cell range address.
static bool convertToCellRangeUnchecked(ScRange &orRange, std::u16string_view aString, sal_Int16 nSheet)
Converts the passed string to a cell range address, without checking any sheet 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.
bool validateCellRange(ScRange &orRange, bool bAllowOverflow, bool bTrackOverflow)
Checks the passed cell range, may try to fit it to current sheet limits.
void convertToCellRangeList(ScRangeList &orRanges, std::u16string_view aString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a cell range list.
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
float u
sal_Int32 nIndex
sal_uInt16 nPos
aStr
@ Exception
int i
void SvStream & rStrm
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
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