1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: xicontent.cxx,v $
10 * $Revision: 1.31.88.5 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
33 #include "xicontent.hxx"
34 #include <sfx2/objsh.hxx>
35 #include <sfx2/docfile.hxx>
36 #include <tools/urlobj.hxx>
37 #include <svx/editeng.hxx>
38 #include <svx/editobj.hxx>
39 #include <svx/linkmgr.hxx>
40 #include <svtools/itemset.hxx>
41 #include "scitems.hxx"
42 #include <svx/eeitem.hxx>
43 #include <svtools/intitem.hxx>
44 #include <svtools/stritem.hxx>
45 #include <svx/flditem.hxx>
46 #include <svx/fhgtitem.hxx>
47 #include <svx/wghtitem.hxx>
48 #include <svx/udlnitem.hxx>
49 #include <svx/postitem.hxx>
50 #include <svx/colritem.hxx>
51 #include <svx/crsditem.hxx>
52 #include "document.hxx"
53 #include "editutil.hxx"
55 #include "validat.hxx"
56 #include "patattr.hxx"
57 #include "docpool.hxx"
58 #include "rangenam.hxx"
59 #include "arealink.hxx"
60 #include "stlsheet.hxx"
61 #include "scextopt.hxx"
62 #include "xlformula.hxx"
63 #include "xltracer.hxx"
64 #include "xistream.hxx"
65 #include "xihelper.hxx"
66 #include "xistyle.hxx"
67 #include "xiescher.hxx"
70 #include "excform.hxx"
71 #include "tabprotection.hxx"
75 using ::com::sun::star::uno::Sequence
;
76 using ::std::auto_ptr
;
78 // Shared string table ========================================================
80 XclImpSst::XclImpSst( const XclImpRoot
& rRoot
) :
85 void XclImpSst::ReadSst( XclImpStream
& rStrm
)
91 maStrings
.reserve( static_cast< size_t >( nStrCount
) );
92 while( (nStrCount
> 0) && rStrm
.IsValid() )
95 aString
.Read( rStrm
);
96 maStrings
.push_back( aString
);
101 const XclImpString
* XclImpSst::GetString( sal_uInt32 nSstIndex
) const
103 return (nSstIndex
< maStrings
.size()) ? &maStrings
[ nSstIndex
] : 0;
106 ScBaseCell
* XclImpSst::CreateCell( sal_uInt32 nSstIndex
, sal_uInt16 nXFIndex
) const
108 ScBaseCell
* pCell
= 0;
109 if( const XclImpString
* pString
= GetString( nSstIndex
) )
110 pCell
= XclImpStringHelper::CreateCell( *this, *pString
, nXFIndex
);
114 // Hyperlinks =================================================================
118 /** Reads character array and stores it into rString.
119 @param nChars Number of following characters (not byte count!).
120 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
121 void lclAppendString32( String
& rString
, XclImpStream
& rStrm
, sal_uInt32 nChars
, bool b16Bit
)
123 sal_uInt16 nReadChars
= ulimit_cast
< sal_uInt16
>( nChars
);
124 rString
.Append( rStrm
.ReadRawUniString( nReadChars
, b16Bit
) );
125 // ignore remaining chars
126 sal_Size nIgnore
= nChars
- nReadChars
;
129 rStrm
.Ignore( nIgnore
);
132 /** Reads 32-bit string length and the character array and stores it into rString.
133 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
134 void lclAppendString32( String
& rString
, XclImpStream
& rStrm
, bool b16Bit
)
136 lclAppendString32( rString
, rStrm
, rStrm
.ReaduInt32(), b16Bit
);
139 /** Reads 32-bit string length and ignores following character array.
140 @param b16Bit true = 16-bit characters, false = 8-bit characters. */
141 void lclIgnoreString32( XclImpStream
& rStrm
, bool b16Bit
)
147 rStrm
.Ignore( nChars
);
150 /** Converts a path to an absolute path.
151 @param rPath The source path. The resulting path is returned here.
152 @param nLevel Number of parent directories to add in front of the path. */
153 void lclGetAbsPath( String
& rPath
, sal_uInt16 nLevel
, SfxObjectShell
* pDocShell
)
158 aTmpStr
.AppendAscii( "../" );
165 bool bWasAbs
= false;
166 rPath
= pDocShell
->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr
, bWasAbs
).GetMainURL( INetURLObject::NO_DECODE
);
167 // full path as stored in SvxURLField must be encoded
173 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
174 void lclInsertUrl( const XclImpRoot
& rRoot
, const String
& rUrl
, SCCOL nScCol
, SCROW nScRow
, SCTAB nScTab
)
176 ScDocument
& rDoc
= rRoot
.GetDoc();
177 ScAddress
aScPos( nScCol
, nScRow
, nScTab
);
178 CellType eCellType
= rDoc
.GetCellType( aScPos
);
181 // #i54261# hyperlinks in string cells
182 case CELLTYPE_STRING
:
186 rDoc
.GetString( nScCol
, nScRow
, nScTab
, aDisplText
);
187 if( !aDisplText
.Len() )
190 ScEditEngineDefaulter
& rEE
= rRoot
.GetEditEngine();
191 SvxURLField
aUrlField( rUrl
, aDisplText
, SVXURLFORMAT_APPDEFAULT
);
193 const ScEditCell
* pEditCell
= (eCellType
== CELLTYPE_EDIT
) ? static_cast< const ScEditCell
* >( rDoc
.GetCell( aScPos
) ) : 0;
194 const EditTextObject
* pEditObj
= pEditCell
? pEditCell
->GetData() : 0;
197 rEE
.SetText( *pEditObj
);
198 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection( 0, 0, 0xFFFF, 0 ) );
202 rEE
.SetText( EMPTY_STRING
);
203 rEE
.QuickInsertField( SvxFieldItem( aUrlField
, EE_FEATURE_FIELD
), ESelection() );
204 if( const ScPatternAttr
* pPattern
= rDoc
.GetPattern( aScPos
.Col(), aScPos
.Row(), nScTab
) )
206 SfxItemSet
aItemSet( rEE
.GetEmptyItemSet() );
207 pPattern
->FillEditItemSet( &aItemSet
);
208 rEE
.QuickSetAttribs( aItemSet
, ESelection( 0, 0, 0xFFFF, 0 ) );
211 ::std::auto_ptr
< EditTextObject
> xTextObj( rEE
.CreateTextObject() );
213 ScEditCell
* pCell
= new ScEditCell( xTextObj
.get(), &rDoc
, rEE
.GetEditTextObjectPool() );
214 rDoc
.PutCell( aScPos
, pCell
);
218 // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
222 // #i31050# replace number with HYPERLINK function
223 ScTokenArray aTokenArray
;
224 aTokenArray
.AddOpCode( ocHyperLink
);
225 aTokenArray
.AddOpCode( ocOpen
);
226 aTokenArray
.AddString( rUrl
);
227 aTokenArray
.AddOpCode( ocSep
);
228 aTokenArray
.AddDouble( rDoc
.GetValue( aScPos
) );
229 aTokenArray
.AddOpCode( ocClose
);
230 rDoc
.PutCell( aScPos
, new ScFormulaCell( &rDoc
, aScPos
, &aTokenArray
) );
241 // ----------------------------------------------------------------------------
243 void XclImpHyperlink::ReadHlink( XclImpStream
& rStrm
)
245 XclRange
aXclRange( ScAddress::UNINITIALIZED
);
247 // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
248 aXclRange
.maFirst
.mnCol
&= 0xFF;
249 aXclRange
.maLast
.mnCol
&= 0xFF;
250 String aString
= ReadEmbeddedData( rStrm
);
251 if ( aString
.Len() > 0 )
252 rStrm
.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange
, aString
);
255 String
XclImpHyperlink::ReadEmbeddedData( XclImpStream
& rStrm
)
257 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
258 SfxObjectShell
* pDocShell
= rRoot
.GetDocShell();
260 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
268 DBG_ASSERT( aGuid
== XclTools::maGuidStdLink
, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
270 sal_uInt16 nLevel
= 0; // counter for level to climb down in path
271 ::std::auto_ptr
< String
> xLongName
; // link / file name
272 ::std::auto_ptr
< String
> xShortName
; // 8.3-representation of file name
273 ::std::auto_ptr
< String
> xTextMark
; // text mark
275 // description (ignore)
276 if( ::get_flag( nFlags
, EXC_HLINK_DESCR
) )
277 lclIgnoreString32( rStrm
, true );
278 // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
279 if( ::get_flag( nFlags
, EXC_HLINK_FRAME
) )
280 lclIgnoreString32( rStrm
, true );
282 // URL fields are zero-terminated - do not let the stream replace them
283 // in the lclAppendString32() with the '?' character.
284 rStrm
.SetNulSubstChar( '\0' );
287 if( ::get_flag( nFlags
, EXC_HLINK_UNC
) )
289 xLongName
.reset( new String
);
290 lclAppendString32( *xLongName
, rStrm
, true );
291 lclGetAbsPath( *xLongName
, 0, pDocShell
);
294 else if( ::get_flag( nFlags
, EXC_HLINK_BODY
) )
298 if( aGuid
== XclTools::maGuidFileMoniker
)
301 xShortName
.reset( new String
);
302 lclAppendString32( *xShortName
, rStrm
, false );
310 nStrLen
/= 2; // it's byte count here...
312 xLongName
.reset( new String
);
313 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
314 lclGetAbsPath( *xLongName
, nLevel
, pDocShell
);
317 lclGetAbsPath( *xShortName
, nLevel
, pDocShell
);
319 else if( aGuid
== XclTools::maGuidUrlMoniker
)
323 nStrLen
/= 2; // it's byte count here...
324 xLongName
.reset( new String
);
325 lclAppendString32( *xLongName
, rStrm
, nStrLen
, true );
326 if( !::get_flag( nFlags
, EXC_HLINK_ABS
) )
327 lclGetAbsPath( *xLongName
, 0, pDocShell
);
331 DBG_ERRORFILE( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
336 if( ::get_flag( nFlags
, EXC_HLINK_MARK
) )
338 xTextMark
.reset( new String
);
339 lclAppendString32( *xTextMark
, rStrm
, true );
342 rStrm
.SetNulSubstChar(); // back to default
344 DBG_ASSERT( rStrm
.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
346 if( !xLongName
.get() && xShortName
.get() )
347 xLongName
= xShortName
;
348 else if( !xLongName
.get() && xTextMark
.get() )
349 xLongName
.reset( new String
);
351 if( xLongName
.get() )
353 if( xTextMark
.get() )
355 if( xLongName
->Len() == 0 )
356 xTextMark
->SearchAndReplaceAll( '!', '.' );
357 xLongName
->Append( '#' );
358 xLongName
->Append( *xTextMark
);
362 return String::EmptyString();
365 void XclImpHyperlink::ConvertToValidTabName(String
& rUrl
)
367 xub_StrLen n
= rUrl
.Len();
369 // Needs at least 4 characters.
372 sal_Unicode c
= rUrl
.GetChar(0);
373 if (c
!= sal_Unicode('#'))
374 // the 1st character must be '#'.
377 String
aNewUrl(sal_Unicode('#')), aTabName
;
379 bool bInQuote
= false;
380 bool bQuoteTabName
= false;
381 for (xub_StrLen i
= 1; i
< n
; ++i
)
384 if (c
== sal_Unicode('\''))
386 if (bInQuote
&& i
+1 < n
&& rUrl
.GetChar(i
+1) == sal_Unicode('\''))
388 // Two consecutive single quotes ('') signify a single literal
389 // quite. When this occurs, the whole table name needs to be
391 bQuoteTabName
= true;
398 bInQuote
= !bInQuote
;
399 if (!bInQuote
&& aTabName
.Len() > 0)
402 aNewUrl
.Append(sal_Unicode('\''));
403 aNewUrl
.Append(aTabName
);
405 aNewUrl
.Append(sal_Unicode('\''));
415 // It should be outside the quotes!
418 // All is good. Pass the new URL.
422 void XclImpHyperlink::InsertUrl( const XclImpRoot
& rRoot
, const XclRange
& rXclRange
, const String
& rUrl
)
425 ConvertToValidTabName(aUrl
);
427 SCTAB nScTab
= rRoot
.GetCurrScTab();
428 ScRange
aScRange( ScAddress::UNINITIALIZED
);
429 if( rRoot
.GetAddressConverter().ConvertRange( aScRange
, rXclRange
, nScTab
, nScTab
, true ) )
431 SCCOL nScCol1
, nScCol2
;
432 SCROW nScRow1
, nScRow2
;
433 aScRange
.GetVars( nScCol1
, nScRow1
, nScTab
, nScCol2
, nScRow2
, nScTab
);
434 for( SCCOL nScCol
= nScCol1
; nScCol
<= nScCol2
; ++nScCol
)
435 for( SCROW nScRow
= nScRow1
; nScRow
<= nScRow2
; ++nScRow
)
436 lclInsertUrl( rRoot
, aUrl
, nScCol
, nScRow
, nScTab
);
440 // Label ranges ===============================================================
442 void XclImpLabelranges::ReadLabelranges( XclImpStream
& rStrm
)
444 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
445 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
447 ScDocument
& rDoc
= rRoot
.GetDoc();
448 SCTAB nScTab
= rRoot
.GetCurrScTab();
449 XclImpAddressConverter
& rAddrConv
= rRoot
.GetAddressConverter();
450 ScRangePairListRef xLabelRangesRef
;
451 const ScRange
* pScRange
= 0;
453 XclRangeList aRowXclRanges
, aColXclRanges
;
454 rStrm
>> aRowXclRanges
>> aColXclRanges
;
457 ScRangeList aRowScRanges
;
458 rAddrConv
.ConvertRangeList( aRowScRanges
, aRowXclRanges
, nScTab
, false );
459 xLabelRangesRef
= rDoc
.GetRowNameRangesRef();
460 for( pScRange
= aRowScRanges
.First(); pScRange
; pScRange
= aRowScRanges
.Next() )
462 ScRange
aDataRange( *pScRange
);
463 if( aDataRange
.aEnd
.Col() < MAXCOL
)
465 aDataRange
.aStart
.SetCol( aDataRange
.aEnd
.Col() + 1 );
466 aDataRange
.aEnd
.SetCol( MAXCOL
);
468 else if( aDataRange
.aStart
.Col() > 0 )
470 aDataRange
.aEnd
.SetCol( aDataRange
.aStart
.Col() - 1 );
471 aDataRange
.aStart
.SetCol( 0 );
473 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
476 // column label ranges
477 ScRangeList aColScRanges
;
478 rAddrConv
.ConvertRangeList( aColScRanges
, aColXclRanges
, nScTab
, false );
479 xLabelRangesRef
= rDoc
.GetColNameRangesRef();
480 for( pScRange
= aColScRanges
.First(); pScRange
; pScRange
= aColScRanges
.Next() )
482 ScRange
aDataRange( *pScRange
);
483 if( aDataRange
.aEnd
.Row() < MAXROW
)
485 aDataRange
.aStart
.SetRow( aDataRange
.aEnd
.Row() + 1 );
486 aDataRange
.aEnd
.SetRow( MAXROW
);
488 else if( aDataRange
.aStart
.Row() > 0 )
490 aDataRange
.aEnd
.SetRow( aDataRange
.aStart
.Row() - 1 );
491 aDataRange
.aStart
.SetRow( 0 );
493 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
497 // Conditional formatting =====================================================
499 XclImpCondFormat::XclImpCondFormat( const XclImpRoot
& rRoot
, sal_uInt32 nFormatIndex
) :
501 mnFormatIndex( nFormatIndex
),
507 XclImpCondFormat::~XclImpCondFormat()
511 void XclImpCondFormat::ReadCondfmt( XclImpStream
& rStrm
)
513 DBG_ASSERT( !mnCondCount
, "XclImpCondFormat::ReadCondfmt - already initialized" );
514 XclRangeList aXclRanges
;
515 rStrm
>> mnCondCount
;
518 GetAddressConverter().ConvertRangeList( maRanges
, aXclRanges
, GetCurrScTab(), true );
521 void XclImpCondFormat::ReadCF( XclImpStream
& rStrm
)
523 if( mnCondIndex
>= mnCondCount
)
525 DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
529 // entire conditional format outside of valid range?
530 if( !maRanges
.Count() )
533 sal_uInt8 nType
, nOperator
;
534 sal_uInt16 nFmlaSize1
, nFmlaSize2
;
537 rStrm
>> nType
>> nOperator
>> nFmlaSize1
>> nFmlaSize2
>> nFlags
;
540 // *** mode and comparison operator ***
542 ScConditionMode eMode
= SC_COND_NONE
;
545 case EXC_CF_TYPE_CELL
:
549 case EXC_CF_CMP_BETWEEN
: eMode
= SC_COND_BETWEEN
; break;
550 case EXC_CF_CMP_NOT_BETWEEN
: eMode
= SC_COND_NOTBETWEEN
; break;
551 case EXC_CF_CMP_EQUAL
: eMode
= SC_COND_EQUAL
; break;
552 case EXC_CF_CMP_NOT_EQUAL
: eMode
= SC_COND_NOTEQUAL
; break;
553 case EXC_CF_CMP_GREATER
: eMode
= SC_COND_GREATER
; break;
554 case EXC_CF_CMP_LESS
: eMode
= SC_COND_LESS
; break;
555 case EXC_CF_CMP_GREATER_EQUAL
: eMode
= SC_COND_EQGREATER
; break;
556 case EXC_CF_CMP_LESS_EQUAL
: eMode
= SC_COND_EQLESS
; break;
558 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator
);
563 case EXC_CF_TYPE_FMLA
:
564 eMode
= SC_COND_DIRECT
;
568 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType
);
572 // *** create style sheet ***
574 String
aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex
, mnCondIndex
) );
575 SfxItemSet
& rStyleItemSet
= ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName
, true ).GetItemSet();
577 const XclImpPalette
& rPalette
= GetPalette();
579 // *** font block ***
581 if( ::get_flag( nFlags
, EXC_CF_BLOCK_FONT
) )
583 XclImpFont
aFont( GetRoot() );
584 aFont
.ReadCFFontBlock( rStrm
);
585 aFont
.FillToItemSet( rStyleItemSet
, EXC_FONTITEM_CELL
);
588 // *** border block ***
590 if( ::get_flag( nFlags
, EXC_CF_BLOCK_BORDER
) )
592 sal_uInt16 nLineStyle
;
593 sal_uInt32 nLineColor
;
594 rStrm
>> nLineStyle
>> nLineColor
;
597 XclImpCellBorder aBorder
;
598 aBorder
.FillFromCF8( nLineStyle
, nLineColor
, nFlags
);
599 aBorder
.FillToItemSet( rStyleItemSet
, rPalette
);
602 // *** pattern block ***
604 if( ::get_flag( nFlags
, EXC_CF_BLOCK_AREA
) )
606 sal_uInt16 nPattern
, nColor
;
607 rStrm
>> nPattern
>> nColor
;
609 XclImpCellArea aArea
;
610 aArea
.FillFromCF8( nPattern
, nColor
, nFlags
);
611 aArea
.FillToItemSet( rStyleItemSet
, rPalette
);
616 const ScAddress
& rPos
= maRanges
.GetObject( 0 )->aStart
; // assured above that maRanges is not empty
617 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
619 ExcelConverterBase::ConvertParam aParam
;
620 aParam
.mbAllowArrays
= false;
622 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
625 const ScTokenArray
* pTokArr
= 0;
626 rFmlaConv
.Reset( rPos
);
627 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize1
, aParam
, FT_RangeName
);
628 // formula converter owns pTokArr -> create a copy of the token array
630 xTokArr1
.reset( pTokArr
->Clone() );
633 ::std::auto_ptr
< ScTokenArray
> pTokArr2
;
636 const ScTokenArray
* pTokArr
= 0;
637 rFmlaConv
.Reset( rPos
);
638 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize2
, aParam
, FT_RangeName
);
639 // formula converter owns pTokArr -> create a copy of the token array
641 pTokArr2
.reset( pTokArr
->Clone() );
644 // *** create the Calc conditional formatting ***
646 if( !mxScCondFmt
.get() )
649 mxScCondFmt
.reset( new ScConditionalFormat( nKey
, GetDocPtr() ) );
652 ScCondFormatEntry
aEntry( eMode
, xTokArr1
.get(), pTokArr2
.get(), GetDocPtr(), rPos
, aStyleName
);
653 mxScCondFmt
->AddEntry( aEntry
);
657 void XclImpCondFormat::Apply()
659 if( mxScCondFmt
.get() )
661 ScDocument
& rDoc
= GetDoc();
663 ULONG nKey
= rDoc
.AddCondFormat( *mxScCondFmt
);
664 ScPatternAttr
aPattern( rDoc
.GetPool() );
665 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL
, nKey
) );
667 // maRanges contains only valid cell ranges
668 for( const ScRange
* pScRange
= maRanges
.First(); pScRange
; pScRange
= maRanges
.Next() )
670 rDoc
.ApplyPatternAreaTab(
671 pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
672 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(),
673 pScRange
->aStart
.Tab(), aPattern
);
678 // ----------------------------------------------------------------------------
680 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot
& rRoot
) :
685 void XclImpCondFormatManager::ReadCondfmt( XclImpStream
& rStrm
)
687 XclImpCondFormat
* pFmt
= new XclImpCondFormat( GetRoot(), maCondFmtList
.Count() );
688 pFmt
->ReadCondfmt( rStrm
);
689 maCondFmtList
.Append( pFmt
);
692 void XclImpCondFormatManager::ReadCF( XclImpStream
& rStrm
)
694 DBG_ASSERT( !maCondFmtList
.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
695 if( !maCondFmtList
.Empty() )
696 maCondFmtList
.GetObject( maCondFmtList
.Count() - 1 )->ReadCF( rStrm
);
699 void XclImpCondFormatManager::Apply()
701 for( XclImpCondFormat
* pFmt
= maCondFmtList
.First(); pFmt
; pFmt
= maCondFmtList
.Next() )
703 maCondFmtList
.Clear();
706 // Data Validation ============================================================
708 void XclImpValidation::ReadDval( XclImpStream
& rStrm
)
710 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
711 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
716 if( nObjId
!= EXC_DVAL_NOOBJ
)
718 DBG_ASSERT( nObjId
<= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
719 rRoot
.GetObjectManager().SetSkipObj( rRoot
.GetCurrScTab(), static_cast< sal_uInt16
>( nObjId
) );
723 void XclImpValidation::ReadDV( XclImpStream
& rStrm
)
725 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
726 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
728 ScDocument
& rDoc
= rRoot
.GetDoc();
729 SCTAB nScTab
= rRoot
.GetCurrScTab();
730 ExcelToSc
& rFmlaConv
= rRoot
.GetOldFmlaConverter();
737 /* Empty strings are single NUL characters in Excel (string length is 1).
738 -> Do not let the stream replace them with '?' characters. */
739 rStrm
.SetNulSubstChar( '\0' );
740 String
aPromptTitle( rStrm
.ReadUniString() );
741 String
aErrorTitle( rStrm
.ReadUniString() );
742 String
aPromptMessage( rStrm
.ReadUniString() );
743 String
aErrorMessage( rStrm
.ReadUniString() );
744 rStrm
.SetNulSubstChar(); // back to default
746 ExcelConverterBase::ConvertParam aParam
;
747 aParam
.mbAllowArrays
= false;
750 if( rStrm
.GetRecLeft() > 8 )
755 // string list is single tStr token with NUL separators -> replace them with LF
756 rStrm
.SetNulSubstChar( '\n' );
757 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
762 const ScTokenArray
* pTokArr
= 0;
764 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, aParam
, FT_RangeName
);
765 // formula converter owns pTokArr -> create a copy of the token array
767 xTokArr1
.reset( pTokArr
->Clone() );
769 rStrm
.SetNulSubstChar(); // back to default
772 ::std::auto_ptr
< ScTokenArray
> xTokArr2
;
777 const ScTokenArray
* pTokArr
= 0;
779 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, aParam
, FT_RangeName
);
780 // formula converter owns pTokArr -> create a copy of the token array
782 xTokArr2
.reset( pTokArr
->Clone() );
785 // read all cell ranges
786 XclRangeList aXclRanges
;
789 // convert to Calc range list
790 ScRangeList aScRanges
;
791 rRoot
.GetAddressConverter().ConvertRangeList( aScRanges
, aXclRanges
, nScTab
, true );
793 // only continue if there are valid ranges
794 if( aScRanges
.Count() )
796 bool bIsValid
= true; // valid settings in flags field
798 ScValidationMode eValMode
= SC_VALID_ANY
;
799 switch( nFlags
& EXC_DV_MODE_MASK
)
801 case EXC_DV_MODE_ANY
: eValMode
= SC_VALID_ANY
; break;
802 case EXC_DV_MODE_WHOLE
: eValMode
= SC_VALID_WHOLE
; break;
803 case EXC_DV_MODE_DECIMAL
: eValMode
= SC_VALID_DECIMAL
; break;
804 case EXC_DV_MODE_LIST
: eValMode
= SC_VALID_LIST
; break;
805 case EXC_DV_MODE_DATE
: eValMode
= SC_VALID_DATE
; break;
806 case EXC_DV_MODE_TIME
: eValMode
= SC_VALID_TIME
; break;
807 case EXC_DV_MODE_TEXTLEN
: eValMode
= SC_VALID_TEXTLEN
; break;
808 case EXC_DV_MODE_CUSTOM
: eValMode
= SC_VALID_CUSTOM
; break;
809 default: bIsValid
= false;
811 rRoot
.GetTracer().TraceDVType(eValMode
== SC_VALID_CUSTOM
);
813 ScConditionMode eCondMode
= SC_COND_BETWEEN
;
814 switch( nFlags
& EXC_DV_COND_MASK
)
816 case EXC_DV_COND_BETWEEN
: eCondMode
= SC_COND_BETWEEN
; break;
817 case EXC_DV_COND_NOTBETWEEN
:eCondMode
= SC_COND_NOTBETWEEN
; break;
818 case EXC_DV_COND_EQUAL
: eCondMode
= SC_COND_EQUAL
; break;
819 case EXC_DV_COND_NOTEQUAL
: eCondMode
= SC_COND_NOTEQUAL
; break;
820 case EXC_DV_COND_GREATER
: eCondMode
= SC_COND_GREATER
; break;
821 case EXC_DV_COND_LESS
: eCondMode
= SC_COND_LESS
; break;
822 case EXC_DV_COND_EQGREATER
: eCondMode
= SC_COND_EQGREATER
; break;
823 case EXC_DV_COND_EQLESS
: eCondMode
= SC_COND_EQLESS
; break;
824 default: bIsValid
= false;
829 // first range for base address for relative references
830 const ScRange
& rScRange
= *aScRanges
.GetObject( 0 ); // aScRanges is not empty
832 // process string list of a list validity (convert to list of string tokens)
833 if( xTokArr1
.get() && (eValMode
== SC_VALID_LIST
) && ::get_flag( nFlags
, EXC_DV_STRINGLIST
) )
834 XclTokenArrayHelper::ConvertStringToList( *xTokArr1
, '\n', true );
836 ScValidationData
aValidData( eValMode
, eCondMode
, xTokArr1
.get(), xTokArr2
.get(), &rDoc
, rScRange
.aStart
);
838 aValidData
.SetIgnoreBlank( ::get_flag( nFlags
, EXC_DV_IGNOREBLANK
) );
839 aValidData
.SetListType( ::get_flagvalue( nFlags
, EXC_DV_SUPPRESSDROPDOWN
, ValidListType::INVISIBLE
, ValidListType::UNSORTED
) );
841 // *** prompt box ***
842 if( aPromptTitle
.Len() || aPromptMessage
.Len() )
844 // set any text stored in the record
845 aValidData
.SetInput( aPromptTitle
, aPromptMessage
);
846 if( !::get_flag( nFlags
, EXC_DV_SHOWPROMPT
) )
847 aValidData
.ResetInput();
851 ScValidErrorStyle eErrStyle
= SC_VALERR_STOP
;
852 switch( nFlags
& EXC_DV_ERROR_MASK
)
854 case EXC_DV_ERROR_WARNING
: eErrStyle
= SC_VALERR_WARNING
; break;
855 case EXC_DV_ERROR_INFO
: eErrStyle
= SC_VALERR_INFO
; break;
857 // set texts and error style
858 aValidData
.SetError( aErrorTitle
, aErrorMessage
, eErrStyle
);
859 if( !::get_flag( nFlags
, EXC_DV_SHOWERROR
) )
860 aValidData
.ResetError();
863 ULONG nHandle
= rDoc
.AddValidationEntry( aValidData
);
864 ScPatternAttr
aPattern( rDoc
.GetPool() );
865 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nHandle
) );
868 for( const ScRange
* pScRange
= aScRanges
.First(); pScRange
; pScRange
= aScRanges
.Next() )
869 rDoc
.ApplyPatternAreaTab( pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
870 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(), nScTab
, aPattern
);
876 // Web queries ================================================================
878 XclImpWebQuery::XclImpWebQuery( const ScRange
& rDestRange
) :
879 maDestRange( rDestRange
),
880 meMode( xlWQUnknown
),
885 void XclImpWebQuery::ReadParamqry( XclImpStream
& rStrm
)
887 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
888 sal_uInt16 nType
= ::extract_value
< sal_uInt16
>( nFlags
, 0, 3 );
889 if( (nType
== EXC_PQRYTYPE_WEBQUERY
) && ::get_flag( nFlags
, EXC_PQRY_WEBQUERY
) )
891 if( ::get_flag( nFlags
, EXC_PQRY_TABLES
) )
893 meMode
= xlWQAllTables
;
894 maTables
= ScfTools::GetHTMLTablesName();
898 meMode
= xlWQDocument
;
899 maTables
= ScfTools::GetHTMLDocName();
904 void XclImpWebQuery::ReadWqstring( XclImpStream
& rStrm
)
906 maURL
= rStrm
.ReadUniString();
909 void XclImpWebQuery::ReadWqsettings( XclImpStream
& rStrm
)
917 if( ::get_flag( nFlags
, EXC_WQSETT_SPECTABLES
) && (meMode
== xlWQAllTables
) )
918 meMode
= xlWQSpecTables
;
921 void XclImpWebQuery::ReadWqtables( XclImpStream
& rStrm
)
923 if( meMode
== xlWQSpecTables
)
926 String
aTables( rStrm
.ReadUniString() );
928 const sal_Unicode cSep
= ';';
929 aTables
.SearchAndReplaceAll( ',', cSep
);
930 String
aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
931 xub_StrLen nTokenCnt
= aTables
.GetQuotedTokenCount( aQuotedPairs
, cSep
);
933 xub_StrLen nStringIx
= 0;
934 for( xub_StrLen nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
936 String
aToken( aTables
.GetQuotedToken( 0, aQuotedPairs
, cSep
, nStringIx
) );
937 sal_Int32 nTabNum
= CharClass::isAsciiNumeric( aToken
) ? aToken
.ToInt32() : 0;
939 ScGlobal::AddToken( maTables
, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32
>( nTabNum
) ), cSep
);
942 ScGlobal::EraseQuotes( aToken
, '"', false );
944 ScGlobal::AddToken( maTables
, ScfTools::GetNameFromHTMLName( aToken
), cSep
);
950 void XclImpWebQuery::Apply( ScDocument
& rDoc
, const String
& rFilterName
)
952 if( maURL
.Len() && (meMode
!= xlWQUnknown
) && rDoc
.GetDocumentShell() )
954 ScAreaLink
* pLink
= new ScAreaLink( rDoc
.GetDocumentShell(),
955 maURL
, rFilterName
, EMPTY_STRING
, maTables
, maDestRange
, mnRefresh
* 60UL );
956 rDoc
.GetLinkManager()->InsertFileLink( *pLink
, OBJECT_CLIENT_FILE
,
957 maURL
, &rFilterName
, &maTables
);
961 // ----------------------------------------------------------------------------
963 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot
& rRoot
) :
968 void XclImpWebQueryBuffer::ReadQsi( XclImpStream
& rStrm
)
970 if( GetBiff() == EXC_BIFF8
)
973 String
aXclName( rStrm
.ReadUniString() );
975 // #i64794# Excel replaces spaces with underscores
976 aXclName
.SearchAndReplaceAll( ' ', '_' );
978 // #101529# find the defined name used in Calc
979 if( const XclImpName
* pName
= GetNameManager().FindName( aXclName
, GetCurrScTab() ) )
981 if( const ScRangeData
* pRangeData
= pName
->GetScRangeData() )
984 if( pRangeData
->IsReference( aRange
) )
985 maWQList
.Append( new XclImpWebQuery( aRange
) );
995 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream
& rStrm
)
997 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
998 pQuery
->ReadParamqry( rStrm
);
1001 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream
& rStrm
)
1003 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
1004 pQuery
->ReadWqstring( rStrm
);
1007 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream
& rStrm
)
1009 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
1010 pQuery
->ReadWqsettings( rStrm
);
1013 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream
& rStrm
)
1015 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
1016 pQuery
->ReadWqtables( rStrm
);
1019 void XclImpWebQueryBuffer::Apply()
1021 ScDocument
& rDoc
= GetDoc();
1022 String
aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER
) );
1023 for( XclImpWebQuery
* pQuery
= maWQList
.First(); pQuery
; pQuery
= maWQList
.Next() )
1024 pQuery
->Apply( rDoc
, aFilterName
);
1027 // Decryption =================================================================
1031 XclImpDecrypterRef
lclReadFilepass5( XclImpStream
& rStrm
)
1033 XclImpDecrypterRef xDecr
;
1034 DBG_ASSERT( rStrm
.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1035 if( rStrm
.GetRecLeft() == 4 )
1037 sal_uInt16 nKey
, nHash
;
1038 rStrm
>> nKey
>> nHash
;
1039 xDecr
.reset( new XclImpBiff5Decrypter( nKey
, nHash
) );
1044 XclImpDecrypterRef
lclReadFilepass8_Standard( XclImpStream
& rStrm
)
1046 XclImpDecrypterRef xDecr
;
1047 DBG_ASSERT( rStrm
.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1048 if( rStrm
.GetRecLeft() == 48 )
1050 sal_uInt8 pnSalt
[ 16 ];
1051 sal_uInt8 pnVerifier
[ 16 ];
1052 sal_uInt8 pnVerifierHash
[ 16 ];
1053 rStrm
.Read( pnSalt
, 16 );
1054 rStrm
.Read( pnVerifier
, 16 );
1055 rStrm
.Read( pnVerifierHash
, 16 );
1056 xDecr
.reset( new XclImpBiff8Decrypter( pnSalt
, pnVerifier
, pnVerifierHash
) );
1061 XclImpDecrypterRef
lclReadFilepass8_Strong( XclImpStream
& /*rStrm*/ )
1064 return XclImpDecrypterRef();
1067 XclImpDecrypterRef
lclReadFilepass8( XclImpStream
& rStrm
)
1069 XclImpDecrypterRef xDecr
;
1075 case EXC_FILEPASS_BIFF5
:
1076 xDecr
= lclReadFilepass5( rStrm
);
1079 case EXC_FILEPASS_BIFF8
:
1082 sal_uInt16 nSubMode
;
1086 case EXC_FILEPASS_BIFF8_STD
:
1087 xDecr
= lclReadFilepass8_Standard( rStrm
);
1089 case EXC_FILEPASS_BIFF8_STRONG
:
1090 xDecr
= lclReadFilepass8_Strong( rStrm
);
1093 DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1099 DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
1107 // ----------------------------------------------------------------------------
1109 ErrCode
XclImpDecryptHelper::ReadFilepass( XclImpStream
& rStrm
)
1111 XclImpDecrypterRef xDecr
;
1112 rStrm
.DisableDecryption();
1114 // read the FILEPASS record and create a new decrypter object
1115 switch( rStrm
.GetRoot().GetBiff() )
1120 case EXC_BIFF5
: xDecr
= lclReadFilepass5( rStrm
); break;
1121 case EXC_BIFF8
: xDecr
= lclReadFilepass8( rStrm
); break;
1122 default: DBG_ERROR_BIFF();
1125 // set decrypter at import stream
1126 rStrm
.SetDecrypter( xDecr
);
1128 // request and verify a password (decrypter implements IDocPasswordVerifier)
1130 rStrm
.GetRoot().RequestPassword( *xDecr
);
1132 // return error code (success, wrong password, etc.)
1133 return xDecr
.is() ? xDecr
->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT
;
1136 // Document protection ========================================================
1138 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot
& rRoot
) :
1139 XclImpRoot( rRoot
),
1141 mbDocProtect(false),
1146 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream
& rStrm
)
1148 mbDocProtect
= rStrm
.ReaduInt16() ? true : false;
1151 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream
& rStrm
)
1153 mbWinProtect
= rStrm
.ReaduInt16() ? true : false;
1156 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
)
1158 rStrm
.EnableDecryption();
1159 mnPassHash
= rStrm
.ReaduInt16();
1162 void XclImpDocProtectBuffer::Apply() const
1164 if (!mbDocProtect
&& !mbWinProtect
)
1165 // Excel requires either the structure or windows protection is set.
1166 // If neither is set then the document is not protected at all.
1169 auto_ptr
<ScDocProtection
> pProtect(new ScDocProtection
);
1170 pProtect
->setProtected(true);
1172 #if ENABLE_SHEET_PROTECTION
1175 // 16-bit password pash.
1176 Sequence
<sal_Int8
> aPass(2);
1177 aPass
[0] = (mnPassHash
>> 8) & 0xFF;
1178 aPass
[1] = mnPassHash
& 0xFF;
1179 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1183 // document protection options
1184 pProtect
->setOption(ScDocProtection::STRUCTURE
, mbDocProtect
);
1185 pProtect
->setOption(ScDocProtection::WINDOWS
, mbWinProtect
);
1187 GetDoc().SetDocProtection(pProtect
.get());
1190 // Sheet Protection ===========================================================
1192 XclImpSheetProtectBuffer::Sheet::Sheet() :
1194 mnPasswordHash(0x0000),
1199 // ----------------------------------------------------------------------------
1201 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet
& r
) :
1202 mbProtected(r
.mbProtected
),
1203 mnPasswordHash(r
.mnPasswordHash
),
1204 mnOptions(r
.mnOptions
)
1208 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot
& rRoot
) :
1213 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream
& rStrm
, SCTAB nTab
)
1215 if ( rStrm
.ReaduInt16() )
1217 Sheet
* pSheet
= GetSheetItem(nTab
);
1219 pSheet
->mbProtected
= true;
1223 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream
& rStrm
, SCTAB nTab
)
1226 sal_uInt16 nOptions
;
1229 Sheet
* pSheet
= GetSheetItem(nTab
);
1231 pSheet
->mnOptions
= nOptions
;
1234 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
, SCTAB nTab
)
1238 Sheet
* pSheet
= GetSheetItem(nTab
);
1240 pSheet
->mnPasswordHash
= nHash
;
1243 void XclImpSheetProtectBuffer::Apply() const
1245 for (ProtectedSheetMap::const_iterator itr
= maProtectedSheets
.begin(), itrEnd
= maProtectedSheets
.end();
1246 itr
!= itrEnd
; ++itr
)
1248 if (!itr
->second
.mbProtected
)
1249 // This sheet is (for whatever reason) not protected.
1252 auto_ptr
<ScTableProtection
> pProtect(new ScTableProtection
);
1253 pProtect
->setProtected(true);
1255 #if ENABLE_SHEET_PROTECTION
1256 // 16-bit hash password
1257 const sal_uInt16 nHash
= itr
->second
.mnPasswordHash
;
1260 Sequence
<sal_Int8
> aPass(2);
1261 aPass
[0] = (nHash
>> 8) & 0xFF;
1262 aPass
[1] = nHash
& 0xFF;
1263 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1267 // sheet protection options
1268 const sal_uInt16 nOptions
= itr
->second
.mnOptions
;
1269 pProtect
->setOption( ScTableProtection::OBJECTS
, (nOptions
& 0x0001) );
1270 pProtect
->setOption( ScTableProtection::SCENARIOS
, (nOptions
& 0x0002) );
1271 pProtect
->setOption( ScTableProtection::FORMAT_CELLS
, (nOptions
& 0x0004) );
1272 pProtect
->setOption( ScTableProtection::FORMAT_COLUMNS
, (nOptions
& 0x0008) );
1273 pProtect
->setOption( ScTableProtection::FORMAT_ROWS
, (nOptions
& 0x0010) );
1274 pProtect
->setOption( ScTableProtection::INSERT_COLUMNS
, (nOptions
& 0x0020) );
1275 pProtect
->setOption( ScTableProtection::INSERT_ROWS
, (nOptions
& 0x0040) );
1276 pProtect
->setOption( ScTableProtection::INSERT_HYPERLINKS
, (nOptions
& 0x0080) );
1277 pProtect
->setOption( ScTableProtection::DELETE_COLUMNS
, (nOptions
& 0x0100) );
1278 pProtect
->setOption( ScTableProtection::DELETE_ROWS
, (nOptions
& 0x0200) );
1279 pProtect
->setOption( ScTableProtection::SELECT_LOCKED_CELLS
, (nOptions
& 0x0400) );
1280 pProtect
->setOption( ScTableProtection::SORT
, (nOptions
& 0x0800) );
1281 pProtect
->setOption( ScTableProtection::AUTOFILTER
, (nOptions
& 0x1000) );
1282 pProtect
->setOption( ScTableProtection::PIVOT_TABLES
, (nOptions
& 0x2000) );
1283 pProtect
->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS
, (nOptions
& 0x4000) );
1285 // all done. now commit.
1286 GetDoc().SetTabProtection(itr
->first
, pProtect
.get());
1290 XclImpSheetProtectBuffer::Sheet
* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab
)
1292 ProtectedSheetMap::iterator itr
= maProtectedSheets
.find(nTab
);
1293 if (itr
== maProtectedSheets
.end())
1296 if ( !maProtectedSheets
.insert( ProtectedSheetMap::value_type(nTab
, Sheet()) ).second
)
1299 itr
= maProtectedSheets
.find(nTab
);
1302 return &itr
->second
;
1305 // ============================================================================