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>
27 #include <oox/core/filterbase.hxx>
29 
30 namespace oox::xls {
31 
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;
36 
37 namespace {
38 
40 const sal_Int16 API_MAXTAB = MAXTAB;
41 
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 );
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 
141 bool AddressConverter::parseOoxAddress2d( sal_Int32& ornColumn, sal_Int32& ornRow, const char* pStr )
142 {
143  ornColumn = ornRow = 0;
144 
145  enum { STATE_COL, STATE_ROW } eState = STATE_COL;
146 
147  while (*pStr)
148  {
149  char cChar = *pStr;
150  switch( eState )
151  {
152  case STATE_COL:
153  {
154  if( ('a' <= cChar) && (cChar <= 'z') )
155  cChar = (cChar - 'a') + 'A';
156  if( ('A' <= cChar) && (cChar <= 'Z') )
157  {
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);
163  }
164  else if( ornColumn > 0 )
165  {
166  --pStr;
167  eState = STATE_ROW;
168  }
169  else
170  return false;
171  }
172  break;
173 
174  case STATE_ROW:
175  {
176  if( ('0' <= cChar) && (cChar <= '9') )
177  {
178  // return, if 1-based row is already 9 digits long
179  if( ornRow >= 100000000 )
180  return false;
181  ornRow = (ornRow * 10) + (cChar - '0');
182  }
183  else
184  return false;
185  }
186  break;
187  }
188  ++pStr;
189  }
190 
191  --ornColumn;
192  --ornRow;
193  return (ornColumn >= 0) && (ornRow >= 0);
194 }
195 
197  sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
198  sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
199  const OUString& rString, sal_Int32 nStart )
200 {
201  ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
202  if( (nStart < 0) || (nStart >= rString.getLength()) )
203  return false;
204 
205  sal_Int32 nEnd = nStart + ( rString.getLength() - nStart );
206  sal_Int32 nColonPos = rString.indexOf( ':', nStart );
207  if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
208  {
209  return
210  parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
211  parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, SAL_MAX_INT32 - nColonPos - 1 );
212  }
213 
214  if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart ) )
215  {
216  ornEndColumn = ornStartColumn;
217  ornEndRow = ornStartRow;
218  return true;
219  }
220 
221  return false;
222 }
223 
224 bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
225 {
226  bool bValid = (0 <= nCol) && ( nCol <= maMaxPos.Col() );
227  if( !bValid && bTrackOverflow )
228  mbColOverflow = true;
229  return bValid;
230 }
231 
232 bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
233 {
234  bool bValid = (0 <= nRow) && ( nRow <= maMaxPos.Row() );
235  if( !bValid && bTrackOverflow )
236  mbRowOverflow = true;
237  return bValid;
238 }
239 
240 bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
241 {
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;
246 }
247 
248 bool AddressConverter::checkCellAddress( const ScAddress& rAddress, bool bTrackOverflow )
249 {
250  return
251  checkTab( rAddress.Tab(), bTrackOverflow ) &&
252  checkCol( rAddress.Col(), bTrackOverflow ) &&
253  checkRow( rAddress.Row(), bTrackOverflow );
254 }
255 
257  const OUString& rString, sal_Int16 nSheet )
258 {
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);
265 
266  return bRes;
267 }
268 
270  ScAddress& orAddress, const char* pStr, sal_Int16 nSheet )
271 {
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);
278 
279  return bRes;
280 }
281 
283  const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
284 {
285  return
286  convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
287  checkCellAddress( orAddress, bTrackOverflow );
288 }
289 
291  ScAddress& rAddress,
292  const char* pStr, sal_Int16 nSheet, bool bTrackOverflow )
293 {
294  if (!convertToCellAddressUnchecked(rAddress, pStr, nSheet))
295  return false;
296 
297  return checkCellAddress(rAddress, bTrackOverflow);
298 }
299 
301  const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
302 {
303  ScAddress aAddress( 0, 0, 0 );
304  if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
305  {
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() ) );
309  }
310  return aAddress;
311 }
312 
314  const BinAddress& rBinAddress, sal_Int16 nSheet )
315 {
316  orAddress.SetTab(nSheet);
317  orAddress.SetCol(rBinAddress.mnCol);
318  orAddress.SetRow(rBinAddress.mnRow);
319 }
320 
322  const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
323 {
324  convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
325  return checkCellAddress( orAddress, bTrackOverflow );
326 }
327 
329  const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
330 {
331  ScAddress aAddress ( 0, 0, 0 );
332  if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
333  {
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() ) ) );
337  }
338  return aAddress;
339 }
340 
341 bool AddressConverter::checkCellRange( const ScRange& rRange, bool bAllowOverflow, bool bTrackOverflow )
342 {
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 );
349 }
350 
351 bool AddressConverter::validateCellRange( ScRange& orRange, bool bAllowOverflow, bool bTrackOverflow )
352 {
353  if( orRange.aStart.Col() > orRange.aEnd.Col() )
354  {
355  SCCOL nCol = orRange.aStart.Col();
356  orRange.aStart.SetCol( orRange.aEnd.Col() );
357  orRange.aEnd.SetCol( nCol );
358  }
359  if( orRange.aStart.Row() > orRange.aEnd.Row() )
360  {
361  SCROW nRow = orRange.aStart.Row();
362  orRange.aStart.SetRow( orRange.aEnd.Row() );
363  orRange.aEnd.SetRow( nRow );
364  }
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;
372 }
373 
375  const OUString& rString, sal_Int16 nSheet )
376 {
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;
389 }
390 
392  const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
393 {
394  return
395  convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
396  validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
397 }
398 
400  const BinRange& rBinRange, sal_Int16 nSheet )
401 {
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 );
408 }
409 
411  const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
412 {
413  convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
414  return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
415 }
416 
417 void AddressConverter::validateCellRangeList( ScRangeList& orRanges, bool bTrackOverflow )
418 {
419  for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
420  if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
421  orRanges.Remove( nIndex - 1 );
422 }
423 
425  const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
426 {
427  sal_Int32 nPos = 0;
428  sal_Int32 nLen = rString.getLength();
429  ScRange aRange;
430  while( (0 <= nPos) && (nPos < nLen) )
431  {
432  OUString aToken = rString.getToken( 0, ' ', nPos );
433  if( !aToken.isEmpty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
434  orRanges.push_back(aRange);
435  }
436 }
437 
439  const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
440 {
441  ScRange aRange;
442  for( const auto& rBinRange : rBinRanges )
443  if( convertToCellRange( aRange, rBinRange, nSheet, true, bTrackOverflow ) )
444  orRanges.push_back( aRange );
445 }
446 
447 Sequence<CellRangeAddress> AddressConverter::toApiSequence(const ScRangeList& orRanges)
448 {
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)
453  {
454  ScUnoConversion::FillApiRange(pApiRanges[i], orRanges[i]);
455  }
456  return aRangeSequence;
457 }
458 
459 // private --------------------------------------------------------------------
460 
462  sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
463 {
464  maMaxXlsPos.Set( nMaxXlsCol, nMaxXlsRow, nMaxXlsTab);
465 
466  // maximum cell position in Calc
467  try
468  {
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 );
474  }
475  catch( Exception& )
476  {
477  OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
478  }
479 }
480 
481 } // namespace oox
482 
483 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static css::uno::Sequence< css::table::CellRangeAddress > toApiSequence(const ScRangeList &orRanges)
Converts the passed range list to a sequence of cell range addresses.
Helper class to provide access to global workbook data.
bool checkCellRange(const ScRange &rRange, bool bAllowOverflow, bool bTrackOverflow)
Checks the passed cell range if it fits into the spreadsheet limits.
sal_Int32 nIndex
ScAddress aStart
Definition: address.hxx:500
bool checkCellAddress(const ScAddress &rAddress, bool bTrackOverflow)
Checks the passed cell address if it fits into the spreadsheet limits.
SCROW Row() const
Definition: address.hxx:262
bool checkCol(sal_Int32 nCol, bool bTrackOverflow)
Checks if the passed column index is valid.
A 2D cell range address list for binary filters.
A 2D cell address struct for binary filters.
bool validateCellRange(ScRange &orRange, bool bAllowOverflow, bool bTrackOverflow)
Checks the passed cell range, may try to fit it to current sheet limits.
A 2D cell range address struct for binary filters.
ScAddress maMaxPos
Maximum valid cell address in Excel.
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.
ScAddress aEnd
Definition: address.hxx:501
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.
sal_uInt16 sal_Unicode
int nCount
::oox::core::FilterBase & getBaseFilter() const
Returns the base filter object (base class of all filters).
void push_back(const ScRange &rRange)
Definition: rangelst.cxx:1144
SCTAB Tab() const
Definition: address.hxx:271
void SetRow(SCROW nRowP)
Definition: address.hxx:275
void SetCol(SCCOL nColP)
Definition: address.hxx:279
::std::vector< BinRange > mvRanges
bool convertToCellAddress(ScAddress &orAddress, const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a single cell address.
bool checkTab(sal_Int16 nSheet, bool bTrackOverflow)
Checks if the passed sheet index is valid.
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.
void Remove(size_t nPos)
Definition: rangelst.cxx:1100
void SetTab(SCTAB nTabP)
Definition: address.hxx:283
void read(SequenceInputStream &rStrm)
#define SAL_MAX_INT32
bool mbRowOverflow
Flag for "columns overflow".
int i
void Set(SCCOL nCol, SCROW nRow, SCTAB nTab)
Definition: address.hxx:406
const css::uno::Reference< css::sheet::XSpreadsheetDocument > & getDocument() const
Returns a reference to the source/target spreadsheet document model.
sal_Int16 SCCOL
Definition: types.hxx:22
bool checkRow(sal_Int32 nRow, bool bTrackOverflow)
Checks if the passed row index is valid.
size_t size() const
Definition: rangelst.hxx:90
void convertToCellRangeList(ScRangeList &orRanges, const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Tries to convert the passed string to a cell range list.
const SCTAB MAXTAB
Definition: address.hxx:71
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.
SCCOL Col() const
Definition: address.hxx:267
void initializeMaxPos(sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow)
bool mbTabOverflow
Flag for "rows overflow".
sal_Int32 SCROW
Definition: types.hxx:18
sal_Int64 getRemaining() const
ScAddress createValidCellAddress(const OUString &rString, sal_Int16 nSheet, bool bTrackOverflow)
Returns a valid cell address by moving it into allowed dimensions.
AddressConverter(const WorkbookHelper &rHelper)
void read(SequenceInputStream &rStrm)
void validateCellRangeList(ScRangeList &orRanges, bool bTrackOverflow)
Tries to restrict the passed cell range list to current sheet limits.
ScAddress maMaxXlsPos
Maximum valid cell address in Calc.
static void FillApiRange(css::table::CellRangeAddress &rApiRange, const ScRange &rScRange)
Definition: convuno.hxx:88
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.
void read(SequenceInputStream &rStrm)
sal_uInt16 nPos
bool isImportFilter() const