1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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"
58 #include "excform.hxx"
59 #include "tabprotection.hxx"
60 #include "documentimport.hxx"
65 using ::com::sun::star::uno::Sequence
;
66 using ::std::unique_ptr
;
68 // Shared string table ========================================================
70 XclImpSst::XclImpSst( const XclImpRoot
& rRoot
) :
75 void XclImpSst::ReadSst( XclImpStream
& rStrm
)
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
;
86 maStrings
.reserve(nStrCount
);
87 while( (nStrCount
> 0) && rStrm
.IsValid() )
90 aString
.Read( rStrm
);
91 maStrings
.push_back( aString
);
96 const XclImpString
* XclImpSst::GetString( sal_uInt32 nSstIndex
) const
98 return (nSstIndex
< maStrings
.size()) ? &maStrings
[ nSstIndex
] : 0;
101 // Hyperlinks =================================================================
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
;
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();
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
;
145 aTmpStr
.append( "../" );
148 aTmpStr
.append( rPath
);
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
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
);
168 // #i54261# hyperlinks in string cells
169 case CELLTYPE_STRING
:
172 OUString aDisplText
= rDoc
.getDoc().GetString(nScCol
, nScRow
, nScTab
);
173 if (aDisplText
.isEmpty())
176 ScEditEngineDefaulter
& rEE
= rRoot
.GetEditEngine();
177 SvxURLField
aUrlField( rUrl
, aDisplText
, SVXURLFORMAT_APPDEFAULT
);
179 const EditTextObject
* pEditObj
= rDoc
.getDoc().GetEditText(aScPos
);
182 rEE
.SetText( *pEditObj
);
183 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection( 0, 0, EE_PARA_ALL
, 0 ) );
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());
203 // Handle other cell types e.g. formulas ( and ? ) that have associated
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
);
222 void XclImpHyperlink::ReadHlink( XclImpStream
& rStrm
)
224 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
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
);
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' );
265 if( ::get_flag( nFlags
, EXC_HLINK_UNC
) )
267 xLongName
.reset( new OUString
);
268 lclAppendString32( *xLongName
, rStrm
, true );
269 lclGetAbsPath( *xLongName
, 0, pDocShell
);
272 else if( ::get_flag( nFlags
, EXC_HLINK_BODY
) )
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 );
284 sal_uInt32 nStrLen
= 0;
285 nStrLen
= rStrm
.ReaduInt32();
289 nStrLen
= rStrm
.ReaduInt32();
290 nStrLen
/= 2; // it's byte count here...
292 xLongName
.reset( new OUString
);
293 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
294 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
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
);
311 OSL_FAIL( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
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();
349 // Needs at least 4 characters.
353 // the 1st character must be '#'.
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
];
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
370 bQuoteTabName
= true;
371 aTabName
+= OUString(c
);
372 aTabName
+= OUString(c
);
377 bInQuote
= !bInQuote
;
378 if (!bInQuote
&& !aTabName
.isEmpty())
381 aNewUrl
+= OUString('\'');
384 aNewUrl
+= OUString('\'');
388 aTabName
+= OUString(c
);
390 aNewUrl
+= OUString(c
);
394 // It should be outside the quotes!
397 // All is good. Pass the new URL.
401 void XclImpHyperlink::InsertUrl( XclImpRoot
& rRoot
, const XclRange
& rXclRange
, const OUString
& 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
;
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
) :
483 mnFormatIndex( nFormatIndex
),
489 XclImpCondFormat::~XclImpCondFormat()
493 void XclImpCondFormat::ReadCondfmt( XclImpStream
& rStrm
)
495 OSL_ENSURE( !mnCondCount
, "XclImpCondFormat::ReadCondfmt - already initialized" );
496 XclRangeList aXclRanges
;
497 mnCondCount
= rStrm
.ReaduInt16();
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" );
511 // entire conditional format outside of valid range?
512 if( maRanges
.empty() )
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
;
527 case EXC_CF_TYPE_CELL
:
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;
541 "sc.filter", "unknown CF comparison " << nOperator
);
546 case EXC_CF_TYPE_FMLA
:
547 eMode
= SC_COND_DIRECT
;
551 SAL_INFO("sc.filter", "unknown CF mode " << nType
);
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();
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
);
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
);
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();
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
);
633 const ScAddress
& rPos
= maRanges
.front()->aStart
; // assured above that maRanges is not empty
634 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
636 ::std::unique_ptr
< ScTokenArray
> xTokArr1
;
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
644 xTokArr1
.reset( pTokArr
->Clone() );
647 ::std::unique_ptr
< ScTokenArray
> pTokArr2
;
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
655 pTokArr2
.reset( pTokArr
->Clone() );
658 // *** create the Calc conditional formatting ***
660 if( !mxScCondFmt
.get() )
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
);
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
) :
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
)
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
) :
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);
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();
748 sal_uInt32
nFlags(0);
749 nFlags
= rStrm
.ReaduInt32();
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
762 if ( rStrm
.GetRecLeft() <= 8 )
763 // Not enough bytes left in the record. Bail out.
767 // string list is single tStr token with NUL separators -> replace them with LF
768 rStrm
.SetNulSubstChar( '\n' );
769 ::std::unique_ptr
< ScTokenArray
> xTokArr1
;
772 nLen
= rStrm
.ReaduInt16();
776 const ScTokenArray
* pTokArr
= 0;
778 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_CondFormat
);
779 // formula converter owns pTokArr -> create a copy of the token array
781 xTokArr1
.reset( pTokArr
->Clone() );
783 rStrm
.SetNulSubstChar(); // back to default
786 ::std::unique_ptr
< ScTokenArray
> xTokArr2
;
789 nLen
= rStrm
.ReaduInt16();
793 const ScTokenArray
* pTokArr
= 0;
795 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_CondFormat
);
796 // formula converter owns pTokArr -> create a copy of the token array
798 xTokArr2
.reset( pTokArr
->Clone() );
801 // read all cell ranges
802 XclRangeList 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() )
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;
845 // No valid validation found. Bail out.
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);
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();
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
;
892 sal_uLong nHandle
= rDoc
.AddValidationEntry( rItem
.maValidData
);
893 ScPatternAttr
aPattern( rDoc
.GetPool() );
894 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nHandle
) );
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
);
907 // Web queries ================================================================
909 XclImpWebQuery::XclImpWebQuery( const ScRange
& rDestRange
) :
910 maDestRange( rDestRange
),
911 meMode( xlWQUnknown
),
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();
929 meMode
= xlWQDocument
;
930 maTables
= ScfTools::GetHTMLDocName();
935 void XclImpWebQuery::ReadWqstring( XclImpStream
& rStrm
)
937 maURL
= rStrm
.ReadUniString();
940 void XclImpWebQuery::ReadWqsettings( XclImpStream
& rStrm
)
943 sal_uInt16
nFlags(0);
944 nFlags
= rStrm
.ReaduInt16();
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
)
957 OUString
aTables( rStrm
.ReadUniString() );
959 const sal_Unicode cSep
= ';';
960 OUString
aQuotedPairs( "\"\"" );
961 sal_Int32 nTokenCnt
= ScStringUtil::GetQuotedTokenCount( aTables
, aQuotedPairs
, ',' );
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;
969 maTables
= ScGlobal::addToken( maTables
, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32
>( nTabNum
) ), cSep
);
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
) :
996 void XclImpWebQueryBuffer::ReadQsi( XclImpStream
& rStrm
)
998 if( GetBiff() == EXC_BIFF8
)
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() )
1012 if( pRangeData
->IsReference( aRange
) )
1013 maWQList
.push_back( new XclImpWebQuery( aRange
) );
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 =================================================================
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
) );
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
) );
1090 XclImpDecrypterRef
lclReadFilepass8_Strong( XclImpStream
& /*rStrm*/ )
1093 return XclImpDecrypterRef();
1096 XclImpDecrypterRef
lclReadFilepass8( XclImpStream
& rStrm
)
1098 XclImpDecrypterRef xDecr
;
1100 sal_uInt16
nMode(0);
1101 nMode
= rStrm
.ReaduInt16();
1104 case EXC_FILEPASS_BIFF5
:
1105 xDecr
= lclReadFilepass5( rStrm
);
1108 case EXC_FILEPASS_BIFF8
:
1111 sal_uInt16
nSubMode(0);
1112 nSubMode
= rStrm
.ReaduInt16();
1115 case EXC_FILEPASS_BIFF8_STD
:
1116 xDecr
= lclReadFilepass8_Standard( rStrm
);
1118 case EXC_FILEPASS_BIFF8_STRONG
:
1119 xDecr
= lclReadFilepass8_Strong( rStrm
);
1122 OSL_FAIL( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1128 OSL_FAIL( "lclReadFilepass8 - unknown encryption mode" );
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() )
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)
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
),
1168 mbDocProtect(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.
1196 unique_ptr
<ScDocProtection
> pProtect(new ScDocProtection
);
1197 pProtect
->setProtected(true);
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() :
1219 mnPasswordHash(0x0000),
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
) :
1236 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream
& rStrm
, SCTAB nTab
)
1238 if ( rStrm
.ReaduInt16() )
1240 Sheet
* pSheet
= GetSheetItem(nTab
);
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)
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
);
1264 pSheet
->mnOptions
= nOptions
;
1267 void XclImpSheetProtectBuffer::AppendEnhancedProtection( const ScEnhancedProtection
& rProt
, SCTAB nTab
)
1269 Sheet
* pSheet
= GetSheetItem(nTab
);
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
);
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.
1292 unique_ptr
<ScTableProtection
> pProtect(new ScTableProtection
);
1293 pProtect
->setProtected(true);
1295 // 16-bit hash password
1296 const sal_uInt16 nHash
= itr
->second
.mnPasswordHash
;
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())
1337 if ( !maProtectedSheets
.insert( ProtectedSheetMap::value_type(nTab
, Sheet()) ).second
)
1340 itr
= maProtectedSheets
.find(nTab
);
1343 return &itr
->second
;
1346 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */