fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / filter / excel / xicontent.cxx
blob96130197302b7bb091e6d0f2dec97210391b2190
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 "xicontent.hxx"
21 #include <sfx2/objsh.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <tools/urlobj.hxx>
24 #include <editeng/editeng.hxx>
25 #include <editeng/editobj.hxx>
26 #include <sfx2/linkmgr.hxx>
27 #include <svl/itemset.hxx>
28 #include "scitems.hxx"
29 #include <editeng/eeitem.hxx>
30 #include <svl/intitem.hxx>
31 #include <svl/stritem.hxx>
32 #include <editeng/flditem.hxx>
33 #include <editeng/fhgtitem.hxx>
34 #include <editeng/wghtitem.hxx>
35 #include <editeng/udlnitem.hxx>
36 #include <editeng/postitem.hxx>
37 #include <editeng/colritem.hxx>
38 #include <editeng/crossedoutitem.hxx>
39 #include "stringutil.hxx"
40 #include "document.hxx"
41 #include "editutil.hxx"
42 #include "formulacell.hxx"
43 #include "validat.hxx"
44 #include "patattr.hxx"
45 #include "docpool.hxx"
46 #include "rangenam.hxx"
47 #include "arealink.hxx"
48 #include "stlsheet.hxx"
49 #include "scextopt.hxx"
50 #include "xlformula.hxx"
51 #include "xltracer.hxx"
52 #include "xistream.hxx"
53 #include "xihelper.hxx"
54 #include "xistyle.hxx"
55 #include "xiescher.hxx"
56 #include "xiname.hxx"
58 #include "excform.hxx"
59 #include "tabprotection.hxx"
60 #include "documentimport.hxx"
62 #include <memory>
63 #include <utility>
65 using ::com::sun::star::uno::Sequence;
66 using ::std::unique_ptr;
68 // Shared string table ========================================================
70 XclImpSst::XclImpSst( const XclImpRoot& rRoot ) :
71 XclImpRoot( rRoot )
75 void XclImpSst::ReadSst( XclImpStream& rStrm )
77 rStrm.Ignore( 4 );
78 sal_uInt32 nStrCount = rStrm.ReaduInt32();
79 auto nBytesAvailable = rStrm.GetRecLeft();
80 if (nStrCount > nBytesAvailable)
82 SAL_WARN("sc.filter", "xls claimed to have " << nStrCount << " strings, but only " << nBytesAvailable << " bytes available, truncating");
83 nStrCount = nBytesAvailable;
85 maStrings.clear();
86 maStrings.reserve(nStrCount);
87 while( (nStrCount > 0) && rStrm.IsValid() )
89 XclImpString aString;
90 aString.Read( rStrm );
91 maStrings.push_back( aString );
92 --nStrCount;
96 const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
98 return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
101 // Hyperlinks =================================================================
103 namespace {
105 /** Reads character array and stores it into rString.
106 @param nChars Number of following characters (not byte count!).
107 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
108 void lclAppendString32( OUString& rString, XclImpStream& rStrm, sal_uInt32 nChars, bool b16Bit )
110 sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
111 rString += rStrm.ReadRawUniString( nReadChars, b16Bit );
112 // ignore remaining chars
113 sal_Size nIgnore = nChars - nReadChars;
114 if( b16Bit )
115 nIgnore *= 2;
116 rStrm.Ignore( nIgnore );
119 /** Reads 32-bit string length and the character array and stores it into rString.
120 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
121 void lclAppendString32( OUString& rString, XclImpStream& rStrm, bool b16Bit )
123 lclAppendString32( rString, rStrm, rStrm.ReaduInt32(), b16Bit );
126 /** Reads 32-bit string length and ignores following character array.
127 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
128 void lclIgnoreString32( XclImpStream& rStrm, bool b16Bit )
130 sal_uInt32 nChars(0);
131 nChars = rStrm.ReaduInt32();
132 if( b16Bit )
133 nChars *= 2;
134 rStrm.Ignore( nChars );
137 /** Converts a path to an absolute path.
138 @param rPath The source path. The resulting path is returned here.
139 @param nLevel Number of parent directories to add in front of the path. */
140 void lclGetAbsPath( OUString& rPath, sal_uInt16 nLevel, SfxObjectShell* pDocShell )
142 OUStringBuffer aTmpStr;
143 while( nLevel )
145 aTmpStr.append( "../" );
146 --nLevel;
148 aTmpStr.append( rPath );
150 if( pDocShell )
152 bool bWasAbs = false;
153 rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr.makeStringAndClear(), bWasAbs ).GetMainURL( INetURLObject::NO_DECODE );
154 // full path as stored in SvxURLField must be encoded
156 else
157 rPath = aTmpStr.makeStringAndClear();
160 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
161 void lclInsertUrl( XclImpRoot& rRoot, const OUString& rUrl, SCCOL nScCol, SCROW nScRow, SCTAB nScTab )
163 ScDocumentImport& rDoc = rRoot.GetDocImport();
164 ScAddress aScPos( nScCol, nScRow, nScTab );
165 CellType eCellType = rDoc.getDoc().GetCellType(aScPos);
166 switch( eCellType )
168 // #i54261# hyperlinks in string cells
169 case CELLTYPE_STRING:
170 case CELLTYPE_EDIT:
172 OUString aDisplText = rDoc.getDoc().GetString(nScCol, nScRow, nScTab);
173 if (aDisplText.isEmpty())
174 aDisplText = rUrl;
176 ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
177 SvxURLField aUrlField( rUrl, aDisplText, SVXURLFORMAT_APPDEFAULT );
179 const EditTextObject* pEditObj = rDoc.getDoc().GetEditText(aScPos);
180 if( pEditObj )
182 rEE.SetText( *pEditObj );
183 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0, 0, EE_PARA_ALL, 0 ) );
185 else
187 rEE.SetText( EMPTY_OUSTRING );
188 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection() );
189 if( const ScPatternAttr* pPattern = rDoc.getDoc().GetPattern( aScPos.Col(), aScPos.Row(), nScTab ) )
191 SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
192 pPattern->FillEditItemSet( &aItemSet );
193 rEE.QuickSetAttribs( aItemSet, ESelection( 0, 0, EE_PARA_ALL, 0 ) );
197 // The cell will own the text object instance.
198 rDoc.setEditCell(aScPos, rEE.CreateTextObject());
200 break;
202 default:
203 // Handle other cell types e.g. formulas ( and ? ) that have associated
204 // hyperlinks.
205 // Ideally all hyperlinks should be treated as below. For the moment,
206 // given the current absence of ods support lets just handle what we
207 // previously didn't handle the new way.
208 // Unfortunately we won't be able to preserve such hyperlinks when
209 // saving to ods. Note: when we are able to save such hyperlinks to ods
210 // we should handle *all* imported hyperlinks as below ( e.g. as cell
211 // attribute ) for better interoperability.
213 SfxStringItem aItem( ATTR_HYPERLINK, rUrl );
214 rDoc.getDoc().ApplyAttr(nScCol, nScRow, nScTab, aItem);
215 break;
220 } // namespace
222 void XclImpHyperlink::ReadHlink( XclImpStream& rStrm )
224 XclRange aXclRange( ScAddress::UNINITIALIZED );
225 rStrm >> aXclRange;
226 // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
227 aXclRange.maFirst.mnCol &= 0xFF;
228 aXclRange.maLast.mnCol &= 0xFF;
229 OUString aString = ReadEmbeddedData( rStrm );
230 if ( !aString.isEmpty() )
231 rStrm.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange, aString );
234 OUString XclImpHyperlink::ReadEmbeddedData( XclImpStream& rStrm )
236 const XclImpRoot& rRoot = rStrm.GetRoot();
237 SfxObjectShell* pDocShell = rRoot.GetDocShell();
239 OSL_ENSURE_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
241 XclGuid aGuid;
242 rStrm >> aGuid;
243 rStrm.Ignore( 4 );
244 sal_uInt32 nFlags(0);
245 nFlags = rStrm.ReaduInt32();
247 OSL_ENSURE( aGuid == XclTools::maGuidStdLink, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
249 ::std::unique_ptr< OUString > xLongName; // link / file name
250 ::std::unique_ptr< OUString > xShortName; // 8.3-representation of file name
251 ::std::unique_ptr< OUString > xTextMark; // text mark
253 // description (ignore)
254 if( ::get_flag( nFlags, EXC_HLINK_DESCR ) )
255 lclIgnoreString32( rStrm, true );
256 // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
257 if( ::get_flag( nFlags, EXC_HLINK_FRAME ) )
258 lclIgnoreString32( rStrm, true );
260 // URL fields are zero-terminated - do not let the stream replace them
261 // in the lclAppendString32() with the '?' character.
262 rStrm.SetNulSubstChar( '\0' );
264 // UNC path
265 if( ::get_flag( nFlags, EXC_HLINK_UNC ) )
267 xLongName.reset( new OUString );
268 lclAppendString32( *xLongName, rStrm, true );
269 lclGetAbsPath( *xLongName, 0, pDocShell );
271 // file link or URL
272 else if( ::get_flag( nFlags, EXC_HLINK_BODY ) )
274 rStrm >> aGuid;
276 if( aGuid == XclTools::maGuidFileMoniker )
278 sal_uInt16 nLevel = 0; // counter for level to climb down in path
279 nLevel = rStrm.ReaduInt16();
280 xShortName.reset( new OUString );
281 lclAppendString32( *xShortName, rStrm, false );
282 rStrm.Ignore( 24 );
284 sal_uInt32 nStrLen = 0;
285 nStrLen = rStrm.ReaduInt32();
286 if( nStrLen )
288 nStrLen = 0;
289 nStrLen = rStrm.ReaduInt32();
290 nStrLen /= 2; // it's byte count here...
291 rStrm.Ignore( 2 );
292 xLongName.reset( new OUString );
293 lclAppendString32( *xLongName, rStrm, nStrLen, true );
294 lclGetAbsPath( *xLongName, nLevel, pDocShell );
296 else
297 lclGetAbsPath( *xShortName, nLevel, pDocShell );
299 else if( aGuid == XclTools::maGuidUrlMoniker )
301 sal_uInt32 nStrLen(0);
302 nStrLen = rStrm.ReaduInt32();
303 nStrLen /= 2; // it's byte count here...
304 xLongName.reset( new OUString );
305 lclAppendString32( *xLongName, rStrm, nStrLen, true );
306 if( !::get_flag( nFlags, EXC_HLINK_ABS ) )
307 lclGetAbsPath( *xLongName, 0, pDocShell );
309 else
311 OSL_FAIL( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
315 // text mark
316 if( ::get_flag( nFlags, EXC_HLINK_MARK ) )
318 xTextMark.reset( new OUString );
319 lclAppendString32( *xTextMark, rStrm, true );
322 rStrm.SetNulSubstChar(); // back to default
324 OSL_ENSURE( rStrm.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
326 if( !xLongName.get() && xShortName.get() )
327 xLongName = std::move(xShortName);
328 else if( !xLongName.get() && xTextMark.get() )
329 xLongName.reset( new OUString );
331 if( xLongName.get() )
333 if( xTextMark.get() )
335 if( xLongName->isEmpty() )
336 xTextMark.reset( new OUString( xTextMark->replace( '!', '.' ) ) );
337 xLongName.reset( new OUString( *xLongName + "#" ) );
338 xLongName.reset( new OUString( *xLongName + *xTextMark ) );
340 return( *xLongName );
342 return( OUString() );
345 void XclImpHyperlink::ConvertToValidTabName(OUString& rUrl)
347 sal_Int32 n = rUrl.getLength();
348 if (n < 4)
349 // Needs at least 4 characters.
350 return;
352 if (rUrl[0] != '#')
353 // the 1st character must be '#'.
354 return;
356 OUString aNewUrl('#'), aTabName;
358 bool bInQuote = false;
359 bool bQuoteTabName = false;
360 for( sal_Int32 i = 1; i < n; ++i )
362 sal_Unicode c = rUrl[i];
363 if (c == '\'')
365 if (bInQuote && i+1 < n && rUrl[i+1] == '\'')
367 // Two consecutive single quotes ('') signify a single literal
368 // quite. When this occurs, the whole table name needs to be
369 // quoted.
370 bQuoteTabName = true;
371 aTabName += OUString(c);
372 aTabName += OUString(c);
373 ++i;
374 continue;
377 bInQuote = !bInQuote;
378 if (!bInQuote && !aTabName.isEmpty())
380 if (bQuoteTabName)
381 aNewUrl += OUString('\'');
382 aNewUrl += aTabName;
383 if (bQuoteTabName)
384 aNewUrl += OUString('\'');
387 else if (bInQuote)
388 aTabName += OUString(c);
389 else
390 aNewUrl += OUString(c);
393 if (bInQuote)
394 // It should be outside the quotes!
395 return;
397 // All is good. Pass the new URL.
398 rUrl = aNewUrl;
401 void XclImpHyperlink::InsertUrl( XclImpRoot& rRoot, const XclRange& rXclRange, const OUString& rUrl )
403 OUString aUrl(rUrl);
404 ConvertToValidTabName(aUrl);
406 SCTAB nScTab = rRoot.GetCurrScTab();
407 ScRange aScRange( ScAddress::UNINITIALIZED );
408 if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
410 SCCOL nScCol1, nScCol2;
411 SCROW nScRow1, nScRow2;
412 aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
413 for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
414 for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
415 lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
419 // Label ranges ===============================================================
421 void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
423 const XclImpRoot& rRoot = rStrm.GetRoot();
424 OSL_ENSURE_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
426 ScDocument& rDoc = rRoot.GetDoc();
427 SCTAB nScTab = rRoot.GetCurrScTab();
428 XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
429 ScRangePairListRef xLabelRangesRef;
430 const ScRange* pScRange = 0;
432 XclRangeList aRowXclRanges, aColXclRanges;
433 rStrm >> aRowXclRanges >> aColXclRanges;
435 // row label ranges
436 ScRangeList aRowScRanges;
437 rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
438 xLabelRangesRef = rDoc.GetRowNameRangesRef();
439 for ( size_t i = 0, nRanges = aRowScRanges.size(); i < nRanges; ++i )
441 pScRange = aRowScRanges[ i ];
442 ScRange aDataRange( *pScRange );
443 if( aDataRange.aEnd.Col() < MAXCOL )
445 aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
446 aDataRange.aEnd.SetCol( MAXCOL );
448 else if( aDataRange.aStart.Col() > 0 )
450 aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
451 aDataRange.aStart.SetCol( 0 );
453 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
456 // column label ranges
457 ScRangeList aColScRanges;
458 rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
459 xLabelRangesRef = rDoc.GetColNameRangesRef();
461 for ( size_t i = 0, nRanges = aColScRanges.size(); i < nRanges; ++i )
463 pScRange = aColScRanges[ i ];
464 ScRange aDataRange( *pScRange );
465 if( aDataRange.aEnd.Row() < MAXROW )
467 aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
468 aDataRange.aEnd.SetRow( MAXROW );
470 else if( aDataRange.aStart.Row() > 0 )
472 aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
473 aDataRange.aStart.SetRow( 0 );
475 xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
479 // Conditional formatting =====================================================
481 XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
482 XclImpRoot( rRoot ),
483 mnFormatIndex( nFormatIndex ),
484 mnCondCount( 0 ),
485 mnCondIndex( 0 )
489 XclImpCondFormat::~XclImpCondFormat()
493 void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
495 OSL_ENSURE( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
496 XclRangeList aXclRanges;
497 mnCondCount = rStrm.ReaduInt16();
498 rStrm.Ignore( 10 );
499 rStrm >> aXclRanges;
500 GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
503 void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
505 if( mnCondIndex >= mnCondCount )
507 OSL_FAIL( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
508 return;
511 // entire conditional format outside of valid range?
512 if( maRanges.empty() )
513 return;
515 sal_uInt8 nType = rStrm.ReaduInt8();
516 sal_uInt8 nOperator = rStrm.ReaduInt8();
517 sal_uInt16 nFmlaSize1 = rStrm.ReaduInt16();
518 sal_uInt16 nFmlaSize2 = rStrm.ReaduInt16();
519 sal_uInt32 nFlags = rStrm.ReaduInt32();
520 rStrm.Ignore( 2 ); //nFlagsExtended
522 // *** mode and comparison operator ***
524 ScConditionMode eMode = SC_COND_NONE;
525 switch( nType )
527 case EXC_CF_TYPE_CELL:
529 switch( nOperator )
531 case EXC_CF_CMP_BETWEEN: eMode = SC_COND_BETWEEN; break;
532 case EXC_CF_CMP_NOT_BETWEEN: eMode = SC_COND_NOTBETWEEN; break;
533 case EXC_CF_CMP_EQUAL: eMode = SC_COND_EQUAL; break;
534 case EXC_CF_CMP_NOT_EQUAL: eMode = SC_COND_NOTEQUAL; break;
535 case EXC_CF_CMP_GREATER: eMode = SC_COND_GREATER; break;
536 case EXC_CF_CMP_LESS: eMode = SC_COND_LESS; break;
537 case EXC_CF_CMP_GREATER_EQUAL: eMode = SC_COND_EQGREATER; break;
538 case EXC_CF_CMP_LESS_EQUAL: eMode = SC_COND_EQLESS; break;
539 default:
540 SAL_INFO(
541 "sc.filter", "unknown CF comparison " << nOperator);
544 break;
546 case EXC_CF_TYPE_FMLA:
547 eMode = SC_COND_DIRECT;
548 break;
550 default:
551 SAL_INFO("sc.filter", "unknown CF mode " << nType);
552 return;
555 // *** create style sheet ***
557 OUString aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
558 SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
560 const XclImpPalette& rPalette = GetPalette();
562 // number format
564 if( get_flag( nFlags, EXC_CF_BLOCK_NUMFMT ) )
566 XclImpNumFmtBuffer& rNumFmtBuffer = GetRoot().GetNumFmtBuffer();
567 bool bIFmt = get_flag( nFlags, EXC_CF_IFMT_USER );
568 sal_uInt16 nFormat = rNumFmtBuffer.ReadCFFormat( rStrm, bIFmt );
569 rNumFmtBuffer.FillToItemSet( rStyleItemSet, nFormat );
572 // *** font block ***
574 if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
576 XclImpFont aFont( GetRoot() );
577 aFont.ReadCFFontBlock( rStrm );
578 aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
581 // alignment
582 if( get_flag( nFlags, EXC_CF_BLOCK_ALIGNMENT ) )
584 XclImpCellAlign aAlign;
585 sal_uInt16 nAlign(0);
586 sal_uInt16 nAlignMisc(0);
587 nAlign = rStrm.ReaduInt16();
588 nAlignMisc = rStrm.ReaduInt16();
589 aAlign.FillFromCF( nAlign, nAlignMisc );
590 aAlign.FillToItemSet( rStyleItemSet, NULL );
591 rStrm.Ignore(4);
594 // *** border block ***
596 if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
598 sal_uInt16 nLineStyle(0);
599 sal_uInt32 nLineColor(0);
600 nLineStyle = rStrm.ReaduInt16();
601 nLineColor = rStrm.ReaduInt32();
602 rStrm.Ignore( 2 );
604 XclImpCellBorder aBorder;
605 aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
606 aBorder.FillToItemSet( rStyleItemSet, rPalette );
609 // *** pattern block ***
611 if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
613 sal_uInt16 nPattern(0), nColor(0);
614 nPattern = rStrm.ReaduInt16();
615 nColor = rStrm.ReaduInt16();
617 XclImpCellArea aArea;
618 aArea.FillFromCF8( nPattern, nColor, nFlags );
619 aArea.FillToItemSet( rStyleItemSet, rPalette );
622 if( get_flag( nFlags, EXC_CF_BLOCK_PROTECTION ) )
624 sal_uInt16 nCellProt;
625 nCellProt = rStrm.ReaduInt16();
626 XclImpCellProt aCellProt;
627 aCellProt.FillFromXF3(nCellProt);
628 aCellProt.FillToItemSet( rStyleItemSet );
631 // *** formulas ***
633 const ScAddress& rPos = maRanges.front()->aStart; // assured above that maRanges is not empty
634 ExcelToSc& rFmlaConv = GetOldFmlaConverter();
636 ::std::unique_ptr< ScTokenArray > xTokArr1;
637 if( nFmlaSize1 > 0 )
639 const ScTokenArray* pTokArr = 0;
640 rFmlaConv.Reset( rPos );
641 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_CondFormat );
642 // formula converter owns pTokArr -> create a copy of the token array
643 if( pTokArr )
644 xTokArr1.reset( pTokArr->Clone() );
647 ::std::unique_ptr< ScTokenArray > pTokArr2;
648 if( nFmlaSize2 > 0 )
650 const ScTokenArray* pTokArr = 0;
651 rFmlaConv.Reset( rPos );
652 rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_CondFormat );
653 // formula converter owns pTokArr -> create a copy of the token array
654 if( pTokArr )
655 pTokArr2.reset( pTokArr->Clone() );
658 // *** create the Calc conditional formatting ***
660 if( !mxScCondFmt.get() )
662 sal_uLong nKey = 0;
663 mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
664 if(maRanges.size() > 1)
665 maRanges.Join(*maRanges[0], true);
666 mxScCondFmt->SetRange(maRanges);
669 ScCondFormatEntry* pEntry = new ScCondFormatEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
670 mxScCondFmt->AddEntry( pEntry );
671 ++mnCondIndex;
674 void XclImpCondFormat::Apply()
676 if( mxScCondFmt.get() )
678 ScDocument& rDoc = GetDoc();
680 SCTAB nTab = maRanges.front()->aStart.Tab();
681 sal_uLong nKey = rDoc.AddCondFormat( mxScCondFmt->Clone(), nTab );
683 rDoc.AddCondFormatData( maRanges, nTab, nKey );
687 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
688 XclImpRoot( rRoot )
692 void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
694 XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.size() );
695 pFmt->ReadCondfmt( rStrm );
696 maCondFmtList.push_back( pFmt );
699 void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
701 OSL_ENSURE( !maCondFmtList.empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
702 if( !maCondFmtList.empty() )
703 maCondFmtList.back().ReadCF( rStrm );
706 void XclImpCondFormatManager::Apply()
708 for( XclImpCondFmtList::iterator itFmt = maCondFmtList.begin(); itFmt != maCondFmtList.end(); ++itFmt )
709 itFmt->Apply();
710 maCondFmtList.clear();
713 // Data Validation ============================================================
715 XclImpValidationManager::DVItem::DVItem( const ScRangeList& rRanges, const ScValidationData& rValidData ) :
716 maRanges(rRanges), maValidData(rValidData) {}
718 XclImpValidationManager::XclImpValidationManager( const XclImpRoot& rRoot ) :
719 XclImpRoot( rRoot )
723 void XclImpValidationManager::ReadDval( XclImpStream& rStrm )
725 const XclImpRoot& rRoot = rStrm.GetRoot();
726 OSL_ENSURE_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
728 sal_uInt32 nObjId(0);
729 rStrm.Ignore( 10 );
730 nObjId = rStrm.ReaduInt32();
731 if( nObjId != EXC_DVAL_NOOBJ )
733 OSL_ENSURE( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
734 rRoot.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16 >( nObjId ) );
738 void XclImpValidationManager::ReadDV( XclImpStream& rStrm )
740 const XclImpRoot& rRoot = rStrm.GetRoot();
741 OSL_ENSURE_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
743 ScDocument& rDoc = rRoot.GetDoc();
744 SCTAB nScTab = rRoot.GetCurrScTab();
745 ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
747 // flags
748 sal_uInt32 nFlags(0);
749 nFlags = rStrm.ReaduInt32();
751 // message strings
752 /* Empty strings are single NUL characters in Excel (string length is 1).
753 -> Do not let the stream replace them with '?' characters. */
754 rStrm.SetNulSubstChar( '\0' );
755 OUString aPromptTitle( rStrm.ReadUniString() );
756 OUString aErrorTitle( rStrm.ReadUniString() );
757 OUString aPromptMessage( rStrm.ReadUniString() );
758 OUString aErrorMessage( rStrm.ReadUniString() );
759 rStrm.SetNulSubstChar(); // back to default
761 // formula(s)
762 if ( rStrm.GetRecLeft() <= 8 )
763 // Not enough bytes left in the record. Bail out.
764 return;
766 // first formula
767 // string list is single tStr token with NUL separators -> replace them with LF
768 rStrm.SetNulSubstChar( '\n' );
769 ::std::unique_ptr< ScTokenArray > xTokArr1;
771 sal_uInt16 nLen = 0;
772 nLen = rStrm.ReaduInt16();
773 rStrm.Ignore( 2 );
774 if( nLen > 0 )
776 const ScTokenArray* pTokArr = 0;
777 rFmlaConv.Reset();
778 rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_CondFormat );
779 // formula converter owns pTokArr -> create a copy of the token array
780 if( pTokArr )
781 xTokArr1.reset( pTokArr->Clone() );
783 rStrm.SetNulSubstChar(); // back to default
785 // second formula
786 ::std::unique_ptr< ScTokenArray > xTokArr2;
788 nLen = 0;
789 nLen = rStrm.ReaduInt16();
790 rStrm.Ignore( 2 );
791 if( nLen > 0 )
793 const ScTokenArray* pTokArr = 0;
794 rFmlaConv.Reset();
795 rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_CondFormat );
796 // formula converter owns pTokArr -> create a copy of the token array
797 if( pTokArr )
798 xTokArr2.reset( pTokArr->Clone() );
801 // read all cell ranges
802 XclRangeList aXclRanges;
803 rStrm >> aXclRanges;
805 // convert to Calc range list
806 ScRangeList aScRanges;
807 rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
809 // only continue if there are valid ranges
810 if ( aScRanges.empty() )
811 return;
813 bool bIsValid = true; // valid settings in flags field
815 ScValidationMode eValMode = SC_VALID_ANY;
816 switch( nFlags & EXC_DV_MODE_MASK )
818 case EXC_DV_MODE_ANY: eValMode = SC_VALID_ANY; break;
819 case EXC_DV_MODE_WHOLE: eValMode = SC_VALID_WHOLE; break;
820 case EXC_DV_MODE_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
821 case EXC_DV_MODE_LIST: eValMode = SC_VALID_LIST; break;
822 case EXC_DV_MODE_DATE: eValMode = SC_VALID_DATE; break;
823 case EXC_DV_MODE_TIME: eValMode = SC_VALID_TIME; break;
824 case EXC_DV_MODE_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
825 case EXC_DV_MODE_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
826 default: bIsValid = false;
828 rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
830 ScConditionMode eCondMode = SC_COND_BETWEEN;
831 switch( nFlags & EXC_DV_COND_MASK )
833 case EXC_DV_COND_BETWEEN: eCondMode = SC_COND_BETWEEN; break;
834 case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
835 case EXC_DV_COND_EQUAL: eCondMode = SC_COND_EQUAL; break;
836 case EXC_DV_COND_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break;
837 case EXC_DV_COND_GREATER: eCondMode = SC_COND_GREATER; break;
838 case EXC_DV_COND_LESS: eCondMode = SC_COND_LESS; break;
839 case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER; break;
840 case EXC_DV_COND_EQLESS: eCondMode = SC_COND_EQLESS; break;
841 default: bIsValid = false;
844 if ( !bIsValid )
845 // No valid validation found. Bail out.
846 return;
848 // first range for base address for relative references
849 const ScRange& rScRange = *aScRanges.front(); // aScRanges is not empty
851 // process string list of a list validity (convert to list of string tokens)
852 if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
853 XclTokenArrayHelper::ConvertStringToList(*xTokArr1, rDoc.GetSharedStringPool(), '\n', true);
855 maDVItems.push_back(
856 new DVItem(aScRanges, ScValidationData(eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart)));
857 DVItem& rItem = maDVItems.back();
859 rItem.maValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
860 rItem.maValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, css::sheet::TableValidationVisibility::INVISIBLE, css::sheet::TableValidationVisibility::UNSORTED ) );
862 // *** prompt box ***
863 if( !aPromptTitle.isEmpty() || !aPromptMessage.isEmpty() )
865 // set any text stored in the record
866 rItem.maValidData.SetInput( aPromptTitle, aPromptMessage );
867 if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
868 rItem.maValidData.ResetInput();
871 // *** error box ***
872 ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
873 switch( nFlags & EXC_DV_ERROR_MASK )
875 case EXC_DV_ERROR_WARNING: eErrStyle = SC_VALERR_WARNING; break;
876 case EXC_DV_ERROR_INFO: eErrStyle = SC_VALERR_INFO; break;
878 // set texts and error style
879 rItem.maValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
880 if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
881 rItem.maValidData.ResetError();
884 void XclImpValidationManager::Apply()
886 ScDocument& rDoc = GetRoot().GetDoc();
887 DVItemList::iterator itr = maDVItems.begin(), itrEnd = maDVItems.end();
888 for (; itr != itrEnd; ++itr)
890 DVItem& rItem = *itr;
891 // set the handle ID
892 sal_uLong nHandle = rDoc.AddValidationEntry( rItem.maValidData );
893 ScPatternAttr aPattern( rDoc.GetPool() );
894 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
896 // apply all ranges
897 for ( size_t i = 0, nRanges = rItem.maRanges.size(); i < nRanges; ++i )
899 const ScRange* pScRange = rItem.maRanges[ i ];
900 rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
901 pScRange->aEnd.Col(), pScRange->aEnd.Row(), pScRange->aStart.Tab(), aPattern );
904 maDVItems.clear();
907 // Web queries ================================================================
909 XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
910 maDestRange( rDestRange ),
911 meMode( xlWQUnknown ),
912 mnRefresh( 0 )
916 void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
918 sal_uInt16 nFlags = rStrm.ReaduInt16();
919 sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
920 if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
922 if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
924 meMode = xlWQAllTables;
925 maTables = ScfTools::GetHTMLTablesName();
927 else
929 meMode = xlWQDocument;
930 maTables = ScfTools::GetHTMLDocName();
935 void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
937 maURL = rStrm.ReadUniString();
940 void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
942 rStrm.Ignore( 10 );
943 sal_uInt16 nFlags(0);
944 nFlags = rStrm.ReaduInt16();
945 rStrm.Ignore( 10 );
946 mnRefresh = rStrm.ReaduInt16();
948 if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
949 meMode = xlWQSpecTables;
952 void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
954 if( meMode == xlWQSpecTables )
956 rStrm.Ignore( 4 );
957 OUString aTables( rStrm.ReadUniString() );
959 const sal_Unicode cSep = ';';
960 OUString aQuotedPairs( "\"\"" );
961 sal_Int32 nTokenCnt = ScStringUtil::GetQuotedTokenCount( aTables, aQuotedPairs, ',' );
962 maTables.clear();
963 sal_Int32 nStringIx = 0;
964 for( sal_Int32 nToken = 0; nToken < nTokenCnt; ++nToken )
966 OUString aToken( ScStringUtil::GetQuotedToken( aTables, 0, aQuotedPairs, ',', nStringIx ) );
967 sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.toInt32() : 0;
968 if( nTabNum > 0 )
969 maTables = ScGlobal::addToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
970 else
972 ScGlobal::EraseQuotes( aToken, '"', false );
973 if( !aToken.isEmpty() )
974 maTables = ScGlobal::addToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
980 void XclImpWebQuery::Apply( ScDocument& rDoc, const OUString& rFilterName )
982 if( !maURL.isEmpty() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
984 ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
985 maURL, rFilterName, EMPTY_OUSTRING, maTables, maDestRange, mnRefresh * 60UL );
986 rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
987 maURL, &rFilterName, &maTables );
991 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
992 XclImpRoot( rRoot )
996 void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
998 if( GetBiff() == EXC_BIFF8 )
1000 rStrm.Ignore( 10 );
1001 OUString aXclName( rStrm.ReadUniString() );
1003 // #i64794# Excel replaces spaces with underscores
1004 aXclName = aXclName.replaceAll( " ", "_" );
1006 // find the defined name used in Calc
1007 if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
1009 if( const ScRangeData* pRangeData = pName->GetScRangeData() )
1011 ScRange aRange;
1012 if( pRangeData->IsReference( aRange ) )
1013 maWQList.push_back( new XclImpWebQuery( aRange ) );
1017 else
1019 DBG_ERROR_BIFF();
1023 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
1025 if (!maWQList.empty())
1026 maWQList.back().ReadParamqry( rStrm );
1029 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
1031 if (!maWQList.empty())
1032 maWQList.back().ReadWqstring( rStrm );
1035 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
1037 if (!maWQList.empty())
1038 maWQList.back().ReadWqsettings( rStrm );
1041 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
1043 if (!maWQList.empty())
1044 maWQList.back().ReadWqtables( rStrm );
1047 void XclImpWebQueryBuffer::Apply()
1049 ScDocument& rDoc = GetDoc();
1050 OUString aFilterName( EXC_WEBQRY_FILTER );
1051 for( XclImpWebQueryList::iterator itQuery = maWQList.begin(); itQuery != maWQList.end(); ++itQuery )
1052 itQuery->Apply( rDoc, aFilterName );
1055 // Decryption =================================================================
1057 namespace {
1059 XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
1061 XclImpDecrypterRef xDecr;
1062 OSL_ENSURE( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1063 if( rStrm.GetRecLeft() == 4 )
1065 sal_uInt16 nKey(0), nHash(0);
1066 nKey = rStrm.ReaduInt16();
1067 nHash = rStrm.ReaduInt16();
1068 xDecr.reset( new XclImpBiff5Decrypter( nKey, nHash ) );
1070 return xDecr;
1073 XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
1075 XclImpDecrypterRef xDecr;
1076 OSL_ENSURE( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1077 if( rStrm.GetRecLeft() == 48 )
1079 sal_uInt8 pnSalt[ 16 ];
1080 sal_uInt8 pnVerifier[ 16 ];
1081 sal_uInt8 pnVerifierHash[ 16 ];
1082 rStrm.Read( pnSalt, 16 );
1083 rStrm.Read( pnVerifier, 16 );
1084 rStrm.Read( pnVerifierHash, 16 );
1085 xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
1087 return xDecr;
1090 XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
1092 // not supported
1093 return XclImpDecrypterRef();
1096 XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
1098 XclImpDecrypterRef xDecr;
1100 sal_uInt16 nMode(0);
1101 nMode = rStrm.ReaduInt16();
1102 switch( nMode )
1104 case EXC_FILEPASS_BIFF5:
1105 xDecr = lclReadFilepass5( rStrm );
1106 break;
1108 case EXC_FILEPASS_BIFF8:
1110 rStrm.Ignore( 2 );
1111 sal_uInt16 nSubMode(0);
1112 nSubMode = rStrm.ReaduInt16();
1113 switch( nSubMode )
1115 case EXC_FILEPASS_BIFF8_STD:
1116 xDecr = lclReadFilepass8_Standard( rStrm );
1117 break;
1118 case EXC_FILEPASS_BIFF8_STRONG:
1119 xDecr = lclReadFilepass8_Strong( rStrm );
1120 break;
1121 default:
1122 OSL_FAIL( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1125 break;
1127 default:
1128 OSL_FAIL( "lclReadFilepass8 - unknown encryption mode" );
1131 return xDecr;
1134 } // namespace
1136 ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
1138 XclImpDecrypterRef xDecr;
1139 rStrm.DisableDecryption();
1141 // read the FILEPASS record and create a new decrypter object
1142 switch( rStrm.GetRoot().GetBiff() )
1144 case EXC_BIFF2:
1145 case EXC_BIFF3:
1146 case EXC_BIFF4:
1147 case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm ); break;
1148 case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm ); break;
1149 default: DBG_ERROR_BIFF();
1152 // set decrypter at import stream
1153 rStrm.SetDecrypter( xDecr );
1155 // request and verify a password (decrypter implements IDocPasswordVerifier)
1156 if( xDecr )
1157 rStrm.GetRoot().RequestEncryptionData( *xDecr );
1159 // return error code (success, wrong password, etc.)
1160 return xDecr ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
1163 // Document protection ========================================================
1165 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
1166 XclImpRoot( rRoot ),
1167 mnPassHash(0x0000),
1168 mbDocProtect(false),
1169 mbWinProtect(false)
1173 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
1175 mbDocProtect = rStrm.ReaduInt16() != 0;
1178 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
1180 mbWinProtect = rStrm.ReaduInt16() != 0;
1183 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
1185 rStrm.EnableDecryption();
1186 mnPassHash = rStrm.ReaduInt16();
1189 void XclImpDocProtectBuffer::Apply() const
1191 if (!mbDocProtect && !mbWinProtect)
1192 // Excel requires either the structure or windows protection is set.
1193 // If neither is set then the document is not protected at all.
1194 return;
1196 unique_ptr<ScDocProtection> pProtect(new ScDocProtection);
1197 pProtect->setProtected(true);
1199 if (mnPassHash)
1201 // 16-bit password pash.
1202 Sequence<sal_Int8> aPass(2);
1203 aPass[0] = (mnPassHash >> 8) & 0xFF;
1204 aPass[1] = mnPassHash & 0xFF;
1205 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1208 // document protection options
1209 pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
1210 pProtect->setOption(ScDocProtection::WINDOWS, mbWinProtect);
1212 GetDoc().SetDocProtection(pProtect.get());
1215 // Sheet Protection ===========================================================
1217 XclImpSheetProtectBuffer::Sheet::Sheet() :
1218 mbProtected(false),
1219 mnPasswordHash(0x0000),
1220 mnOptions(0x4400)
1224 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
1225 mbProtected(r.mbProtected),
1226 mnPasswordHash(r.mnPasswordHash),
1227 mnOptions(r.mnOptions)
1231 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
1232 XclImpRoot( rRoot )
1236 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
1238 if ( rStrm.ReaduInt16() )
1240 Sheet* pSheet = GetSheetItem(nTab);
1241 if (pSheet)
1242 pSheet->mbProtected = true;
1246 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
1248 // The flag size specifies the size of bytes that follows that stores
1249 // feature data. If -1 it depends on the feature type imported earlier.
1250 // For enhanced protection data, the size is always 4. For the most xls
1251 // documents out there this value is almost always -1.
1252 sal_Int32 nFlagSize(0);
1253 nFlagSize = rStrm.ReadInt32();
1254 if (nFlagSize != -1)
1255 return;
1257 // There are actually 4 bytes to read, but the upper 2 bytes currently
1258 // don't store any bits.
1259 sal_uInt16 nOptions(0);
1260 nOptions = rStrm.ReaduInt16();
1262 Sheet* pSheet = GetSheetItem(nTab);
1263 if (pSheet)
1264 pSheet->mnOptions = nOptions;
1267 void XclImpSheetProtectBuffer::AppendEnhancedProtection( const ScEnhancedProtection & rProt, SCTAB nTab )
1269 Sheet* pSheet = GetSheetItem(nTab);
1270 if (pSheet)
1271 pSheet->maEnhancedProtections.push_back( rProt);
1274 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
1276 sal_uInt16 nHash(0);
1277 nHash = rStrm.ReaduInt16();
1278 Sheet* pSheet = GetSheetItem(nTab);
1279 if (pSheet)
1280 pSheet->mnPasswordHash = nHash;
1283 void XclImpSheetProtectBuffer::Apply() const
1285 for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
1286 itr != itrEnd; ++itr)
1288 if (!itr->second.mbProtected)
1289 // This sheet is (for whatever reason) not protected.
1290 continue;
1292 unique_ptr<ScTableProtection> pProtect(new ScTableProtection);
1293 pProtect->setProtected(true);
1295 // 16-bit hash password
1296 const sal_uInt16 nHash = itr->second.mnPasswordHash;
1297 if (nHash)
1299 Sequence<sal_Int8> aPass(2);
1300 aPass[0] = (nHash >> 8) & 0xFF;
1301 aPass[1] = nHash & 0xFF;
1302 pProtect->setPasswordHash(aPass, PASSHASH_XL);
1305 // sheet protection options
1306 const sal_uInt16 nOptions = itr->second.mnOptions;
1307 pProtect->setOption( ScTableProtection::OBJECTS, (nOptions & 0x0001) );
1308 pProtect->setOption( ScTableProtection::SCENARIOS, (nOptions & 0x0002) );
1309 pProtect->setOption( ScTableProtection::FORMAT_CELLS, (nOptions & 0x0004) );
1310 pProtect->setOption( ScTableProtection::FORMAT_COLUMNS, (nOptions & 0x0008) );
1311 pProtect->setOption( ScTableProtection::FORMAT_ROWS, (nOptions & 0x0010) );
1312 pProtect->setOption( ScTableProtection::INSERT_COLUMNS, (nOptions & 0x0020) );
1313 pProtect->setOption( ScTableProtection::INSERT_ROWS, (nOptions & 0x0040) );
1314 pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS, (nOptions & 0x0080) );
1315 pProtect->setOption( ScTableProtection::DELETE_COLUMNS, (nOptions & 0x0100) );
1316 pProtect->setOption( ScTableProtection::DELETE_ROWS, (nOptions & 0x0200) );
1317 pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS, (nOptions & 0x0400) );
1318 pProtect->setOption( ScTableProtection::SORT, (nOptions & 0x0800) );
1319 pProtect->setOption( ScTableProtection::AUTOFILTER, (nOptions & 0x1000) );
1320 pProtect->setOption( ScTableProtection::PIVOT_TABLES, (nOptions & 0x2000) );
1321 pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
1323 // Enhanced protection containing editable ranges and permissions.
1324 pProtect->setEnhancedProtection( itr->second.maEnhancedProtections);
1326 // all done. now commit.
1327 GetDoc().SetTabProtection(itr->first, pProtect.get());
1331 XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
1333 ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
1334 if (itr == maProtectedSheets.end())
1336 // new sheet
1337 if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
1338 return NULL;
1340 itr = maProtectedSheets.find(nTab);
1343 return &itr->second;
1346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */