summaryrefslogtreecommitdiff
path: root/sc/source/filter/excel/xicontent.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel/xicontent.cxx')
-rw-r--r--sc/source/filter/excel/xicontent.cxx1319
1 files changed, 1319 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xicontent.cxx b/sc/source/filter/excel/xicontent.cxx
new file mode 100644
index 000000000000..fb1eb9a3bf44
--- /dev/null
+++ b/sc/source/filter/excel/xicontent.cxx
@@ -0,0 +1,1319 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sc.hxx"
+#include "xicontent.hxx"
+#include <sfx2/objsh.hxx>
+#include <sfx2/docfile.hxx>
+#include <tools/urlobj.hxx>
+#include <editeng/editeng.hxx>
+#include <editeng/editobj.hxx>
+#include <sfx2/linkmgr.hxx>
+#include <svl/itemset.hxx>
+#include "scitems.hxx"
+#include <editeng/eeitem.hxx>
+#include <svl/intitem.hxx>
+#include <svl/stritem.hxx>
+#include <editeng/flditem.hxx>
+#include <editeng/fhgtitem.hxx>
+#include <editeng/wghtitem.hxx>
+#include <editeng/udlnitem.hxx>
+#include <editeng/postitem.hxx>
+#include <editeng/colritem.hxx>
+#include <editeng/crsditem.hxx>
+#include "document.hxx"
+#include "editutil.hxx"
+#include "cell.hxx"
+#include "validat.hxx"
+#include "patattr.hxx"
+#include "docpool.hxx"
+#include "rangenam.hxx"
+#include "arealink.hxx"
+#include "stlsheet.hxx"
+#include "scextopt.hxx"
+#include "xlformula.hxx"
+#include "xltracer.hxx"
+#include "xistream.hxx"
+#include "xihelper.hxx"
+#include "xistyle.hxx"
+#include "xiescher.hxx"
+#include "xiname.hxx"
+
+#include "excform.hxx"
+#include "tabprotection.hxx"
+
+#include <memory>
+
+using ::com::sun::star::uno::Sequence;
+using ::std::auto_ptr;
+
+// Shared string table ========================================================
+
+XclImpSst::XclImpSst( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpSst::ReadSst( XclImpStream& rStrm )
+{
+ sal_uInt32 nStrCount;
+ rStrm.Ignore( 4 );
+ rStrm >> nStrCount;
+ maStrings.clear();
+ maStrings.reserve( static_cast< size_t >( nStrCount ) );
+ while( (nStrCount > 0) && rStrm.IsValid() )
+ {
+ XclImpString aString;
+ aString.Read( rStrm );
+ maStrings.push_back( aString );
+ --nStrCount;
+ }
+}
+
+const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
+{
+ return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
+}
+
+ScBaseCell* XclImpSst::CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex ) const
+{
+ ScBaseCell* pCell = 0;
+ if( const XclImpString* pString = GetString( nSstIndex ) )
+ pCell = XclImpStringHelper::CreateCell( *this, *pString, nXFIndex );
+ return pCell;
+}
+
+// Hyperlinks =================================================================
+
+namespace {
+
+/** Reads character array and stores it into rString.
+ @param nChars Number of following characters (not byte count!).
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclAppendString32( String& rString, XclImpStream& rStrm, sal_uInt32 nChars, bool b16Bit )
+{
+ sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
+ rString.Append( rStrm.ReadRawUniString( nReadChars, b16Bit ) );
+ // ignore remaining chars
+ sal_Size nIgnore = nChars - nReadChars;
+ if( b16Bit )
+ nIgnore *= 2;
+ rStrm.Ignore( nIgnore );
+}
+
+/** Reads 32-bit string length and the character array and stores it into rString.
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclAppendString32( String& rString, XclImpStream& rStrm, bool b16Bit )
+{
+ lclAppendString32( rString, rStrm, rStrm.ReaduInt32(), b16Bit );
+}
+
+/** Reads 32-bit string length and ignores following character array.
+ @param b16Bit true = 16-bit characters, false = 8-bit characters. */
+void lclIgnoreString32( XclImpStream& rStrm, bool b16Bit )
+{
+ sal_uInt32 nChars;
+ rStrm >> nChars;
+ if( b16Bit )
+ nChars *= 2;
+ rStrm.Ignore( nChars );
+}
+
+/** Converts a path to an absolute path.
+ @param rPath The source path. The resulting path is returned here.
+ @param nLevel Number of parent directories to add in front of the path. */
+void lclGetAbsPath( String& rPath, sal_uInt16 nLevel, SfxObjectShell* pDocShell )
+{
+ String aTmpStr;
+ while( nLevel )
+ {
+ aTmpStr.AppendAscii( "../" );
+ --nLevel;
+ }
+ aTmpStr += rPath;
+
+ if( pDocShell )
+ {
+ bool bWasAbs = false;
+ rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr, bWasAbs ).GetMainURL( INetURLObject::NO_DECODE );
+ // full path as stored in SvxURLField must be encoded
+ }
+ else
+ rPath = aTmpStr;
+}
+
+/** Inserts the URL into a text cell. Does not modify value or formula cells. */
+void lclInsertUrl( const XclImpRoot& rRoot, const String& rUrl, SCCOL nScCol, SCROW nScRow, SCTAB nScTab )
+{
+ ScDocument& rDoc = rRoot.GetDoc();
+ ScAddress aScPos( nScCol, nScRow, nScTab );
+ CellType eCellType = rDoc.GetCellType( aScPos );
+ switch( eCellType )
+ {
+ // #i54261# hyperlinks in string cells
+ case CELLTYPE_STRING:
+ case CELLTYPE_EDIT:
+ {
+ String aDisplText;
+ rDoc.GetString( nScCol, nScRow, nScTab, aDisplText );
+ if( !aDisplText.Len() )
+ aDisplText = rUrl;
+
+ ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
+ SvxURLField aUrlField( rUrl, aDisplText, SVXURLFORMAT_APPDEFAULT );
+
+ const ScEditCell* pEditCell = (eCellType == CELLTYPE_EDIT) ? static_cast< const ScEditCell* >( rDoc.GetCell( aScPos ) ) : 0;
+ const EditTextObject* pEditObj = pEditCell ? pEditCell->GetData() : 0;
+ if( pEditObj )
+ {
+ rEE.SetText( *pEditObj );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0, 0, 0xFFFF, 0 ) );
+ }
+ else
+ {
+ rEE.SetText( EMPTY_STRING );
+ rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection() );
+ if( const ScPatternAttr* pPattern = rDoc.GetPattern( aScPos.Col(), aScPos.Row(), nScTab ) )
+ {
+ SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
+ pPattern->FillEditItemSet( &aItemSet );
+ rEE.QuickSetAttribs( aItemSet, ESelection( 0, 0, 0xFFFF, 0 ) );
+ }
+ }
+ ::std::auto_ptr< EditTextObject > xTextObj( rEE.CreateTextObject() );
+
+ ScEditCell* pCell = new ScEditCell( xTextObj.get(), &rDoc, rEE.GetEditTextObjectPool() );
+ rDoc.PutCell( aScPos, pCell );
+ }
+ break;
+
+ // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
+#if 0
+ case CELLTYPE_VALUE:
+ {
+ // #i31050# replace number with HYPERLINK function
+ ScTokenArray aTokenArray;
+ aTokenArray.AddOpCode( ocHyperLink );
+ aTokenArray.AddOpCode( ocOpen );
+ aTokenArray.AddString( rUrl );
+ aTokenArray.AddOpCode( ocSep );
+ aTokenArray.AddDouble( rDoc.GetValue( aScPos ) );
+ aTokenArray.AddOpCode( ocClose );
+ rDoc.PutCell( aScPos, new ScFormulaCell( &rDoc, aScPos, &aTokenArray ) );
+ }
+ break;
+#endif
+
+ default:;
+ }
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+void XclImpHyperlink::ReadHlink( XclImpStream& rStrm )
+{
+ XclRange aXclRange( ScAddress::UNINITIALIZED );
+ rStrm >> aXclRange;
+ // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
+ aXclRange.maFirst.mnCol &= 0xFF;
+ aXclRange.maLast.mnCol &= 0xFF;
+ String aString = ReadEmbeddedData( rStrm );
+ if ( aString.Len() > 0 )
+ rStrm.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange, aString );
+}
+
+String XclImpHyperlink::ReadEmbeddedData( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ SfxObjectShell* pDocShell = rRoot.GetDocShell();
+
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ sal_uInt32 nFlags;
+ XclGuid aGuid;
+ rStrm >> aGuid;
+ rStrm.Ignore( 4 );
+ rStrm >> nFlags;
+
+ DBG_ASSERT( aGuid == XclTools::maGuidStdLink, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
+
+ sal_uInt16 nLevel = 0; // counter for level to climb down in path
+ ::std::auto_ptr< String > xLongName; // link / file name
+ ::std::auto_ptr< String > xShortName; // 8.3-representation of file name
+ ::std::auto_ptr< String > xTextMark; // text mark
+
+ // description (ignore)
+ if( ::get_flag( nFlags, EXC_HLINK_DESCR ) )
+ lclIgnoreString32( rStrm, true );
+ // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
+ if( ::get_flag( nFlags, EXC_HLINK_FRAME ) )
+ lclIgnoreString32( rStrm, true );
+
+ // URL fields are zero-terminated - do not let the stream replace them
+ // in the lclAppendString32() with the '?' character.
+ rStrm.SetNulSubstChar( '\0' );
+
+ // UNC path
+ if( ::get_flag( nFlags, EXC_HLINK_UNC ) )
+ {
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, true );
+ lclGetAbsPath( *xLongName, 0, pDocShell );
+ }
+ // file link or URL
+ else if( ::get_flag( nFlags, EXC_HLINK_BODY ) )
+ {
+ rStrm >> aGuid;
+
+ if( aGuid == XclTools::maGuidFileMoniker )
+ {
+ rStrm >> nLevel;
+ xShortName.reset( new String );
+ lclAppendString32( *xShortName, rStrm, false );
+ rStrm.Ignore( 24 );
+
+ sal_uInt32 nStrLen;
+ rStrm >> nStrLen;
+ if( nStrLen )
+ {
+ rStrm >> nStrLen;
+ nStrLen /= 2; // it's byte count here...
+ rStrm.Ignore( 2 );
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, nStrLen, true );
+ lclGetAbsPath( *xLongName, nLevel, pDocShell );
+ }
+ else
+ lclGetAbsPath( *xShortName, nLevel, pDocShell );
+ }
+ else if( aGuid == XclTools::maGuidUrlMoniker )
+ {
+ sal_uInt32 nStrLen;
+ rStrm >> nStrLen;
+ nStrLen /= 2; // it's byte count here...
+ xLongName.reset( new String );
+ lclAppendString32( *xLongName, rStrm, nStrLen, true );
+ if( !::get_flag( nFlags, EXC_HLINK_ABS ) )
+ lclGetAbsPath( *xLongName, 0, pDocShell );
+ }
+ else
+ {
+ DBG_ERRORFILE( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
+ }
+ }
+
+ // text mark
+ if( ::get_flag( nFlags, EXC_HLINK_MARK ) )
+ {
+ xTextMark.reset( new String );
+ lclAppendString32( *xTextMark, rStrm, true );
+ }
+
+ rStrm.SetNulSubstChar(); // back to default
+
+ DBG_ASSERT( rStrm.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
+
+ if( !xLongName.get() && xShortName.get() )
+ xLongName = xShortName;
+ else if( !xLongName.get() && xTextMark.get() )
+ xLongName.reset( new String );
+
+ if( xLongName.get() )
+ {
+ if( xTextMark.get() )
+ {
+ if( xLongName->Len() == 0 )
+ xTextMark->SearchAndReplaceAll( '!', '.' );
+ xLongName->Append( '#' );
+ xLongName->Append( *xTextMark );
+ }
+ return *xLongName;
+ }
+ return String::EmptyString();
+}
+
+void XclImpHyperlink::ConvertToValidTabName(String& rUrl)
+{
+ xub_StrLen n = rUrl.Len();
+ if (n < 4)
+ // Needs at least 4 characters.
+ return;
+
+ sal_Unicode c = rUrl.GetChar(0);
+ if (c != sal_Unicode('#'))
+ // the 1st character must be '#'.
+ return;
+
+ String aNewUrl(sal_Unicode('#')), aTabName;
+
+ bool bInQuote = false;
+ bool bQuoteTabName = false;
+ for (xub_StrLen i = 1; i < n; ++i)
+ {
+ c = rUrl.GetChar(i);
+ if (c == sal_Unicode('\''))
+ {
+ if (bInQuote && i+1 < n && rUrl.GetChar(i+1) == sal_Unicode('\''))
+ {
+ // Two consecutive single quotes ('') signify a single literal
+ // quite. When this occurs, the whole table name needs to be
+ // quoted.
+ bQuoteTabName = true;
+ aTabName.Append(c);
+ aTabName.Append(c);
+ ++i;
+ continue;
+ }
+
+ bInQuote = !bInQuote;
+ if (!bInQuote && aTabName.Len() > 0)
+ {
+ if (bQuoteTabName)
+ aNewUrl.Append(sal_Unicode('\''));
+ aNewUrl.Append(aTabName);
+ if (bQuoteTabName)
+ aNewUrl.Append(sal_Unicode('\''));
+ }
+ }
+ else if (bInQuote)
+ aTabName.Append(c);
+ else
+ aNewUrl.Append(c);
+ }
+
+ if (bInQuote)
+ // It should be outside the quotes!
+ return;
+
+ // All is good. Pass the new URL.
+ rUrl = aNewUrl;
+}
+
+void XclImpHyperlink::InsertUrl( const XclImpRoot& rRoot, const XclRange& rXclRange, const String& rUrl )
+{
+ String aUrl(rUrl);
+ ConvertToValidTabName(aUrl);
+
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ ScRange aScRange( ScAddress::UNINITIALIZED );
+ if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
+ {
+ SCCOL nScCol1, nScCol2;
+ SCROW nScRow1, nScRow2;
+ aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
+ for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
+ for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
+ lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
+ }
+}
+
+// Label ranges ===============================================================
+
+void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ ScDocument& rDoc = rRoot.GetDoc();
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
+ ScRangePairListRef xLabelRangesRef;
+ const ScRange* pScRange = 0;
+
+ XclRangeList aRowXclRanges, aColXclRanges;
+ rStrm >> aRowXclRanges >> aColXclRanges;
+
+ // row label ranges
+ ScRangeList aRowScRanges;
+ rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
+ xLabelRangesRef = rDoc.GetRowNameRangesRef();
+ for( pScRange = aRowScRanges.First(); pScRange; pScRange = aRowScRanges.Next() )
+ {
+ ScRange aDataRange( *pScRange );
+ if( aDataRange.aEnd.Col() < MAXCOL )
+ {
+ aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
+ aDataRange.aEnd.SetCol( MAXCOL );
+ }
+ else if( aDataRange.aStart.Col() > 0 )
+ {
+ aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
+ aDataRange.aStart.SetCol( 0 );
+ }
+ xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
+ }
+
+ // column label ranges
+ ScRangeList aColScRanges;
+ rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
+ xLabelRangesRef = rDoc.GetColNameRangesRef();
+ for( pScRange = aColScRanges.First(); pScRange; pScRange = aColScRanges.Next() )
+ {
+ ScRange aDataRange( *pScRange );
+ if( aDataRange.aEnd.Row() < MAXROW )
+ {
+ aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
+ aDataRange.aEnd.SetRow( MAXROW );
+ }
+ else if( aDataRange.aStart.Row() > 0 )
+ {
+ aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
+ aDataRange.aStart.SetRow( 0 );
+ }
+ xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
+ }
+}
+
+// Conditional formatting =====================================================
+
+XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
+ XclImpRoot( rRoot ),
+ mnFormatIndex( nFormatIndex ),
+ mnCondCount( 0 ),
+ mnCondIndex( 0 )
+{
+}
+
+XclImpCondFormat::~XclImpCondFormat()
+{
+}
+
+void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
+{
+ DBG_ASSERT( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
+ XclRangeList aXclRanges;
+ rStrm >> mnCondCount;
+ rStrm.Ignore( 10 );
+ rStrm >> aXclRanges;
+ GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
+}
+
+void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
+{
+ if( mnCondIndex >= mnCondCount )
+ {
+ DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
+ return;
+ }
+
+ // entire conditional format outside of valid range?
+ if( !maRanges.Count() )
+ return;
+
+ sal_uInt8 nType, nOperator;
+ sal_uInt16 nFmlaSize1, nFmlaSize2;
+ sal_uInt32 nFlags;
+
+ rStrm >> nType >> nOperator >> nFmlaSize1 >> nFmlaSize2 >> nFlags;
+ rStrm.Ignore( 2 );
+
+ // *** mode and comparison operator ***
+
+ ScConditionMode eMode = SC_COND_NONE;
+ switch( nType )
+ {
+ case EXC_CF_TYPE_CELL:
+ {
+ switch( nOperator )
+ {
+ case EXC_CF_CMP_BETWEEN: eMode = SC_COND_BETWEEN; break;
+ case EXC_CF_CMP_NOT_BETWEEN: eMode = SC_COND_NOTBETWEEN; break;
+ case EXC_CF_CMP_EQUAL: eMode = SC_COND_EQUAL; break;
+ case EXC_CF_CMP_NOT_EQUAL: eMode = SC_COND_NOTEQUAL; break;
+ case EXC_CF_CMP_GREATER: eMode = SC_COND_GREATER; break;
+ case EXC_CF_CMP_LESS: eMode = SC_COND_LESS; break;
+ case EXC_CF_CMP_GREATER_EQUAL: eMode = SC_COND_EQGREATER; break;
+ case EXC_CF_CMP_LESS_EQUAL: eMode = SC_COND_EQLESS; break;
+ default:
+ DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator );
+ }
+ }
+ break;
+
+ case EXC_CF_TYPE_FMLA:
+ eMode = SC_COND_DIRECT;
+ break;
+
+ default:
+ DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType );
+ return;
+ }
+
+ // *** create style sheet ***
+
+ String aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
+ SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
+
+ const XclImpPalette& rPalette = GetPalette();
+
+ // *** font block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
+ {
+ XclImpFont aFont( GetRoot() );
+ aFont.ReadCFFontBlock( rStrm );
+ aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
+ }
+
+ // *** border block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
+ {
+ sal_uInt16 nLineStyle;
+ sal_uInt32 nLineColor;
+ rStrm >> nLineStyle >> nLineColor;
+ rStrm.Ignore( 2 );
+
+ XclImpCellBorder aBorder;
+ aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
+ aBorder.FillToItemSet( rStyleItemSet, rPalette );
+ }
+
+ // *** pattern block ***
+
+ if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
+ {
+ sal_uInt16 nPattern, nColor;
+ rStrm >> nPattern >> nColor;
+
+ XclImpCellArea aArea;
+ aArea.FillFromCF8( nPattern, nColor, nFlags );
+ aArea.FillToItemSet( rStyleItemSet, rPalette );
+ }
+
+ // *** formulas ***
+
+ const ScAddress& rPos = maRanges.GetObject( 0 )->aStart; // assured above that maRanges is not empty
+ ExcelToSc& rFmlaConv = GetOldFmlaConverter();
+
+ ::std::auto_ptr< ScTokenArray > xTokArr1;
+ if( nFmlaSize1 > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset( rPos );
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr1.reset( pTokArr->Clone() );
+ }
+
+ ::std::auto_ptr< ScTokenArray > pTokArr2;
+ if( nFmlaSize2 > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset( rPos );
+ rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ pTokArr2.reset( pTokArr->Clone() );
+ }
+
+ // *** create the Calc conditional formatting ***
+
+ if( !mxScCondFmt.get() )
+ {
+ ULONG nKey = 0;
+ mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
+ }
+
+ ScCondFormatEntry aEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
+ mxScCondFmt->AddEntry( aEntry );
+ ++mnCondIndex;
+}
+
+void XclImpCondFormat::Apply()
+{
+ if( mxScCondFmt.get() )
+ {
+ ScDocument& rDoc = GetDoc();
+
+ ULONG nKey = rDoc.AddCondFormat( *mxScCondFmt );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL, nKey ) );
+
+ // maRanges contains only valid cell ranges
+ for( const ScRange* pScRange = maRanges.First(); pScRange; pScRange = maRanges.Next() )
+ {
+ rDoc.ApplyPatternAreaTab(
+ pScRange->aStart.Col(), pScRange->aStart.Row(),
+ pScRange->aEnd.Col(), pScRange->aEnd.Row(),
+ pScRange->aStart.Tab(), aPattern );
+ }
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
+{
+ XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.Count() );
+ pFmt->ReadCondfmt( rStrm );
+ maCondFmtList.Append( pFmt );
+}
+
+void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
+{
+ DBG_ASSERT( !maCondFmtList.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
+ if( !maCondFmtList.Empty() )
+ maCondFmtList.GetObject( maCondFmtList.Count() - 1 )->ReadCF( rStrm );
+}
+
+void XclImpCondFormatManager::Apply()
+{
+ for( XclImpCondFormat* pFmt = maCondFmtList.First(); pFmt; pFmt = maCondFmtList.Next() )
+ pFmt->Apply();
+ maCondFmtList.Clear();
+}
+
+// Data Validation ============================================================
+
+void XclImpValidation::ReadDval( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ sal_uInt32 nObjId;
+ rStrm.Ignore( 10 );
+ rStrm >> nObjId;
+ if( nObjId != EXC_DVAL_NOOBJ )
+ {
+ DBG_ASSERT( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
+ rRoot.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16 >( nObjId ) );
+ }
+}
+
+void XclImpValidation::ReadDV( XclImpStream& rStrm )
+{
+ const XclImpRoot& rRoot = rStrm.GetRoot();
+ DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
+
+ ScDocument& rDoc = rRoot.GetDoc();
+ SCTAB nScTab = rRoot.GetCurrScTab();
+ ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
+
+ // flags
+ sal_uInt32 nFlags;
+ rStrm >> nFlags;
+
+ // message strings
+ /* Empty strings are single NUL characters in Excel (string length is 1).
+ -> Do not let the stream replace them with '?' characters. */
+ rStrm.SetNulSubstChar( '\0' );
+ String aPromptTitle( rStrm.ReadUniString() );
+ String aErrorTitle( rStrm.ReadUniString() );
+ String aPromptMessage( rStrm.ReadUniString() );
+ String aErrorMessage( rStrm.ReadUniString() );
+ rStrm.SetNulSubstChar(); // back to default
+
+ // formula(s)
+ if( rStrm.GetRecLeft() > 8 )
+ {
+ sal_uInt16 nLen;
+
+ // first formula
+ // string list is single tStr token with NUL separators -> replace them with LF
+ rStrm.SetNulSubstChar( '\n' );
+ ::std::auto_ptr< ScTokenArray > xTokArr1;
+ rStrm >> nLen;
+ rStrm.Ignore( 2 );
+ if( nLen > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset();
+ rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr1.reset( pTokArr->Clone() );
+ }
+ rStrm.SetNulSubstChar(); // back to default
+
+ // second formula
+ ::std::auto_ptr< ScTokenArray > xTokArr2;
+ rStrm >> nLen;
+ rStrm.Ignore( 2 );
+ if( nLen > 0 )
+ {
+ const ScTokenArray* pTokArr = 0;
+ rFmlaConv.Reset();
+ rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_RangeName );
+ // formula converter owns pTokArr -> create a copy of the token array
+ if( pTokArr )
+ xTokArr2.reset( pTokArr->Clone() );
+ }
+
+ // read all cell ranges
+ XclRangeList aXclRanges;
+ rStrm >> aXclRanges;
+
+ // convert to Calc range list
+ ScRangeList aScRanges;
+ rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
+
+ // only continue if there are valid ranges
+ if( aScRanges.Count() )
+ {
+ bool bIsValid = true; // valid settings in flags field
+
+ ScValidationMode eValMode = SC_VALID_ANY;
+ switch( nFlags & EXC_DV_MODE_MASK )
+ {
+ case EXC_DV_MODE_ANY: eValMode = SC_VALID_ANY; break;
+ case EXC_DV_MODE_WHOLE: eValMode = SC_VALID_WHOLE; break;
+ case EXC_DV_MODE_DECIMAL: eValMode = SC_VALID_DECIMAL; break;
+ case EXC_DV_MODE_LIST: eValMode = SC_VALID_LIST; break;
+ case EXC_DV_MODE_DATE: eValMode = SC_VALID_DATE; break;
+ case EXC_DV_MODE_TIME: eValMode = SC_VALID_TIME; break;
+ case EXC_DV_MODE_TEXTLEN: eValMode = SC_VALID_TEXTLEN; break;
+ case EXC_DV_MODE_CUSTOM: eValMode = SC_VALID_CUSTOM; break;
+ default: bIsValid = false;
+ }
+ rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
+
+ ScConditionMode eCondMode = SC_COND_BETWEEN;
+ switch( nFlags & EXC_DV_COND_MASK )
+ {
+ case EXC_DV_COND_BETWEEN: eCondMode = SC_COND_BETWEEN; break;
+ case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
+ case EXC_DV_COND_EQUAL: eCondMode = SC_COND_EQUAL; break;
+ case EXC_DV_COND_NOTEQUAL: eCondMode = SC_COND_NOTEQUAL; break;
+ case EXC_DV_COND_GREATER: eCondMode = SC_COND_GREATER; break;
+ case EXC_DV_COND_LESS: eCondMode = SC_COND_LESS; break;
+ case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER; break;
+ case EXC_DV_COND_EQLESS: eCondMode = SC_COND_EQLESS; break;
+ default: bIsValid = false;
+ }
+
+ if( bIsValid )
+ {
+ // first range for base address for relative references
+ const ScRange& rScRange = *aScRanges.GetObject( 0 ); // aScRanges is not empty
+
+ // process string list of a list validity (convert to list of string tokens)
+ if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
+ XclTokenArrayHelper::ConvertStringToList( *xTokArr1, '\n', true );
+
+ ScValidationData aValidData( eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart );
+
+ aValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
+ aValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, ValidListType::INVISIBLE, ValidListType::UNSORTED ) );
+
+ // *** prompt box ***
+ if( aPromptTitle.Len() || aPromptMessage.Len() )
+ {
+ // set any text stored in the record
+ aValidData.SetInput( aPromptTitle, aPromptMessage );
+ if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
+ aValidData.ResetInput();
+ }
+
+ // *** error box ***
+ ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
+ switch( nFlags & EXC_DV_ERROR_MASK )
+ {
+ case EXC_DV_ERROR_WARNING: eErrStyle = SC_VALERR_WARNING; break;
+ case EXC_DV_ERROR_INFO: eErrStyle = SC_VALERR_INFO; break;
+ }
+ // set texts and error style
+ aValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
+ if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
+ aValidData.ResetError();
+
+ // set the handle ID
+ ULONG nHandle = rDoc.AddValidationEntry( aValidData );
+ ScPatternAttr aPattern( rDoc.GetPool() );
+ aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
+
+ // apply all ranges
+ for( const ScRange* pScRange = aScRanges.First(); pScRange; pScRange = aScRanges.Next() )
+ rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
+ pScRange->aEnd.Col(), pScRange->aEnd.Row(), nScTab, aPattern );
+ }
+ }
+ }
+}
+
+// Web queries ================================================================
+
+XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
+ maDestRange( rDestRange ),
+ meMode( xlWQUnknown ),
+ mnRefresh( 0 )
+{
+}
+
+void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags = rStrm.ReaduInt16();
+ sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
+ if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
+ {
+ if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
+ {
+ meMode = xlWQAllTables;
+ maTables = ScfTools::GetHTMLTablesName();
+ }
+ else
+ {
+ meMode = xlWQDocument;
+ maTables = ScfTools::GetHTMLDocName();
+ }
+ }
+}
+
+void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
+{
+ maURL = rStrm.ReadUniString();
+}
+
+void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
+{
+ sal_uInt16 nFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> nFlags;
+ rStrm.Ignore( 10 );
+ rStrm >> mnRefresh;
+
+ if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
+ meMode = xlWQSpecTables;
+}
+
+void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
+{
+ if( meMode == xlWQSpecTables )
+ {
+ rStrm.Ignore( 4 );
+ String aTables( rStrm.ReadUniString() );
+
+ const sal_Unicode cSep = ';';
+ aTables.SearchAndReplaceAll( ',', cSep );
+ String aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
+ xub_StrLen nTokenCnt = aTables.GetQuotedTokenCount( aQuotedPairs, cSep );
+ maTables.Erase();
+ xub_StrLen nStringIx = 0;
+ for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
+ {
+ String aToken( aTables.GetQuotedToken( 0, aQuotedPairs, cSep, nStringIx ) );
+ sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.ToInt32() : 0;
+ if( nTabNum > 0 )
+ ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
+ else
+ {
+ ScGlobal::EraseQuotes( aToken, '"', false );
+ if( aToken.Len() )
+ ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
+ }
+ }
+ }
+}
+
+void XclImpWebQuery::Apply( ScDocument& rDoc, const String& rFilterName )
+{
+ if( maURL.Len() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
+ {
+ ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
+ maURL, rFilterName, EMPTY_STRING, maTables, maDestRange, mnRefresh * 60UL );
+ rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
+ maURL, &rFilterName, &maTables );
+ }
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
+{
+ if( GetBiff() == EXC_BIFF8 )
+ {
+ rStrm.Ignore( 10 );
+ String aXclName( rStrm.ReadUniString() );
+
+ // #i64794# Excel replaces spaces with underscores
+ aXclName.SearchAndReplaceAll( ' ', '_' );
+
+ // #101529# find the defined name used in Calc
+ if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
+ {
+ if( const ScRangeData* pRangeData = pName->GetScRangeData() )
+ {
+ ScRange aRange;
+ if( pRangeData->IsReference( aRange ) )
+ maWQList.Append( new XclImpWebQuery( aRange ) );
+ }
+ }
+ }
+ else
+ {
+ DBG_ERROR_BIFF();
+ }
+}
+
+void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
+{
+ if( XclImpWebQuery* pQuery = maWQList.Last() )
+ pQuery->ReadParamqry( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
+{
+ if( XclImpWebQuery* pQuery = maWQList.Last() )
+ pQuery->ReadWqstring( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
+{
+ if( XclImpWebQuery* pQuery = maWQList.Last() )
+ pQuery->ReadWqsettings( rStrm );
+}
+
+void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
+{
+ if( XclImpWebQuery* pQuery = maWQList.Last() )
+ pQuery->ReadWqtables( rStrm );
+}
+
+void XclImpWebQueryBuffer::Apply()
+{
+ ScDocument& rDoc = GetDoc();
+ String aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER ) );
+ for( XclImpWebQuery* pQuery = maWQList.First(); pQuery; pQuery = maWQList.Next() )
+ pQuery->Apply( rDoc, aFilterName );
+}
+
+// Decryption =================================================================
+
+namespace {
+
+XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ DBG_ASSERT( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
+ if( rStrm.GetRecLeft() == 4 )
+ {
+ sal_uInt16 nKey, nHash;
+ rStrm >> nKey >> nHash;
+ xDecr.reset( new XclImpBiff5Decrypter( nKey, nHash ) );
+ }
+ return xDecr;
+}
+
+XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ DBG_ASSERT( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
+ if( rStrm.GetRecLeft() == 48 )
+ {
+ sal_uInt8 pnSalt[ 16 ];
+ sal_uInt8 pnVerifier[ 16 ];
+ sal_uInt8 pnVerifierHash[ 16 ];
+ rStrm.Read( pnSalt, 16 );
+ rStrm.Read( pnVerifier, 16 );
+ rStrm.Read( pnVerifierHash, 16 );
+ xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
+ }
+ return xDecr;
+}
+
+XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
+{
+ // not supported
+ return XclImpDecrypterRef();
+}
+
+XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+
+ sal_uInt16 nMode;
+ rStrm >> nMode;
+ switch( nMode )
+ {
+ case EXC_FILEPASS_BIFF5:
+ xDecr = lclReadFilepass5( rStrm );
+ break;
+
+ case EXC_FILEPASS_BIFF8:
+ {
+ rStrm.Ignore( 2 );
+ sal_uInt16 nSubMode;
+ rStrm >> nSubMode;
+ switch( nSubMode )
+ {
+ case EXC_FILEPASS_BIFF8_STD:
+ xDecr = lclReadFilepass8_Standard( rStrm );
+ break;
+ case EXC_FILEPASS_BIFF8_STRONG:
+ xDecr = lclReadFilepass8_Strong( rStrm );
+ break;
+ default:
+ DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
+ }
+ }
+ break;
+
+ default:
+ DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
+ }
+
+ return xDecr;
+}
+
+} // namespace
+
+// ----------------------------------------------------------------------------
+
+ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
+{
+ XclImpDecrypterRef xDecr;
+ rStrm.DisableDecryption();
+
+ // read the FILEPASS record and create a new decrypter object
+ switch( rStrm.GetRoot().GetBiff() )
+ {
+ case EXC_BIFF2:
+ case EXC_BIFF3:
+ case EXC_BIFF4:
+ case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm ); break;
+ case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm ); break;
+ default: DBG_ERROR_BIFF();
+ };
+
+ // set decrypter at import stream
+ rStrm.SetDecrypter( xDecr );
+
+ // request and verify a password (decrypter implements IDocPasswordVerifier)
+ if( xDecr.is() )
+ rStrm.GetRoot().RequestPassword( *xDecr );
+
+ // return error code (success, wrong password, etc.)
+ return xDecr.is() ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
+}
+
+// Document protection ========================================================
+
+XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mnPassHash(0x0000),
+ mbDocProtect(false),
+ mbWinProtect(false)
+{
+}
+
+void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
+{
+ mbDocProtect = rStrm.ReaduInt16() ? true : false;
+}
+
+void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
+{
+ mbWinProtect = rStrm.ReaduInt16() ? true : false;
+}
+
+void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
+{
+ rStrm.EnableDecryption();
+ mnPassHash = rStrm.ReaduInt16();
+}
+
+void XclImpDocProtectBuffer::Apply() const
+{
+ if (!mbDocProtect && !mbWinProtect)
+ // Excel requires either the structure or windows protection is set.
+ // If neither is set then the document is not protected at all.
+ return;
+
+ auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
+ pProtect->setProtected(true);
+
+#if ENABLE_SHEET_PROTECTION
+ if (mnPassHash)
+ {
+ // 16-bit password pash.
+ Sequence<sal_Int8> aPass(2);
+ aPass[0] = (mnPassHash >> 8) & 0xFF;
+ aPass[1] = mnPassHash & 0xFF;
+ pProtect->setPasswordHash(aPass, PASSHASH_XL);
+ }
+#endif
+
+ // document protection options
+ pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
+ pProtect->setOption(ScDocProtection::WINDOWS, mbWinProtect);
+
+ GetDoc().SetDocProtection(pProtect.get());
+}
+
+// Sheet Protection ===========================================================
+
+XclImpSheetProtectBuffer::Sheet::Sheet() :
+ mbProtected(false),
+ mnPasswordHash(0x0000),
+ mnOptions(0x4400)
+{
+}
+
+// ----------------------------------------------------------------------------
+
+XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
+ mbProtected(r.mbProtected),
+ mnPasswordHash(r.mnPasswordHash),
+ mnOptions(r.mnOptions)
+{
+}
+
+XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot )
+{
+}
+
+void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
+{
+ if ( rStrm.ReaduInt16() )
+ {
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mbProtected = true;
+ }
+}
+
+void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
+{
+ rStrm.Ignore(12);
+
+ // feature type can be either 2 or 4. If 2, this record stores flag for
+ // enhanced protection, whereas if 4 it stores flag for smart tag.
+ sal_uInt16 nFeatureType;
+ rStrm >> nFeatureType;
+ if (nFeatureType != 2)
+ // We currently only support import of enhanced protection data.
+ return;
+
+ rStrm.Ignore(1); // always 1
+
+ // The flag size specifies the size of bytes that follows that stores
+ // feature data. If -1 it depends on the feature type imported earlier.
+ // For enhanced protection data, the size is always 4. For the most xls
+ // documents out there this value is almost always -1.
+ sal_Int32 nFlagSize;
+ rStrm >> nFlagSize;
+ if (nFlagSize != -1)
+ return;
+
+ // There are actually 4 bytes to read, but the upper 2 bytes currently
+ // don't store any bits.
+ sal_uInt16 nOptions;
+ rStrm >> nOptions;
+
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mnOptions = nOptions;
+}
+
+void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
+{
+ sal_uInt16 nHash;
+ rStrm >> nHash;
+ Sheet* pSheet = GetSheetItem(nTab);
+ if (pSheet)
+ pSheet->mnPasswordHash = nHash;
+}
+
+void XclImpSheetProtectBuffer::Apply() const
+{
+ for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
+ itr != itrEnd; ++itr)
+ {
+ if (!itr->second.mbProtected)
+ // This sheet is (for whatever reason) not protected.
+ continue;
+
+ auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
+ pProtect->setProtected(true);
+
+#if ENABLE_SHEET_PROTECTION
+ // 16-bit hash password
+ const sal_uInt16 nHash = itr->second.mnPasswordHash;
+ if (nHash)
+ {
+ Sequence<sal_Int8> aPass(2);
+ aPass[0] = (nHash >> 8) & 0xFF;
+ aPass[1] = nHash & 0xFF;
+ pProtect->setPasswordHash(aPass, PASSHASH_XL);
+ }
+#endif
+
+ // sheet protection options
+ const sal_uInt16 nOptions = itr->second.mnOptions;
+ pProtect->setOption( ScTableProtection::OBJECTS, (nOptions & 0x0001) );
+ pProtect->setOption( ScTableProtection::SCENARIOS, (nOptions & 0x0002) );
+ pProtect->setOption( ScTableProtection::FORMAT_CELLS, (nOptions & 0x0004) );
+ pProtect->setOption( ScTableProtection::FORMAT_COLUMNS, (nOptions & 0x0008) );
+ pProtect->setOption( ScTableProtection::FORMAT_ROWS, (nOptions & 0x0010) );
+ pProtect->setOption( ScTableProtection::INSERT_COLUMNS, (nOptions & 0x0020) );
+ pProtect->setOption( ScTableProtection::INSERT_ROWS, (nOptions & 0x0040) );
+ pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS, (nOptions & 0x0080) );
+ pProtect->setOption( ScTableProtection::DELETE_COLUMNS, (nOptions & 0x0100) );
+ pProtect->setOption( ScTableProtection::DELETE_ROWS, (nOptions & 0x0200) );
+ pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS, (nOptions & 0x0400) );
+ pProtect->setOption( ScTableProtection::SORT, (nOptions & 0x0800) );
+ pProtect->setOption( ScTableProtection::AUTOFILTER, (nOptions & 0x1000) );
+ pProtect->setOption( ScTableProtection::PIVOT_TABLES, (nOptions & 0x2000) );
+ pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
+
+ // all done. now commit.
+ GetDoc().SetTabProtection(itr->first, pProtect.get());
+ }
+}
+
+XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
+{
+ ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
+ if (itr == maProtectedSheets.end())
+ {
+ // new sheet
+ if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
+ return NULL;
+
+ itr = maProtectedSheets.find(nTab);
+ }
+
+ return &itr->second;
+}
+
+// ============================================================================
+