/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_scfilt.hxx" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "cell.hxx" #include "drwlayer.hxx" #include "xcl97rec.hxx" #include "xcl97esc.hxx" #include "editutil.hxx" #include "xecontent.hxx" #include "xeescher.hxx" #include "xestyle.hxx" #include "xelink.hxx" #include "scitems.hxx" #include #include #include #include #include #include #include #include #include #include "document.hxx" #include "conditio.hxx" #include "rangelst.hxx" #include "stlpool.hxx" #include "viewopti.hxx" #include "scextopt.hxx" #include "docoptio.hxx" #include "patattr.hxx" #include "tabprotection.hxx" using namespace ::oox; using ::rtl::OString; using ::rtl::OUString; using namespace ::com::sun::star; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::drawing::XShape; // ============================================================================ XclExpObjList::XclExpObjList( const XclExpRoot& rRoot, XclEscherEx& rEscherEx ) : XclExpRoot( rRoot ), mrEscherEx( rEscherEx ), pSolverContainer( 0 ) { pMsodrawingPerSheet = new XclExpMsoDrawing( rEscherEx ); // open the DGCONTAINER and the patriarch group shape mrEscherEx.OpenContainer( ESCHER_DgContainer ); Rectangle aRect( 0, 0, 0, 0 ); mrEscherEx.EnterGroup( &aRect ); mrEscherEx.UpdateDffFragmentEnd(); } XclExpObjList::~XclExpObjList() { for ( XclObj* p = First(); p; p = Next() ) delete p; delete pMsodrawingPerSheet; delete pSolverContainer; } sal_uInt16 XclExpObjList::Add( XclObj* pObj ) { DBG_ASSERT( Count() < 0xFFFF, "XclExpObjList::Add: too much for Xcl" ); if ( Count() < 0xFFFF ) { Insert( pObj, LIST_APPEND ); sal_uInt16 nCnt = (sal_uInt16) Count(); pObj->SetId( nCnt ); return nCnt; } else { delete pObj; return 0; } } void XclExpObjList::EndSheet() { // Is there still something in the stream? -> The solver container if( mrEscherEx.HasPendingDffData() ) pSolverContainer = new XclExpMsoDrawing( mrEscherEx ); // close the DGCONTAINER created by XclExpObjList ctor MSODRAWING mrEscherEx.CloseContainer(); } void XclExpObjList::Save( XclExpStream& rStrm ) { //! Escher must be written, even if there are no objects pMsodrawingPerSheet->Save( rStrm ); for ( XclObj* p = First(); p; p = Next() ) p->Save( rStrm ); if( pSolverContainer ) pSolverContainer->Save( rStrm ); } // --- class XclObj -------------------------------------------------- XclObj::XclObj( XclExpObjectManager& rObjMgr, sal_uInt16 nObjType, bool bOwnEscher ) : XclExpRecord( EXC_ID_OBJ, 26 ), mrEscherEx( rObjMgr.GetEscherEx() ), pClientTextbox( NULL ), pTxo( NULL ), mnObjType( nObjType ), nObjId(0), nGrbit( 0x6011 ), // AutoLine, AutoFill, Printable, Locked bFirstOnSheet( !rObjMgr.HasObj() ), mbOwnEscher( bOwnEscher ) { //! first object continues the first MSODRAWING record if ( bFirstOnSheet ) pMsodrawing = rObjMgr.GetMsodrawingPerSheet(); else pMsodrawing = new XclExpMsoDrawing( mrEscherEx ); } XclObj::~XclObj() { if ( !bFirstOnSheet ) delete pMsodrawing; delete pClientTextbox; delete pTxo; } void XclObj::ImplWriteAnchor( const XclExpRoot& /*rRoot*/, const SdrObject* pSdrObj, const Rectangle* pChildAnchor ) { if( pChildAnchor ) { mrEscherEx.AddChildAnchor( *pChildAnchor ); } else if( pSdrObj ) { ::std::auto_ptr< XclExpDffAnchorBase > xDffAnchor( mrEscherEx.CreateDffAnchor( *pSdrObj ) ); xDffAnchor->WriteDffData( mrEscherEx ); } } void XclObj::SetEscherShapeType( sal_uInt16 nType ) { //2do: what about the other defined ot... types? switch ( nType ) { case ESCHER_ShpInst_Line : mnObjType = EXC_OBJTYPE_LINE; break; case ESCHER_ShpInst_Rectangle : case ESCHER_ShpInst_RoundRectangle : mnObjType = EXC_OBJTYPE_RECTANGLE; break; case ESCHER_ShpInst_Ellipse : mnObjType = EXC_OBJTYPE_OVAL; break; case ESCHER_ShpInst_Arc : mnObjType = EXC_OBJTYPE_ARC; break; case ESCHER_ShpInst_TextBox : mnObjType = EXC_OBJTYPE_TEXT; break; case ESCHER_ShpInst_PictureFrame : mnObjType = EXC_OBJTYPE_PICTURE; break; default: mnObjType = EXC_OBJTYPE_DRAWING; } } void XclObj::SetText( const XclExpRoot& rRoot, const SdrTextObj& rObj ) { DBG_ASSERT( !pClientTextbox, "XclObj::SetText: already set" ); if ( !pClientTextbox ) { mrEscherEx.UpdateDffFragmentEnd(); pClientTextbox = new XclExpMsoDrawing( mrEscherEx ); mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record mrEscherEx.UpdateDffFragmentEnd(); pTxo = new XclTxo( rRoot, rObj ); } } void XclObj::WriteBody( XclExpStream& rStrm ) { DBG_ASSERT( mnObjType != EXC_OBJTYPE_UNKNOWN, "XclObj::WriteBody - unknown type" ); // create a substream to be able to create subrecords SvMemoryStream aMemStrm; ::std::auto_ptr< XclExpStream > pXclStrm( new XclExpStream( aMemStrm, rStrm.GetRoot() ) ); // write the ftCmo subrecord pXclStrm->StartRecord( EXC_ID_OBJCMO, 18 ); *pXclStrm << mnObjType << nObjId << nGrbit; pXclStrm->WriteZeroBytes( 12 ); pXclStrm->EndRecord(); // write other subrecords WriteSubRecs( *pXclStrm ); // write the ftEnd subrecord pXclStrm->StartRecord( EXC_ID_OBJEND, 0 ); pXclStrm->EndRecord(); // copy the data to the OBJ record pXclStrm.reset(); aMemStrm.Seek( 0 ); rStrm.CopyFromStream( aMemStrm ); } void XclObj::Save( XclExpStream& rStrm ) { // MSODRAWING record (msofbtSpContainer) if ( !bFirstOnSheet ) pMsodrawing->Save( rStrm ); // OBJ XclExpRecord::Save( rStrm ); // second MSODRAWING record and TXO and CONTINUE records SaveTextRecs( rStrm ); } void XclObj::WriteSubRecs( XclExpStream& /*rStrm*/ ) { } void XclObj::SaveTextRecs( XclExpStream& rStrm ) { // MSODRAWING record (msofbtClientTextbox) if ( pClientTextbox ) pClientTextbox->Save( rStrm ); // TXO and CONTINUE records if ( pTxo ) pTxo->Save( rStrm ); } // --- class XclObjComment ------------------------------------------- XclObjComment::XclObjComment( XclExpObjectManager& rObjMgr, const Rectangle& rRect, const EditTextObject& rEditObj, SdrObject* pCaption, bool bVisible ) : XclObj( rObjMgr, EXC_OBJTYPE_NOTE, true ) { ProcessEscherObj( rObjMgr.GetRoot(), rRect, pCaption, bVisible); // TXO pTxo = new XclTxo( rObjMgr.GetRoot(), rEditObj, pCaption ); } void XclObjComment::ProcessEscherObj( const XclExpRoot& rRoot, const Rectangle& rRect, SdrObject* pCaption, const bool bVisible ) { Reference aXShape; EscherPropertyContainer aPropOpt; if(pCaption) { aXShape = GetXShapeForSdrObject(pCaption); Reference< XPropertySet > aXPropSet( aXShape, UNO_QUERY ); if( aXPropSet.is() ) { aPropOpt.CreateFillProperties( aXPropSet, sal_True); aPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // undocumented aPropOpt.AddOpt( 0x0158, 0x00000000 ); // undocumented sal_uInt32 nValue = 0; if(!aPropOpt.GetOpt( ESCHER_Prop_FitTextToShape, nValue )) aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field if(aPropOpt.GetOpt( ESCHER_Prop_fillColor, nValue )) { // If the Colour is the same as the 'ToolTip' System colour then // use the default rather than the explicit colour value. This will // be incorrect where user has chosen to use this colour explicity. Color aColor = Color( (sal_uInt8)nValue, (sal_uInt8)( nValue >> 8 ), (sal_uInt8)( nValue >> 16 ) ); const StyleSettings& rSett = Application::GetSettings().GetStyleSettings(); if(aColor == rSett.GetHelpColor().GetColor()) { aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000050 ); aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000050 ); } } else aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000050 ); if(!aPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nValue )) aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000050 ); if(!aPropOpt.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue )) aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 ); // bool field if(!aPropOpt.GetOpt( ESCHER_Prop_shadowColor, nValue )) aPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x00000000 ); if(!aPropOpt.GetOpt( ESCHER_Prop_fshadowObscured, nValue )) // bool field aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00030003 ); // bool field } } nGrbit = 0; // all off: AutoLine, AutoFill, Printable, Locked mrEscherEx.OpenContainer( ESCHER_SpContainer ); mrEscherEx.AddShape( ESCHER_ShpInst_TextBox, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT ); sal_uInt32 nFlags = 0x000A0000; ::set_flag( nFlags, sal_uInt32(2), !bVisible ); aPropOpt.AddOpt( ESCHER_Prop_fPrint, nFlags ); // bool field aPropOpt.Commit( mrEscherEx.GetStream() ); XclExpDffNoteAnchor( rRoot, rRect ).WriteDffData( mrEscherEx ); mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record mrEscherEx.UpdateDffFragmentEnd(); //! Be sure to construct the MSODRAWING ClientTextbox record _after_ the //! base OBJ's MSODRAWING record Escher data is completed. pClientTextbox = new XclExpMsoDrawing( mrEscherEx ); mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record mrEscherEx.UpdateDffFragmentEnd(); mrEscherEx.CloseContainer(); // ESCHER_SpContainer } XclObjComment::~XclObjComment() { } void XclObjComment::Save( XclExpStream& rStrm ) { // content of this record XclObj::Save( rStrm ); } // --- class XclObjDropDown ------------------------------------------ XclObjDropDown::XclObjDropDown( XclExpObjectManager& rObjMgr, const ScAddress& rPos, sal_Bool bFilt ) : XclObj( rObjMgr, EXC_OBJTYPE_DROPDOWN, true ), bIsFiltered( bFilt ) { SetLocked( sal_True ); SetPrintable( sal_False ); SetAutoFill( sal_True ); SetAutoLine( sal_False ); nGrbit |= 0x0100; // undocumented mrEscherEx.OpenContainer( ESCHER_SpContainer ); mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, SHAPEFLAG_HAVEANCHOR | SHAPEFLAG_HAVESPT ); EscherPropertyContainer aPropOpt; aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 ); // bool field aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00010000 ); // bool field aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x000A0000 ); // bool field aPropOpt.Commit( mrEscherEx.GetStream() ); XclExpDffDropDownAnchor( rObjMgr.GetRoot(), rPos ).WriteDffData( mrEscherEx ); mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record mrEscherEx.UpdateDffFragmentEnd(); mrEscherEx.CloseContainer(); // ESCHER_SpContainer // old size + ftSbs + ftLbsData AddRecSize( 24 + 20 ); } XclObjDropDown::~XclObjDropDown() { } void XclObjDropDown::WriteSubRecs( XclExpStream& rStrm ) { // ftSbs subrecord - Scroll bars (dummy) rStrm.StartRecord( EXC_ID_OBJSBS, 20 ); rStrm.WriteZeroBytes( 20 ); rStrm.EndRecord(); // ftLbsData subrecord - Listbox data sal_uInt16 nDropDownFlags = 0; ::insert_value( nDropDownFlags, EXC_OBJ_DROPDOWN_SIMPLE, 0, 2 ); ::set_flag( nDropDownFlags, EXC_OBJ_DROPDOWN_FILTERED, bIsFiltered ); rStrm.StartRecord( EXC_ID_OBJLBSDATA, 16 ); rStrm << (sal_uInt32)0 << (sal_uInt16)0 << (sal_uInt16)0x0301 << (sal_uInt16)0 << nDropDownFlags << sal_uInt16( 20 ) << sal_uInt16( 130 ); rStrm.EndRecord(); } // --- class XclTxo -------------------------------------------------- sal_uInt8 lcl_GetHorAlignFromItemSet( const SfxItemSet& rItemSet ) { sal_uInt8 nHorAlign = EXC_OBJ_HOR_LEFT; switch( static_cast< const SvxAdjustItem& >( rItemSet.Get( EE_PARA_JUST ) ).GetAdjust() ) { case SVX_ADJUST_LEFT: nHorAlign = EXC_OBJ_HOR_LEFT; break; case SVX_ADJUST_CENTER: nHorAlign = EXC_OBJ_HOR_CENTER; break; case SVX_ADJUST_RIGHT: nHorAlign = EXC_OBJ_HOR_RIGHT; break; case SVX_ADJUST_BLOCK: nHorAlign = EXC_OBJ_HOR_JUSTIFY; break; default:; } return nHorAlign; } sal_uInt8 lcl_GetVerAlignFromItemSet( const SfxItemSet& rItemSet ) { sal_uInt8 nVerAlign = EXC_OBJ_VER_TOP; switch( static_cast< const SdrTextVertAdjustItem& >( rItemSet.Get( SDRATTR_TEXT_VERTADJUST ) ).GetValue() ) { case SDRTEXTVERTADJUST_TOP: nVerAlign = EXC_OBJ_VER_TOP; break; case SDRTEXTVERTADJUST_CENTER: nVerAlign = EXC_OBJ_VER_CENTER; break; case SDRTEXTVERTADJUST_BOTTOM: nVerAlign = EXC_OBJ_VER_BOTTOM; break; case SDRTEXTVERTADJUST_BLOCK: nVerAlign = EXC_OBJ_VER_JUSTIFY; break; } return nVerAlign; } XclTxo::XclTxo( const String& rString, sal_uInt16 nFontIx ) : mpString( new XclExpString( rString ) ), mnRotation( EXC_OBJ_ORIENT_NONE ), mnHorAlign( EXC_OBJ_HOR_LEFT ), mnVerAlign( EXC_OBJ_VER_TOP ) { if( mpString->Len() ) { // If there is text, Excel *needs* the 2nd CONTINUE record with at least two format runs mpString->AppendFormat( 0, nFontIx ); mpString->AppendFormat( mpString->Len(), EXC_FONT_APP ); } } XclTxo::XclTxo( const XclExpRoot& rRoot, const SdrTextObj& rTextObj ) : mpString( XclExpStringHelper::CreateString( rRoot, rTextObj ) ), mnRotation( EXC_OBJ_ORIENT_NONE ), mnHorAlign( EXC_OBJ_HOR_LEFT ), mnVerAlign( EXC_OBJ_VER_TOP ) { // additional alignment and orientation items const SfxItemSet& rItemSet = rTextObj.GetMergedItemSet(); // horizontal alignment SetHorAlign( lcl_GetHorAlignFromItemSet( rItemSet ) ); // vertical alignment SetVerAlign( lcl_GetVerAlignFromItemSet( rItemSet ) ); // rotation long nAngle = rTextObj.GetRotateAngle(); if( (4500 < nAngle) && (nAngle < 13500) ) mnRotation = EXC_OBJ_ORIENT_90CCW; else if( (22500 < nAngle) && (nAngle < 31500) ) mnRotation = EXC_OBJ_ORIENT_90CW; else mnRotation = EXC_OBJ_ORIENT_NONE; } XclTxo::XclTxo( const XclExpRoot& rRoot, const EditTextObject& rEditObj, SdrObject* pCaption ) : mpString( XclExpStringHelper::CreateString( rRoot, rEditObj ) ), mnRotation( EXC_OBJ_ORIENT_NONE ), mnHorAlign( EXC_OBJ_HOR_LEFT ), mnVerAlign( EXC_OBJ_VER_TOP ) { if(pCaption) { // Excel has one alignment per NoteObject while Calc supports // one alignment per paragraph - use the first paragraph // alignment (if set) as our overall alignment. String aParaText( rEditObj.GetText( 0 ) ); if( aParaText.Len() ) { SfxItemSet aSet( rEditObj.GetParaAttribs( 0)); const SfxPoolItem* pItem = NULL; if( aSet.GetItemState( EE_PARA_JUST, sal_True, &pItem ) == SFX_ITEM_SET ) { SvxAdjust eEEAlign = static_cast< const SvxAdjustItem& >( *pItem ).GetAdjust(); pCaption->SetMergedItem( SvxAdjustItem( eEEAlign, EE_PARA_JUST ) ); } } const SfxItemSet& rItemSet = pCaption->GetMergedItemSet(); // horizontal alignment SetHorAlign( lcl_GetHorAlignFromItemSet( rItemSet ) ); // vertical alignment SetVerAlign( lcl_GetVerAlignFromItemSet( rItemSet ) ); // orientation alignment const SvxWritingModeItem& rItem = static_cast< const SvxWritingModeItem& >( rItemSet.Get( SDRATTR_TEXTDIRECTION ) ); if( rItem.GetValue() == com::sun::star::text::WritingMode_TB_RL ) mnRotation = EXC_OBJ_ORIENT_90CW; } } void XclTxo::SaveCont( XclExpStream& rStrm ) { DBG_ASSERT( mpString.get(), "XclTxo::SaveCont - missing string" ); // #i96858# do not save existing string formatting if text is empty sal_uInt16 nRunLen = mpString->IsEmpty() ? 0 : (8 * mpString->GetFormatsCount()); // alignment sal_uInt16 nFlags = 0; ::insert_value( nFlags, mnHorAlign, 1, 3 ); ::insert_value( nFlags, mnVerAlign, 4, 3 ); rStrm << nFlags << mnRotation; rStrm.WriteZeroBytes( 6 ); rStrm << mpString->Len() << nRunLen << sal_uInt32( 0 ); } void XclTxo::Save( XclExpStream& rStrm ) { // Write the TXO part ExcRecord::Save( rStrm ); // CONTINUE records are only written if there is some text if( !mpString->IsEmpty() ) { // CONTINUE for character array rStrm.StartRecord( EXC_ID_CONT, mpString->GetBufferSize() + 1 ); rStrm << static_cast< sal_uInt8 >( mpString->GetFlagField() & EXC_STRF_16BIT ); // only Unicode flag mpString->WriteBuffer( rStrm ); rStrm.EndRecord(); // CONTINUE for formatting runs rStrm.StartRecord( EXC_ID_CONT, 8 * mpString->GetFormatsCount() ); const XclFormatRunVec& rFormats = mpString->GetFormats(); for( XclFormatRunVec::const_iterator aIt = rFormats.begin(), aEnd = rFormats.end(); aIt != aEnd; ++aIt ) rStrm << aIt->mnChar << aIt->mnFontIdx << sal_uInt32( 0 ); rStrm.EndRecord(); } } sal_uInt16 XclTxo::GetNum() const { return EXC_ID_TXO; } sal_Size XclTxo::GetLen() const { return 18; } // --- class XclObjOle ------------------------------------------- XclObjOle::XclObjOle( XclExpObjectManager& rObjMgr, const SdrObject& rObj ) : XclObj( rObjMgr, EXC_OBJTYPE_PICTURE ), rOleObj( rObj ), pRootStorage( rObjMgr.GetRoot().GetRootStorage() ) { } XclObjOle::~XclObjOle() { } void XclObjOle::WriteSubRecs( XclExpStream& rStrm ) { // write only as embedded, not linked String aStorageName( RTL_CONSTASCII_USTRINGPARAM( "MBD" ) ); sal_Char aBuf[ sizeof(sal_uInt32) * 2 + 1 ]; // FIXME Eeek! Is this just a way to get a unique id? sal_uInt32 nPictureId = sal_uInt32(sal_uIntPtr(this) >> 2); sprintf( aBuf, "%08X", static_cast< unsigned int >( nPictureId ) ); // #100211# - checked aStorageName.AppendAscii( aBuf ); SotStorageRef xOleStg = pRootStorage->OpenSotStorage( aStorageName, STREAM_READWRITE| STREAM_SHARE_DENYALL ); if( xOleStg.Is() ) { uno::Reference < embed::XEmbeddedObject > xObj( ((SdrOle2Obj&)rOleObj).GetObjRef() ); if ( xObj.is() ) { // set version to "old" version, because it must be // saved in MS notation. sal_uInt32 nFl = 0; SvtFilterOptions* pFltOpts = SvtFilterOptions::Get(); if( pFltOpts ) { if( pFltOpts->IsMath2MathType() ) nFl |= OLE_STARMATH_2_MATHTYPE; if( pFltOpts->IsWriter2WinWord() ) nFl |= OLE_STARWRITER_2_WINWORD; if( pFltOpts->IsCalc2Excel() ) nFl |= OLE_STARCALC_2_EXCEL; if( pFltOpts->IsImpress2PowerPoint() ) nFl |= OLE_STARIMPRESS_2_POWERPOINT; } SvxMSExportOLEObjects aOLEExpFilt( nFl ); aOLEExpFilt.ExportOLEObject( xObj, *xOleStg ); // OBJCF subrecord, undocumented as usual rStrm.StartRecord( EXC_ID_OBJCF, 2 ); rStrm << sal_uInt16(0x0002); rStrm.EndRecord(); // OBJFLAGS subrecord, undocumented as usual rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 ); sal_uInt16 nFlags = EXC_OBJ_PIC_MANUALSIZE; ::set_flag( nFlags, EXC_OBJ_PIC_SYMBOL, ((SdrOle2Obj&)rOleObj).GetAspect() == embed::Aspects::MSOLE_ICON ); rStrm << nFlags; rStrm.EndRecord(); // OBJPICTFMLA subrecord, undocumented as usual XclExpString aName( xOleStg->GetUserName() ); sal_uInt16 nPadLen = (sal_uInt16)(aName.GetSize() & 0x01); sal_uInt16 nFmlaLen = static_cast< sal_uInt16 >( 12 + aName.GetSize() + nPadLen ); sal_uInt16 nSubRecLen = nFmlaLen + 6; rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nSubRecLen ); rStrm << nFmlaLen << sal_uInt16( 5 ) << sal_uInt32( 0 ) << sal_uInt8( 2 ) << sal_uInt32( 0 ) << sal_uInt8( 3 ) << aName; if( nPadLen ) rStrm << sal_uInt8( 0 ); // pad byte rStrm << nPictureId; rStrm.EndRecord(); } } } void XclObjOle::Save( XclExpStream& rStrm ) { // content of this record XclObj::Save( rStrm ); } // --- class XclObjAny ------------------------------------------- XclObjAny::XclObjAny( XclExpObjectManager& rObjMgr ) : XclObj( rObjMgr, EXC_OBJTYPE_UNKNOWN ) { } XclObjAny::~XclObjAny() { } void XclObjAny::WriteSubRecs( XclExpStream& rStrm ) { if( mnObjType == EXC_OBJTYPE_GROUP ) // ftGmo subrecord rStrm << EXC_ID_OBJGMO << sal_uInt16(2) << sal_uInt16(0); } void XclObjAny::Save( XclExpStream& rStrm ) { if( mnObjType == EXC_OBJTYPE_GROUP ) // old size + ftGmo AddRecSize( 6 ); // content of this record XclObj::Save( rStrm ); } // --- class ExcBof8_Base -------------------------------------------- ExcBof8_Base::ExcBof8_Base() { nVers = 0x0600; nRupBuild = 0x0dbb; nRupYear = 0x07cc; // nFileHistory = 0x00000001; // last edited by Microsoft Excel for Windows nFileHistory = 0x00000000; nLowestBiffVer = 0x00000006; // Biff8 } void ExcBof8_Base::SaveCont( XclExpStream& rStrm ) { rStrm.DisableEncryption(); rStrm << nVers << nDocType << nRupBuild << nRupYear << nFileHistory << nLowestBiffVer; } sal_uInt16 ExcBof8_Base::GetNum() const { return 0x0809; } sal_Size ExcBof8_Base::GetLen() const { return 16; } // --- class ExcBof8 ------------------------------------------------- ExcBof8::ExcBof8() { nDocType = 0x0010; } // --- class ExcBofW8 ------------------------------------------------ ExcBofW8::ExcBofW8() { nDocType = 0x0005; } // --- class ExcBundlesheet8 ----------------------------------------- ExcBundlesheet8::ExcBundlesheet8( RootData& rRootData, SCTAB _nTab ) : ExcBundlesheetBase( rRootData, static_cast(_nTab) ), sUnicodeName( rRootData.pER->GetTabInfo().GetScTabName( _nTab ) ) { } ExcBundlesheet8::ExcBundlesheet8( const String& rString ) : ExcBundlesheetBase(), sUnicodeName( rString ) { } XclExpString ExcBundlesheet8::GetName() const { return XclExpString( sUnicodeName, EXC_STR_8BITLENGTH ); } void ExcBundlesheet8::SaveCont( XclExpStream& rStrm ) { nOwnPos = rStrm.GetSvStreamPos(); // write dummy position, real position comes later rStrm.DisableEncryption(); rStrm << sal_uInt32(0); rStrm.EnableEncryption(); rStrm << nGrbit << GetName(); } sal_Size ExcBundlesheet8::GetLen() const { // Text max 255 chars return 8 + GetName().GetBufferSize(); } void ExcBundlesheet8::SaveXml( XclExpXmlStream& rStrm ) { OUString sId; rStrm.CreateOutputStream( XclXmlUtils::GetStreamName( "xl/", "worksheets/sheet", nTab+1), XclXmlUtils::GetStreamName( NULL, "worksheets/sheet", nTab+1), rStrm.GetCurrentStream()->getOutputStream(), "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml", "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", &sId ); rStrm.GetCurrentStream()->singleElement( XML_sheet, XML_name, XclXmlUtils::ToOString( sUnicodeName ).getStr(), XML_sheetId, rtl::OString::valueOf( (sal_Int32)( nTab+1 ) ).getStr(), XML_state, nGrbit == 0x0000 ? "visible" : "hidden", FSNS( XML_r, XML_id ), XclXmlUtils::ToOString( sId ).getStr(), FSEND ); } // --- class XclObproj ----------------------------------------------- sal_uInt16 XclObproj::GetNum() const { return 0x00D3; } sal_Size XclObproj::GetLen() const { return 0; } // ---- class XclCodename -------------------------------------------- XclCodename::XclCodename( const String& r ) : aName( r ) { } void XclCodename::SaveCont( XclExpStream& rStrm ) { rStrm << aName; } sal_uInt16 XclCodename::GetNum() const { return 0x01BA; } sal_Size XclCodename::GetLen() const { return aName.GetSize(); } // ---- Scenarios ---------------------------------------------------- ExcEScenarioCell::ExcEScenarioCell( sal_uInt16 nC, sal_uInt16 nR, const String& rTxt ) : nCol( nC ), nRow( nR ), sText( rTxt, EXC_STR_DEFAULT, 255 ) { } void ExcEScenarioCell::WriteAddress( XclExpStream& rStrm ) { rStrm << nRow << nCol; } void ExcEScenarioCell::WriteText( XclExpStream& rStrm ) { rStrm << sText; } void ExcEScenarioCell::SaveXml( XclExpXmlStream& rStrm ) { rStrm.GetCurrentStream()->singleElement( XML_inputCells, // OOXTODO: XML_deleted, // OOXTODO: XML_numFmtId, XML_r, XclXmlUtils::ToOString( ScAddress( nCol, nRow, 0 ) ).getStr(), // OOXTODO: XML_undone, XML_val, XclXmlUtils::ToOString( sText ).getStr(), FSEND ); } ExcEScenario::ExcEScenario( const XclExpRoot& rRoot, SCTAB nTab ) { String sTmpName; String sTmpComm; Color aDummyCol; sal_uInt16 nFlags; ScDocument& rDoc = rRoot.GetDoc(); rDoc.GetName( nTab, sTmpName ); sName.Assign( sTmpName, EXC_STR_8BITLENGTH ); nRecLen = 8 + sName.GetBufferSize(); rDoc.GetScenarioData( nTab, sTmpComm, aDummyCol, nFlags ); sComment.Assign( sTmpComm, EXC_STR_DEFAULT, 255 ); if( sComment.Len() ) nRecLen += sComment.GetSize(); nProtected = (nFlags & SC_SCENARIO_PROTECT) ? 1 : 0; sUserName.Assign( rRoot.GetUserName(), EXC_STR_DEFAULT, 255 ); nRecLen += sUserName.GetSize(); const ScRangeList* pRList = rDoc.GetScenarioRanges( nTab ); if( !pRList ) return; sal_Bool bContLoop = sal_True; SCROW nRow; SCCOL nCol; String sText; double fVal; for( sal_uInt32 nRange = 0; (nRange < pRList->Count()) && bContLoop; nRange++ ) { const ScRange* pRange = pRList->GetObject( nRange ); for( nRow = pRange->aStart.Row(); (nRow <= pRange->aEnd.Row()) && bContLoop; nRow++ ) for( nCol = pRange->aStart.Col(); (nCol <= pRange->aEnd.Col()) && bContLoop; nCol++ ) { if( rDoc.HasValueData( nCol, nRow, nTab ) ) { rDoc.GetValue( nCol, nRow, nTab, fVal ); sText = ::rtl::math::doubleToUString( fVal, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, ScGlobal::pLocaleData->getNumDecimalSep().GetChar(0), sal_True ); } else rDoc.GetString( nCol, nRow, nTab, sText ); bContLoop = Append( static_cast(nCol), static_cast(nRow), sText ); } } } ExcEScenario::~ExcEScenario() { for( ExcEScenarioCell* pCell = _First(); pCell; pCell = _Next() ) delete pCell; } sal_Bool ExcEScenario::Append( sal_uInt16 nCol, sal_uInt16 nRow, const String& rTxt ) { if( List::Count() == EXC_SCEN_MAXCELL ) return sal_False; ExcEScenarioCell* pCell = new ExcEScenarioCell( nCol, nRow, rTxt ); List::Insert( pCell, LIST_APPEND ); nRecLen += 6 + pCell->GetStringBytes(); // 4 bytes address, 2 bytes ifmt return sal_True; } void ExcEScenario::SaveCont( XclExpStream& rStrm ) { rStrm << (sal_uInt16) List::Count() // number of cells << nProtected // fProtection << (sal_uInt8) 0 // fHidden << (sal_uInt8) sName.Len() // length of scen name << (sal_uInt8) sComment.Len() // length of comment << (sal_uInt8) sUserName.Len(); // length of user name sName.WriteFlagField( rStrm ); sName.WriteBuffer( rStrm ); rStrm << sUserName; if( sComment.Len() ) rStrm << sComment; ExcEScenarioCell* pCell; for( pCell = _First(); pCell; pCell = _Next() ) pCell->WriteAddress( rStrm ); // pos of cell for( pCell = _First(); pCell; pCell = _Next() ) pCell->WriteText( rStrm ); // string content rStrm.SetSliceSize( 2 ); rStrm.WriteZeroBytes( 2 * List::Count() ); // date format } sal_uInt16 ExcEScenario::GetNum() const { return 0x00AF; } sal_Size ExcEScenario::GetLen() const { return nRecLen; } void ExcEScenario::SaveXml( XclExpXmlStream& rStrm ) { sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream(); rWorkbook->startElement( XML_scenario, XML_name, XclXmlUtils::ToOString( sName ).getStr(), XML_locked, XclXmlUtils::ToPsz( nProtected ), // OOXTODO: XML_hidden, XML_count, OString::valueOf( (sal_Int32) List::Count() ).getStr(), XML_user, XESTRING_TO_PSZ( sUserName ), XML_comment, XESTRING_TO_PSZ( sComment ), FSEND ); for( ExcEScenarioCell* pCell = _First(); pCell; pCell = _Next() ) pCell->SaveXml( rStrm ); rWorkbook->endElement( XML_scenario ); } ExcEScenarioManager::ExcEScenarioManager( const XclExpRoot& rRoot, SCTAB nTab ) : nActive( 0 ) { ScDocument& rDoc = rRoot.GetDoc(); if( rDoc.IsScenario( nTab ) ) return; SCTAB nFirstTab = nTab + 1; SCTAB nNewTab = nFirstTab; while( rDoc.IsScenario( nNewTab ) ) { Append( new ExcEScenario( rRoot, nNewTab ) ); if( rDoc.IsActiveScenario( nNewTab ) ) nActive = static_cast(nNewTab - nFirstTab); nNewTab++; } } ExcEScenarioManager::~ExcEScenarioManager() { for( ExcEScenario* pScen = _First(); pScen; pScen = _Next() ) delete pScen; } void ExcEScenarioManager::SaveCont( XclExpStream& rStrm ) { rStrm << (sal_uInt16) List::Count() // number of scenarios << nActive // active scen << nActive // last displayed << (sal_uInt16) 0; // reference areas } void ExcEScenarioManager::Save( XclExpStream& rStrm ) { if( List::Count() ) ExcRecord::Save( rStrm ); for( ExcEScenario* pScen = _First(); pScen; pScen = _Next() ) pScen->Save( rStrm ); } void ExcEScenarioManager::SaveXml( XclExpXmlStream& rStrm ) { if( ! List::Count() ) return; sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream(); rWorkbook->startElement( XML_scenarios, XML_current, OString::valueOf( (sal_Int32)nActive ).getStr(), XML_show, OString::valueOf( (sal_Int32)nActive ).getStr(), // OOXTODO: XML_sqref, FSEND ); for( ExcEScenario* pScen = _First(); pScen; pScen = _Next() ) pScen->SaveXml( rStrm ); rWorkbook->endElement( XML_scenarios ); } sal_uInt16 ExcEScenarioManager::GetNum() const { return 0x00AE; } sal_Size ExcEScenarioManager::GetLen() const { return 8; } // ============================================================================ struct XclExpTabProtectOption { ScTableProtection::Option eOption; sal_uInt16 nMask; }; XclExpSheetProtectOptions::XclExpSheetProtectOptions( const XclExpRoot& rRoot, SCTAB nTab ) : XclExpRecord( 0x0867, 23 ) { static const XclExpTabProtectOption aTable[] = { { ScTableProtection::OBJECTS, 0x0001 }, { ScTableProtection::SCENARIOS, 0x0002 }, { ScTableProtection::FORMAT_CELLS, 0x0004 }, { ScTableProtection::FORMAT_COLUMNS, 0x0008 }, { ScTableProtection::FORMAT_ROWS, 0x0010 }, { ScTableProtection::INSERT_COLUMNS, 0x0020 }, { ScTableProtection::INSERT_ROWS, 0x0040 }, { ScTableProtection::INSERT_HYPERLINKS, 0x0080 }, { ScTableProtection::DELETE_COLUMNS, 0x0100 }, { ScTableProtection::DELETE_ROWS, 0x0200 }, { ScTableProtection::SELECT_LOCKED_CELLS, 0x0400 }, { ScTableProtection::SORT, 0x0800 }, { ScTableProtection::AUTOFILTER, 0x1000 }, { ScTableProtection::PIVOT_TABLES, 0x2000 }, { ScTableProtection::SELECT_UNLOCKED_CELLS, 0x4000 }, { ScTableProtection::NONE, 0x0000 } }; mnOptions = 0x0000; ScTableProtection* pProtect = rRoot.GetDoc().GetTabProtection(nTab); if (!pProtect) return; for (int i = 0; aTable[i].nMask != 0x0000; ++i) { if ( pProtect->isOptionEnabled(aTable[i].eOption) ) mnOptions |= aTable[i].nMask; } } void XclExpSheetProtectOptions::WriteBody( XclExpStream& rStrm ) { sal_uInt16 nBytes = 0x0867; rStrm << nBytes; sal_uChar nZero = 0x00; for (int i = 0; i < 9; ++i) rStrm << nZero; nBytes = 0x0200; rStrm << nBytes; nBytes = 0x0100; rStrm << nBytes; nBytes = 0xFFFF; rStrm << nBytes << nBytes; rStrm << mnOptions; nBytes = 0; rStrm << nBytes; } // ============================================================================ void XclCalccount::SaveCont( XclExpStream& rStrm ) { rStrm << nCount; } XclCalccount::XclCalccount( const ScDocument& rDoc ) { nCount = rDoc.GetDocOptions().GetIterCount(); } sal_uInt16 XclCalccount::GetNum() const { return 0x000C; } sal_Size XclCalccount::GetLen() const { return 2; } void XclCalccount::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_iterateCount, OString::valueOf( (sal_Int32)nCount ).getStr(), FSEND ); } void XclIteration::SaveCont( XclExpStream& rStrm ) { rStrm << nIter; } XclIteration::XclIteration( const ScDocument& rDoc ) { nIter = rDoc.GetDocOptions().IsIter()? 1 : 0; } sal_uInt16 XclIteration::GetNum() const { return 0x0011; } sal_Size XclIteration::GetLen() const { return 2; } void XclIteration::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_iterate, XclXmlUtils::ToPsz( nIter == 1 ), FSEND ); } void XclDelta::SaveCont( XclExpStream& rStrm ) { rStrm << fDelta; } XclDelta::XclDelta( const ScDocument& rDoc ) { fDelta = rDoc.GetDocOptions().GetIterEps(); } sal_uInt16 XclDelta::GetNum() const { return 0x0010; } sal_Size XclDelta::GetLen() const { return 8; } void XclDelta::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_iterateDelta, OString::valueOf( fDelta ).getStr(), FSEND ); } // ============================================================================ XclExpFileEncryption::XclExpFileEncryption( const XclExpRoot& rRoot ) : XclExpRecord(0x002F, 54), mrRoot(rRoot) { } XclExpFileEncryption::~XclExpFileEncryption() { } void XclExpFileEncryption::WriteBody( XclExpStream& rStrm ) { // 0x0000 - neither standard nor strong encryption // 0x0001 - standard or strong encryption rStrm << static_cast(0x0001); // 0x0000 - non standard encryption // 0x0001 - standard encryption sal_uInt16 nStdEnc = 0x0001; rStrm << nStdEnc << nStdEnc; sal_uInt8 pnDocId[16]; sal_uInt8 pnSalt[16]; sal_uInt8 pnSaltHash[16]; XclExpEncrypterRef xEnc( new XclExpBiff8Encrypter(mrRoot) ); xEnc->GetDocId(pnDocId); xEnc->GetSalt(pnSalt); xEnc->GetSaltDigest(pnSaltHash); rStrm.Write(pnDocId, 16); rStrm.Write(pnSalt, 16); rStrm.Write(pnSaltHash, 16); rStrm.SetEncrypter(xEnc); } // ============================================================================ XclExpInterfaceHdr::XclExpInterfaceHdr( sal_uInt16 nCodePage ) : XclExpUInt16Record( EXC_ID_INTERFACEHDR, nCodePage ) { } void XclExpInterfaceHdr::WriteBody( XclExpStream& rStrm ) { rStrm.DisableEncryption(); rStrm << GetValue(); } // ============================================================================ XclExpInterfaceEnd::XclExpInterfaceEnd() : XclExpRecord(0x00E2, 0) {} XclExpInterfaceEnd::~XclExpInterfaceEnd() {} void XclExpInterfaceEnd::WriteBody( XclExpStream& rStrm ) { // Don't forget to re-enable encryption. rStrm.EnableEncryption(); } // ============================================================================ XclExpWriteAccess::XclExpWriteAccess() : XclExpRecord(0x005C, 112) { } XclExpWriteAccess::~XclExpWriteAccess() { } void XclExpWriteAccess::WriteBody( XclExpStream& rStrm ) { static const sal_uInt8 aData[] = { 0x04, 0x00, 0x00, 'C', 'a', 'l', 'c', 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }; sal_Size nDataSize = sizeof(aData); for (sal_Size i = 0; i < nDataSize; ++i) rStrm << aData[i]; } // ============================================================================ XclExpFileSharing::XclExpFileSharing( const XclExpRoot& rRoot, sal_uInt16 nPasswordHash, bool bRecommendReadOnly ) : XclExpRecord( EXC_ID_FILESHARING ), mnPasswordHash( nPasswordHash ), mbRecommendReadOnly( bRecommendReadOnly ) { if( rRoot.GetBiff() <= EXC_BIFF5 ) maUserName.AssignByte( rRoot.GetUserName(), rRoot.GetTextEncoding(), EXC_STR_8BITLENGTH ); else maUserName.Assign( rRoot.GetUserName() ); } void XclExpFileSharing::Save( XclExpStream& rStrm ) { if( (mnPasswordHash != 0) || mbRecommendReadOnly ) XclExpRecord::Save( rStrm ); } void XclExpFileSharing::WriteBody( XclExpStream& rStrm ) { rStrm << sal_uInt16( mbRecommendReadOnly ? 1 : 0 ) << mnPasswordHash << maUserName; } // ============================================================================ XclExpProt4Rev::XclExpProt4Rev() : XclExpRecord(0x01AF, 2) { } XclExpProt4Rev::~XclExpProt4Rev() { } void XclExpProt4Rev::WriteBody( XclExpStream& rStrm ) { rStrm << static_cast(0x0000); } // ============================================================================ XclExpProt4RevPass::XclExpProt4RevPass() : XclExpRecord(0x01BC, 2) { } XclExpProt4RevPass::~XclExpProt4RevPass() { } void XclExpProt4RevPass::WriteBody( XclExpStream& rStrm ) { rStrm << static_cast(0x0000); } // ============================================================================ static const sal_uInt8 nDataRecalcId[] = { 0xC1, 0x01, 0x00, 0x00, 0x54, 0x8D, 0x01, 0x00 }; XclExpRecalcId::XclExpRecalcId() : XclExpDummyRecord(0x01C1, nDataRecalcId, sizeof(nDataRecalcId)) { } // ============================================================================ static const sal_uInt8 nDataBookExt[] = { 0x63, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 }; XclExpBookExt::XclExpBookExt() : XclExpDummyRecord(0x0863, nDataBookExt, sizeof(nDataBookExt)) { } // ============================================================================ XclRefmode::XclRefmode( const ScDocument& rDoc ) : XclExpBoolRecord( 0x000F, rDoc.GetAddressConvention() != formula::FormulaGrammar::CONV_XL_R1C1 ) { } void XclRefmode::SaveXml( XclExpXmlStream& rStrm ) { rStrm.WriteAttributes( XML_refMode, GetBool() ? "A1" : "R1C1", FSEND ); }