Line data Source code
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 <osl/diagnose.h>
26 : #include <rtl/strbuf.hxx>
27 : #include <rtl/ustrbuf.hxx>
28 : #include "oox/core/filterbase.hxx"
29 : #include "biffinputstream.hxx"
30 :
31 : namespace oox {
32 : namespace xls {
33 :
34 : // ============================================================================
35 :
36 : using namespace ::com::sun::star::container;
37 : using namespace ::com::sun::star::sheet;
38 : using namespace ::com::sun::star::table;
39 : using namespace ::com::sun::star::uno;
40 :
41 :
42 : // ============================================================================
43 :
44 : namespace {
45 :
46 : //! TODO: this limit may change, is there a way to obtain it via API?
47 : const sal_Int16 API_MAXTAB = MAXTAB;
48 :
49 : const sal_Int32 OOX_MAXCOL = static_cast< sal_Int32 >( (1 << 14) - 1 );
50 : const sal_Int32 OOX_MAXROW = static_cast< sal_Int32 >( (1 << 20) - 1 );
51 : const sal_Int16 OOX_MAXTAB = static_cast< sal_Int16 >( (1 << 15) - 1 );
52 :
53 : const sal_Int32 BIFF2_MAXCOL = 255;
54 : const sal_Int32 BIFF2_MAXROW = 16383;
55 : const sal_Int16 BIFF2_MAXTAB = 0;
56 :
57 : const sal_Int32 BIFF3_MAXCOL = BIFF2_MAXCOL;
58 : const sal_Int32 BIFF3_MAXROW = BIFF2_MAXROW;
59 : const sal_Int16 BIFF3_MAXTAB = BIFF2_MAXTAB;
60 :
61 : const sal_Int32 BIFF4_MAXCOL = BIFF3_MAXCOL;
62 : const sal_Int32 BIFF4_MAXROW = BIFF3_MAXROW;
63 : const sal_Int16 BIFF4_MAXTAB = 32767;
64 :
65 : const sal_Int32 BIFF5_MAXCOL = BIFF4_MAXCOL;
66 : const sal_Int32 BIFF5_MAXROW = BIFF4_MAXROW;
67 : const sal_Int16 BIFF5_MAXTAB = BIFF4_MAXTAB;
68 :
69 : const sal_Int32 BIFF8_MAXCOL = BIFF5_MAXCOL;
70 : const sal_Int32 BIFF8_MAXROW = 65535;
71 : const sal_Int16 BIFF8_MAXTAB = BIFF5_MAXTAB;
72 :
73 : const sal_Unicode BIFF_URL_DRIVE = '\x01'; /// DOS drive letter or UNC path.
74 : const sal_Unicode BIFF_URL_ROOT = '\x02'; /// Root directory of current drive.
75 : const sal_Unicode BIFF_URL_SUBDIR = '\x03'; /// Subdirectory delimiter.
76 : const sal_Unicode BIFF_URL_PARENT = '\x04'; /// Parent directory.
77 : const sal_Unicode BIFF_URL_RAW = '\x05'; /// Unencoded URL.
78 : const sal_Unicode BIFF_URL_INSTALL = '\x06'; /// Application installation directory.
79 : const sal_Unicode BIFF_URL_INSTALL2 = '\x07'; /// Alternative application installation directory.
80 : const sal_Unicode BIFF_URL_LIBRARY = '\x08'; /// Library directory in application installation.
81 : const sal_Unicode BIFF4_URL_SHEET = '\x09'; /// BIFF4 internal sheet.
82 : const sal_Unicode BIFF_URL_UNC = '@'; /// UNC path root.
83 :
84 : const sal_Unicode BIFF_DCON_ENCODED = '\x01'; /// First character of an encoded path from DCON* records.
85 : const sal_Unicode BIFF_DCON_INTERN = '\x02'; /// First character of an encoded sheet name from DCON* records.
86 :
87 : } // namespace
88 :
89 : // ============================================================================
90 : // ============================================================================
91 :
92 98 : CellAddress ApiCellRangeList::getBaseAddress() const
93 : {
94 98 : if( empty() )
95 0 : return CellAddress();
96 98 : return CellAddress( front().Sheet, front().StartColumn, front().StartRow );
97 : }
98 :
99 : // ============================================================================
100 :
101 0 : void BinAddress::read( SequenceInputStream& rStrm )
102 : {
103 0 : rStrm >> mnRow >> mnCol;
104 0 : }
105 :
106 0 : void BinAddress::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
107 : {
108 0 : mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
109 0 : mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
110 0 : }
111 :
112 : // ============================================================================
113 :
114 0 : void BinRange::read( SequenceInputStream& rStrm )
115 : {
116 0 : rStrm >> maFirst.mnRow >> maLast.mnRow >> maFirst.mnCol >> maLast.mnCol;
117 0 : }
118 :
119 0 : void BinRange::read( BiffInputStream& rStrm, bool bCol16Bit, bool bRow32Bit )
120 : {
121 0 : maFirst.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
122 0 : maLast.mnRow = bRow32Bit ? rStrm.readInt32() : rStrm.readuInt16();
123 0 : maFirst.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
124 0 : maLast.mnCol = bCol16Bit ? rStrm.readuInt16() : rStrm.readuInt8();
125 0 : }
126 :
127 : // ============================================================================
128 :
129 0 : void BinRangeList::read( SequenceInputStream& rStrm )
130 : {
131 0 : sal_Int32 nCount = rStrm.readInt32();
132 0 : resize( getLimitedValue< size_t, sal_Int64 >( nCount, 0, rStrm.getRemaining() / 16 ) );
133 0 : for( iterator aIt = begin(), aEnd = end(); aIt != aEnd; ++aIt )
134 0 : aIt->read( rStrm );
135 0 : }
136 :
137 : // ============================================================================
138 :
139 21 : AddressConverter::AddressConverter( const WorkbookHelper& rHelper ) :
140 : WorkbookHelper( rHelper ),
141 : mbColOverflow( false ),
142 : mbRowOverflow( false ),
143 21 : mbTabOverflow( false )
144 : {
145 21 : maDConChars.set( 0xFFFF, '\x01', 0xFFFF, '\x02', 0xFFFF );
146 21 : switch( getFilterType() )
147 : {
148 : case FILTER_OOXML:
149 21 : initializeMaxPos( OOX_MAXTAB, OOX_MAXCOL, OOX_MAXROW );
150 21 : break;
151 0 : case FILTER_BIFF: switch( getBiff() )
152 : {
153 : case BIFF2:
154 0 : initializeMaxPos( BIFF2_MAXTAB, BIFF2_MAXCOL, BIFF2_MAXROW );
155 0 : maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
156 0 : break;
157 : case BIFF3:
158 0 : initializeMaxPos( BIFF3_MAXTAB, BIFF3_MAXCOL, BIFF3_MAXROW );
159 0 : maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, 0xFFFF );
160 0 : break;
161 : case BIFF4:
162 0 : initializeMaxPos( BIFF4_MAXTAB, BIFF4_MAXCOL, BIFF4_MAXROW );
163 0 : maLinkChars.set( 0xFFFF, '\x01', '\x02', 0xFFFF, '\x00' );
164 0 : break;
165 : case BIFF5:
166 0 : initializeMaxPos( BIFF5_MAXTAB, BIFF5_MAXCOL, BIFF5_MAXROW );
167 0 : maLinkChars.set( '\x04', '\x01', '\x02', '\x03', '\x00' );
168 0 : break;
169 : case BIFF8:
170 0 : initializeMaxPos( BIFF8_MAXTAB, BIFF8_MAXCOL, BIFF8_MAXROW );
171 0 : maLinkChars.set( '\x04', '\x01', 0xFFFF, '\x02', '\x00' );
172 0 : break;
173 0 : case BIFF_UNKNOWN: break;
174 : }
175 0 : break;
176 0 : case FILTER_UNKNOWN: break;
177 : }
178 21 : }
179 :
180 : // ----------------------------------------------------------------------------
181 :
182 1129 : bool AddressConverter::parseOoxAddress2d(
183 : sal_Int32& ornColumn, sal_Int32& ornRow,
184 : const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
185 : {
186 1129 : ornColumn = ornRow = 0;
187 1129 : if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
188 16 : return false;
189 :
190 1113 : const sal_Unicode* pcChar = rString.getStr() + nStart;
191 1113 : const sal_Unicode* pcEndChar = pcChar + ::std::min( nLength, rString.getLength() - nStart );
192 :
193 1113 : enum { STATE_COL, STATE_ROW } eState = STATE_COL;
194 5998 : while( pcChar < pcEndChar )
195 : {
196 3772 : sal_Unicode cChar = *pcChar;
197 3772 : switch( eState )
198 : {
199 : case STATE_COL:
200 : {
201 2226 : if( ('a' <= cChar) && (cChar <= 'z') )
202 0 : (cChar -= 'a') += 'A';
203 2226 : if( ('A' <= cChar) && (cChar <= 'Z') )
204 : {
205 : /* Return, if 1-based column index is already 6 characters
206 : long (12356631 is column index for column AAAAAA). */
207 1113 : if( ornColumn >= 12356631 )
208 0 : return false;
209 1113 : (ornColumn *= 26) += (cChar - 'A' + 1);
210 : }
211 1113 : else if( ornColumn > 0 )
212 : {
213 1113 : --pcChar;
214 1113 : eState = STATE_ROW;
215 : }
216 : else
217 0 : return false;
218 : }
219 2226 : break;
220 :
221 : case STATE_ROW:
222 : {
223 1546 : if( ('0' <= cChar) && (cChar <= '9') )
224 : {
225 : // return, if 1-based row is already 9 digits long
226 1546 : if( ornRow >= 100000000 )
227 0 : return false;
228 1546 : (ornRow *= 10) += (cChar - '0');
229 : }
230 : else
231 0 : return false;
232 : }
233 1546 : break;
234 : }
235 3772 : ++pcChar;
236 : }
237 :
238 1113 : --ornColumn;
239 1113 : --ornRow;
240 1113 : return (ornColumn >= 0) && (ornRow >= 0);
241 : }
242 :
243 168 : bool AddressConverter::parseOoxRange2d(
244 : sal_Int32& ornStartColumn, sal_Int32& ornStartRow,
245 : sal_Int32& ornEndColumn, sal_Int32& ornEndRow,
246 : const OUString& rString, sal_Int32 nStart, sal_Int32 nLength )
247 : {
248 168 : ornStartColumn = ornStartRow = ornEndColumn = ornEndRow = 0;
249 168 : if( (nStart < 0) || (nStart >= rString.getLength()) || (nLength < 2) )
250 41 : return false;
251 :
252 127 : sal_Int32 nEnd = nStart + ::std::min( nLength, rString.getLength() - nStart );
253 127 : sal_Int32 nColonPos = rString.indexOf( ':', nStart );
254 127 : if( (nStart < nColonPos) && (nColonPos + 1 < nEnd) )
255 : {
256 : return
257 150 : parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nColonPos - nStart ) &&
258 150 : parseOoxAddress2d( ornEndColumn, ornEndRow, rString, nColonPos + 1, nLength - nColonPos - 1 );
259 : }
260 :
261 52 : if( parseOoxAddress2d( ornStartColumn, ornStartRow, rString, nStart, nLength ) )
262 : {
263 52 : ornEndColumn = ornStartColumn;
264 52 : ornEndRow = ornStartRow;
265 52 : return true;
266 : }
267 :
268 0 : return false;
269 : }
270 :
271 : // ----------------------------------------------------------------------------
272 :
273 1238 : bool AddressConverter::checkCol( sal_Int32 nCol, bool bTrackOverflow )
274 : {
275 1238 : bool bValid = (0 <= nCol) && (nCol <= maMaxPos.Column);
276 1238 : if( !bValid && bTrackOverflow )
277 26 : mbColOverflow = true;
278 1238 : return bValid;
279 : }
280 :
281 1422 : bool AddressConverter::checkRow( sal_Int32 nRow, bool bTrackOverflow )
282 : {
283 1422 : bool bValid = (0 <= nRow) && (nRow <= maMaxPos.Row);
284 1422 : if( !bValid && bTrackOverflow )
285 0 : mbRowOverflow = true;
286 1422 : return bValid;
287 : }
288 :
289 1037 : bool AddressConverter::checkTab( sal_Int16 nSheet, bool bTrackOverflow )
290 : {
291 1037 : bool bValid = (0 <= nSheet) && (nSheet <= maMaxPos.Sheet);
292 1037 : if( !bValid && bTrackOverflow )
293 0 : mbTabOverflow |= (nSheet > maMaxPos.Sheet); // do not warn for deleted refs (-1)
294 1037 : return bValid;
295 : }
296 :
297 : // ----------------------------------------------------------------------------
298 :
299 916 : bool AddressConverter::checkCellAddress( const CellAddress& rAddress, bool bTrackOverflow )
300 : {
301 : return
302 1832 : checkTab( rAddress.Sheet, bTrackOverflow ) &&
303 1832 : checkCol( rAddress.Column, bTrackOverflow ) &&
304 1832 : checkRow( rAddress.Row, bTrackOverflow );
305 : }
306 :
307 927 : bool AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
308 : const OUString& rString, sal_Int16 nSheet )
309 : {
310 927 : orAddress.Sheet = nSheet;
311 927 : return parseOoxAddress2d( orAddress.Column, orAddress.Row, rString );
312 : }
313 :
314 927 : bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
315 : const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
316 : {
317 : return
318 1838 : convertToCellAddressUnchecked( orAddress, rString, nSheet ) &&
319 1838 : checkCellAddress( orAddress, bTrackOverflow );
320 : }
321 :
322 76 : CellAddress AddressConverter::createValidCellAddress(
323 : const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
324 : {
325 76 : CellAddress aAddress;
326 76 : if( !convertToCellAddress( aAddress, rString, nSheet, bTrackOverflow ) )
327 : {
328 16 : aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
329 16 : aAddress.Column = ::std::min( aAddress.Column, maMaxPos.Column );
330 16 : aAddress.Row = ::std::min( aAddress.Row, maMaxPos.Row );
331 : }
332 76 : return aAddress;
333 : }
334 :
335 4 : void AddressConverter::convertToCellAddressUnchecked( CellAddress& orAddress,
336 : const BinAddress& rBinAddress, sal_Int16 nSheet )
337 : {
338 4 : orAddress.Sheet = nSheet;
339 4 : orAddress.Column = rBinAddress.mnCol;
340 4 : orAddress.Row = rBinAddress.mnRow;
341 4 : }
342 :
343 4 : bool AddressConverter::convertToCellAddress( CellAddress& orAddress,
344 : const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
345 : {
346 4 : convertToCellAddressUnchecked( orAddress, rBinAddress, nSheet );
347 4 : return checkCellAddress( orAddress, bTrackOverflow );
348 : }
349 :
350 4 : CellAddress AddressConverter::createValidCellAddress(
351 : const BinAddress& rBinAddress, sal_Int16 nSheet, bool bTrackOverflow )
352 : {
353 4 : CellAddress aAddress;
354 4 : if( !convertToCellAddress( aAddress, rBinAddress, nSheet, bTrackOverflow ) )
355 : {
356 0 : aAddress.Sheet = getLimitedValue< sal_Int16, sal_Int16 >( nSheet, 0, maMaxPos.Sheet );
357 0 : aAddress.Column = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnCol, 0, maMaxPos.Column );
358 0 : aAddress.Row = getLimitedValue< sal_Int32, sal_Int32 >( rBinAddress.mnRow, 0, maMaxPos.Row );
359 : }
360 4 : return aAddress;
361 : }
362 :
363 : // ----------------------------------------------------------------------------
364 :
365 121 : bool AddressConverter::checkCellRange( const CellRangeAddress& rRange, bool bAllowOverflow, bool bTrackOverflow )
366 : {
367 : return
368 242 : (checkCol( rRange.EndColumn, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkCol to track overflow!
369 242 : (checkRow( rRange.EndRow, bTrackOverflow ) || bAllowOverflow) && // bAllowOverflow after checkRow to track overflow!
370 242 : checkTab( rRange.Sheet, bTrackOverflow ) &&
371 363 : checkCol( rRange.StartColumn, bTrackOverflow ) &&
372 242 : checkRow( rRange.StartRow, bTrackOverflow );
373 : }
374 :
375 121 : bool AddressConverter::validateCellRange( CellRangeAddress& orRange, bool bAllowOverflow, bool bTrackOverflow )
376 : {
377 121 : if( orRange.StartColumn > orRange.EndColumn )
378 0 : ::std::swap( orRange.StartColumn, orRange.EndColumn );
379 121 : if( orRange.StartRow > orRange.EndRow )
380 0 : ::std::swap( orRange.StartRow, orRange.EndRow );
381 121 : if( !checkCellRange( orRange, bAllowOverflow, bTrackOverflow ) )
382 0 : return false;
383 121 : if( orRange.EndColumn > maMaxPos.Column )
384 0 : orRange.EndColumn = maMaxPos.Column;
385 121 : if( orRange.EndRow > maMaxPos.Row )
386 0 : orRange.EndRow = maMaxPos.Row;
387 121 : return true;
388 : }
389 :
390 168 : bool AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
391 : const OUString& rString, sal_Int16 nSheet )
392 : {
393 168 : orRange.Sheet = nSheet;
394 168 : return parseOoxRange2d( orRange.StartColumn, orRange.StartRow, orRange.EndColumn, orRange.EndRow, rString );
395 : }
396 :
397 123 : bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
398 : const OUString& rString, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
399 : {
400 : return
401 205 : convertToCellRangeUnchecked( orRange, rString, nSheet ) &&
402 205 : validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
403 : }
404 :
405 0 : void AddressConverter::convertToCellRangeUnchecked( CellRangeAddress& orRange,
406 : const BinRange& rBinRange, sal_Int16 nSheet )
407 : {
408 0 : orRange.Sheet = nSheet;
409 0 : orRange.StartColumn = rBinRange.maFirst.mnCol;
410 0 : orRange.StartRow = rBinRange.maFirst.mnRow;
411 0 : orRange.EndColumn = rBinRange.maLast.mnCol;
412 0 : orRange.EndRow = rBinRange.maLast.mnRow;
413 0 : }
414 :
415 0 : bool AddressConverter::convertToCellRange( CellRangeAddress& orRange,
416 : const BinRange& rBinRange, sal_Int16 nSheet, bool bAllowOverflow, bool bTrackOverflow )
417 : {
418 0 : convertToCellRangeUnchecked( orRange, rBinRange, nSheet );
419 0 : return validateCellRange( orRange, bAllowOverflow, bTrackOverflow );
420 : }
421 :
422 : // ----------------------------------------------------------------------------
423 :
424 0 : void AddressConverter::validateCellRangeList( ApiCellRangeList& orRanges, bool bTrackOverflow )
425 : {
426 0 : for( size_t nIndex = orRanges.size(); nIndex > 0; --nIndex )
427 0 : if( !validateCellRange( orRanges[ nIndex - 1 ], true, bTrackOverflow ) )
428 0 : orRanges.erase( orRanges.begin() + nIndex - 1 );
429 0 : }
430 :
431 80 : void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
432 : const OUString& rString, sal_Int16 nSheet, bool bTrackOverflow )
433 : {
434 80 : sal_Int32 nPos = 0;
435 80 : sal_Int32 nLen = rString.getLength();
436 80 : CellRangeAddress aRange;
437 240 : while( (0 <= nPos) && (nPos < nLen) )
438 : {
439 80 : OUString aToken = rString.getToken( 0, ' ', nPos );
440 80 : if( !aToken.isEmpty() && convertToCellRange( aRange, aToken, nSheet, true, bTrackOverflow ) )
441 80 : orRanges.push_back( aRange );
442 80 : }
443 80 : }
444 :
445 0 : void AddressConverter::convertToCellRangeList( ApiCellRangeList& orRanges,
446 : const BinRangeList& rBinRanges, sal_Int16 nSheet, bool bTrackOverflow )
447 : {
448 0 : CellRangeAddress aRange;
449 0 : for( BinRangeList::const_iterator aIt = rBinRanges.begin(), aEnd = rBinRanges.end(); aIt != aEnd; ++aIt )
450 0 : if( convertToCellRange( aRange, *aIt, nSheet, true, bTrackOverflow ) )
451 0 : orRanges.push_back( aRange );
452 0 : }
453 :
454 : // private --------------------------------------------------------------------
455 :
456 21 : void AddressConverter::ControlCharacters::set(
457 : sal_Unicode cThisWorkbook, sal_Unicode cExternal,
458 : sal_Unicode cThisSheet, sal_Unicode cInternal, sal_Unicode cSameSheet )
459 : {
460 21 : mcThisWorkbook = cThisWorkbook;
461 21 : mcExternal = cExternal;
462 21 : mcThisSheet = cThisSheet;
463 21 : mcInternal = cInternal;
464 21 : mcSameSheet = cSameSheet;
465 21 : }
466 :
467 21 : void AddressConverter::initializeMaxPos(
468 : sal_Int16 nMaxXlsTab, sal_Int32 nMaxXlsCol, sal_Int32 nMaxXlsRow )
469 : {
470 21 : maMaxXlsPos.Sheet = nMaxXlsTab;
471 21 : maMaxXlsPos.Column = nMaxXlsCol;
472 21 : maMaxXlsPos.Row = nMaxXlsRow;
473 :
474 : // maximum cell position in Calc
475 : try
476 : {
477 21 : Reference< XIndexAccess > xSheetsIA( getDocument()->getSheets(), UNO_QUERY_THROW );
478 42 : Reference< XCellRangeAddressable > xAddressable( xSheetsIA->getByIndex( 0 ), UNO_QUERY_THROW );
479 21 : CellRangeAddress aRange = xAddressable->getRangeAddress();
480 21 : maMaxApiPos = CellAddress( API_MAXTAB, aRange.EndColumn, aRange.EndRow );
481 42 : maMaxPos = getBaseFilter().isImportFilter() ? maMaxApiPos : maMaxXlsPos;
482 : }
483 0 : catch( Exception& )
484 : {
485 : OSL_FAIL( "AddressConverter::AddressConverter - cannot get sheet limits" );
486 : }
487 21 : }
488 :
489 : // ============================================================================
490 :
491 : } // namespace xls
492 15 : } // namespace oox
493 :
494 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|