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 "cellform.hxx"
41 #include "cellvalue.hxx"
42 #include "document.hxx"
43 #include "editutil.hxx"
44 #include "formulacell.hxx"
45 #include "validat.hxx"
46 #include "patattr.hxx"
47 #include "docpool.hxx"
48 #include "rangenam.hxx"
49 #include "arealink.hxx"
50 #include "stlsheet.hxx"
51 #include "scextopt.hxx"
52 #include "xlformula.hxx"
53 #include "xltracer.hxx"
54 #include "xistream.hxx"
55 #include "xihelper.hxx"
56 #include "xistyle.hxx"
57 #include "xiescher.hxx"
60 #include "excform.hxx"
61 #include "tabprotection.hxx"
62 #include "documentimport.hxx"
66 #include <o3tl/make_unique.hxx>
67 #include <oox/helper/helper.hxx>
69 using ::com::sun::star::uno::Sequence
;
70 using ::std::unique_ptr
;
72 // Shared string table ========================================================
74 XclImpSst::XclImpSst( const XclImpRoot
& rRoot
) :
79 void XclImpSst::ReadSst( XclImpStream
& rStrm
)
82 sal_uInt32 nStrCount
= rStrm
.ReaduInt32();
83 auto nBytesAvailable
= rStrm
.GetRecLeft();
84 if (nStrCount
> nBytesAvailable
)
86 SAL_WARN("sc.filter", "xls claimed to have " << nStrCount
<< " strings, but only " << nBytesAvailable
<< " bytes available, truncating");
87 nStrCount
= nBytesAvailable
;
90 maStrings
.reserve(nStrCount
);
91 while( (nStrCount
> 0) && rStrm
.IsValid() )
94 aString
.Read( rStrm
);
95 maStrings
.push_back( aString
);
100 const XclImpString
* XclImpSst::GetString( sal_uInt32 nSstIndex
) const
102 return (nSstIndex
< maStrings
.size()) ? &maStrings
[ nSstIndex
] : nullptr;
105 // Hyperlinks =================================================================
109 /** Reads character array and stores it into rString.
110 @param nChars Number of following characters (not byte count!).
111 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
112 void lclAppendString32( OUString
& rString
, XclImpStream
& rStrm
, sal_uInt32 nChars
, bool b16Bit
)
114 sal_uInt16 nReadChars
= ulimit_cast
< sal_uInt16
>( nChars
);
115 rString
+= rStrm
.ReadRawUniString( nReadChars
, b16Bit
);
116 // ignore remaining chars
117 sal_Size nIgnore
= nChars
- nReadChars
;
120 rStrm
.Ignore( nIgnore
);
123 /** Reads 32-bit string length and the character array and stores it into rString.
124 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
125 void lclAppendString32( OUString
& rString
, XclImpStream
& rStrm
, bool b16Bit
)
127 lclAppendString32( rString
, rStrm
, rStrm
.ReaduInt32(), b16Bit
);
130 /** Reads 32-bit string length and ignores following character array.
131 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
132 void lclIgnoreString32( XclImpStream
& rStrm
, bool b16Bit
)
134 sal_uInt32
nChars(0);
135 nChars
= rStrm
.ReaduInt32();
138 rStrm
.Ignore( nChars
);
141 /** Converts a path to an absolute path.
142 @param rPath The source path. The resulting path is returned here.
143 @param nLevel Number of parent directories to add in front of the path. */
144 void lclGetAbsPath( OUString
& rPath
, sal_uInt16 nLevel
, SfxObjectShell
* pDocShell
)
146 OUStringBuffer aTmpStr
;
149 aTmpStr
.append( "../" );
152 aTmpStr
.append( rPath
);
156 bool bWasAbs
= false;
157 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
.makeStringAndClear(), bWasAbs
).GetMainURL( INetURLObject::NO_DECODE
);
158 // full path as stored in SvxURLField must be encoded
161 rPath
= aTmpStr
.makeStringAndClear();
164 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
165 void lclInsertUrl( XclImpRoot
& rRoot
, const OUString
& rUrl
, SCCOL nScCol
, SCROW nScRow
, SCTAB nScTab
)
167 ScDocumentImport
& rDoc
= rRoot
.GetDocImport();
168 ScAddress
aScPos( nScCol
, nScRow
, nScTab
);
169 ScRefCellValue
aCell(rDoc
.getDoc(), aScPos
);
170 switch( aCell
.meType
)
172 // #i54261# hyperlinks in string cells
173 case CELLTYPE_STRING
:
176 sal_uLong nNumFmt
= rDoc
.getDoc().GetNumberFormat(aScPos
);
177 SvNumberFormatter
* pFormatter
= rDoc
.getDoc().GetFormatTable();
180 ScCellFormat::GetString(aCell
, nNumFmt
, aDisplText
, &pColor
, *pFormatter
, &rDoc
.getDoc());
181 if (aDisplText
.isEmpty())
184 ScEditEngineDefaulter
& rEE
= rRoot
.GetEditEngine();
185 SvxURLField
aUrlField( rUrl
, aDisplText
, SVXURLFORMAT_APPDEFAULT
);
187 if( aCell
.meType
== CELLTYPE_EDIT
)
189 const EditTextObject
* pEditObj
= aCell
.mpEditText
;
190 rEE
.SetText( *pEditObj
);
191 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection( 0, 0, EE_PARA_ALL
, 0 ) );
195 rEE
.SetText( EMPTY_OUSTRING
);
196 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection() );
197 if( const ScPatternAttr
* pPattern
= rDoc
.getDoc().GetPattern( aScPos
.Col(), aScPos
.Row(), nScTab
) )
199 SfxItemSet
aItemSet( rEE
.GetEmptyItemSet() );
200 pPattern
->FillEditItemSet( &aItemSet
);
201 rEE
.QuickSetAttribs( aItemSet
, ESelection( 0, 0, EE_PARA_ALL
, 0 ) );
205 // The cell will own the text object instance.
206 rDoc
.setEditCell(aScPos
, rEE
.CreateTextObject());
211 // Handle other cell types e.g. formulas ( and ? ) that have associated
213 // Ideally all hyperlinks should be treated as below. For the moment,
214 // given the current absence of ods support lets just handle what we
215 // previously didn't handle the new way.
216 // Unfortunately we won't be able to preserve such hyperlinks when
217 // saving to ods. Note: when we are able to save such hyperlinks to ods
218 // we should handle *all* imported hyperlinks as below ( e.g. as cell
219 // attribute ) for better interoperability.
221 SfxStringItem
aItem( ATTR_HYPERLINK
, rUrl
);
222 rDoc
.getDoc().ApplyAttr(nScCol
, nScRow
, nScTab
, aItem
);
230 void XclImpHyperlink::ReadHlink( XclImpStream
& rStrm
)
232 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
234 // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
235 aXclRange
.maFirst
.mnCol
&= 0xFF;
236 aXclRange
.maLast
.mnCol
&= 0xFF;
237 OUString aString
= ReadEmbeddedData( rStrm
);
238 if ( !aString
.isEmpty() )
239 rStrm
.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange
, aString
);
242 OUString
XclImpHyperlink::ReadEmbeddedData( XclImpStream
& rStrm
)
244 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
245 SfxObjectShell
* pDocShell
= rRoot
.GetDocShell();
247 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
252 sal_uInt32
nFlags(0);
253 nFlags
= rStrm
.ReaduInt32();
255 OSL_ENSURE( aGuid
== XclTools::maGuidStdLink
, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
257 ::std::unique_ptr
< OUString
> xLongName
; // link / file name
258 ::std::unique_ptr
< OUString
> xShortName
; // 8.3-representation of file name
259 ::std::unique_ptr
< OUString
> xTextMark
; // text mark
261 // description (ignore)
262 if( ::get_flag( nFlags
, EXC_HLINK_DESCR
) )
263 lclIgnoreString32( rStrm
, true );
264 // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
265 if( ::get_flag( nFlags
, EXC_HLINK_FRAME
) )
266 lclIgnoreString32( rStrm
, true );
268 // URL fields are zero-terminated - do not let the stream replace them
269 // in the lclAppendString32() with the '?' character.
270 rStrm
.SetNulSubstChar( '\0' );
273 if( ::get_flag( nFlags
, EXC_HLINK_UNC
) )
275 xLongName
.reset( new OUString
);
276 lclAppendString32( *xLongName
, rStrm
, true );
277 lclGetAbsPath( *xLongName
, 0, pDocShell
);
280 else if( ::get_flag( nFlags
, EXC_HLINK_BODY
) )
284 if( aGuid
== XclTools::maGuidFileMoniker
)
286 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
287 nLevel
= rStrm
.ReaduInt16();
288 xShortName
.reset( new OUString
);
289 lclAppendString32( *xShortName
, rStrm
, false );
292 sal_uInt32 nStrLen
= 0;
293 nStrLen
= rStrm
.ReaduInt32();
296 nStrLen
= rStrm
.ReaduInt32();
297 nStrLen
/= 2; // it's byte count here...
299 xLongName
.reset( new OUString
);
300 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
301 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
304 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
306 else if( aGuid
== XclTools::maGuidUrlMoniker
)
308 sal_uInt32
nStrLen(0);
309 nStrLen
= rStrm
.ReaduInt32();
310 nStrLen
/= 2; // it's byte count here...
311 xLongName
.reset( new OUString
);
312 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
313 if( !::get_flag( nFlags
, EXC_HLINK_ABS
) )
314 lclGetAbsPath( *xLongName
, 0, pDocShell
);
318 OSL_FAIL( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
323 if( ::get_flag( nFlags
, EXC_HLINK_MARK
) )
325 xTextMark
.reset( new OUString
);
326 lclAppendString32( *xTextMark
, rStrm
, true );
329 rStrm
.SetNulSubstChar(); // back to default
331 OSL_ENSURE( rStrm
.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
333 if( !xLongName
.get() && xShortName
.get() )
334 xLongName
= std::move(xShortName
);
335 else if( !xLongName
.get() && xTextMark
.get() )
336 xLongName
.reset( new OUString
);
338 if( xLongName
.get() )
340 if( xTextMark
.get() )
342 if( xLongName
->isEmpty() )
344 sal_Int32 nSepPos
= xTextMark
->lastIndexOf( '!' );
347 // Do not attempt to blindly convert '#SheetName!A1' to
348 // '#SheetName.A1', it can be #SheetName!R1C1 as well.
349 // Hyperlink handler has to handle all, but prefer
350 // '#SheetName.A1' if possible.
351 if (nSepPos
< xTextMark
->getLength() - 1)
354 if ((aRange
.ParseAny( xTextMark
->copy( nSepPos
+ 1 ), nullptr, formula::FormulaGrammar::CONV_XL_R1C1
)
355 & ScRefFlags::VALID
) == ScRefFlags::ZERO
)
356 xTextMark
.reset( new OUString( xTextMark
->replaceAt( nSepPos
, 1, OUString( '.' ))));
360 xLongName
.reset( new OUString( *xLongName
+ "#" + *xTextMark
) );
362 return( *xLongName
);
364 return( OUString() );
367 void XclImpHyperlink::ConvertToValidTabName(OUString
& rUrl
)
369 sal_Int32 n
= rUrl
.getLength();
371 // Needs at least 4 characters.
375 // the 1st character must be '#'.
378 OUString
aNewUrl('#'), aTabName
;
380 bool bInQuote
= false;
381 bool bQuoteTabName
= false;
382 for( sal_Int32 i
= 1; i
< n
; ++i
)
384 sal_Unicode c
= rUrl
[i
];
387 if (bInQuote
&& i
+1 < n
&& rUrl
[i
+1] == '\'')
389 // Two consecutive single quotes ('') signify a single literal
390 // quite. When this occurs, the whole table name needs to be
392 bQuoteTabName
= true;
393 aTabName
+= OUString(c
);
394 aTabName
+= OUString(c
);
399 bInQuote
= !bInQuote
;
400 if (!bInQuote
&& !aTabName
.isEmpty())
410 aTabName
+= OUString(c
);
412 aNewUrl
+= OUString(c
);
416 // It should be outside the quotes!
419 // All is good. Pass the new URL.
423 void XclImpHyperlink::InsertUrl( XclImpRoot
& rRoot
, const XclRange
& rXclRange
, const OUString
& rUrl
)
426 ConvertToValidTabName(aUrl
);
428 SCTAB nScTab
= rRoot
.GetCurrScTab();
429 ScRange
aScRange( ScAddress::UNINITIALIZED
);
430 if( rRoot
.GetAddressConverter().ConvertRange( aScRange
, rXclRange
, nScTab
, nScTab
, true ) )
432 SCCOL nScCol1
, nScCol2
;
433 SCROW nScRow1
, nScRow2
;
434 aScRange
.GetVars( nScCol1
, nScRow1
, nScTab
, nScCol2
, nScRow2
, nScTab
);
435 for( SCCOL nScCol
= nScCol1
; nScCol
<= nScCol2
; ++nScCol
)
436 for( SCROW nScRow
= nScRow1
; nScRow
<= nScRow2
; ++nScRow
)
437 lclInsertUrl( rRoot
, aUrl
, nScCol
, nScRow
, nScTab
);
441 // Label ranges ===============================================================
443 void XclImpLabelranges::ReadLabelranges( XclImpStream
& rStrm
)
445 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
446 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
448 ScDocument
& rDoc
= rRoot
.GetDoc();
449 SCTAB nScTab
= rRoot
.GetCurrScTab();
450 XclImpAddressConverter
& rAddrConv
= rRoot
.GetAddressConverter();
451 ScRangePairListRef xLabelRangesRef
;
452 const ScRange
* pScRange
= nullptr;
454 XclRangeList aRowXclRanges
, aColXclRanges
;
455 rStrm
>> aRowXclRanges
>> aColXclRanges
;
458 ScRangeList aRowScRanges
;
459 rAddrConv
.ConvertRangeList( aRowScRanges
, aRowXclRanges
, nScTab
, false );
460 xLabelRangesRef
= rDoc
.GetRowNameRangesRef();
461 for ( size_t i
= 0, nRanges
= aRowScRanges
.size(); i
< nRanges
; ++i
)
463 pScRange
= aRowScRanges
[ i
];
464 ScRange
aDataRange( *pScRange
);
465 if( aDataRange
.aEnd
.Col() < MAXCOL
)
467 aDataRange
.aStart
.SetCol( aDataRange
.aEnd
.Col() + 1 );
468 aDataRange
.aEnd
.SetCol( MAXCOL
);
470 else if( aDataRange
.aStart
.Col() > 0 )
472 aDataRange
.aEnd
.SetCol( aDataRange
.aStart
.Col() - 1 );
473 aDataRange
.aStart
.SetCol( 0 );
475 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
478 // column label ranges
479 ScRangeList aColScRanges
;
480 rAddrConv
.ConvertRangeList( aColScRanges
, aColXclRanges
, nScTab
, false );
481 xLabelRangesRef
= rDoc
.GetColNameRangesRef();
483 for ( size_t i
= 0, nRanges
= aColScRanges
.size(); i
< nRanges
; ++i
)
485 pScRange
= aColScRanges
[ i
];
486 ScRange
aDataRange( *pScRange
);
487 if( aDataRange
.aEnd
.Row() < MAXROW
)
489 aDataRange
.aStart
.SetRow( aDataRange
.aEnd
.Row() + 1 );
490 aDataRange
.aEnd
.SetRow( MAXROW
);
492 else if( aDataRange
.aStart
.Row() > 0 )
494 aDataRange
.aEnd
.SetRow( aDataRange
.aStart
.Row() - 1 );
495 aDataRange
.aStart
.SetRow( 0 );
497 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
501 // Conditional formatting =====================================================
503 XclImpCondFormat::XclImpCondFormat( const XclImpRoot
& rRoot
, sal_uInt32 nFormatIndex
) :
505 mnFormatIndex( nFormatIndex
),
511 XclImpCondFormat::~XclImpCondFormat()
515 void XclImpCondFormat::ReadCondfmt( XclImpStream
& rStrm
)
517 OSL_ENSURE( !mnCondCount
, "XclImpCondFormat::ReadCondfmt - already initialized" );
518 XclRangeList aXclRanges
;
519 mnCondCount
= rStrm
.ReaduInt16();
522 GetAddressConverter().ConvertRangeList( maRanges
, aXclRanges
, GetCurrScTab(), true );
525 void XclImpCondFormat::ReadCF( XclImpStream
& rStrm
)
527 if( mnCondIndex
>= mnCondCount
)
529 OSL_FAIL( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
533 // entire conditional format outside of valid range?
534 if( maRanges
.empty() )
537 sal_uInt8 nType
= rStrm
.ReaduInt8();
538 sal_uInt8 nOperator
= rStrm
.ReaduInt8();
539 sal_uInt16 nFmlaSize1
= rStrm
.ReaduInt16();
540 sal_uInt16 nFmlaSize2
= rStrm
.ReaduInt16();
541 sal_uInt32 nFlags
= rStrm
.ReaduInt32();
542 rStrm
.Ignore( 2 ); //nFlagsExtended
544 // *** mode and comparison operator ***
546 ScConditionMode eMode
= SC_COND_NONE
;
549 case EXC_CF_TYPE_CELL
:
553 case EXC_CF_CMP_BETWEEN
: eMode
= SC_COND_BETWEEN
; break;
554 case EXC_CF_CMP_NOT_BETWEEN
: eMode
= SC_COND_NOTBETWEEN
; break;
555 case EXC_CF_CMP_EQUAL
: eMode
= SC_COND_EQUAL
; break;
556 case EXC_CF_CMP_NOT_EQUAL
: eMode
= SC_COND_NOTEQUAL
; break;
557 case EXC_CF_CMP_GREATER
: eMode
= SC_COND_GREATER
; break;
558 case EXC_CF_CMP_LESS
: eMode
= SC_COND_LESS
; break;
559 case EXC_CF_CMP_GREATER_EQUAL
: eMode
= SC_COND_EQGREATER
; break;
560 case EXC_CF_CMP_LESS_EQUAL
: eMode
= SC_COND_EQLESS
; break;
563 "sc.filter", "unknown CF comparison " << nOperator
);
568 case EXC_CF_TYPE_FMLA
:
569 eMode
= SC_COND_DIRECT
;
573 SAL_INFO("sc.filter", "unknown CF mode " << nType
);
577 // *** create style sheet ***
579 OUString
aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex
, mnCondIndex
) );
580 SfxItemSet
& rStyleItemSet
= ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName
, true ).GetItemSet();
582 const XclImpPalette
& rPalette
= GetPalette();
586 if( get_flag( nFlags
, EXC_CF_BLOCK_NUMFMT
) )
588 XclImpNumFmtBuffer
& rNumFmtBuffer
= GetRoot().GetNumFmtBuffer();
589 bool bIFmt
= get_flag( nFlags
, EXC_CF_IFMT_USER
);
590 sal_uInt16 nFormat
= rNumFmtBuffer
.ReadCFFormat( rStrm
, bIFmt
);
591 rNumFmtBuffer
.FillToItemSet( rStyleItemSet
, nFormat
);
594 // *** font block ***
596 if( ::get_flag( nFlags
, EXC_CF_BLOCK_FONT
) )
598 XclImpFont
aFont( GetRoot() );
599 aFont
.ReadCFFontBlock( rStrm
);
600 aFont
.FillToItemSet( rStyleItemSet
, EXC_FONTITEM_CELL
);
604 if( get_flag( nFlags
, EXC_CF_BLOCK_ALIGNMENT
) )
606 XclImpCellAlign aAlign
;
607 sal_uInt16
nAlign(0);
608 sal_uInt16
nAlignMisc(0);
609 nAlign
= rStrm
.ReaduInt16();
610 nAlignMisc
= rStrm
.ReaduInt16();
611 aAlign
.FillFromCF( nAlign
, nAlignMisc
);
612 aAlign
.FillToItemSet( rStyleItemSet
, nullptr );
616 // *** border block ***
618 if( ::get_flag( nFlags
, EXC_CF_BLOCK_BORDER
) )
620 sal_uInt16
nLineStyle(0);
621 sal_uInt32
nLineColor(0);
622 nLineStyle
= rStrm
.ReaduInt16();
623 nLineColor
= rStrm
.ReaduInt32();
626 XclImpCellBorder aBorder
;
627 aBorder
.FillFromCF8( nLineStyle
, nLineColor
, nFlags
);
628 aBorder
.FillToItemSet( rStyleItemSet
, rPalette
);
631 // *** pattern block ***
633 if( ::get_flag( nFlags
, EXC_CF_BLOCK_AREA
) )
635 sal_uInt16
nPattern(0), nColor(0);
636 nPattern
= rStrm
.ReaduInt16();
637 nColor
= rStrm
.ReaduInt16();
639 XclImpCellArea aArea
;
640 aArea
.FillFromCF8( nPattern
, nColor
, nFlags
);
641 aArea
.FillToItemSet( rStyleItemSet
, rPalette
);
644 if( get_flag( nFlags
, EXC_CF_BLOCK_PROTECTION
) )
646 sal_uInt16 nCellProt
;
647 nCellProt
= rStrm
.ReaduInt16();
648 XclImpCellProt aCellProt
;
649 aCellProt
.FillFromXF3(nCellProt
);
650 aCellProt
.FillToItemSet( rStyleItemSet
);
655 const ScAddress
& rPos
= maRanges
.front()->aStart
; // assured above that maRanges is not empty
656 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
658 ::std::unique_ptr
< ScTokenArray
> xTokArr1
;
661 const ScTokenArray
* pTokArr
= nullptr;
662 rFmlaConv
.Reset( rPos
);
663 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize1
, false, FT_CondFormat
);
664 // formula converter owns pTokArr -> create a copy of the token array
666 xTokArr1
.reset( pTokArr
->Clone() );
669 ::std::unique_ptr
< ScTokenArray
> pTokArr2
;
672 const ScTokenArray
* pTokArr
= nullptr;
673 rFmlaConv
.Reset( rPos
);
674 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize2
, false, FT_CondFormat
);
675 // formula converter owns pTokArr -> create a copy of the token array
677 pTokArr2
.reset( pTokArr
->Clone() );
680 // *** create the Calc conditional formatting ***
682 if( !mxScCondFmt
.get() )
685 mxScCondFmt
.reset( new ScConditionalFormat( nKey
, &GetDocRef() ) );
686 if(maRanges
.size() > 1)
687 maRanges
.Join(*maRanges
[0], true);
688 mxScCondFmt
->SetRange(maRanges
);
691 ScCondFormatEntry
* pEntry
= new ScCondFormatEntry( eMode
, xTokArr1
.get(), pTokArr2
.get(), &GetDocRef(), rPos
, aStyleName
);
692 mxScCondFmt
->AddEntry( pEntry
);
696 void XclImpCondFormat::Apply()
698 if( mxScCondFmt
.get() )
700 ScDocument
& rDoc
= GetDoc();
702 SCTAB nTab
= maRanges
.front()->aStart
.Tab();
703 sal_uLong nKey
= rDoc
.AddCondFormat( mxScCondFmt
->Clone(), nTab
);
705 rDoc
.AddCondFormatData( maRanges
, nTab
, nKey
);
709 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot
& rRoot
) :
714 void XclImpCondFormatManager::ReadCondfmt( XclImpStream
& rStrm
)
716 XclImpCondFormat
* pFmt
= new XclImpCondFormat( GetRoot(), maCondFmtList
.size() );
717 pFmt
->ReadCondfmt( rStrm
);
718 maCondFmtList
.push_back( std::unique_ptr
<XclImpCondFormat
>(pFmt
) );
721 void XclImpCondFormatManager::ReadCF( XclImpStream
& rStrm
)
723 OSL_ENSURE( !maCondFmtList
.empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
724 if( !maCondFmtList
.empty() )
725 maCondFmtList
.back()->ReadCF( rStrm
);
728 void XclImpCondFormatManager::Apply()
730 for( XclImpCondFmtList::iterator itFmt
= maCondFmtList
.begin(); itFmt
!= maCondFmtList
.end(); ++itFmt
)
732 maCondFmtList
.clear();
735 // Data Validation ============================================================
737 XclImpValidationManager::DVItem::DVItem( const ScRangeList
& rRanges
, const ScValidationData
& rValidData
) :
738 maRanges(rRanges
), maValidData(rValidData
) {}
740 XclImpValidationManager::XclImpValidationManager( const XclImpRoot
& rRoot
) :
745 void XclImpValidationManager::ReadDval( XclImpStream
& rStrm
)
747 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
748 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
750 sal_uInt32
nObjId(0);
752 nObjId
= rStrm
.ReaduInt32();
753 if( nObjId
!= EXC_DVAL_NOOBJ
)
755 OSL_ENSURE( nObjId
<= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
756 rRoot
.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16
>( nObjId
) );
760 void XclImpValidationManager::ReadDV( XclImpStream
& rStrm
)
762 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
763 OSL_ENSURE_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
765 ScDocument
& rDoc
= rRoot
.GetDoc();
766 SCTAB nScTab
= rRoot
.GetCurrScTab();
767 ExcelToSc
& rFmlaConv
= rRoot
.GetOldFmlaConverter();
770 sal_uInt32
nFlags(0);
771 nFlags
= rStrm
.ReaduInt32();
774 /* Empty strings are single NUL characters in Excel (string length is 1).
775 -> Do not let the stream replace them with '?' characters. */
776 rStrm
.SetNulSubstChar( '\0' );
777 OUString
aPromptTitle( rStrm
.ReadUniString() );
778 OUString
aErrorTitle( rStrm
.ReadUniString() );
779 OUString
aPromptMessage( rStrm
.ReadUniString() );
780 OUString
aErrorMessage( rStrm
.ReadUniString() );
781 rStrm
.SetNulSubstChar(); // back to default
784 if ( rStrm
.GetRecLeft() <= 8 )
785 // Not enough bytes left in the record. Bail out.
789 // string list is single tStr token with NUL separators -> replace them with LF
790 rStrm
.SetNulSubstChar( '\n' );
791 ::std::unique_ptr
< ScTokenArray
> xTokArr1
;
793 // We can't import the formula directly because we need the range
794 sal_uInt16 nLenFormula1
= rStrm
.ReaduInt16();
796 XclImpStreamPos aPosFormula1
;
797 rStrm
.StorePosition(aPosFormula1
);
798 rStrm
.Ignore(nLenFormula1
);
801 ::std::unique_ptr
< ScTokenArray
> xTokArr2
;
803 sal_uInt16 nLenFormula2
= rStrm
.ReaduInt16();
805 XclImpStreamPos aPosFormula2
;
806 rStrm
.StorePosition(aPosFormula2
);
807 rStrm
.Ignore(nLenFormula2
);
809 // read all cell ranges
810 XclRangeList aXclRanges
;
813 // convert to Calc range list
814 ScRangeList aScRanges
;
815 rRoot
.GetAddressConverter().ConvertRangeList( aScRanges
, aXclRanges
, nScTab
, true );
817 // only continue if there are valid ranges
818 if ( aScRanges
.empty() )
821 ScRange aCombinedRange
= aScRanges
.Combine();
823 XclImpStreamPos aCurrentPos
;
824 rStrm
.StorePosition(aCurrentPos
);
825 rStrm
.RestorePosition(aPosFormula1
);
826 if( nLenFormula1
> 0 )
828 const ScTokenArray
* pTokArr
= nullptr;
829 rFmlaConv
.Reset(aCombinedRange
.aStart
);
830 rFmlaConv
.Convert( pTokArr
, rStrm
, nLenFormula1
, false, FT_CondFormat
);
831 // formula converter owns pTokArr -> create a copy of the token array
833 xTokArr1
.reset( pTokArr
->Clone() );
835 rStrm
.SetNulSubstChar(); // back to default
836 if (nLenFormula2
> 0)
838 rStrm
.RestorePosition(aPosFormula2
);
839 const ScTokenArray
* pTokArr
= nullptr;
840 rFmlaConv
.Reset(aCombinedRange
.aStart
);
841 rFmlaConv
.Convert( pTokArr
, rStrm
, nLenFormula2
, false, FT_CondFormat
);
842 // formula converter owns pTokArr -> create a copy of the token array
844 xTokArr2
.reset( pTokArr
->Clone() );
847 rStrm
.RestorePosition(aCurrentPos
);
849 bool bIsValid
= true; // valid settings in flags field
851 ScValidationMode eValMode
= SC_VALID_ANY
;
852 switch( nFlags
& EXC_DV_MODE_MASK
)
854 case EXC_DV_MODE_ANY
: eValMode
= SC_VALID_ANY
; break;
855 case EXC_DV_MODE_WHOLE
: eValMode
= SC_VALID_WHOLE
; break;
856 case EXC_DV_MODE_DECIMAL
: eValMode
= SC_VALID_DECIMAL
; break;
857 case EXC_DV_MODE_LIST
: eValMode
= SC_VALID_LIST
; break;
858 case EXC_DV_MODE_DATE
: eValMode
= SC_VALID_DATE
; break;
859 case EXC_DV_MODE_TIME
: eValMode
= SC_VALID_TIME
; break;
860 case EXC_DV_MODE_TEXTLEN
: eValMode
= SC_VALID_TEXTLEN
; break;
861 case EXC_DV_MODE_CUSTOM
: eValMode
= SC_VALID_CUSTOM
; break;
862 default: bIsValid
= false;
864 rRoot
.GetTracer().TraceDVType(eValMode
== SC_VALID_CUSTOM
);
866 ScConditionMode eCondMode
= SC_COND_BETWEEN
;
867 switch( nFlags
& EXC_DV_COND_MASK
)
869 case EXC_DV_COND_BETWEEN
: eCondMode
= SC_COND_BETWEEN
; break;
870 case EXC_DV_COND_NOTBETWEEN
:eCondMode
= SC_COND_NOTBETWEEN
; break;
871 case EXC_DV_COND_EQUAL
: eCondMode
= SC_COND_EQUAL
; break;
872 case EXC_DV_COND_NOTEQUAL
: eCondMode
= SC_COND_NOTEQUAL
; break;
873 case EXC_DV_COND_GREATER
: eCondMode
= SC_COND_GREATER
; break;
874 case EXC_DV_COND_LESS
: eCondMode
= SC_COND_LESS
; break;
875 case EXC_DV_COND_EQGREATER
: eCondMode
= SC_COND_EQGREATER
; break;
876 case EXC_DV_COND_EQLESS
: eCondMode
= SC_COND_EQLESS
; break;
877 default: bIsValid
= false;
881 // No valid validation found. Bail out.
884 // first range for base address for relative references
885 const ScRange
& rScRange
= *aScRanges
.front(); // aScRanges is not empty
887 // process string list of a list validity (convert to list of string tokens)
888 if( xTokArr1
.get() && (eValMode
== SC_VALID_LIST
) && ::get_flag( nFlags
, EXC_DV_STRINGLIST
) )
889 XclTokenArrayHelper::ConvertStringToList(*xTokArr1
, rDoc
.GetSharedStringPool(), '\n', true);
892 o3tl::make_unique
<DVItem
>(aScRanges
, ScValidationData(eValMode
, eCondMode
, xTokArr1
.get(), xTokArr2
.get(), &rDoc
, rScRange
.aStart
)));
893 DVItem
& rItem
= *maDVItems
.back().get();
895 rItem
.maValidData
.SetIgnoreBlank( ::get_flag( nFlags
, EXC_DV_IGNOREBLANK
) );
896 rItem
.maValidData
.SetListType( ::get_flagvalue( nFlags
, EXC_DV_SUPPRESSDROPDOWN
, css::sheet::TableValidationVisibility::INVISIBLE
, css::sheet::TableValidationVisibility::UNSORTED
) );
898 // *** prompt box ***
899 if( !aPromptTitle
.isEmpty() || !aPromptMessage
.isEmpty() )
901 // set any text stored in the record
902 rItem
.maValidData
.SetInput( aPromptTitle
, aPromptMessage
);
903 if( !::get_flag( nFlags
, EXC_DV_SHOWPROMPT
) )
904 rItem
.maValidData
.ResetInput();
908 ScValidErrorStyle eErrStyle
= SC_VALERR_STOP
;
909 switch( nFlags
& EXC_DV_ERROR_MASK
)
911 case EXC_DV_ERROR_WARNING
: eErrStyle
= SC_VALERR_WARNING
; break;
912 case EXC_DV_ERROR_INFO
: eErrStyle
= SC_VALERR_INFO
; break;
914 // set texts and error style
915 rItem
.maValidData
.SetError( aErrorTitle
, aErrorMessage
, eErrStyle
);
916 if( !::get_flag( nFlags
, EXC_DV_SHOWERROR
) )
917 rItem
.maValidData
.ResetError();
920 void XclImpValidationManager::Apply()
922 ScDocument
& rDoc
= GetRoot().GetDoc();
923 DVItemList::iterator itr
= maDVItems
.begin(), itrEnd
= maDVItems
.end();
924 for (; itr
!= itrEnd
; ++itr
)
926 DVItem
& rItem
= *itr
->get();
928 sal_uLong nHandle
= rDoc
.AddValidationEntry( rItem
.maValidData
);
929 ScPatternAttr
aPattern( rDoc
.GetPool() );
930 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nHandle
) );
933 for ( size_t i
= 0, nRanges
= rItem
.maRanges
.size(); i
< nRanges
; ++i
)
935 const ScRange
* pScRange
= rItem
.maRanges
[ i
];
936 rDoc
.ApplyPatternAreaTab( pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
937 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(), pScRange
->aStart
.Tab(), aPattern
);
943 // Web queries ================================================================
945 XclImpWebQuery::XclImpWebQuery( const ScRange
& rDestRange
) :
946 maDestRange( rDestRange
),
947 meMode( xlWQUnknown
),
952 void XclImpWebQuery::ReadParamqry( XclImpStream
& rStrm
)
954 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
955 sal_uInt16 nType
= ::extract_value
< sal_uInt16
>( nFlags
, 0, 3 );
956 if( (nType
== EXC_PQRYTYPE_WEBQUERY
) && ::get_flag( nFlags
, EXC_PQRY_WEBQUERY
) )
958 if( ::get_flag( nFlags
, EXC_PQRY_TABLES
) )
960 meMode
= xlWQAllTables
;
961 maTables
= ScfTools::GetHTMLTablesName();
965 meMode
= xlWQDocument
;
966 maTables
= ScfTools::GetHTMLDocName();
971 void XclImpWebQuery::ReadWqstring( XclImpStream
& rStrm
)
973 maURL
= rStrm
.ReadUniString();
976 void XclImpWebQuery::ReadWqsettings( XclImpStream
& rStrm
)
979 sal_uInt16
nFlags(0);
980 nFlags
= rStrm
.ReaduInt16();
982 mnRefresh
= rStrm
.ReaduInt16();
984 if( ::get_flag( nFlags
, EXC_WQSETT_SPECTABLES
) && (meMode
== xlWQAllTables
) )
985 meMode
= xlWQSpecTables
;
988 void XclImpWebQuery::ReadWqtables( XclImpStream
& rStrm
)
990 if( meMode
== xlWQSpecTables
)
993 OUString
aTables( rStrm
.ReadUniString() );
995 const sal_Unicode cSep
= ';';
996 OUString
aQuotedPairs( "\"\"" );
997 sal_Int32 nTokenCnt
= ScStringUtil::GetQuotedTokenCount( aTables
, aQuotedPairs
, ',' );
999 sal_Int32 nStringIx
= 0;
1000 for( sal_Int32 nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
1002 OUString
aToken( ScStringUtil::GetQuotedToken( aTables
, 0, aQuotedPairs
, ',', nStringIx
) );
1003 sal_Int32 nTabNum
= CharClass::isAsciiNumeric( aToken
) ? aToken
.toInt32() : 0;
1005 maTables
= ScGlobal::addToken( maTables
, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32
>( nTabNum
) ), cSep
);
1008 ScGlobal::EraseQuotes( aToken
, '"', false );
1009 if( !aToken
.isEmpty() )
1010 maTables
= ScGlobal::addToken( maTables
, ScfTools::GetNameFromHTMLName( aToken
), cSep
);
1016 void XclImpWebQuery::Apply( ScDocument
& rDoc
, const OUString
& rFilterName
)
1018 if( !maURL
.isEmpty() && (meMode
!= xlWQUnknown
) && rDoc
.GetDocumentShell() )
1020 ScAreaLink
* pLink
= new ScAreaLink( rDoc
.GetDocumentShell(),
1021 maURL
, rFilterName
, EMPTY_OUSTRING
, maTables
, maDestRange
, mnRefresh
* 60UL );
1022 rDoc
.GetLinkManager()->InsertFileLink( *pLink
, OBJECT_CLIENT_FILE
,
1023 maURL
, &rFilterName
, &maTables
);
1027 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot
& rRoot
) :
1032 void XclImpWebQueryBuffer::ReadQsi( XclImpStream
& rStrm
)
1034 if( GetBiff() == EXC_BIFF8
)
1037 OUString
aXclName( rStrm
.ReadUniString() );
1039 // #i64794# Excel replaces spaces with underscores
1040 aXclName
= aXclName
.replaceAll( " ", "_" );
1042 // find the defined name used in Calc
1043 if( const XclImpName
* pName
= GetNameManager().FindName( aXclName
, GetCurrScTab() ) )
1045 if( const ScRangeData
* pRangeData
= pName
->GetScRangeData() )
1048 if( pRangeData
->IsReference( aRange
) )
1049 maWQList
.push_back( XclImpWebQuery( aRange
) );
1059 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream
& rStrm
)
1061 if (!maWQList
.empty())
1062 maWQList
.back().ReadParamqry( rStrm
);
1065 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream
& rStrm
)
1067 if (!maWQList
.empty())
1068 maWQList
.back().ReadWqstring( rStrm
);
1071 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream
& rStrm
)
1073 if (!maWQList
.empty())
1074 maWQList
.back().ReadWqsettings( rStrm
);
1077 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream
& rStrm
)
1079 if (!maWQList
.empty())
1080 maWQList
.back().ReadWqtables( rStrm
);
1083 void XclImpWebQueryBuffer::Apply()
1085 ScDocument
& rDoc
= GetDoc();
1086 OUString
aFilterName( EXC_WEBQRY_FILTER
);
1087 for( XclImpWebQueryList::iterator itQuery
= maWQList
.begin(); itQuery
!= maWQList
.end(); ++itQuery
)
1088 itQuery
->Apply( rDoc
, aFilterName
);
1091 // Decryption =================================================================
1095 XclImpDecrypterRef
lclReadFilepass5( XclImpStream
& rStrm
)
1097 XclImpDecrypterRef xDecr
;
1098 OSL_ENSURE( rStrm
.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1099 if( rStrm
.GetRecLeft() == 4 )
1101 sal_uInt16
nKey(0), nHash(0);
1102 nKey
= rStrm
.ReaduInt16();
1103 nHash
= rStrm
.ReaduInt16();
1104 xDecr
.reset( new XclImpBiff5Decrypter( nKey
, nHash
) );
1109 XclImpDecrypterRef
lclReadFilepass8_Standard( XclImpStream
& rStrm
)
1111 XclImpDecrypterRef xDecr
;
1112 OSL_ENSURE( rStrm
.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1113 if( rStrm
.GetRecLeft() == 48 )
1115 std::vector
<sal_uInt8
> aSalt(16);
1116 std::vector
<sal_uInt8
> aVerifier(16);
1117 std::vector
<sal_uInt8
> aVerifierHash(16);
1118 rStrm
.Read(aSalt
.data(), 16);
1119 rStrm
.Read(aVerifier
.data(), 16);
1120 rStrm
.Read(aVerifierHash
.data(), 16);
1121 xDecr
.reset(new XclImpBiff8StdDecrypter(aSalt
, aVerifier
, aVerifierHash
));
1126 XclImpDecrypterRef
lclReadFilepass8_Strong(XclImpStream
& rStream
)
1128 //Its possible there are other variants in existance but these
1129 //are the defaults I get with Excel 2013
1130 XclImpDecrypterRef xDecr
;
1132 msfilter::RC4EncryptionInfo info
;
1134 info
.header
.flags
= rStream
.ReaduInt32();
1135 if (oox::getFlag( info
.header
.flags
, msfilter::ENCRYPTINFO_EXTERNAL
))
1138 sal_uInt32 nHeaderSize
= rStream
.ReaduInt32();
1139 sal_uInt32 actualHeaderSize
= sizeof(info
.header
);
1141 if( (nHeaderSize
< actualHeaderSize
) )
1144 info
.header
.flags
= rStream
.ReaduInt32();
1145 info
.header
.sizeExtra
= rStream
.ReaduInt32();
1146 info
.header
.algId
= rStream
.ReaduInt32();
1147 info
.header
.algIdHash
= rStream
.ReaduInt32();
1148 info
.header
.keyBits
= rStream
.ReaduInt32();
1149 info
.header
.providedType
= rStream
.ReaduInt32();
1150 info
.header
.reserved1
= rStream
.ReaduInt32();
1151 info
.header
.reserved2
= rStream
.ReaduInt32();
1153 rStream
.Ignore(nHeaderSize
- actualHeaderSize
);
1155 info
.verifier
.saltSize
= rStream
.ReaduInt32();
1156 if (info
.verifier
.saltSize
!= msfilter::SALT_LENGTH
)
1158 rStream
.Read(&info
.verifier
.salt
, sizeof(info
.verifier
.salt
));
1159 rStream
.Read(&info
.verifier
.encryptedVerifier
, sizeof(info
.verifier
.encryptedVerifier
));
1161 info
.verifier
.encryptedVerifierHashSize
= rStream
.ReaduInt32();
1162 if (info
.verifier
.encryptedVerifierHashSize
!= RTL_DIGEST_LENGTH_SHA1
)
1164 rStream
.Read(&info
.verifier
.encryptedVerifierHash
, info
.verifier
.encryptedVerifierHashSize
);
1166 // check flags and algorithm IDs, required are AES128 and SHA-1
1167 if (!oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_CRYPTOAPI
))
1170 if (oox::getFlag(info
.header
.flags
, msfilter::ENCRYPTINFO_AES
))
1173 if (info
.header
.algId
!= msfilter::ENCRYPT_ALGO_RC4
)
1176 // hash algorithm ID 0 defaults to SHA-1 too
1177 if (info
.header
.algIdHash
!= 0 && info
.header
.algIdHash
!= msfilter::ENCRYPT_HASH_SHA1
)
1180 xDecr
.reset(new XclImpBiff8CryptoAPIDecrypter(
1181 std::vector
<sal_uInt8
>(info
.verifier
.salt
,
1182 info
.verifier
.salt
+ SAL_N_ELEMENTS(info
.verifier
.salt
)),
1183 std::vector
<sal_uInt8
>(info
.verifier
.encryptedVerifier
,
1184 info
.verifier
.encryptedVerifier
+ SAL_N_ELEMENTS(info
.verifier
.encryptedVerifier
)),
1185 std::vector
<sal_uInt8
>(info
.verifier
.encryptedVerifierHash
,
1186 info
.verifier
.encryptedVerifierHash
+ SAL_N_ELEMENTS(info
.verifier
.encryptedVerifierHash
))));
1191 XclImpDecrypterRef
lclReadFilepass8( XclImpStream
& rStrm
)
1193 XclImpDecrypterRef xDecr
;
1195 sal_uInt16
nMode(0);
1196 nMode
= rStrm
.ReaduInt16();
1199 case EXC_FILEPASS_BIFF5
:
1200 xDecr
= lclReadFilepass5( rStrm
);
1203 case EXC_FILEPASS_BIFF8
:
1205 sal_uInt32 nVersion
= rStrm
.ReaduInt32();
1206 if (nVersion
== msfilter::VERSION_INFO_1997_FORMAT
)
1208 //A Version structure where Version.vMajor MUST be 0x0001,
1209 //and Version.vMinor MUST be 0x0001.
1210 xDecr
= lclReadFilepass8_Standard(rStrm
);
1212 else if (nVersion
== msfilter::VERSION_INFO_2007_FORMAT
||
1213 nVersion
== msfilter::VERSION_INFO_2007_FORMAT_SP2
)
1215 //Version.vMajor MUST be 0x0002, 0x0003 or 0x0004 and
1216 //Version.vMinor MUST be 0x0002.
1217 xDecr
= lclReadFilepass8_Strong(rStrm
);
1220 OSL_FAIL("lclReadFilepass8 - unknown BIFF8 encryption sub mode");
1225 OSL_FAIL( "lclReadFilepass8 - unknown encryption mode" );
1233 ErrCode
XclImpDecryptHelper::ReadFilepass( XclImpStream
& rStrm
)
1235 XclImpDecrypterRef xDecr
;
1236 rStrm
.DisableDecryption();
1238 // read the FILEPASS record and create a new decrypter object
1239 switch( rStrm
.GetRoot().GetBiff() )
1244 case EXC_BIFF5
: xDecr
= lclReadFilepass5( rStrm
); break;
1245 case EXC_BIFF8
: xDecr
= lclReadFilepass8( rStrm
); break;
1246 default: DBG_ERROR_BIFF();
1249 // set decrypter at import stream
1250 rStrm
.SetDecrypter( xDecr
);
1252 // request and verify a password (decrypter implements IDocPasswordVerifier)
1254 rStrm
.GetRoot().RequestEncryptionData( *xDecr
);
1256 // return error code (success, wrong password, etc.)
1257 return xDecr
? xDecr
->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT
;
1260 // Document protection ========================================================
1262 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot
& rRoot
) :
1263 XclImpRoot( rRoot
),
1265 mbDocProtect(false),
1270 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream
& rStrm
)
1272 mbDocProtect
= rStrm
.ReaduInt16() != 0;
1275 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream
& rStrm
)
1277 mbWinProtect
= rStrm
.ReaduInt16() != 0;
1280 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
)
1282 rStrm
.EnableDecryption();
1283 mnPassHash
= rStrm
.ReaduInt16();
1286 void XclImpDocProtectBuffer::Apply() const
1288 if (!mbDocProtect
&& !mbWinProtect
)
1289 // Excel requires either the structure or windows protection is set.
1290 // If neither is set then the document is not protected at all.
1293 unique_ptr
<ScDocProtection
> pProtect(new ScDocProtection
);
1294 pProtect
->setProtected(true);
1298 // 16-bit password hash.
1299 Sequence
<sal_Int8
> aPass(2);
1300 aPass
[0] = (mnPassHash
>> 8) & 0xFF;
1301 aPass
[1] = mnPassHash
& 0xFF;
1302 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1305 // document protection options
1306 pProtect
->setOption(ScDocProtection::STRUCTURE
, mbDocProtect
);
1307 pProtect
->setOption(ScDocProtection::WINDOWS
, mbWinProtect
);
1309 GetDoc().SetDocProtection(pProtect
.get());
1312 // Sheet Protection ===========================================================
1314 XclImpSheetProtectBuffer::Sheet::Sheet() :
1316 mnPasswordHash(0x0000),
1321 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet
& r
) :
1322 mbProtected(r
.mbProtected
),
1323 mnPasswordHash(r
.mnPasswordHash
),
1324 mnOptions(r
.mnOptions
)
1328 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot
& rRoot
) :
1333 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream
& rStrm
, SCTAB nTab
)
1335 if ( rStrm
.ReaduInt16() )
1337 Sheet
* pSheet
= GetSheetItem(nTab
);
1339 pSheet
->mbProtected
= true;
1343 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream
& rStrm
, SCTAB nTab
)
1345 // The flag size specifies the size of bytes that follows that stores
1346 // feature data. If -1 it depends on the feature type imported earlier.
1347 // For enhanced protection data, the size is always 4. For the most xls
1348 // documents out there this value is almost always -1.
1349 sal_Int32
nFlagSize(0);
1350 nFlagSize
= rStrm
.ReadInt32();
1351 if (nFlagSize
!= -1)
1354 // There are actually 4 bytes to read, but the upper 2 bytes currently
1355 // don't store any bits.
1356 sal_uInt16
nOptions(0);
1357 nOptions
= rStrm
.ReaduInt16();
1359 Sheet
* pSheet
= GetSheetItem(nTab
);
1361 pSheet
->mnOptions
= nOptions
;
1364 void XclImpSheetProtectBuffer::AppendEnhancedProtection( const ScEnhancedProtection
& rProt
, SCTAB nTab
)
1366 Sheet
* pSheet
= GetSheetItem(nTab
);
1368 pSheet
->maEnhancedProtections
.push_back( rProt
);
1371 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
, SCTAB nTab
)
1373 sal_uInt16
nHash(0);
1374 nHash
= rStrm
.ReaduInt16();
1375 Sheet
* pSheet
= GetSheetItem(nTab
);
1377 pSheet
->mnPasswordHash
= nHash
;
1380 void XclImpSheetProtectBuffer::Apply() const
1382 for (ProtectedSheetMap::const_iterator itr
= maProtectedSheets
.begin(), itrEnd
= maProtectedSheets
.end();
1383 itr
!= itrEnd
; ++itr
)
1385 if (!itr
->second
.mbProtected
)
1386 // This sheet is (for whatever reason) not protected.
1389 unique_ptr
<ScTableProtection
> pProtect(new ScTableProtection
);
1390 pProtect
->setProtected(true);
1392 // 16-bit hash password
1393 const sal_uInt16 nHash
= itr
->second
.mnPasswordHash
;
1396 Sequence
<sal_Int8
> aPass(2);
1397 aPass
[0] = (nHash
>> 8) & 0xFF;
1398 aPass
[1] = nHash
& 0xFF;
1399 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1402 // sheet protection options
1403 const sal_uInt16 nOptions
= itr
->second
.mnOptions
;
1404 pProtect
->setOption( ScTableProtection::OBJECTS
, (nOptions
& 0x0001) );
1405 pProtect
->setOption( ScTableProtection::SCENARIOS
, (nOptions
& 0x0002) );
1406 pProtect
->setOption( ScTableProtection::FORMAT_CELLS
, (nOptions
& 0x0004) );
1407 pProtect
->setOption( ScTableProtection::FORMAT_COLUMNS
, (nOptions
& 0x0008) );
1408 pProtect
->setOption( ScTableProtection::FORMAT_ROWS
, (nOptions
& 0x0010) );
1409 pProtect
->setOption( ScTableProtection::INSERT_COLUMNS
, (nOptions
& 0x0020) );
1410 pProtect
->setOption( ScTableProtection::INSERT_ROWS
, (nOptions
& 0x0040) );
1411 pProtect
->setOption( ScTableProtection::INSERT_HYPERLINKS
, (nOptions
& 0x0080) );
1412 pProtect
->setOption( ScTableProtection::DELETE_COLUMNS
, (nOptions
& 0x0100) );
1413 pProtect
->setOption( ScTableProtection::DELETE_ROWS
, (nOptions
& 0x0200) );
1414 pProtect
->setOption( ScTableProtection::SELECT_LOCKED_CELLS
, (nOptions
& 0x0400) );
1415 pProtect
->setOption( ScTableProtection::SORT
, (nOptions
& 0x0800) );
1416 pProtect
->setOption( ScTableProtection::AUTOFILTER
, (nOptions
& 0x1000) );
1417 pProtect
->setOption( ScTableProtection::PIVOT_TABLES
, (nOptions
& 0x2000) );
1418 pProtect
->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS
, (nOptions
& 0x4000) );
1420 // Enhanced protection containing editable ranges and permissions.
1421 pProtect
->setEnhancedProtection( itr
->second
.maEnhancedProtections
);
1423 // all done. now commit.
1424 GetDoc().SetTabProtection(itr
->first
, pProtect
.get());
1428 XclImpSheetProtectBuffer::Sheet
* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab
)
1430 ProtectedSheetMap::iterator itr
= maProtectedSheets
.find(nTab
);
1431 if (itr
== maProtectedSheets
.end())
1434 if ( !maProtectedSheets
.insert( ProtectedSheetMap::value_type(nTab
, Sheet()) ).second
)
1437 itr
= maProtectedSheets
.find(nTab
);
1440 return &itr
->second
;
1443 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */