LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / xcl97 / xcl97rec.cxx
blob5ed6cccde2a262f74387ec447dd54bb872f9b2a2
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/sdtaitm.hxx>
21 #include <svx/svdotext.hxx>
22 #include <editeng/editobj.hxx>
23 #include <svx/svdoole2.hxx>
24 #include <sot/storage.hxx>
25 #include <svl/itemset.hxx>
26 #include <svx/svdocapt.hxx>
27 #include <svx/unoapi.hxx>
28 #include <editeng/writingmodeitem.hxx>
29 #include <tools/urlobj.hxx>
31 #include <rtl/math.hxx>
32 #include <rtl/uuid.h>
33 #include <sal/log.hxx>
34 #include <drwlayer.hxx>
36 #include <root.hxx>
37 #include <xcl97rec.hxx>
38 #include <xcl97esc.hxx>
39 #include <xeescher.hxx>
40 #include <xehelper.hxx>
41 #include <xelink.hxx>
42 #include <xlcontent.hxx>
44 #include <unotools/fltrcfg.hxx>
45 #include <editeng/adjustitem.hxx>
46 #include <editeng/eeitem.hxx>
47 #include <filter/msfilter/msoleexp.hxx>
49 #include <unotools/localedatawrapper.hxx>
51 #include <stdio.h>
53 #include <document.hxx>
54 #include <rangelst.hxx>
55 #include <docoptio.hxx>
56 #include <tabprotection.hxx>
58 #include <com/sun/star/embed/Aspects.hpp>
59 #include <com/sun/star/chart/XChartDocument.hpp>
60 #include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
61 #include <com/sun/star/chart2/XChartTypeContainer.hpp>
62 #include <com/sun/star/chart2/XChartDocument.hpp>
64 #include <sax/fastattribs.hxx>
65 #include <oox/token/tokens.hxx>
66 #include <oox/token/namespaces.hxx>
67 #include <oox/token/relationship.hxx>
68 #include <oox/export/shapes.hxx>
69 #include <oox/export/utils.hxx>
70 #include <oox/export/vmlexport.hxx>
71 #include <detfunc.hxx>
73 #include <memory>
75 using namespace ::com::sun::star;
76 using ::com::sun::star::uno::Reference;
77 using ::com::sun::star::uno::UNO_QUERY;
78 using ::com::sun::star::beans::XPropertySet;
79 using ::com::sun::star::drawing::XShape;
80 using ::oox::drawingml::ShapeExport;
81 using ::oox::vml::VMLExport;
82 using namespace oox;
84 XclExpObjList::XclExpObjList( const XclExpRoot& rRoot, XclEscherEx& rEscherEx ) :
85 XclExpRoot( rRoot ),
86 mnScTab( rRoot.GetCurrScTab() ),
87 mrEscherEx( rEscherEx )
89 pMsodrawingPerSheet.reset( new XclExpMsoDrawing( rEscherEx ) );
90 // open the DGCONTAINER and the patriarch group shape
91 mrEscherEx.OpenContainer( ESCHER_DgContainer );
92 tools::Rectangle aRect( 0, 0, 0, 0 );
93 mrEscherEx.EnterGroup( &aRect );
94 mrEscherEx.UpdateDffFragmentEnd();
97 XclExpObjList::~XclExpObjList()
99 maObjs.clear();
100 pMsodrawingPerSheet.reset();
101 pSolverContainer.reset();
104 sal_uInt16 XclExpObjList::Add( std::unique_ptr<XclObj> pObj )
106 OSL_ENSURE( maObjs.size() < 0xFFFF, "XclExpObjList::Add: too much for Xcl" );
108 size_t nSize = maObjs.size();
110 if ( nSize < 0xFFFF )
112 pObj->SetId( nSize+1 );
113 pObj->SetTab( mnScTab );
114 maObjs.push_back(std::move(pObj));
115 ++nSize;
117 else
119 nSize = 0;
122 return nSize;
125 std::unique_ptr<XclObj> XclExpObjList::pop_back ()
127 auto ret = std::move(maObjs.back());
128 maObjs.pop_back();
129 return ret;
132 void XclExpObjList::EndSheet()
134 // Is there still something in the stream? -> The solver container
135 if( mrEscherEx.HasPendingDffData() )
136 pSolverContainer.reset( new XclExpMsoDrawing( mrEscherEx ) );
138 // close the DGCONTAINER created by XclExpObjList ctor MSODRAWING
139 mrEscherEx.CloseContainer();
142 void XclExpObjList::Save( XclExpStream& rStrm )
144 //! Escher must be written, even if there are no objects
145 pMsodrawingPerSheet->Save( rStrm );
147 for ( const auto& rxObj : maObjs )
148 rxObj->Save( rStrm );
150 if( pSolverContainer )
151 pSolverContainer->Save( rStrm );
154 namespace {
156 bool IsFormControlObject( const XclObj *rObj )
158 switch( rObj->GetObjType() )
160 case EXC_OBJTYPE_CHECKBOX:
161 case EXC_OBJTYPE_BUTTON:
162 return true;
163 default:
164 return false;
168 bool IsVmlObject( const XclObj *rObj )
170 switch( rObj->GetObjType() )
172 case EXC_OBJTYPE_NOTE:
173 return true;
174 default:
175 return false;
179 sal_Int32 GetVmlObjectCount( XclExpObjList& rList )
181 return static_cast<sal_Int32>(std::count_if(rList.begin(), rList.end(),
182 [](const std::unique_ptr<XclObj>& rxObj) { return IsVmlObject( rxObj.get() ) || IsFormControlObject( rxObj.get() ); }));
185 bool IsValidObject( const XclObj& rObj )
187 if (rObj.GetObjType() == EXC_OBJTYPE_CHART)
189 // Chart object. Make sure it's a valid chart object. We skip
190 // invalid chart objects from exporting to prevent Excel from
191 // complaining on load.
193 const XclExpChartObj& rChartObj = static_cast<const XclExpChartObj&>(rObj);
194 uno::Reference<chart2::XChartDocument> xChartDoc(rChartObj.GetChartDoc(), uno::UNO_QUERY);
195 if (!xChartDoc.is())
196 return false;
198 uno::Reference<chart2::XDiagram> xDiagram = xChartDoc->getFirstDiagram();
199 if (!xDiagram.is())
200 return false;
202 uno::Reference<chart2::XCoordinateSystemContainer> xCooSysContainer(xDiagram, uno::UNO_QUERY);
203 if (!xCooSysContainer.is())
204 return false;
206 const uno::Sequence<uno::Reference<chart2::XCoordinateSystem>> xCooSysSeq = xCooSysContainer->getCoordinateSystems();
207 for (const auto& rCooSys : xCooSysSeq)
209 Reference<chart2::XChartTypeContainer> xChartTypeCont(rCooSys, uno::UNO_QUERY);
210 if (!xChartTypeCont.is())
211 return false;
213 uno::Sequence<uno::Reference<chart2::XChartType>> xChartTypeSeq = xChartTypeCont->getChartTypes();
214 if (!xChartTypeSeq.hasElements())
215 // No chart type. Not good.
216 return false;
220 return true;
223 void SaveDrawingMLObjects( XclExpObjList& rList, XclExpXmlStream& rStrm )
225 std::vector<XclObj*> aList;
226 aList.reserve(rList.size());
227 for (const auto& rxObj : rList)
229 if (IsVmlObject(rxObj.get()) || !IsValidObject(*rxObj))
230 continue;
232 aList.push_back(rxObj.get());
235 if (aList.empty())
236 return;
238 sal_Int32 nDrawing = drawingml::DrawingML::getNewDrawingUniqueId();
239 OUString sId;
240 sax_fastparser::FSHelperPtr pDrawing = rStrm.CreateOutputStream(
241 XclXmlUtils::GetStreamName( "xl/", "drawings/drawing", nDrawing ),
242 XclXmlUtils::GetStreamName( "../", "drawings/drawing", nDrawing ),
243 rStrm.GetCurrentStream()->getOutputStream(),
244 "application/vnd.openxmlformats-officedocument.drawing+xml",
245 oox::getRelationship(Relationship::DRAWING),
246 &sId );
248 rStrm.GetCurrentStream()->singleElement(XML_drawing, FSNS(XML_r, XML_id), sId.toUtf8());
250 rStrm.PushStream( pDrawing );
251 pDrawing->startElement( FSNS( XML_xdr, XML_wsDr ),
252 FSNS(XML_xmlns, XML_xdr), rStrm.getNamespaceURL(OOX_NS(dmlSpreadDr)).toUtf8(),
253 FSNS(XML_xmlns, XML_a), rStrm.getNamespaceURL(OOX_NS(dml)).toUtf8(),
254 FSNS(XML_xmlns, XML_r), rStrm.getNamespaceURL(OOX_NS(officeRel)).toUtf8() );
256 sal_Int32 nShapeId = 1000; // unique id of the shape inside one worksheet (not the whole document)
257 for (const auto& rpObj : aList)
259 // validate shapeId
260 if ( IsFormControlObject( rpObj ) )
262 XclExpTbxControlObj* pXclExpTbxControlObj = dynamic_cast<XclExpTbxControlObj*>(rpObj);
263 if (pXclExpTbxControlObj)
265 pXclExpTbxControlObj->setShapeId(++nShapeId);
269 rpObj->SaveXml(rStrm);
272 pDrawing->endElement( FSNS( XML_xdr, XML_wsDr ) );
274 rStrm.PopStream();
277 void SaveFormControlObjects(XclExpObjList& rList, XclExpXmlStream& rStrm)
279 bool hasControls = false;
280 for (const auto& rxObj : rList)
282 if (IsFormControlObject(rxObj.get()))
284 hasControls = true;
285 break;
289 if (!hasControls)
291 return;
294 sax_fastparser::FSHelperPtr& rWorksheet = rStrm.GetCurrentStream();
296 rWorksheet->startElement(FSNS(XML_mc, XML_AlternateContent),
297 FSNS(XML_xmlns, XML_mc), rStrm.getNamespaceURL(OOX_NS(mce)).toUtf8());
298 rWorksheet->startElement(FSNS(XML_mc, XML_Choice), XML_Requires, "x14");
299 rWorksheet->startElement(XML_controls);
301 for (const auto& rxObj : rList)
303 if (IsFormControlObject(rxObj.get()))
305 XclExpTbxControlObj* pXclExpTbxControlObj = dynamic_cast<XclExpTbxControlObj*>(rxObj.get());
306 if (pXclExpTbxControlObj)
308 const OUString aIdFormControlPr = pXclExpTbxControlObj->SaveControlPropertiesXml(rStrm);
309 pXclExpTbxControlObj->SaveSheetXml(rStrm, aIdFormControlPr);
314 rWorksheet->endElement(XML_controls);
315 rWorksheet->endElement(FSNS(XML_mc, XML_Choice));
316 rWorksheet->endElement(FSNS(XML_mc, XML_AlternateContent));
319 void SaveVmlObjects( XclExpObjList& rList, XclExpXmlStream& rStrm )
321 if( GetVmlObjectCount( rList ) == 0 )
322 return;
324 sal_Int32 nDrawing = drawingml::DrawingML::getNewVMLUniqueId();
325 OUString sId;
326 sax_fastparser::FSHelperPtr pVmlDrawing = rStrm.CreateOutputStream(
327 XclXmlUtils::GetStreamName( "xl/", "drawings/vmlDrawing", nDrawing ),
328 XclXmlUtils::GetStreamName( "../", "drawings/vmlDrawing", nDrawing ),
329 rStrm.GetCurrentStream()->getOutputStream(),
330 "application/vnd.openxmlformats-officedocument.vmlDrawing",
331 oox::getRelationship(Relationship::VMLDRAWING),
332 &sId );
334 rStrm.GetCurrentStream()->singleElement(XML_legacyDrawing, FSNS(XML_r, XML_id), sId.toUtf8());
336 rStrm.PushStream( pVmlDrawing );
337 pVmlDrawing->write("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n");
338 pVmlDrawing->startElement( XML_xml,
339 FSNS(XML_xmlns, XML_v), rStrm.getNamespaceURL(OOX_NS(vml)).toUtf8(),
340 FSNS(XML_xmlns, XML_o), rStrm.getNamespaceURL(OOX_NS(vmlOffice)).toUtf8(),
341 FSNS(XML_xmlns, XML_x), rStrm.getNamespaceURL(OOX_NS(vmlExcel)).toUtf8(),
342 FSNS(XML_xmlns, XML_w10), rStrm.getNamespaceURL(OOX_NS(vmlWord)).toUtf8() );
344 for ( const auto& rxObj : rList )
346 if (IsFormControlObject(rxObj.get()))
348 auto pFormControlObject = dynamic_cast<XclExpTbxControlObj*>(rxObj.get());
349 if (pFormControlObject)
351 pFormControlObject->SaveVml(rStrm);
355 if( !IsVmlObject( rxObj.get() ) )
356 continue;
357 rxObj->SaveXml( rStrm );
360 pVmlDrawing->endElement( XML_xml );
362 rStrm.PopStream();
367 void XclExpObjList::SaveXml( XclExpXmlStream& rStrm )
369 if( pSolverContainer )
370 pSolverContainer->SaveXml( rStrm );
372 if( maObjs.empty())
373 return;
375 SaveDrawingMLObjects( *this, rStrm );
376 SaveVmlObjects( *this, rStrm );
377 SaveFormControlObjects( *this, rStrm );
380 // --- class XclObj --------------------------------------------------
382 XclObj::XclObj( XclExpObjectManager& rObjMgr, sal_uInt16 nObjType, bool bOwnEscher ) :
383 XclExpRecord( EXC_ID_OBJ, 26 ),
384 mrEscherEx( rObjMgr.GetEscherEx() ),
385 mnObjType( nObjType ),
386 nObjId(0),
387 nGrbit( 0x6011 ), // AutoLine, AutoFill, Printable, Locked
388 mnScTab(0),
389 bFirstOnSheet( !rObjMgr.HasObj() ),
390 mbOwnEscher( bOwnEscher )
392 //! first object continues the first MSODRAWING record
393 if ( bFirstOnSheet )
394 pMsodrawing = rObjMgr.GetMsodrawingPerSheet();
395 else
396 pMsodrawing = new XclExpMsoDrawing( mrEscherEx );
399 XclObj::~XclObj()
401 if ( !bFirstOnSheet )
402 delete pMsodrawing;
403 pClientTextbox.reset();
404 pTxo.reset();
407 void XclObj::ImplWriteAnchor( const SdrObject* pSdrObj, const tools::Rectangle* pChildAnchor )
409 if( pChildAnchor )
411 mrEscherEx.AddChildAnchor( *pChildAnchor );
413 else if( pSdrObj )
415 std::unique_ptr< XclExpDffAnchorBase > xDffAnchor( mrEscherEx.CreateDffAnchor( *pSdrObj ) );
416 xDffAnchor->WriteDffData( mrEscherEx );
420 void XclObj::SetEscherShapeType( sal_uInt16 nType )
422 //ToDo: what about the other defined or... types?
423 switch ( nType )
425 case ESCHER_ShpInst_Line :
426 mnObjType = EXC_OBJTYPE_LINE;
427 break;
428 case ESCHER_ShpInst_Rectangle :
429 case ESCHER_ShpInst_RoundRectangle :
430 mnObjType = EXC_OBJTYPE_RECTANGLE;
431 break;
432 case ESCHER_ShpInst_Ellipse :
433 mnObjType = EXC_OBJTYPE_OVAL;
434 break;
435 case ESCHER_ShpInst_Arc :
436 mnObjType = EXC_OBJTYPE_ARC;
437 break;
438 case ESCHER_ShpInst_TextBox :
439 mnObjType = EXC_OBJTYPE_TEXT;
440 break;
441 case ESCHER_ShpInst_PictureFrame :
442 mnObjType = EXC_OBJTYPE_PICTURE;
443 break;
444 default:
445 mnObjType = EXC_OBJTYPE_DRAWING;
449 void XclObj::SetText( const XclExpRoot& rRoot, const SdrTextObj& rObj )
451 OSL_ENSURE( !pClientTextbox, "XclObj::SetText: already set" );
452 if ( !pClientTextbox )
454 mrEscherEx.UpdateDffFragmentEnd();
455 pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
456 mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
457 mrEscherEx.UpdateDffFragmentEnd();
458 pTxo.reset( new XclTxo( rRoot, rObj ) );
462 void XclObj::WriteBody( XclExpStream& rStrm )
464 OSL_ENSURE( mnObjType != EXC_OBJTYPE_UNKNOWN, "XclObj::WriteBody - unknown type" );
466 // create a substream to be able to create subrecords
467 SvMemoryStream aMemStrm;
468 std::optional< XclExpStream > pXclStrm( std::in_place, aMemStrm, rStrm.GetRoot() );
470 // write the ftCmo subrecord
471 pXclStrm->StartRecord( EXC_ID_OBJCMO, 18 );
472 *pXclStrm << mnObjType << nObjId << nGrbit;
473 pXclStrm->WriteZeroBytes( 12 );
474 pXclStrm->EndRecord();
476 // write other subrecords
477 WriteSubRecs( *pXclStrm );
479 // write the ftEnd subrecord
480 pXclStrm->StartRecord( EXC_ID_OBJEND, 0 );
481 pXclStrm->EndRecord();
483 // copy the data to the OBJ record
484 pXclStrm.reset();
485 aMemStrm.Seek( 0 );
486 rStrm.CopyFromStream( aMemStrm );
489 void XclObj::Save( XclExpStream& rStrm )
491 // MSODRAWING record (msofbtSpContainer)
492 if ( !bFirstOnSheet )
493 pMsodrawing->Save( rStrm );
495 // OBJ
496 XclExpRecord::Save( rStrm );
498 // second MSODRAWING record and TXO and CONTINUE records
499 SaveTextRecs( rStrm );
502 void XclObj::WriteSubRecs( XclExpStream& rStrm )
504 if( mnObjType != EXC_OBJTYPE_NOTE )
505 return;
507 // FtNts subrecord
508 AddRecSize( 26 );
509 // ft, cb
510 rStrm << EXC_ID_OBJNTS << sal_uInt16(0x0016);
511 sal_uInt8 aGUID[16];
512 rtl_createUuid( aGUID, nullptr, false );
513 // guid
514 rStrm.SetSliceSize( 16 );
515 for( int i = 0; i < 16; i++ )
516 rStrm << aGUID[i];
517 rStrm.SetSliceSize( 0 );
518 // fSharedNote
519 rStrm << sal_uInt16(0);
520 // unused
521 rStrm.WriteZeroBytes( 4 );
524 void XclObj::SaveTextRecs( XclExpStream& rStrm )
526 // MSODRAWING record (msofbtClientTextbox)
527 if ( pClientTextbox )
528 pClientTextbox->Save( rStrm );
529 // TXO and CONTINUE records
530 if ( pTxo )
531 pTxo->Save( rStrm );
534 // --- class XclObjComment ------------------------------------------
536 // tdf#118662 static helper to allow single function access as friend in SdrCaptionObj
537 void setSuppressGetBitmapFromXclObjComment(SdrCaptionObj* pSdrCaptionObj, bool bValue)
539 if(nullptr != pSdrCaptionObj)
541 pSdrCaptionObj->setSuppressGetBitmap(bValue);
545 XclObjComment::XclObjComment( XclExpObjectManager& rObjMgr, const tools::Rectangle& rRect, const EditTextObject& rEditObj, SdrCaptionObj* pCaption, bool bVisible, const ScAddress& rAddress, const tools::Rectangle &rFrom, const tools::Rectangle &rTo ) :
546 XclObj( rObjMgr, EXC_OBJTYPE_NOTE, true )
547 , maScPos( rAddress )
548 , mpCaption( pCaption )
549 , mbVisible( bVisible )
550 , maFrom ( rFrom )
551 , maTo ( rTo )
553 // tdf#118662 due to no longer cloning the SdrCaptionObj an old 'hack' using the
554 // fact that no Graphics gets created when a SdrObject is not inserted in a SdrPage
555 // does not work anymore. In SvxShape::GetBitmap that info was used, and here the
556 // SdrCaptionObj was cloned for the only reason to have one not added to a SdrPage.
557 // To emulate old behaviour, use a boolean flag at the SdrCaptionObj.
558 setSuppressGetBitmapFromXclObjComment(mpCaption, true);
560 ProcessEscherObj( rObjMgr.GetRoot(), rRect, pCaption, bVisible);
561 // TXO
562 pTxo .reset(new XclTxo( rObjMgr.GetRoot(), rEditObj, pCaption ));
565 static void lcl_FillProps( EscherPropertyContainer& rPropOpt, SdrObject* pCaption, bool bVisible )
567 if( pCaption )
569 Reference< XShape > aXShape = GetXShapeForSdrObject( pCaption );
570 Reference< XPropertySet > aXPropSet( aXShape, UNO_QUERY );
571 if( aXPropSet.is() )
573 rPropOpt.CreateFillProperties( aXPropSet, true);
575 rPropOpt.AddOpt( ESCHER_Prop_lTxid, 0 ); // undocumented
576 rPropOpt.AddOpt( 0x0158, 0x00000000 ); // undocumented
578 sal_uInt32 nValue = 0;
579 if( !rPropOpt.GetOpt( ESCHER_Prop_FitTextToShape, nValue ) )
580 rPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
582 // Maybe the colour is the same as the 'ToolTip' System colour, but the tooltip
583 // colour shouldn't have influence on the fill colour of the exported shape
584 if( !rPropOpt.GetOpt( ESCHER_Prop_fillColor, nValue ) )
585 rPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000050 );
586 if( !rPropOpt.GetOpt( ESCHER_Prop_fillBackColor, nValue ) )
587 rPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000050 );
588 if( !rPropOpt.GetOpt( ESCHER_Prop_fNoFillHitTest, nValue ) )
589 rPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 ); // bool field
590 if( !rPropOpt.GetOpt( ESCHER_Prop_shadowColor, nValue ) )
591 rPropOpt.AddOpt( ESCHER_Prop_shadowColor, 0x00000000 );
592 if( !rPropOpt.GetOpt( ESCHER_Prop_fshadowObscured, nValue ) ) // bool field
593 rPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x00030003 ); // bool field
597 sal_uInt32 nFlags = 0x000A0000;
598 ::set_flag( nFlags, sal_uInt32(2), !bVisible );
599 rPropOpt.AddOpt( ESCHER_Prop_fPrint, nFlags ); // bool field
602 void XclObjComment::ProcessEscherObj( const XclExpRoot& rRoot, const tools::Rectangle& rRect, SdrObject* pCaption, const bool bVisible )
604 EscherPropertyContainer aPropOpt;
606 lcl_FillProps( aPropOpt, pCaption, bVisible );
608 nGrbit = 0; // all off: AutoLine, AutoFill, Printable, Locked
609 mrEscherEx.OpenContainer( ESCHER_SpContainer );
610 mrEscherEx.AddShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
611 aPropOpt.Commit( mrEscherEx.GetStream() );
613 XclExpDffNoteAnchor( rRoot, rRect ).WriteDffData( mrEscherEx );
615 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
616 mrEscherEx.UpdateDffFragmentEnd();
618 //! Be sure to construct the MSODRAWING ClientTextbox record _after_ the
619 //! base OBJ's MSODRAWING record Escher data is completed.
620 pClientTextbox.reset( new XclExpMsoDrawing( mrEscherEx ) );
621 mrEscherEx.AddAtom( 0, ESCHER_ClientTextbox ); // TXO record
622 mrEscherEx.UpdateDffFragmentEnd();
623 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
626 XclObjComment::~XclObjComment()
628 // tdf#118662 reset flag
629 setSuppressGetBitmapFromXclObjComment(mpCaption, false);
632 void XclObjComment::Save( XclExpStream& rStrm )
634 // content of this record
635 XclObj::Save( rStrm );
638 namespace {
640 class VmlCommentExporter : public VMLExport
642 ScAddress maScPos;
643 SdrCaptionObj* mpCaption;
644 bool mbVisible;
645 tools::Rectangle maFrom;
646 tools::Rectangle maTo;
648 public:
649 VmlCommentExporter ( const sax_fastparser::FSHelperPtr& p, const ScAddress& aScPos, SdrCaptionObj* pCaption, bool bVisible, const tools::Rectangle &aFrom, const tools::Rectangle &aTo );
650 protected:
651 virtual void Commit( EscherPropertyContainer& rProps, const tools::Rectangle& rRect ) override;
652 using VMLExport::StartShape;
653 virtual sal_Int32 StartShape() override;
654 using VMLExport::EndShape;
655 virtual void EndShape( sal_Int32 nShapeElement ) override;
660 VmlCommentExporter::VmlCommentExporter( const sax_fastparser::FSHelperPtr& p, const ScAddress& aScPos, SdrCaptionObj* pCaption,
661 bool bVisible, const tools::Rectangle &aFrom, const tools::Rectangle &aTo )
662 : VMLExport( p )
663 , maScPos( aScPos )
664 , mpCaption( pCaption )
665 , mbVisible( bVisible )
666 , maFrom ( aFrom )
667 , maTo ( aTo )
671 void VmlCommentExporter::Commit( EscherPropertyContainer& rProps, const tools::Rectangle& rRect )
673 lcl_FillProps( rProps, mpCaption, mbVisible );
674 rProps.AddOpt( ESCHER_Prop_fHidden, sal_uInt32(mbVisible) ); // bool field
676 // shadow property value for comment ( set in lcl_FillProps [*] ) has been
677 // overwritten by new value ( 0x20000 ) in the generic part of the export
678 // ( see EscherPropertyContainer::CreateShadowProperties )
679 // Safer option here is to just force the needed value here for oox vml
680 // export alone ( and avoid potential problems with binary export )
681 // #TODO investigate value of ESCHER_Prop_fshadowObscured generally
682 // in binary export ( if indeed this value is good for binary export )
683 // we can change the heuristics and/or initialisation path and get
684 // rid of line below.
685 // [*] lcl_FillProps seems to be called twice when exporting to xlsx
686 // once from XclObjComment::ProcessEscherObj #TODO look into that also
687 rProps.AddOpt( ESCHER_Prop_fshadowObscured, 0x00030003 ); // force value for comments
689 VMLExport::Commit( rProps, rRect );
692 sal_Int32 VmlCommentExporter::StartShape()
694 AddShapeAttribute( XML_type, "#_x0000_t202" );
696 sal_Int32 nId = VMLExport::StartShape();
698 return nId;
701 static const char* lcl_GetHorizAlignFromItemSetChar(const SfxItemSet& rItemSet)
703 switch (rItemSet.Get(EE_PARA_JUST).GetAdjust())
705 case SvxAdjust::Center:
706 return "Center";
707 case SvxAdjust::Right:
708 return "Right";
709 case SvxAdjust::Block:
710 return "Justify";
711 default:
712 return "Left";
716 static const char* lcl_GetVertAlignFromItemSetChar( const SfxItemSet& rItemSet )
718 switch( rItemSet.Get( SDRATTR_TEXT_VERTADJUST ).GetValue() )
720 case SDRTEXTVERTADJUST_CENTER:
721 return "Center";
722 case SDRTEXTVERTADJUST_BOTTOM:
723 return "Bottom";
724 case SDRTEXTVERTADJUST_BLOCK:
725 return "Justify";
726 case SDRTEXTVERTADJUST_TOP:
727 default:
728 return "Top";
732 void VmlCommentExporter::EndShape( sal_Int32 nShapeElement )
734 char pAnchor[100];
735 sax_fastparser::FSHelperPtr pVmlDrawing = GetFS();
736 snprintf( pAnchor, 100, "%" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64 ", %" SAL_PRIdINT64,
737 sal_Int64(maFrom.Left()), sal_Int64(maFrom.Top()), sal_Int64(maFrom.Right()), sal_Int64(maFrom.Bottom()),
738 sal_Int64(maTo.Left()), sal_Int64(maTo.Top()), sal_Int64(maTo.Right()), sal_Int64(maTo.Bottom()) );
740 // Getting comment text alignments
741 const char* pVertAlign = lcl_GetVertAlignFromItemSetChar(mpCaption->GetMergedItemSet());
742 const char* pHorizAlign = lcl_GetHorizAlignFromItemSetChar(mpCaption->GetMergedItemSet());
744 pVmlDrawing->startElement(FSNS(XML_x, XML_ClientData), XML_ObjectType, "Note");
745 pVmlDrawing->singleElement(FSNS(XML_x, XML_MoveWithCells));
746 pVmlDrawing->singleElement(FSNS(XML_x, XML_SizeWithCells));
747 XclXmlUtils::WriteElement( pVmlDrawing, FSNS( XML_x, XML_Anchor ), pAnchor );
748 XclXmlUtils::WriteElement( pVmlDrawing, FSNS( XML_x, XML_AutoFill ), "False" );
749 XclXmlUtils::WriteElement( pVmlDrawing, FSNS( XML_x, XML_TextVAlign ), pVertAlign );
750 XclXmlUtils::WriteElement( pVmlDrawing, FSNS( XML_x, XML_TextHAlign ), pHorizAlign );
751 XclXmlUtils::WriteElement( pVmlDrawing, FSNS( XML_x, XML_Row ), maScPos.Row() );
752 XclXmlUtils::WriteElement( pVmlDrawing, FSNS(XML_x, XML_Column), sal_Int32(maScPos.Col()));
753 if(mbVisible)
754 pVmlDrawing->singleElement(FSNS(XML_x, XML_Visible));
755 pVmlDrawing->endElement( FSNS( XML_x, XML_ClientData ) );
757 VMLExport::EndShape( nShapeElement );
760 void XclObjComment::SaveXml( XclExpXmlStream& rStrm )
762 VmlCommentExporter aCommentExporter( rStrm.GetCurrentStream(), maScPos, mpCaption, mbVisible, maFrom, maTo );
763 aCommentExporter.AddSdrObject( *mpCaption );
766 // --- class XclObjDropDown ------------------------------------------
768 XclObjDropDown::XclObjDropDown( XclExpObjectManager& rObjMgr, const ScAddress& rPos, bool bFilt ) :
769 XclObj( rObjMgr, EXC_OBJTYPE_DROPDOWN, true ),
770 bIsFiltered( bFilt )
772 SetLocked( true );
773 SetPrintable( false );
774 SetAutoFill( true );
775 SetAutoLine( false );
776 nGrbit |= 0x0100; // undocumented
777 mrEscherEx.OpenContainer( ESCHER_SpContainer );
778 mrEscherEx.AddShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveAnchor | ShapeFlag::HaveShapeProperty );
779 EscherPropertyContainer aPropOpt;
780 aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x01040104 ); // bool field
781 aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); // bool field
782 aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00010000 ); // bool field
783 aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x00080000 ); // bool field
784 aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x000A0000 ); // bool field
785 aPropOpt.Commit( mrEscherEx.GetStream() );
787 XclExpDffDropDownAnchor( rObjMgr.GetRoot(), rPos ).WriteDffData( mrEscherEx );
789 mrEscherEx.AddAtom( 0, ESCHER_ClientData ); // OBJ record
790 mrEscherEx.UpdateDffFragmentEnd();
791 mrEscherEx.CloseContainer(); // ESCHER_SpContainer
793 // old size + ftSbs + ftLbsData
794 AddRecSize( 24 + 20 );
797 XclObjDropDown::~XclObjDropDown()
801 void XclObjDropDown::WriteSubRecs( XclExpStream& rStrm )
803 // ftSbs subrecord - Scroll bars (dummy)
804 rStrm.StartRecord( EXC_ID_OBJSBS, 20 );
805 rStrm.WriteZeroBytes( 20 );
806 rStrm.EndRecord();
808 // ftLbsData subrecord - Listbox data
809 sal_uInt16 nDropDownFlags = 0;
810 ::insert_value( nDropDownFlags, EXC_OBJ_DROPDOWN_SIMPLE, 0, 2 );
811 ::set_flag( nDropDownFlags, EXC_OBJ_DROPDOWN_FILTERED, bIsFiltered );
812 rStrm.StartRecord( EXC_ID_OBJLBSDATA, 16 );
813 rStrm << sal_uInt32(0) << sal_uInt16(0) << sal_uInt16(0x0301) << sal_uInt16(0)
814 << nDropDownFlags << sal_uInt16( 20 ) << sal_uInt16( 130 );
815 rStrm.EndRecord();
818 // --- class XclTxo --------------------------------------------------
820 static sal_uInt8 lcl_GetHorAlignFromItemSet( const SfxItemSet& rItemSet )
822 sal_uInt8 nHorAlign = EXC_OBJ_HOR_LEFT;
824 switch( rItemSet.Get( EE_PARA_JUST ).GetAdjust() )
826 case SvxAdjust::Left: nHorAlign = EXC_OBJ_HOR_LEFT; break;
827 case SvxAdjust::Center: nHorAlign = EXC_OBJ_HOR_CENTER; break;
828 case SvxAdjust::Right: nHorAlign = EXC_OBJ_HOR_RIGHT; break;
829 case SvxAdjust::Block: nHorAlign = EXC_OBJ_HOR_JUSTIFY; break;
830 default:;
832 return nHorAlign;
835 static sal_uInt8 lcl_GetVerAlignFromItemSet( const SfxItemSet& rItemSet )
837 sal_uInt8 nVerAlign = EXC_OBJ_VER_TOP;
839 switch( rItemSet.Get( SDRATTR_TEXT_VERTADJUST ).GetValue() )
841 case SDRTEXTVERTADJUST_TOP: nVerAlign = EXC_OBJ_VER_TOP; break;
842 case SDRTEXTVERTADJUST_CENTER: nVerAlign = EXC_OBJ_VER_CENTER; break;
843 case SDRTEXTVERTADJUST_BOTTOM: nVerAlign = EXC_OBJ_VER_BOTTOM; break;
844 case SDRTEXTVERTADJUST_BLOCK: nVerAlign = EXC_OBJ_VER_JUSTIFY; break;
845 default:;
847 return nVerAlign;
850 XclTxo::XclTxo( const OUString& rString, sal_uInt16 nFontIx ) :
851 mpString( std::make_shared<XclExpString>( rString ) ),
852 mnRotation( EXC_OBJ_ORIENT_NONE ),
853 mnHorAlign( EXC_OBJ_HOR_LEFT ),
854 mnVerAlign( EXC_OBJ_VER_TOP )
856 if( mpString->Len() )
858 // If there is text, Excel *needs* the 2nd CONTINUE record with at least two format runs
859 mpString->AppendFormat( 0, nFontIx );
860 mpString->AppendFormat( mpString->Len(), EXC_FONT_APP );
864 XclTxo::XclTxo( const XclExpRoot& rRoot, const SdrTextObj& rTextObj ) :
865 mpString( XclExpStringHelper::CreateString( rRoot, rTextObj ) ),
866 mnRotation( EXC_OBJ_ORIENT_NONE ),
867 mnHorAlign( EXC_OBJ_HOR_LEFT ),
868 mnVerAlign( EXC_OBJ_VER_TOP )
870 // additional alignment and orientation items
871 const SfxItemSet& rItemSet = rTextObj.GetMergedItemSet();
873 // horizontal alignment
874 SetHorAlign( lcl_GetHorAlignFromItemSet( rItemSet ) );
876 // vertical alignment
877 SetVerAlign( lcl_GetVerAlignFromItemSet( rItemSet ) );
879 // rotation
880 Degree100 nAngle = rTextObj.GetRotateAngle();
881 if( (4500_deg100 < nAngle) && (nAngle < 13500_deg100) )
882 mnRotation = EXC_OBJ_ORIENT_90CCW;
883 else if( (22500_deg100 < nAngle) && (nAngle < 31500_deg100) )
884 mnRotation = EXC_OBJ_ORIENT_90CW;
885 else
886 mnRotation = EXC_OBJ_ORIENT_NONE;
889 XclTxo::XclTxo( const XclExpRoot& rRoot, const EditTextObject& rEditObj, SdrObject* pCaption ) :
890 mpString( XclExpStringHelper::CreateString( rRoot, rEditObj ) ),
891 mnRotation( EXC_OBJ_ORIENT_NONE ),
892 mnHorAlign( EXC_OBJ_HOR_LEFT ),
893 mnVerAlign( EXC_OBJ_VER_TOP )
895 if(!pCaption)
896 return;
898 // Excel has one alignment per NoteObject while Calc supports
899 // one alignment per paragraph - use the first paragraph
900 // alignment (if set) as our overall alignment.
901 OUString aParaText( rEditObj.GetText( 0 ) );
902 if( !aParaText.isEmpty() )
904 const SfxItemSet& aSet( rEditObj.GetParaAttribs( 0));
905 const SfxPoolItem* pItem = nullptr;
906 if( aSet.GetItemState( EE_PARA_JUST, true, &pItem ) == SfxItemState::SET )
908 SvxAdjust eEEAlign = static_cast< const SvxAdjustItem& >( *pItem ).GetAdjust();
909 pCaption->SetMergedItem( SvxAdjustItem( eEEAlign, EE_PARA_JUST ) );
912 const SfxItemSet& rItemSet = pCaption->GetMergedItemSet();
914 // horizontal alignment
915 SetHorAlign( lcl_GetHorAlignFromItemSet( rItemSet ) );
917 // vertical alignment
918 SetVerAlign( lcl_GetVerAlignFromItemSet( rItemSet ) );
920 // orientation alignment
921 const SvxWritingModeItem& rItem = rItemSet.Get( SDRATTR_TEXTDIRECTION );
922 if( rItem.GetValue() == css::text::WritingMode_TB_RL )
923 mnRotation = EXC_OBJ_ORIENT_90CW;
926 void XclTxo::SaveCont( XclExpStream& rStrm )
928 OSL_ENSURE( mpString, "XclTxo::SaveCont - missing string" );
930 // #i96858# do not save existing string formatting if text is empty
931 sal_uInt16 nRunLen = mpString->IsEmpty() ? 0 : (8 * mpString->GetFormatsCount());
932 // alignment
933 sal_uInt16 nFlags = 0;
934 ::insert_value( nFlags, mnHorAlign, 1, 3 );
935 ::insert_value( nFlags, mnVerAlign, 4, 3 );
937 rStrm << nFlags << mnRotation;
938 rStrm.WriteZeroBytes( 6 );
939 rStrm << mpString->Len() << nRunLen << sal_uInt32( 0 );
942 void XclTxo::Save( XclExpStream& rStrm )
944 // Write the TXO part
945 ExcRecord::Save( rStrm );
947 // CONTINUE records are only written if there is some text
948 if( mpString->IsEmpty() )
949 return;
951 // CONTINUE for character array
952 rStrm.StartRecord( EXC_ID_CONT, mpString->GetBufferSize() + 1 );
953 rStrm << static_cast< sal_uInt8 >( mpString->GetFlagField() & EXC_STRF_16BIT ); // only Unicode flag
954 mpString->WriteBuffer( rStrm );
955 rStrm.EndRecord();
957 // CONTINUE for formatting runs
958 rStrm.StartRecord( EXC_ID_CONT, 8 * mpString->GetFormatsCount() );
959 const XclFormatRunVec& rFormats = mpString->GetFormats();
960 for( const auto& rFormat : rFormats )
961 rStrm << rFormat.mnChar << rFormat.mnFontIdx << sal_uInt32( 0 );
962 rStrm.EndRecord();
965 sal_uInt16 XclTxo::GetNum() const
967 return EXC_ID_TXO;
970 std::size_t XclTxo::GetLen() const
972 return 18;
975 // --- class XclObjOle -------------------------------------------
977 XclObjOle::XclObjOle( XclExpObjectManager& rObjMgr, const SdrObject& rObj ) :
978 XclObj( rObjMgr, EXC_OBJTYPE_PICTURE ),
979 rOleObj( rObj ),
980 pRootStorage( rObjMgr.GetRoot().GetRootStorage().get() )
984 XclObjOle::~XclObjOle()
988 void XclObjOle::WriteSubRecs( XclExpStream& rStrm )
990 // write only as embedded, not linked
991 OUString aStorageName( "MBD" );
992 char aBuf[ sizeof(sal_uInt32) * 2 + 1 ];
993 // FIXME Eeek! Is this just a way to get a unique id?
994 sal_uInt32 nPictureId = sal_uInt32(reinterpret_cast<sal_uIntPtr>(this) >> 2);
995 sprintf( aBuf, "%08X", static_cast< unsigned int >( nPictureId ) );
996 aStorageName += OUString::createFromAscii(aBuf);
997 tools::SvRef<SotStorage> xOleStg = pRootStorage->OpenSotStorage( aStorageName );
998 if( !xOleStg.is() )
999 return;
1001 uno::Reference < embed::XEmbeddedObject > xObj( static_cast<const SdrOle2Obj&>(rOleObj).GetObjRef() );
1002 if ( !xObj.is() )
1003 return;
1005 // set version to "old" version, because it must be
1006 // saved in MS notation.
1007 sal_uInt32 nFl = 0;
1008 const SvtFilterOptions& rFltOpts = SvtFilterOptions::Get();
1009 if( rFltOpts.IsMath2MathType() )
1010 nFl |= OLE_STARMATH_2_MATHTYPE;
1012 if( rFltOpts.IsWriter2WinWord() )
1013 nFl |= OLE_STARWRITER_2_WINWORD;
1015 if( rFltOpts.IsCalc2Excel() )
1016 nFl |= OLE_STARCALC_2_EXCEL;
1018 if( rFltOpts.IsImpress2PowerPoint() )
1019 nFl |= OLE_STARIMPRESS_2_POWERPOINT;
1021 SvxMSExportOLEObjects aOLEExpFilt( nFl );
1022 aOLEExpFilt.ExportOLEObject( xObj, *xOleStg );
1024 // OBJCF subrecord, undocumented as usual
1025 rStrm.StartRecord( EXC_ID_OBJCF, 2 );
1026 rStrm << sal_uInt16(0x0002);
1027 rStrm.EndRecord();
1029 // OBJFLAGS subrecord, undocumented as usual
1030 rStrm.StartRecord( EXC_ID_OBJFLAGS, 2 );
1031 sal_uInt16 nFlags = EXC_OBJ_PIC_MANUALSIZE;
1032 ::set_flag( nFlags, EXC_OBJ_PIC_SYMBOL, static_cast<const SdrOle2Obj&>(rOleObj).GetAspect() == embed::Aspects::MSOLE_ICON );
1033 rStrm << nFlags;
1034 rStrm.EndRecord();
1036 // OBJPICTFMLA subrecord, undocumented as usual
1037 XclExpString aName( xOleStg->GetUserName() );
1038 sal_uInt16 nPadLen = static_cast<sal_uInt16>(aName.GetSize() & 0x01);
1039 sal_uInt16 nFmlaLen = static_cast< sal_uInt16 >( 12 + aName.GetSize() + nPadLen );
1040 sal_uInt16 nSubRecLen = nFmlaLen + 6;
1042 rStrm.StartRecord( EXC_ID_OBJPICTFMLA, nSubRecLen );
1043 rStrm << nFmlaLen
1044 << sal_uInt16( 5 ) << sal_uInt32( 0 ) << sal_uInt8( 2 )
1045 << sal_uInt32( 0 ) << sal_uInt8( 3 )
1046 << aName;
1047 if( nPadLen )
1048 rStrm << sal_uInt8( 0 ); // pad byte
1049 rStrm << nPictureId;
1050 rStrm.EndRecord();
1053 void XclObjOle::Save( XclExpStream& rStrm )
1055 // content of this record
1056 XclObj::Save( rStrm );
1059 // --- class XclObjAny -------------------------------------------
1061 XclObjAny::XclObjAny( XclExpObjectManager& rObjMgr, const Reference< XShape >& rShape, ScDocument* pDoc )
1062 : XclObj( rObjMgr, EXC_OBJTYPE_UNKNOWN )
1063 , mxShape( rShape )
1064 , mpDoc(pDoc)
1068 XclObjAny::~XclObjAny()
1072 void XclObjAny::WriteSubRecs( XclExpStream& rStrm )
1074 if( mnObjType == EXC_OBJTYPE_GROUP )
1075 // ftGmo subrecord
1076 rStrm << EXC_ID_OBJGMO << sal_uInt16(2) << sal_uInt16(0);
1079 void XclObjAny::Save( XclExpStream& rStrm )
1081 if( mnObjType == EXC_OBJTYPE_GROUP )
1082 // old size + ftGmo
1083 AddRecSize( 6 );
1085 // content of this record
1086 XclObj::Save( rStrm );
1089 // --- class ExcBof8_Base --------------------------------------------
1091 ExcBof8_Base::ExcBof8_Base()
1093 nVers = 0x0600;
1094 nRupBuild = 0x0dbb;
1095 nRupYear = 0x07cc;
1098 void XclObjAny::WriteFromTo( XclExpXmlStream& rStrm, const Reference< XShape >& rShape, SCTAB nTab )
1100 sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1102 awt::Point aTopLeft = rShape->getPosition();
1103 awt::Size aSize = rShape->getSize();
1105 // There are a few cases where we must adjust these values
1106 // Do not adjust objects, which have rotation incorporated into their points
1107 // but report a rotation angle nevertheless.
1108 SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rShape);
1109 if (pObj && pObj->GetObjIdentifier() != OBJ_LINE && pObj->GetObjIdentifier() != OBJ_PLIN
1110 && pObj->GetObjIdentifier() != OBJ_PATHLINE && pObj->GetObjIdentifier() != OBJ_FREELINE
1111 && pObj->GetObjIdentifier() != OBJ_PATHPLIN)
1113 Degree100 nRotation = NormAngle36000(pObj->GetRotateAngle());
1114 if (nRotation)
1116 sal_Int16 nHalfWidth = aSize.Width / 2;
1117 sal_Int16 nHalfHeight = aSize.Height / 2;
1119 // Center of bounding box of the rotated shape
1120 const auto aSnapRectCenter(pObj->GetSnapRect().Center());
1121 aTopLeft.X = aSnapRectCenter.X() - nHalfWidth;
1122 aTopLeft.Y = aSnapRectCenter.Y() - nHalfHeight;
1124 // MSO changes the anchor positions at these angles and that does an extra 90 degrees
1125 // rotation on our shapes, so we output it in such position that MSO
1126 // can draw this shape correctly.
1127 if ((nRotation > 4500_deg100 && nRotation <= 13500_deg100) || (nRotation > 22500_deg100 && nRotation <= 31500_deg100))
1129 aTopLeft.X = aTopLeft.X - nHalfHeight + nHalfWidth;
1130 aTopLeft.Y = aTopLeft.Y - nHalfWidth + nHalfHeight;
1132 std::swap(aSize.Width, aSize.Height);
1137 tools::Rectangle aLocation( aTopLeft.X, aTopLeft.Y, aTopLeft.X + aSize.Width, aTopLeft.Y + aSize.Height );
1138 ScRange aRange = rStrm.GetRoot().GetDoc().GetRange( nTab, aLocation );
1139 tools::Rectangle aRangeRect = rStrm.GetRoot().GetDoc().GetMMRect( aRange.aStart.Col(), aRange.aStart.Row(),
1140 aRange.aEnd.Col()-1, aRange.aEnd.Row()-1,
1141 nTab );
1143 pDrawing->startElement(FSNS(XML_xdr, XML_from));
1144 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_col ), static_cast<sal_Int32>(aRange.aStart.Col()) );
1145 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_colOff ),
1146 oox::drawingml::convertHmmToEmu( aLocation.Left() - aRangeRect.Left() ) );
1147 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_row ), static_cast<sal_Int32>(aRange.aStart.Row()) );
1148 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_rowOff ),
1149 oox::drawingml::convertHmmToEmu( aLocation.Top() - aRangeRect.Top() ) );
1150 pDrawing->endElement( FSNS( XML_xdr, XML_from ) );
1152 pDrawing->startElement(FSNS(XML_xdr, XML_to));
1153 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_col ), static_cast<sal_Int32>(aRange.aEnd.Col()) );
1154 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_colOff ),
1155 oox::drawingml::convertHmmToEmu( aLocation.Right() - aRangeRect.Right() ) );
1156 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_row ), static_cast<sal_Int32>(aRange.aEnd.Row()) );
1157 XclXmlUtils::WriteElement( pDrawing, FSNS( XML_xdr, XML_rowOff ),
1158 oox::drawingml::convertHmmToEmu( aLocation.Bottom() - aRangeRect.Bottom() ) );
1159 pDrawing->endElement( FSNS( XML_xdr, XML_to ) );
1162 void XclObjAny::WriteFromTo( XclExpXmlStream& rStrm, const XclObjAny& rObj )
1164 WriteFromTo( rStrm, rObj.GetShape(), rObj.GetTab() );
1167 static const char*
1168 GetEditAs( const XclObjAny& rObj )
1170 if( const SdrObject* pShape = EscherEx::GetSdrObject( rObj.GetShape() ) )
1172 switch( ScDrawLayer::GetAnchorType( *pShape ) )
1174 case SCA_CELL:
1175 return "oneCell";
1176 case SCA_CELL_RESIZE:
1177 return "twoCell";
1178 default:
1179 case SCA_PAGE:
1180 break; // absolute
1183 return "absolute";
1186 namespace {
1188 ScRefFlags parseRange(const OUString& rString, ScRange& rRange, const ScDocument& rDoc)
1190 // start with the address convention set in the document
1191 formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
1192 ScRefFlags nResult = rRange.Parse(rString, rDoc, eConv);
1193 if ( nResult & ScRefFlags::VALID )
1194 return nResult;
1196 // try the default calc address convention
1197 nResult = rRange.Parse(rString, rDoc);
1198 if ( nResult & ScRefFlags::VALID )
1199 return nResult;
1201 // try excel a1
1202 nResult = rRange.Parse(rString, rDoc, formula::FormulaGrammar::CONV_XL_A1);
1203 if ( nResult & ScRefFlags::VALID )
1204 return nResult;
1206 // try r1c1
1207 return rRange.Parse(rString, rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
1210 ScRefFlags parseAddress(const OUString& rString, ScAddress& rAddress, const ScDocument& rDoc)
1212 // start with the address convention set in the document
1213 formula::FormulaGrammar::AddressConvention eConv = rDoc.GetAddressConvention();
1214 ScRefFlags nResult = rAddress.Parse(rString, rDoc, eConv);
1215 if ( nResult & ScRefFlags::VALID )
1216 return nResult;
1218 // try the default calc address convention
1219 nResult = rAddress.Parse(rString, rDoc);
1220 if ( nResult & ScRefFlags::VALID )
1221 return nResult;
1223 // try excel a1
1224 nResult = rAddress.Parse(rString, rDoc, formula::FormulaGrammar::CONV_XL_A1);
1225 if ( nResult & ScRefFlags::VALID )
1226 return nResult;
1228 // try r1c1
1229 return rAddress.Parse(rString, rDoc, formula::FormulaGrammar::CONV_XL_R1C1);
1232 void transformURL(const OUString& rOldURL, OUString& rNewURL, const ScDocument& rDoc)
1234 if (rOldURL.startsWith("#"))
1236 // URL has to be decoded for escaped characters (%20)
1237 OUString aURL = INetURLObject::decode( rOldURL,
1238 INetURLObject::DecodeMechanism::WithCharset );
1239 OUString aAddressString = aURL.copy(1);
1241 ScRange aRange;
1242 ScRefFlags nResult = parseRange(aAddressString, aRange, rDoc);
1243 if ( nResult & ScRefFlags::VALID )
1245 OUString aString = aRange.Format(rDoc, nResult, formula::FormulaGrammar::CONV_XL_OOX);
1246 rNewURL = "#" + aString;
1247 return;
1249 else
1251 ScAddress aAddress;
1252 nResult = parseAddress(aAddressString, aAddress, rDoc);
1253 if( nResult & ScRefFlags::VALID )
1255 OUString aString = aAddress.Format(nResult, &rDoc, formula::FormulaGrammar::CONV_XL_OOX);
1256 rNewURL = "#" + aString;
1257 return;
1262 rNewURL = rOldURL;
1267 ScURLTransformer::ScURLTransformer(ScDocument& rDoc)
1268 : mrDoc(rDoc)
1272 OUString ScURLTransformer::getTransformedString(const OUString& rURL) const
1274 OUString aNewURL;
1275 transformURL(rURL, aNewURL, mrDoc);
1276 return aNewURL;
1279 bool ScURLTransformer::isExternalURL(const OUString& rURL) const
1281 return !rURL.startsWith("#");
1284 void XclObjAny::SaveXml( XclExpXmlStream& rStrm )
1286 // ignore group shapes at the moment, we don't process them correctly
1287 // leading to ms2010 rejecting the content
1288 if( !mxShape.is() || mxShape->getShapeType() == "com.sun.star.drawing.GroupShape" )
1289 return;
1291 // Do not output any of the detective shapes and validation circles.
1292 SdrObject* pObject = SdrObject::getSdrObjectFromXShape(mxShape);
1293 if (pObject)
1295 ScDocument& rDoc = rStrm.GetRoot().GetDoc();
1296 ScDetectiveFunc aDetFunc(rDoc, mnScTab);
1297 ScAddress aPosition;
1298 ScRange aSourceRange;
1299 bool bRedLine;
1300 ScDetectiveObjType eObjType
1301 = aDetFunc.GetDetectiveObjectType(pObject, mnScTab, aPosition, aSourceRange, bRedLine);
1303 if (eObjType != SC_DETOBJ_NONE)
1304 return;
1307 sax_fastparser::FSHelperPtr pDrawing = rStrm.GetCurrentStream();
1309 ShapeExport aDML(XML_xdr, pDrawing, nullptr, &rStrm, drawingml::DOCUMENT_XLSX);
1310 auto pURLTransformer = std::make_shared<ScURLTransformer>(*mpDoc);
1311 aDML.SetURLTranslator(pURLTransformer);
1313 pDrawing->startElement( FSNS( XML_xdr, XML_twoCellAnchor ), // OOXTODO: oneCellAnchor, absoluteAnchor
1314 XML_editAs, GetEditAs( *this ) );
1315 Reference< XPropertySet > xPropSet( mxShape, UNO_QUERY );
1316 if (xPropSet.is())
1318 WriteFromTo( rStrm, *this );
1319 aDML.WriteShape( mxShape );
1322 pDrawing->singleElement( FSNS( XML_xdr, XML_clientData)
1323 // OOXTODO: XML_fLocksWithSheet
1324 // OOXTODO: XML_fPrintsWithSheet
1326 pDrawing->endElement( FSNS( XML_xdr, XML_twoCellAnchor ) );
1329 void ExcBof8_Base::SaveCont( XclExpStream& rStrm )
1331 rStrm.DisableEncryption();
1332 rStrm << nVers << nDocType << nRupBuild << nRupYear
1333 << sal_uInt32(0)/*nFileHistory*/
1334 << sal_uInt32(0x06) /*nLowestBiffVer = Biff8*/;
1337 sal_uInt16 ExcBof8_Base::GetNum() const
1339 return 0x0809;
1342 std::size_t ExcBof8_Base::GetLen() const
1344 return 16;
1347 // --- class ExcBof8 -------------------------------------------------
1349 ExcBof8::ExcBof8()
1351 nDocType = 0x0010;
1354 // --- class ExcBofW8 ------------------------------------------------
1356 ExcBofW8::ExcBofW8()
1358 nDocType = 0x0005;
1361 // --- class ExcBundlesheet8 -----------------------------------------
1363 ExcBundlesheet8::ExcBundlesheet8( const RootData& rRootData, SCTAB _nTab ) :
1364 ExcBundlesheetBase( rRootData, static_cast<sal_uInt16>(_nTab) ),
1365 sUnicodeName( rRootData.pER->GetTabInfo().GetScTabName( _nTab ) )
1369 ExcBundlesheet8::ExcBundlesheet8( const OUString& rString ) :
1370 sUnicodeName( rString )
1374 void ExcBundlesheet8::SaveCont( XclExpStream& rStrm )
1376 m_nOwnPos = rStrm.GetSvStreamPos();
1377 // write dummy position, real position comes later
1378 rStrm.DisableEncryption();
1379 rStrm << sal_uInt32(0);
1380 rStrm.EnableEncryption();
1381 rStrm << nGrbit << GetName();
1384 std::size_t ExcBundlesheet8::GetLen() const
1385 { // Text max 255 chars
1386 return 8 + GetName().GetBufferSize();
1389 void ExcBundlesheet8::SaveXml( XclExpXmlStream& rStrm )
1391 OUString sId;
1392 rStrm.CreateOutputStream(
1393 XclXmlUtils::GetStreamName( "xl/", "worksheets/sheet", nTab+1),
1394 XclXmlUtils::GetStreamName( nullptr, "worksheets/sheet", nTab+1),
1395 rStrm.GetCurrentStream()->getOutputStream(),
1396 "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
1397 oox::getRelationship(Relationship::WORKSHEET),
1398 &sId );
1400 rStrm.GetCurrentStream()->singleElement( XML_sheet,
1401 XML_name, sUnicodeName.toUtf8(),
1402 XML_sheetId, OString::number( nTab+1 ),
1403 XML_state, nGrbit == 0x0000 ? "visible" : "hidden",
1404 FSNS( XML_r, XML_id ), sId.toUtf8() );
1407 // --- class XclObproj -----------------------------------------------
1409 sal_uInt16 XclObproj::GetNum() const
1411 return 0x00D3;
1414 std::size_t XclObproj::GetLen() const
1416 return 0;
1419 // ---- class XclCodename --------------------------------------------
1421 XclCodename::XclCodename( const OUString& r ) : aName( r )
1425 void XclCodename::SaveCont( XclExpStream& rStrm )
1427 rStrm << aName;
1430 sal_uInt16 XclCodename::GetNum() const
1432 return 0x01BA;
1435 std::size_t XclCodename::GetLen() const
1437 return aName.GetSize();
1440 // ---- Scenarios ----------------------------------------------------
1442 ExcEScenarioCell::ExcEScenarioCell( sal_uInt16 nC, sal_uInt16 nR, const OUString& rTxt ) :
1443 nCol( nC ),
1444 nRow( nR ),
1445 sText( rTxt, XclStrFlags::NONE, 255 )
1449 void ExcEScenarioCell::WriteAddress( XclExpStream& rStrm ) const
1451 rStrm << nRow << nCol;
1454 void ExcEScenarioCell::WriteText( XclExpStream& rStrm ) const
1456 rStrm << sText;
1459 void ExcEScenarioCell::SaveXml( XclExpXmlStream& rStrm ) const
1461 rStrm.GetCurrentStream()->singleElement( XML_inputCells,
1462 // OOXTODO: XML_deleted,
1463 // OOXTODO: XML_numFmtId,
1464 XML_r, XclXmlUtils::ToOString( rStrm.GetRoot().GetDoc(), ScAddress( nCol, nRow, 0 ) ),
1465 // OOXTODO: XML_undone,
1466 XML_val, XclXmlUtils::ToOString( sText ) );
1469 ExcEScenario::ExcEScenario( const XclExpRoot& rRoot, SCTAB nTab )
1471 OUString sTmpName;
1472 OUString sTmpComm;
1473 OUString aTmp;
1474 Color aDummyCol;
1475 ScScenarioFlags nFlags;
1477 ScDocument& rDoc = rRoot.GetDoc();
1478 rDoc.GetName(nTab, aTmp);
1479 sTmpName = aTmp;
1480 sName.Assign( sTmpName, XclStrFlags::EightBitLength );
1481 nRecLen = 8 + sName.GetBufferSize();
1483 rDoc.GetScenarioData( nTab, aTmp, aDummyCol, nFlags );
1484 sTmpComm = aTmp;
1485 sComment.Assign( sTmpComm, XclStrFlags::NONE, 255 );
1486 if( sComment.Len() )
1487 nRecLen += sComment.GetSize();
1488 bProtected = (nFlags & ScScenarioFlags::Protected) != ScScenarioFlags::NONE;
1490 sUserName.Assign( rRoot.GetUserName(), XclStrFlags::NONE, 255 );
1491 nRecLen += sUserName.GetSize();
1493 const ScRangeList* pRList = rDoc.GetScenarioRanges( nTab );
1494 if( !pRList )
1495 return;
1497 bool bContLoop = true;
1498 SCROW nRow;
1499 SCCOL nCol;
1500 OUString sText;
1501 double fVal;
1503 for( size_t nRange = 0; (nRange < pRList->size()) && bContLoop; nRange++ )
1505 const ScRange & rRange = (*pRList)[nRange];
1506 for( nRow = rRange.aStart.Row(); (nRow <= rRange.aEnd.Row()) && bContLoop; nRow++ )
1507 for( nCol = rRange.aStart.Col(); (nCol <= rRange.aEnd.Col()) && bContLoop; nCol++ )
1509 if( rDoc.HasValueData( nCol, nRow, nTab ) )
1511 fVal = rDoc.GetValue( nCol, nRow, nTab );
1512 sText = ::rtl::math::doubleToUString( fVal,
1513 rtl_math_StringFormat_Automatic,
1514 rtl_math_DecimalPlaces_Max,
1515 ScGlobal::getLocaleData().getNumDecimalSep()[0],
1516 true );
1518 else
1519 sText = rDoc.GetString(nCol, nRow, nTab);
1520 bContLoop = Append( static_cast<sal_uInt16>(nCol),
1521 static_cast<sal_uInt16>(nRow), sText );
1526 bool ExcEScenario::Append( sal_uInt16 nCol, sal_uInt16 nRow, const OUString& rTxt )
1528 if( aCells.size() == EXC_SCEN_MAXCELL )
1529 return false;
1531 ExcEScenarioCell aCell(nCol, nRow, rTxt);
1532 aCells.push_back(aCell);
1533 nRecLen += 6 + aCell.GetStringBytes(); // 4 bytes address, 2 bytes ifmt
1534 return true;
1537 void ExcEScenario::SaveCont( XclExpStream& rStrm )
1539 sal_uInt16 count = aCells.size();
1541 rStrm << count // number of cells
1542 << sal_uInt8(bProtected) // fProtection
1543 << sal_uInt8(0) // fHidden
1544 << static_cast<sal_uInt8>(sName.Len()) // length of scen name
1545 << static_cast<sal_uInt8>(sComment.Len()) // length of comment
1546 << static_cast<sal_uInt8>(sUserName.Len()); // length of user name
1547 sName.WriteFlagField( rStrm );
1548 sName.WriteBuffer( rStrm );
1550 rStrm << sUserName;
1552 if( sComment.Len() )
1553 rStrm << sComment;
1555 for( const auto& rCell : aCells )
1556 rCell.WriteAddress( rStrm ); // pos of cell
1557 for( const auto& rCell : aCells )
1558 rCell.WriteText( rStrm ); // string content
1559 rStrm.SetSliceSize( 2 );
1560 rStrm.WriteZeroBytes( 2 * count ); // date format
1563 sal_uInt16 ExcEScenario::GetNum() const
1565 return 0x00AF;
1568 std::size_t ExcEScenario::GetLen() const
1570 return nRecLen;
1573 void ExcEScenario::SaveXml( XclExpXmlStream& rStrm )
1575 sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
1576 rWorkbook->startElement( XML_scenario,
1577 XML_name, XclXmlUtils::ToOString( sName ).getStr(),
1578 XML_locked, ToPsz( bProtected ),
1579 // OOXTODO: XML_hidden,
1580 XML_count, OString::number( aCells.size() ).getStr(),
1581 XML_user, XESTRING_TO_PSZ( sUserName ),
1582 XML_comment, XESTRING_TO_PSZ( sComment ) );
1584 for( const auto& rCell : aCells )
1585 rCell.SaveXml( rStrm );
1587 rWorkbook->endElement( XML_scenario );
1590 ExcEScenarioManager::ExcEScenarioManager( const XclExpRoot& rRoot, SCTAB nTab ) :
1591 nActive( 0 )
1593 ScDocument& rDoc = rRoot.GetDoc();
1594 if( rDoc.IsScenario( nTab ) )
1595 return;
1597 SCTAB nFirstTab = nTab + 1;
1598 SCTAB nNewTab = nFirstTab;
1600 while( rDoc.IsScenario( nNewTab ) )
1602 aScenes.emplace_back( rRoot, nNewTab );
1604 if( rDoc.IsActiveScenario( nNewTab ) )
1605 nActive = static_cast<sal_uInt16>(nNewTab - nFirstTab);
1606 nNewTab++;
1610 ExcEScenarioManager::~ExcEScenarioManager()
1614 void ExcEScenarioManager::SaveCont( XclExpStream& rStrm )
1616 rStrm << static_cast<sal_uInt16>(aScenes.size()) // number of scenarios
1617 << nActive // active scen
1618 << nActive // last displayed
1619 << sal_uInt16(0); // reference areas
1622 void ExcEScenarioManager::Save( XclExpStream& rStrm )
1624 if( !aScenes.empty() )
1625 ExcRecord::Save( rStrm );
1627 for( ExcEScenario& rScenario : aScenes )
1628 rScenario.Save( rStrm );
1631 void ExcEScenarioManager::SaveXml( XclExpXmlStream& rStrm )
1633 if( aScenes.empty() )
1634 return;
1636 sax_fastparser::FSHelperPtr& rWorkbook = rStrm.GetCurrentStream();
1637 rWorkbook->startElement( XML_scenarios,
1638 XML_current, OString::number( nActive ),
1639 XML_show, OString::number( nActive )
1640 // OOXTODO: XML_sqref
1643 for( ExcEScenario& rScenario : aScenes )
1644 rScenario.SaveXml( rStrm );
1646 rWorkbook->endElement( XML_scenarios );
1649 sal_uInt16 ExcEScenarioManager::GetNum() const
1651 return 0x00AE;
1654 std::size_t ExcEScenarioManager::GetLen() const
1656 return 8;
1659 namespace {
1661 struct XclExpTabProtectOption
1663 ScTableProtection::Option eOption;
1664 sal_uInt16 nMask;
1669 XclExpSheetProtectOptions::XclExpSheetProtectOptions( const XclExpRoot& rRoot, SCTAB nTab ) :
1670 XclExpRecord( 0x0867, 23 )
1672 static const XclExpTabProtectOption aTable[] =
1674 { ScTableProtection::OBJECTS, 0x0001 },
1675 { ScTableProtection::SCENARIOS, 0x0002 },
1676 { ScTableProtection::FORMAT_CELLS, 0x0004 },
1677 { ScTableProtection::FORMAT_COLUMNS, 0x0008 },
1678 { ScTableProtection::FORMAT_ROWS, 0x0010 },
1679 { ScTableProtection::INSERT_COLUMNS, 0x0020 },
1680 { ScTableProtection::INSERT_ROWS, 0x0040 },
1681 { ScTableProtection::INSERT_HYPERLINKS, 0x0080 },
1683 { ScTableProtection::DELETE_COLUMNS, 0x0100 },
1684 { ScTableProtection::DELETE_ROWS, 0x0200 },
1685 { ScTableProtection::SELECT_LOCKED_CELLS, 0x0400 },
1686 { ScTableProtection::SORT, 0x0800 },
1687 { ScTableProtection::AUTOFILTER, 0x1000 },
1688 { ScTableProtection::PIVOT_TABLES, 0x2000 },
1689 { ScTableProtection::SELECT_UNLOCKED_CELLS, 0x4000 },
1691 { ScTableProtection::NONE, 0x0000 }
1694 mnOptions = 0x0000;
1695 const ScTableProtection* pProtect = rRoot.GetDoc().GetTabProtection(nTab);
1696 if (!pProtect)
1697 return;
1699 for (int i = 0; aTable[i].nMask != 0x0000; ++i)
1701 if ( pProtect->isOptionEnabled(aTable[i].eOption) )
1702 mnOptions |= aTable[i].nMask;
1706 void XclExpSheetProtectOptions::WriteBody( XclExpStream& rStrm )
1708 sal_uInt16 nBytes = 0x0867;
1709 rStrm << nBytes;
1711 for (int i = 0; i < 9; ++i)
1712 rStrm << static_cast<unsigned char>(0);
1714 nBytes = 0x0200;
1715 rStrm << nBytes;
1716 nBytes = 0x0100;
1717 rStrm << nBytes;
1718 nBytes = 0xFFFF;
1719 rStrm << nBytes << nBytes;
1721 rStrm << mnOptions;
1722 nBytes = 0;
1723 rStrm << nBytes;
1726 XclExpSheetEnhancedProtection::XclExpSheetEnhancedProtection( const XclExpRoot& rRoot,
1727 const ScEnhancedProtection & rProt ) :
1728 XclExpRecord( 0x0868 ),
1729 mrRoot( rRoot ),
1730 maEnhancedProtection( rProt )
1734 void XclExpSheetEnhancedProtection::WriteBody( XclExpStream& rStrm )
1736 sal_uInt16 const nRecordType = 0x0868;
1737 rStrm << nRecordType; // frtHeader rt
1738 rStrm.WriteZeroBytesToRecord(10); // frtHeader unused
1739 rStrm << EXC_ISFPROTECTION; // isf
1740 rStrm.WriteZeroBytesToRecord(5); // reserved1 (1 bytes) and reserved2 (4 bytes)
1742 XclRangeList aRefs;
1743 if (maEnhancedProtection.maRangeList.is())
1744 mrRoot.GetAddressConverter().ConvertRangeList( aRefs, *maEnhancedProtection.maRangeList, false);
1745 sal_uInt16 nCref = ulimit_cast<sal_uInt16>(aRefs.size());
1746 rStrm << nCref; // cref
1747 rStrm.WriteZeroBytesToRecord(6); // cbFeatData if EXC_ISFFEC2 (4 bytes) and reserved3 (2 bytes)
1748 aRefs.Write( rStrm, true, nCref); // refs
1750 // FeatProtection structure
1751 rStrm << maEnhancedProtection.mnAreserved; // 1 bit A and 31 bits reserved
1752 rStrm << maEnhancedProtection.mnPasswordVerifier; // wPassword
1753 rStrm << XclExpString( maEnhancedProtection.maTitle); // stTitle
1754 bool bSDContainer = ((maEnhancedProtection.mnAreserved & 0x00000001) == 0x00000001);
1755 sal_uInt32 nCbSD = maEnhancedProtection.maSecurityDescriptor.size();
1756 SAL_WARN_IF( bSDContainer && nCbSD < 20, "sc.filter",
1757 "XclExpSheetEnhancedProtection A flag indicates container but cbSD < 20");
1758 SAL_WARN_IF( !bSDContainer && nCbSD > 0, "sc.filter",
1759 "XclExpSheetEnhancedProtection A flag indicates no container but cbSD > 0");
1760 if (bSDContainer)
1762 rStrm << nCbSD;
1763 rStrm.Write( &maEnhancedProtection.maSecurityDescriptor.front(), nCbSD);
1767 void XclCalccount::SaveCont( XclExpStream& rStrm )
1769 rStrm << nCount;
1772 XclCalccount::XclCalccount( const ScDocument& rDoc )
1774 nCount = rDoc.GetDocOptions().GetIterCount();
1777 sal_uInt16 XclCalccount::GetNum() const
1779 return 0x000C;
1782 std::size_t XclCalccount::GetLen() const
1784 return 2;
1787 void XclCalccount::SaveXml( XclExpXmlStream& rStrm )
1789 rStrm.WriteAttributes(XML_iterateCount, OUString::number(nCount));
1792 void XclIteration::SaveCont( XclExpStream& rStrm )
1794 rStrm << nIter;
1797 XclIteration::XclIteration( const ScDocument& rDoc )
1799 nIter = rDoc.GetDocOptions().IsIter()? 1 : 0;
1802 sal_uInt16 XclIteration::GetNum() const
1804 return 0x0011;
1807 std::size_t XclIteration::GetLen() const
1809 return 2;
1812 void XclIteration::SaveXml( XclExpXmlStream& rStrm )
1814 rStrm.WriteAttributes(XML_iterate, ToPsz(nIter == 1));
1817 void XclDelta::SaveCont( XclExpStream& rStrm )
1819 rStrm << fDelta;
1822 XclDelta::XclDelta( const ScDocument& rDoc )
1824 fDelta = rDoc.GetDocOptions().GetIterEps();
1827 sal_uInt16 XclDelta::GetNum() const
1829 return 0x0010;
1832 std::size_t XclDelta::GetLen() const
1834 return 8;
1837 void XclDelta::SaveXml( XclExpXmlStream& rStrm )
1839 rStrm.WriteAttributes(XML_iterateDelta, OUString::number(fDelta));
1842 XclExpFileEncryption::XclExpFileEncryption( const XclExpRoot& rRoot ) :
1843 XclExpRecord(0x002F, 54),
1844 mrRoot(rRoot)
1848 XclExpFileEncryption::~XclExpFileEncryption()
1852 void XclExpFileEncryption::WriteBody( XclExpStream& rStrm )
1854 // 0x0000 - neither standard nor strong encryption
1855 // 0x0001 - standard or strong encryption
1856 rStrm << static_cast<sal_uInt16>(0x0001);
1858 // 0x0000 - non standard encryption
1859 // 0x0001 - standard encryption
1860 sal_uInt16 nStdEnc = 0x0001;
1861 rStrm << nStdEnc << nStdEnc;
1863 sal_uInt8 pnDocId[16];
1864 sal_uInt8 pnSalt[16];
1865 sal_uInt8 pnSaltHash[16];
1866 XclExpEncrypterRef xEnc = std::make_shared<XclExpBiff8Encrypter>(mrRoot);
1867 xEnc->GetDocId(pnDocId);
1868 xEnc->GetSalt(pnSalt);
1869 xEnc->GetSaltDigest(pnSaltHash);
1871 rStrm.Write(pnDocId, 16);
1872 rStrm.Write(pnSalt, 16);
1873 rStrm.Write(pnSaltHash, 16);
1875 rStrm.SetEncrypter(xEnc);
1878 XclExpInterfaceHdr::XclExpInterfaceHdr( sal_uInt16 nCodePage ) :
1879 XclExpUInt16Record( EXC_ID_INTERFACEHDR, nCodePage )
1883 void XclExpInterfaceHdr::WriteBody( XclExpStream& rStrm )
1885 rStrm.DisableEncryption();
1886 rStrm << GetValue();
1889 XclExpInterfaceEnd::XclExpInterfaceEnd() :
1890 XclExpRecord(0x00E2, 0) {}
1892 XclExpInterfaceEnd::~XclExpInterfaceEnd() {}
1894 void XclExpInterfaceEnd::WriteBody( XclExpStream& rStrm )
1896 // Don't forget to re-enable encryption.
1897 rStrm.EnableEncryption();
1900 XclExpWriteAccess::XclExpWriteAccess() :
1901 XclExpRecord(0x005C, 112)
1905 XclExpWriteAccess::~XclExpWriteAccess()
1909 void XclExpWriteAccess::WriteBody( XclExpStream& rStrm )
1911 static const sal_uInt8 aData[] = {
1912 0x04, 0x00, 0x00, 'C', 'a', 'l', 'c', 0x20,
1913 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1914 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1915 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1916 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1917 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1918 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1919 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1920 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1921 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1922 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1923 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1924 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
1925 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 };
1927 for (std::size_t i = 0; i < sizeof(aData); ++i)
1928 rStrm << aData[i];
1931 XclExpFileSharing::XclExpFileSharing( const XclExpRoot& rRoot, sal_uInt16 nPasswordHash, bool bRecommendReadOnly ) :
1932 XclExpRecord( EXC_ID_FILESHARING ),
1933 mnPasswordHash( nPasswordHash ),
1934 mbRecommendReadOnly( bRecommendReadOnly )
1936 if( rRoot.GetBiff() <= EXC_BIFF5 )
1937 maUserName.AssignByte( rRoot.GetUserName(), rRoot.GetTextEncoding(), XclStrFlags::EightBitLength );
1938 else
1939 maUserName.Assign( rRoot.GetUserName() );
1942 void XclExpFileSharing::Save( XclExpStream& rStrm )
1944 if( (mnPasswordHash != 0) || mbRecommendReadOnly )
1945 XclExpRecord::Save( rStrm );
1948 void XclExpFileSharing::WriteBody( XclExpStream& rStrm )
1950 rStrm << sal_uInt16( mbRecommendReadOnly ? 1 : 0 ) << mnPasswordHash << maUserName;
1953 XclExpProt4Rev::XclExpProt4Rev() :
1954 XclExpRecord(0x01AF, 2)
1958 XclExpProt4Rev::~XclExpProt4Rev()
1962 void XclExpProt4Rev::WriteBody( XclExpStream& rStrm )
1964 rStrm << static_cast<sal_uInt16>(0x0000);
1967 XclExpProt4RevPass::XclExpProt4RevPass() :
1968 XclExpRecord(0x01BC, 2)
1972 XclExpProt4RevPass::~XclExpProt4RevPass()
1976 void XclExpProt4RevPass::WriteBody( XclExpStream& rStrm )
1978 rStrm << static_cast<sal_uInt16>(0x0000);
1981 const sal_uInt8 nDataRecalcId[] = {
1982 0xC1, 0x01, 0x00, 0x00, 0x54, 0x8D, 0x01, 0x00
1985 XclExpRecalcId::XclExpRecalcId() :
1986 XclExpDummyRecord(0x01C1, nDataRecalcId, sizeof(nDataRecalcId))
1990 const sal_uInt8 nDataBookExt[] = {
1991 0x63, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1992 0x00, 0x00, 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1993 0x02
1996 XclExpBookExt::XclExpBookExt() :
1997 XclExpDummyRecord(0x0863, nDataBookExt, sizeof(nDataBookExt))
2001 XclRefmode::XclRefmode( const ScDocument& rDoc ) :
2002 XclExpBoolRecord( 0x000F, rDoc.GetAddressConvention() != formula::FormulaGrammar::CONV_XL_R1C1 )
2006 void XclRefmode::SaveXml( XclExpXmlStream& rStrm )
2008 rStrm.WriteAttributes(XML_refMode, GetBool() ? "A1" : "R1C1");
2011 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */