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 for (xub_StrLen i
= 1; i
< n
; ++i
)
383 if (c
== sal_Unicode('\''))
385 bInQuote
= !bInQuote
;
386 if (!bInQuote
&& aTabName
.Len() > 0)
387 aNewUrl
.Append(aTabName
);
396 // It should be outside the quotes!
399 // All is good. Pass the new URL.
403 void XclImpHyperlink::InsertUrl( const XclImpRoot
& rRoot
, const XclRange
& rXclRange
, const String
& rUrl
)
406 ConvertToValidTabName(aUrl
);
408 SCTAB nScTab
= rRoot
.GetCurrScTab();
409 ScRange
aScRange( ScAddress::UNINITIALIZED
);
410 if( rRoot
.GetAddressConverter().ConvertRange( aScRange
, rXclRange
, nScTab
, nScTab
, true ) )
412 SCCOL nScCol1
, nScCol2
;
413 SCROW nScRow1
, nScRow2
;
414 aScRange
.GetVars( nScCol1
, nScRow1
, nScTab
, nScCol2
, nScRow2
, nScTab
);
415 for( SCCOL nScCol
= nScCol1
; nScCol
<= nScCol2
; ++nScCol
)
416 for( SCROW nScRow
= nScRow1
; nScRow
<= nScRow2
; ++nScRow
)
417 lclInsertUrl( rRoot
, aUrl
, nScCol
, nScRow
, nScTab
);
421 // Label ranges ===============================================================
423 void XclImpLabelranges::ReadLabelranges( XclImpStream
& rStrm
)
425 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
426 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
428 ScDocument
& rDoc
= rRoot
.GetDoc();
429 SCTAB nScTab
= rRoot
.GetCurrScTab();
430 XclImpAddressConverter
& rAddrConv
= rRoot
.GetAddressConverter();
431 ScRangePairListRef xLabelRangesRef
;
432 const ScRange
* pScRange
= 0;
434 XclRangeList aRowXclRanges
, aColXclRanges
;
435 rStrm
>> aRowXclRanges
>> aColXclRanges
;
438 ScRangeList aRowScRanges
;
439 rAddrConv
.ConvertRangeList( aRowScRanges
, aRowXclRanges
, nScTab
, false );
440 xLabelRangesRef
= rDoc
.GetRowNameRangesRef();
441 for( pScRange
= aRowScRanges
.First(); pScRange
; pScRange
= aRowScRanges
.Next() )
443 ScRange
aDataRange( *pScRange
);
444 if( aDataRange
.aEnd
.Col() < MAXCOL
)
446 aDataRange
.aStart
.SetCol( aDataRange
.aEnd
.Col() + 1 );
447 aDataRange
.aEnd
.SetCol( MAXCOL
);
449 else if( aDataRange
.aStart
.Col() > 0 )
451 aDataRange
.aEnd
.SetCol( aDataRange
.aStart
.Col() - 1 );
452 aDataRange
.aStart
.SetCol( 0 );
454 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
457 // column label ranges
458 ScRangeList aColScRanges
;
459 rAddrConv
.ConvertRangeList( aColScRanges
, aColXclRanges
, nScTab
, false );
460 xLabelRangesRef
= rDoc
.GetColNameRangesRef();
461 for( pScRange
= aColScRanges
.First(); pScRange
; pScRange
= aColScRanges
.Next() )
463 ScRange
aDataRange( *pScRange
);
464 if( aDataRange
.aEnd
.Row() < MAXROW
)
466 aDataRange
.aStart
.SetRow( aDataRange
.aEnd
.Row() + 1 );
467 aDataRange
.aEnd
.SetRow( MAXROW
);
469 else if( aDataRange
.aStart
.Row() > 0 )
471 aDataRange
.aEnd
.SetRow( aDataRange
.aStart
.Row() - 1 );
472 aDataRange
.aStart
.SetRow( 0 );
474 xLabelRangesRef
->Append( ScRangePair( *pScRange
, aDataRange
) );
478 // Conditional formatting =====================================================
480 XclImpCondFormat::XclImpCondFormat( const XclImpRoot
& rRoot
, sal_uInt32 nFormatIndex
) :
482 mnFormatIndex( nFormatIndex
),
488 XclImpCondFormat::~XclImpCondFormat()
492 void XclImpCondFormat::ReadCondfmt( XclImpStream
& rStrm
)
494 DBG_ASSERT( !mnCondCount
, "XclImpCondFormat::ReadCondfmt - already initialized" );
495 XclRangeList aXclRanges
;
496 rStrm
>> mnCondCount
;
499 GetAddressConverter().ConvertRangeList( maRanges
, aXclRanges
, GetCurrScTab(), true );
502 void XclImpCondFormat::ReadCF( XclImpStream
& rStrm
)
504 if( mnCondIndex
>= mnCondCount
)
506 DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
510 // entire conditional format outside of valid range?
511 if( !maRanges
.Count() )
514 sal_uInt8 nType
, nOperator
;
515 sal_uInt16 nFmlaSize1
, nFmlaSize2
;
518 rStrm
>> nType
>> nOperator
>> nFmlaSize1
>> nFmlaSize2
>> nFlags
;
521 // *** mode and comparison operator ***
523 ScConditionMode eMode
= SC_COND_NONE
;
526 case EXC_CF_TYPE_CELL
:
530 case EXC_CF_CMP_BETWEEN
: eMode
= SC_COND_BETWEEN
; break;
531 case EXC_CF_CMP_NOT_BETWEEN
: eMode
= SC_COND_NOTBETWEEN
; break;
532 case EXC_CF_CMP_EQUAL
: eMode
= SC_COND_EQUAL
; break;
533 case EXC_CF_CMP_NOT_EQUAL
: eMode
= SC_COND_NOTEQUAL
; break;
534 case EXC_CF_CMP_GREATER
: eMode
= SC_COND_GREATER
; break;
535 case EXC_CF_CMP_LESS
: eMode
= SC_COND_LESS
; break;
536 case EXC_CF_CMP_GREATER_EQUAL
: eMode
= SC_COND_EQGREATER
; break;
537 case EXC_CF_CMP_LESS_EQUAL
: eMode
= SC_COND_EQLESS
; break;
539 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator
);
544 case EXC_CF_TYPE_FMLA
:
545 eMode
= SC_COND_DIRECT
;
549 DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType
);
553 // *** create style sheet ***
555 String
aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex
, mnCondIndex
) );
556 SfxItemSet
& rStyleItemSet
= ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName
, true ).GetItemSet();
558 const XclImpPalette
& rPalette
= GetPalette();
560 // *** font block ***
562 if( ::get_flag( nFlags
, EXC_CF_BLOCK_FONT
) )
564 XclImpFont
aFont( GetRoot() );
565 aFont
.ReadCFFontBlock( rStrm
);
566 aFont
.FillToItemSet( rStyleItemSet
, EXC_FONTITEM_CELL
);
569 // *** border block ***
571 if( ::get_flag( nFlags
, EXC_CF_BLOCK_BORDER
) )
573 sal_uInt16 nLineStyle
;
574 sal_uInt32 nLineColor
;
575 rStrm
>> nLineStyle
>> nLineColor
;
578 XclImpCellBorder aBorder
;
579 aBorder
.FillFromCF8( nLineStyle
, nLineColor
, nFlags
);
580 aBorder
.FillToItemSet( rStyleItemSet
, rPalette
);
583 // *** pattern block ***
585 if( ::get_flag( nFlags
, EXC_CF_BLOCK_AREA
) )
587 sal_uInt16 nPattern
, nColor
;
588 rStrm
>> nPattern
>> nColor
;
590 XclImpCellArea aArea
;
591 aArea
.FillFromCF8( nPattern
, nColor
, nFlags
);
592 aArea
.FillToItemSet( rStyleItemSet
, rPalette
);
597 const ScAddress
& rPos
= maRanges
.GetObject( 0 )->aStart
; // assured above that maRanges is not empty
598 ExcelToSc
& rFmlaConv
= GetOldFmlaConverter();
600 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
603 const ScTokenArray
* pTokArr
= 0;
604 rFmlaConv
.Reset( rPos
);
605 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize1
, false, FT_RangeName
);
606 // formula converter owns pTokArr -> create a copy of the token array
608 xTokArr1
.reset( pTokArr
->Clone() );
611 ::std::auto_ptr
< ScTokenArray
> pTokArr2
;
614 const ScTokenArray
* pTokArr
= 0;
615 rFmlaConv
.Reset( rPos
);
616 rFmlaConv
.Convert( pTokArr
, rStrm
, nFmlaSize2
, false, FT_RangeName
);
617 // formula converter owns pTokArr -> create a copy of the token array
619 pTokArr2
.reset( pTokArr
->Clone() );
622 // *** create the Calc conditional formatting ***
624 if( !mxScCondFmt
.get() )
627 mxScCondFmt
.reset( new ScConditionalFormat( nKey
, GetDocPtr() ) );
630 ScCondFormatEntry
aEntry( eMode
, xTokArr1
.get(), pTokArr2
.get(), GetDocPtr(), rPos
, aStyleName
);
631 mxScCondFmt
->AddEntry( aEntry
);
635 void XclImpCondFormat::Apply()
637 if( mxScCondFmt
.get() )
639 ScDocument
& rDoc
= GetDoc();
641 ULONG nKey
= rDoc
.AddCondFormat( *mxScCondFmt
);
642 ScPatternAttr
aPattern( rDoc
.GetPool() );
643 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL
, nKey
) );
645 // maRanges contains only valid cell ranges
646 for( const ScRange
* pScRange
= maRanges
.First(); pScRange
; pScRange
= maRanges
.Next() )
648 rDoc
.ApplyPatternAreaTab(
649 pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
650 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(),
651 pScRange
->aStart
.Tab(), aPattern
);
656 // ----------------------------------------------------------------------------
658 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot
& rRoot
) :
663 void XclImpCondFormatManager::ReadCondfmt( XclImpStream
& rStrm
)
665 XclImpCondFormat
* pFmt
= new XclImpCondFormat( GetRoot(), maCondFmtList
.Count() );
666 pFmt
->ReadCondfmt( rStrm
);
667 maCondFmtList
.Append( pFmt
);
670 void XclImpCondFormatManager::ReadCF( XclImpStream
& rStrm
)
672 DBG_ASSERT( !maCondFmtList
.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
673 if( !maCondFmtList
.Empty() )
674 maCondFmtList
.GetObject( maCondFmtList
.Count() - 1 )->ReadCF( rStrm
);
677 void XclImpCondFormatManager::Apply()
679 for( XclImpCondFormat
* pFmt
= maCondFmtList
.First(); pFmt
; pFmt
= maCondFmtList
.Next() )
681 maCondFmtList
.Clear();
684 // Data Validation ============================================================
686 void XclImpValidation::ReadDval( XclImpStream
& rStrm
)
688 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
689 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
694 if( nObjId
!= EXC_DVAL_NOOBJ
)
696 DBG_ASSERT( nObjId
<= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
697 rRoot
.GetObjectManager().SetSkipObj( rRoot
.GetCurrScTab(), static_cast< sal_uInt16
>( nObjId
) );
701 void XclImpValidation::ReadDV( XclImpStream
& rStrm
)
703 const XclImpRoot
& rRoot
= rStrm
.GetRoot();
704 DBG_ASSERT_BIFF( rRoot
.GetBiff() == EXC_BIFF8
);
706 ScDocument
& rDoc
= rRoot
.GetDoc();
707 SCTAB nScTab
= rRoot
.GetCurrScTab();
708 ExcelToSc
& rFmlaConv
= rRoot
.GetOldFmlaConverter();
715 /* Empty strings are single NUL characters in Excel (string length is 1).
716 -> Do not let the stream replace them with '?' characters. */
717 rStrm
.SetNulSubstChar( '\0' );
718 String
aPromptTitle( rStrm
.ReadUniString() );
719 String
aErrorTitle( rStrm
.ReadUniString() );
720 String
aPromptMessage( rStrm
.ReadUniString() );
721 String
aErrorMessage( rStrm
.ReadUniString() );
722 rStrm
.SetNulSubstChar(); // back to default
725 if( rStrm
.GetRecLeft() > 8 )
730 // string list is single tStr token with NUL separators -> replace them with LF
731 rStrm
.SetNulSubstChar( '\n' );
732 ::std::auto_ptr
< ScTokenArray
> xTokArr1
;
737 const ScTokenArray
* pTokArr
= 0;
739 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_RangeName
);
740 // formula converter owns pTokArr -> create a copy of the token array
742 xTokArr1
.reset( pTokArr
->Clone() );
744 rStrm
.SetNulSubstChar(); // back to default
747 ::std::auto_ptr
< ScTokenArray
> xTokArr2
;
752 const ScTokenArray
* pTokArr
= 0;
754 rFmlaConv
.Convert( pTokArr
, rStrm
, nLen
, false, FT_RangeName
);
755 // formula converter owns pTokArr -> create a copy of the token array
757 xTokArr2
.reset( pTokArr
->Clone() );
760 // read all cell ranges
761 XclRangeList aXclRanges
;
764 // convert to Calc range list
765 ScRangeList aScRanges
;
766 rRoot
.GetAddressConverter().ConvertRangeList( aScRanges
, aXclRanges
, nScTab
, true );
768 // only continue if there are valid ranges
769 if( aScRanges
.Count() )
771 bool bIsValid
= true; // valid settings in flags field
773 ScValidationMode eValMode
= SC_VALID_ANY
;
774 switch( nFlags
& EXC_DV_MODE_MASK
)
776 case EXC_DV_MODE_ANY
: eValMode
= SC_VALID_ANY
; break;
777 case EXC_DV_MODE_WHOLE
: eValMode
= SC_VALID_WHOLE
; break;
778 case EXC_DV_MODE_DECIMAL
: eValMode
= SC_VALID_DECIMAL
; break;
779 case EXC_DV_MODE_LIST
: eValMode
= SC_VALID_LIST
; break;
780 case EXC_DV_MODE_DATE
: eValMode
= SC_VALID_DATE
; break;
781 case EXC_DV_MODE_TIME
: eValMode
= SC_VALID_TIME
; break;
782 case EXC_DV_MODE_TEXTLEN
: eValMode
= SC_VALID_TEXTLEN
; break;
783 case EXC_DV_MODE_CUSTOM
: eValMode
= SC_VALID_CUSTOM
; break;
784 default: bIsValid
= false;
786 rRoot
.GetTracer().TraceDVType(eValMode
== SC_VALID_CUSTOM
);
788 ScConditionMode eCondMode
= SC_COND_BETWEEN
;
789 switch( nFlags
& EXC_DV_COND_MASK
)
791 case EXC_DV_COND_BETWEEN
: eCondMode
= SC_COND_BETWEEN
; break;
792 case EXC_DV_COND_NOTBETWEEN
:eCondMode
= SC_COND_NOTBETWEEN
; break;
793 case EXC_DV_COND_EQUAL
: eCondMode
= SC_COND_EQUAL
; break;
794 case EXC_DV_COND_NOTEQUAL
: eCondMode
= SC_COND_NOTEQUAL
; break;
795 case EXC_DV_COND_GREATER
: eCondMode
= SC_COND_GREATER
; break;
796 case EXC_DV_COND_LESS
: eCondMode
= SC_COND_LESS
; break;
797 case EXC_DV_COND_EQGREATER
: eCondMode
= SC_COND_EQGREATER
; break;
798 case EXC_DV_COND_EQLESS
: eCondMode
= SC_COND_EQLESS
; break;
799 default: bIsValid
= false;
804 // first range for base address for relative references
805 const ScRange
& rScRange
= *aScRanges
.GetObject( 0 ); // aScRanges is not empty
807 // process string list of a list validity (convert to list of string tokens)
808 if( xTokArr1
.get() && (eValMode
== SC_VALID_LIST
) && ::get_flag( nFlags
, EXC_DV_STRINGLIST
) )
809 XclTokenArrayHelper::ConvertStringToList( *xTokArr1
, '\n', true );
811 ScValidationData
aValidData( eValMode
, eCondMode
, xTokArr1
.get(), xTokArr2
.get(), &rDoc
, rScRange
.aStart
);
813 aValidData
.SetIgnoreBlank( ::get_flag( nFlags
, EXC_DV_IGNOREBLANK
) );
814 aValidData
.SetListType( ::get_flagvalue( nFlags
, EXC_DV_SUPPRESSDROPDOWN
, ValidListType::INVISIBLE
, ValidListType::UNSORTED
) );
816 // *** prompt box ***
817 if( aPromptTitle
.Len() || aPromptMessage
.Len() )
819 // set any text stored in the record
820 aValidData
.SetInput( aPromptTitle
, aPromptMessage
);
821 if( !::get_flag( nFlags
, EXC_DV_SHOWPROMPT
) )
822 aValidData
.ResetInput();
826 ScValidErrorStyle eErrStyle
= SC_VALERR_STOP
;
827 switch( nFlags
& EXC_DV_ERROR_MASK
)
829 case EXC_DV_ERROR_WARNING
: eErrStyle
= SC_VALERR_WARNING
; break;
830 case EXC_DV_ERROR_INFO
: eErrStyle
= SC_VALERR_INFO
; break;
832 // set texts and error style
833 aValidData
.SetError( aErrorTitle
, aErrorMessage
, eErrStyle
);
834 if( !::get_flag( nFlags
, EXC_DV_SHOWERROR
) )
835 aValidData
.ResetError();
838 ULONG nHandle
= rDoc
.AddValidationEntry( aValidData
);
839 ScPatternAttr
aPattern( rDoc
.GetPool() );
840 aPattern
.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA
, nHandle
) );
843 for( const ScRange
* pScRange
= aScRanges
.First(); pScRange
; pScRange
= aScRanges
.Next() )
844 rDoc
.ApplyPatternAreaTab( pScRange
->aStart
.Col(), pScRange
->aStart
.Row(),
845 pScRange
->aEnd
.Col(), pScRange
->aEnd
.Row(), nScTab
, aPattern
);
851 // Web queries ================================================================
853 XclImpWebQuery::XclImpWebQuery( const ScRange
& rDestRange
) :
854 maDestRange( rDestRange
),
855 meMode( xlWQUnknown
),
860 void XclImpWebQuery::ReadParamqry( XclImpStream
& rStrm
)
862 sal_uInt16 nFlags
= rStrm
.ReaduInt16();
863 sal_uInt16 nType
= ::extract_value
< sal_uInt16
>( nFlags
, 0, 3 );
864 if( (nType
== EXC_PQRYTYPE_WEBQUERY
) && ::get_flag( nFlags
, EXC_PQRY_WEBQUERY
) )
866 if( ::get_flag( nFlags
, EXC_PQRY_TABLES
) )
868 meMode
= xlWQAllTables
;
869 maTables
= ScfTools::GetHTMLTablesName();
873 meMode
= xlWQDocument
;
874 maTables
= ScfTools::GetHTMLDocName();
879 void XclImpWebQuery::ReadWqstring( XclImpStream
& rStrm
)
881 maURL
= rStrm
.ReadUniString();
884 void XclImpWebQuery::ReadWqsettings( XclImpStream
& rStrm
)
892 if( ::get_flag( nFlags
, EXC_WQSETT_SPECTABLES
) && (meMode
== xlWQAllTables
) )
893 meMode
= xlWQSpecTables
;
896 void XclImpWebQuery::ReadWqtables( XclImpStream
& rStrm
)
898 if( meMode
== xlWQSpecTables
)
901 String
aTables( rStrm
.ReadUniString() );
903 const sal_Unicode cSep
= ';';
904 aTables
.SearchAndReplaceAll( ',', cSep
);
905 String
aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
906 xub_StrLen nTokenCnt
= aTables
.GetQuotedTokenCount( aQuotedPairs
, cSep
);
908 xub_StrLen nStringIx
= 0;
909 for( xub_StrLen nToken
= 0; nToken
< nTokenCnt
; ++nToken
)
911 String
aToken( aTables
.GetQuotedToken( 0, aQuotedPairs
, cSep
, nStringIx
) );
912 sal_Int32 nTabNum
= CharClass::isAsciiNumeric( aToken
) ? aToken
.ToInt32() : 0;
914 ScGlobal::AddToken( maTables
, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32
>( nTabNum
) ), cSep
);
917 ScGlobal::EraseQuotes( aToken
, '"', false );
919 ScGlobal::AddToken( maTables
, ScfTools::GetNameFromHTMLName( aToken
), cSep
);
925 void XclImpWebQuery::Apply( ScDocument
& rDoc
, const String
& rFilterName
)
927 if( maURL
.Len() && (meMode
!= xlWQUnknown
) && rDoc
.GetDocumentShell() )
929 ScAreaLink
* pLink
= new ScAreaLink( rDoc
.GetDocumentShell(),
930 maURL
, rFilterName
, EMPTY_STRING
, maTables
, maDestRange
, mnRefresh
* 60UL );
931 rDoc
.GetLinkManager()->InsertFileLink( *pLink
, OBJECT_CLIENT_FILE
,
932 maURL
, &rFilterName
, &maTables
);
936 // ----------------------------------------------------------------------------
938 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot
& rRoot
) :
943 void XclImpWebQueryBuffer::ReadQsi( XclImpStream
& rStrm
)
945 if( GetBiff() == EXC_BIFF8
)
948 String
aXclName( rStrm
.ReadUniString() );
950 // #i64794# Excel replaces spaces with underscores
951 aXclName
.SearchAndReplaceAll( ' ', '_' );
953 // #101529# find the defined name used in Calc
954 if( const XclImpName
* pName
= GetNameManager().FindName( aXclName
, GetCurrScTab() ) )
956 if( const ScRangeData
* pRangeData
= pName
->GetScRangeData() )
959 if( pRangeData
->IsReference( aRange
) )
960 maWQList
.Append( new XclImpWebQuery( aRange
) );
970 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream
& rStrm
)
972 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
973 pQuery
->ReadParamqry( rStrm
);
976 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream
& rStrm
)
978 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
979 pQuery
->ReadWqstring( rStrm
);
982 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream
& rStrm
)
984 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
985 pQuery
->ReadWqsettings( rStrm
);
988 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream
& rStrm
)
990 if( XclImpWebQuery
* pQuery
= maWQList
.Last() )
991 pQuery
->ReadWqtables( rStrm
);
994 void XclImpWebQueryBuffer::Apply()
996 ScDocument
& rDoc
= GetDoc();
997 String
aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER
) );
998 for( XclImpWebQuery
* pQuery
= maWQList
.First(); pQuery
; pQuery
= maWQList
.Next() )
999 pQuery
->Apply( rDoc
, aFilterName
);
1002 // Decryption =================================================================
1006 XclImpDecrypterRef
lclReadFilepass5( XclImpStream
& rStrm
)
1008 XclImpDecrypterRef xDecr
;
1009 DBG_ASSERT( rStrm
.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1010 if( rStrm
.GetRecLeft() == 4 )
1012 sal_uInt16 nKey
, nHash
;
1013 rStrm
>> nKey
>> nHash
;
1014 xDecr
.reset( new XclImpBiff5Decrypter( rStrm
.GetRoot(), nKey
, nHash
) );
1019 XclImpDecrypterRef
lclReadFilepass8_Standard( XclImpStream
& rStrm
)
1021 XclImpDecrypterRef xDecr
;
1022 DBG_ASSERT( rStrm
.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1023 if( rStrm
.GetRecLeft() == 48 )
1025 sal_uInt8 pnDocId
[ 16 ];
1026 sal_uInt8 pnSaltData
[ 16 ];
1027 sal_uInt8 pnSaltHash
[ 16 ];
1028 rStrm
.Read( pnDocId
, 16 );
1029 rStrm
.Read( pnSaltData
, 16 );
1030 rStrm
.Read( pnSaltHash
, 16 );
1031 xDecr
.reset( new XclImpBiff8Decrypter(
1032 rStrm
.GetRoot(), pnDocId
, pnSaltData
, pnSaltHash
) );
1037 XclImpDecrypterRef
lclReadFilepass8_Strong( XclImpStream
& /*rStrm*/ )
1040 return XclImpDecrypterRef();
1043 XclImpDecrypterRef
lclReadFilepass8( XclImpStream
& rStrm
)
1045 XclImpDecrypterRef xDecr
;
1051 case EXC_FILEPASS_BIFF5
:
1052 xDecr
= lclReadFilepass5( rStrm
);
1055 case EXC_FILEPASS_BIFF8
:
1058 sal_uInt16 nSubMode
;
1062 case EXC_FILEPASS_BIFF8_STD
:
1063 xDecr
= lclReadFilepass8_Standard( rStrm
);
1065 case EXC_FILEPASS_BIFF8_STRONG
:
1066 xDecr
= lclReadFilepass8_Strong( rStrm
);
1069 DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1075 DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
1083 // ----------------------------------------------------------------------------
1085 ErrCode
XclImpDecryptHelper::ReadFilepass( XclImpStream
& rStrm
)
1087 XclImpDecrypterRef xDecr
;
1088 rStrm
.DisableDecryption();
1090 switch( rStrm
.GetRoot().GetBiff() )
1095 case EXC_BIFF5
: xDecr
= lclReadFilepass5( rStrm
); break;
1096 case EXC_BIFF8
: xDecr
= lclReadFilepass8( rStrm
); break;
1097 default: DBG_ERROR_BIFF();
1101 return EXC_ENCR_ERROR_UNSUPP_CRYPT
;
1103 // set decrypter at import stream
1104 rStrm
.SetDecrypter( xDecr
);
1106 // Store the document password for export.
1107 SfxItemSet
* pSet
= rStrm
.GetRoot().GetDocShell()->GetMedium()->GetItemSet();
1110 String aPass
= xDecr
->GetPassword();
1111 pSet
->Put( SfxStringItem(SID_PASSWORD
, aPass
) );
1114 return xDecr
->GetError();
1117 // Document protection ========================================================
1119 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot
& rRoot
) :
1120 XclImpRoot( rRoot
),
1122 mbDocProtect(false),
1127 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream
& rStrm
)
1129 mbDocProtect
= rStrm
.ReaduInt16() ? true : false;
1132 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream
& rStrm
)
1134 mbWinProtect
= rStrm
.ReaduInt16() ? true : false;
1137 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
)
1139 rStrm
.EnableDecryption();
1140 mnPassHash
= rStrm
.ReaduInt16();
1143 void XclImpDocProtectBuffer::Apply() const
1145 if (!mbDocProtect
&& !mbWinProtect
)
1146 // Excel requires either the structure or windows protection is set.
1147 // If neither is set then the document is not protected at all.
1150 auto_ptr
<ScDocProtection
> pProtect(new ScDocProtection
);
1151 pProtect
->setProtected(true);
1153 #if ENABLE_SHEET_PROTECTION
1156 // 16-bit password pash.
1157 Sequence
<sal_Int8
> aPass(2);
1158 aPass
[0] = (mnPassHash
>> 8) & 0xFF;
1159 aPass
[1] = mnPassHash
& 0xFF;
1160 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1164 // document protection options
1165 pProtect
->setOption(ScDocProtection::STRUCTURE
, mbDocProtect
);
1166 pProtect
->setOption(ScDocProtection::WINDOWS
, mbWinProtect
);
1168 GetDoc().SetDocProtection(pProtect
.get());
1171 // Sheet Protection ===========================================================
1173 XclImpSheetProtectBuffer::Sheet::Sheet() :
1175 mnPasswordHash(0x0000),
1180 // ----------------------------------------------------------------------------
1182 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet
& r
) :
1183 mbProtected(r
.mbProtected
),
1184 mnPasswordHash(r
.mnPasswordHash
),
1185 mnOptions(r
.mnOptions
)
1189 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot
& rRoot
) :
1194 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream
& rStrm
, SCTAB nTab
)
1196 if ( rStrm
.ReaduInt16() )
1198 Sheet
* pSheet
= GetSheetItem(nTab
);
1200 pSheet
->mbProtected
= true;
1204 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream
& rStrm
, SCTAB nTab
)
1207 sal_uInt16 nOptions
;
1210 Sheet
* pSheet
= GetSheetItem(nTab
);
1212 pSheet
->mnOptions
= nOptions
;
1215 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream
& rStrm
, SCTAB nTab
)
1219 Sheet
* pSheet
= GetSheetItem(nTab
);
1221 pSheet
->mnPasswordHash
= nHash
;
1224 void XclImpSheetProtectBuffer::Apply() const
1226 for (ProtectedSheetMap::const_iterator itr
= maProtectedSheets
.begin(), itrEnd
= maProtectedSheets
.end();
1227 itr
!= itrEnd
; ++itr
)
1229 if (!itr
->second
.mbProtected
)
1230 // This sheet is (for whatever reason) not protected.
1233 auto_ptr
<ScTableProtection
> pProtect(new ScTableProtection
);
1234 pProtect
->setProtected(true);
1236 #if ENABLE_SHEET_PROTECTION
1237 // 16-bit hash password
1238 const sal_uInt16 nHash
= itr
->second
.mnPasswordHash
;
1241 Sequence
<sal_Int8
> aPass(2);
1242 aPass
[0] = (nHash
>> 8) & 0xFF;
1243 aPass
[1] = nHash
& 0xFF;
1244 pProtect
->setPasswordHash(aPass
, PASSHASH_XL
);
1248 // sheet protection options
1249 const sal_uInt16 nOptions
= itr
->second
.mnOptions
;
1250 pProtect
->setOption( ScTableProtection::OBJECTS
, (nOptions
& 0x0001) );
1251 pProtect
->setOption( ScTableProtection::SCENARIOS
, (nOptions
& 0x0002) );
1252 pProtect
->setOption( ScTableProtection::FORMAT_CELLS
, (nOptions
& 0x0004) );
1253 pProtect
->setOption( ScTableProtection::FORMAT_COLUMNS
, (nOptions
& 0x0008) );
1254 pProtect
->setOption( ScTableProtection::FORMAT_ROWS
, (nOptions
& 0x0010) );
1255 pProtect
->setOption( ScTableProtection::INSERT_COLUMNS
, (nOptions
& 0x0020) );
1256 pProtect
->setOption( ScTableProtection::INSERT_ROWS
, (nOptions
& 0x0040) );
1257 pProtect
->setOption( ScTableProtection::INSERT_HYPERLINKS
, (nOptions
& 0x0080) );
1258 pProtect
->setOption( ScTableProtection::DELETE_COLUMNS
, (nOptions
& 0x0100) );
1259 pProtect
->setOption( ScTableProtection::DELETE_ROWS
, (nOptions
& 0x0200) );
1260 pProtect
->setOption( ScTableProtection::SELECT_LOCKED_CELLS
, (nOptions
& 0x0400) );
1261 pProtect
->setOption( ScTableProtection::SORT
, (nOptions
& 0x0800) );
1262 pProtect
->setOption( ScTableProtection::AUTOFILTER
, (nOptions
& 0x1000) );
1263 pProtect
->setOption( ScTableProtection::PIVOT_TABLES
, (nOptions
& 0x2000) );
1264 pProtect
->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS
, (nOptions
& 0x4000) );
1266 // all done. now commit.
1267 GetDoc().SetTabProtection(itr
->first
, pProtect
.get());
1271 XclImpSheetProtectBuffer::Sheet
* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab
)
1273 ProtectedSheetMap::iterator itr
= maProtectedSheets
.find(nTab
);
1274 if (itr
== maProtectedSheets
.end())
1277 if ( !maProtectedSheets
.insert( ProtectedSheetMap::value_type(nTab
, Sheet()) ).second
)
1280 itr
= maProtectedSheets
.find(nTab
);
1283 return &itr
->second
;
1286 // ============================================================================