1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 .
23 #include <sot/storage.hxx>
24 #include <XclExpChangeTrack.hxx>
26 #include <xeformula.hxx>
27 #include <xehelper.hxx>
28 #include <xltools.hxx>
29 #include <formulacell.hxx>
30 #include <document.hxx>
31 #include <editutil.hxx>
33 #include <tools/Guid.hxx>
35 #include <oox/export/utils.hxx>
36 #include <oox/token/namespaces.hxx>
37 #include <oox/token/tokens.hxx>
39 #include <svl/sharedstring.hxx>
40 #include <unotools/securityoptions.hxx>
42 #include <com/sun/star/util/DateTime.hpp>
46 static OString
lcl_DateTimeToOString( const DateTime
& rDateTime
)
49 snprintf( sBuf
, sizeof( sBuf
),
50 "%d-%02d-%02dT%02d:%02d:%02d.%09" SAL_PRIuUINT32
"Z",
51 rDateTime
.GetYear(), rDateTime
.GetMonth(), rDateTime
.GetDay(),
52 rDateTime
.GetHour(), rDateTime
.GetMin(), rDateTime
.GetSec(),
53 rDateTime
.GetNanoSec() );
59 static void lcl_WriteDateTime( XclExpStream
& rStrm
, const DateTime
& rDateTime
)
61 rStrm
.SetSliceSize( 7 );
62 rStrm
<< static_cast<sal_uInt16
>(rDateTime
.GetYear())
63 << static_cast<sal_uInt8
>(rDateTime
.GetMonth())
64 << static_cast<sal_uInt8
>(rDateTime
.GetDay())
65 << static_cast<sal_uInt8
>(rDateTime
.GetHour())
66 << static_cast<sal_uInt8
>(rDateTime
.GetMin())
67 << static_cast<sal_uInt8
>(rDateTime
.GetSec());
68 rStrm
.SetSliceSize( 0 );
71 // write string and fill rest of <nLength> with zero bytes
72 // <nLength> is without string header
73 static void lcl_WriteFixedString( XclExpStream
& rStrm
, const XclExpString
& rString
, std::size_t nLength
)
75 std::size_t nStrBytes
= rString
.GetBufferSize();
76 OSL_ENSURE( nLength
>= nStrBytes
, "lcl_WriteFixedString - String too long" );
77 if( rString
.Len() > 0 )
79 if( nLength
> nStrBytes
)
80 rStrm
.WriteZeroBytes( nLength
- nStrBytes
);
83 static void lcl_GenerateGUID( sal_uInt8
* pGUID
, bool& rValidGUID
)
85 rtl_createUuid( pGUID
, rValidGUID
? pGUID
: nullptr, false );
89 static void lcl_WriteGUID( XclExpStream
& rStrm
, const sal_uInt8
* pGUID
)
91 rStrm
.SetSliceSize( 16 );
92 for( std::size_t nIndex
= 0; nIndex
< 16; nIndex
++ )
93 rStrm
<< pGUID
[ nIndex
];
94 rStrm
.SetSliceSize( 0 );
97 XclExpUserBView::XclExpUserBView( const OUString
& rUsername
, const sal_uInt8
* pGUID
) :
98 sUsername( rUsername
)
100 memcpy( aGUID
, pGUID
, 16 );
103 void XclExpUserBView::SaveCont( XclExpStream
& rStrm
)
105 rStrm
<< sal_uInt32(0xFF078014)
106 << sal_uInt32(0x00000001);
107 lcl_WriteGUID( rStrm
, aGUID
);
108 rStrm
.WriteZeroBytes( 8 );
109 rStrm
<< sal_uInt32(1200)
112 << sal_uInt16(0x0CF7)
113 << sal_uInt16(0x0000)
114 << sal_uInt16(0x0001)
115 << sal_uInt16(0x0000);
116 if( sUsername
.Len() > 0 )
120 sal_uInt16
XclExpUserBView::GetNum() const
125 std::size_t XclExpUserBView::GetLen() const
127 return 50 + ((sUsername
.Len() > 0) ? sUsername
.GetSize() : 0);
130 XclExpUserBViewList::XclExpUserBViewList( const ScChangeTrack
& rChangeTrack
)
132 sal_uInt8 aGUID
[ 16 ];
133 bool bValidGUID
= false;
134 const std::set
<OUString
>& rStrColl
= rChangeTrack
.GetUserCollection();
135 aViews
.reserve(rStrColl
.size());
136 for (const auto& rStr
: rStrColl
)
138 lcl_GenerateGUID( aGUID
, bValidGUID
);
139 aViews
.emplace_back( rStr
, aGUID
);
143 XclExpUserBViewList::~XclExpUserBViewList()
147 void XclExpUserBViewList::Save( XclExpStream
& rStrm
)
149 for( XclExpUserBView
& rView
: aViews
)
153 XclExpUsersViewBegin::XclExpUsersViewBegin( const sal_uInt8
* pGUID
, sal_uInt32 nTab
) :
156 memcpy( aGUID
, pGUID
, 16 );
159 void XclExpUsersViewBegin::SaveCont( XclExpStream
& rStrm
)
161 lcl_WriteGUID( rStrm
, aGUID
);
166 << sal_uInt32(0x0000003C)
177 sal_uInt16
XclExpUsersViewBegin::GetNum() const
182 std::size_t XclExpUsersViewBegin::GetLen() const
187 void XclExpUsersViewEnd::SaveCont( XclExpStream
& rStrm
)
189 rStrm
<< sal_uInt16(0x0001);
192 sal_uInt16
XclExpUsersViewEnd::GetNum() const
197 std::size_t XclExpUsersViewEnd::GetLen() const
202 void XclExpChTr0x0191::SaveCont( XclExpStream
& rStrm
)
204 rStrm
<< sal_uInt16(0x0000);
207 sal_uInt16
XclExpChTr0x0191::GetNum() const
212 std::size_t XclExpChTr0x0191::GetLen() const
217 void XclExpChTr0x0198::SaveCont( XclExpStream
& rStrm
)
219 rStrm
<< sal_uInt16(0x0006)
220 << sal_uInt16(0x0000);
223 sal_uInt16
XclExpChTr0x0198::GetNum() const
228 std::size_t XclExpChTr0x0198::GetLen() const
233 void XclExpChTr0x0192::SaveCont( XclExpStream
& rStrm
)
235 rStrm
<< sal_uInt16( 0x0022 );
236 rStrm
.WriteZeroBytes( 510 );
239 sal_uInt16
XclExpChTr0x0192::GetNum() const
244 std::size_t XclExpChTr0x0192::GetLen() const
249 void XclExpChTr0x0197::SaveCont( XclExpStream
& rStrm
)
251 rStrm
<< sal_uInt16(0x0000);
254 sal_uInt16
XclExpChTr0x0197::GetNum() const
259 std::size_t XclExpChTr0x0197::GetLen() const
264 XclExpChTrEmpty::~XclExpChTrEmpty()
268 sal_uInt16
XclExpChTrEmpty::GetNum() const
273 std::size_t XclExpChTrEmpty::GetLen() const
278 XclExpChTr0x0195::~XclExpChTr0x0195()
282 void XclExpChTr0x0195::SaveCont( XclExpStream
& rStrm
)
284 rStrm
.WriteZeroBytes( 162 );
287 sal_uInt16
XclExpChTr0x0195::GetNum() const
292 std::size_t XclExpChTr0x0195::GetLen() const
297 XclExpChTr0x0194::~XclExpChTr0x0194()
301 void XclExpChTr0x0194::SaveCont( XclExpStream
& rStrm
)
303 rStrm
<< sal_uInt32(0);
304 lcl_WriteDateTime( rStrm
, aDateTime
);
305 rStrm
<< sal_uInt8(0);
306 lcl_WriteFixedString( rStrm
, sUsername
, 147 );
309 sal_uInt16
XclExpChTr0x0194::GetNum() const
314 std::size_t XclExpChTr0x0194::GetLen() const
319 XclExpChTrHeader::~XclExpChTrHeader()
323 void XclExpChTrHeader::SaveCont( XclExpStream
& rStrm
)
325 rStrm
<< sal_uInt16(0x0006)
326 << sal_uInt16(0x0000)
327 << sal_uInt16(0x000D);
328 lcl_WriteGUID( rStrm
, aGUID
);
329 lcl_WriteGUID( rStrm
, aGUID
);
331 << sal_uInt16(0x0001)
332 << sal_uInt32(0x00000000)
333 << sal_uInt16(0x001E);
336 sal_uInt16
XclExpChTrHeader::GetNum() const
341 std::size_t XclExpChTrHeader::GetLen() const
346 void XclExpChTrHeader::SaveXml( XclExpXmlStream
& rRevisionHeadersStrm
)
348 sax_fastparser::FSHelperPtr pHeaders
= rRevisionHeadersStrm
.GetCurrentStream();
349 tools::Guid
aGuid(aGUID
);
350 rRevisionHeadersStrm
.WriteAttributes(
351 XML_guid
, aGuid
.getString(),
352 XML_lastGuid
, nullptr, // OOXTODO
353 XML_shared
, nullptr, // OOXTODO
354 XML_diskRevisions
, nullptr, // OOXTODO
355 XML_history
, nullptr, // OOXTODO
356 XML_trackRevisions
, nullptr, // OOXTODO
357 XML_exclusive
, nullptr, // OOXTODO
358 XML_revisionId
, nullptr, // OOXTODO
359 XML_version
, nullptr, // OOXTODO
360 XML_keepChangeHistory
, nullptr, // OOXTODO
361 XML_protected
, nullptr, // OOXTODO
362 XML_preserveHistory
, nullptr); // OOXTODO
363 pHeaders
->write( ">" );
366 void XclExpXmlChTrHeaders::SetGUID( const sal_uInt8
* pGUID
)
368 memcpy(maGUID
, pGUID
, 16);
371 void XclExpXmlChTrHeaders::SaveXml( XclExpXmlStream
& rStrm
)
373 sax_fastparser::FSHelperPtr pHeaders
= rStrm
.GetCurrentStream();
375 pHeaders
->write("<")->writeId(XML_headers
);
377 tools::Guid
aGuid(maGUID
);
378 rStrm
.WriteAttributes(
379 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
380 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)),
381 XML_guid
, aGuid
.getString(),
382 XML_lastGuid
, nullptr, // OOXTODO
383 XML_shared
, nullptr, // OOXTODO
384 XML_diskRevisions
, nullptr, // OOXTODO
385 XML_history
, nullptr, // OOXTODO
386 XML_trackRevisions
, nullptr, // OOXTODO
387 XML_exclusive
, nullptr, // OOXTODO
388 XML_revisionId
, nullptr, // OOXTODO
389 XML_version
, nullptr, // OOXTODO
390 XML_keepChangeHistory
, nullptr, // OOXTODO
391 XML_protected
, nullptr, // OOXTODO
392 XML_preserveHistory
, nullptr); // OOXTODO
394 pHeaders
->write(">");
397 XclExpXmlChTrHeader::XclExpXmlChTrHeader(
398 OUString aUserName
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
,
399 sal_Int32 nLogNumber
, const XclExpChTrTabIdBuffer
& rBuf
) :
400 maUserName(std::move(aUserName
)), maDateTime(rDateTime
), mnLogNumber(nLogNumber
),
401 mnMinAction(0), mnMaxAction(0), mpAuthorIDs(new SvtSecurityMapPersonalInfo
)
403 memcpy(maGUID
, pGUID
, 16);
404 if (rBuf
.GetBufferCount())
406 maTabBuffer
.resize(rBuf
.GetBufferCount());
407 rBuf
.GetBufferCopy(maTabBuffer
.data());
411 void XclExpXmlChTrHeader::SaveXml( XclExpXmlStream
& rStrm
)
413 sax_fastparser::FSHelperPtr pHeader
= rStrm
.GetCurrentStream();
415 pHeader
->write("<")->writeId(XML_header
);
418 sax_fastparser::FSHelperPtr pRevLogStrm
= rStrm
.CreateOutputStream(
419 XclXmlUtils::GetStreamName("xl/revisions/", "revisionLog", mnLogNumber
),
420 XclXmlUtils::GetStreamName(nullptr, "revisionLog", mnLogNumber
),
421 rStrm
.GetCurrentStream()->getOutputStream(),
422 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
423 CREATE_OFFICEDOC_RELATION_TYPE("revisionLog"),
426 tools::Guid
aGuid(maGUID
);
427 bool bRemovePersonalInfo
428 = SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo
)
429 && !SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnKeepRedlineInfo
);
430 if (bRemovePersonalInfo
)
432 maDateTime
= css::util::DateTime(0, 0, 0, 12, 1, 1, 1970, true);
433 maUserName
= "Author" + OUString::number(mpAuthorIDs
->GetInfoID(maUserName
));
435 rStrm
.WriteAttributes(
436 XML_guid
, aGuid
.getString(),
437 XML_dateTime
, lcl_DateTimeToOString(maDateTime
),
438 XML_userName
, maUserName
,
439 FSNS(XML_r
, XML_id
), aRelId
);
442 rStrm
.WriteAttributes(XML_minRId
, OUString::number(mnMinAction
));
445 rStrm
.WriteAttributes(XML_maxRId
, OUString::number(mnMaxAction
));
447 if (!maTabBuffer
.empty())
448 // next available sheet index.
449 rStrm
.WriteAttributes(XML_maxSheetId
, OUString::number(maTabBuffer
.back()+1));
453 if (!maTabBuffer
.empty())
455 // Write sheet index map.
456 size_t n
= maTabBuffer
.size();
457 pHeader
->startElement(XML_sheetIdMap
, XML_count
, OString::number(n
));
459 for (size_t i
= 0; i
< n
; ++i
)
461 pHeader
->singleElement(XML_sheetId
, XML_val
, OString::number(maTabBuffer
[i
]));
463 pHeader
->endElement(XML_sheetIdMap
);
466 // Write all revision logs in a separate stream.
468 rStrm
.PushStream(pRevLogStrm
);
470 pRevLogStrm
->write("<")->writeId(XML_revisions
);
472 rStrm
.WriteAttributes(
473 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
474 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)));
476 pRevLogStrm
->write(">");
478 for (const auto& rxAction
: maActions
)
480 rxAction
->SaveXml(rStrm
);
483 pRevLogStrm
->write("</")->writeId(XML_revisions
)->write(">");
487 pHeader
->write("</")->writeId(XML_header
)->write(">");
490 void XclExpXmlChTrHeader::AppendAction( std::unique_ptr
<XclExpChTrAction
> pAction
)
492 sal_uInt32 nActionNum
= pAction
->GetActionNumber();
493 if (!mnMinAction
|| mnMinAction
> nActionNum
)
494 mnMinAction
= nActionNum
;
496 if (!mnMaxAction
|| mnMaxAction
< nActionNum
)
497 mnMaxAction
= nActionNum
;
499 maActions
.push_back(std::move(pAction
));
502 XclExpChTrInfo::XclExpChTrInfo( const OUString
& rUsername
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
) :
503 sUsername( rUsername
),
504 aDateTime( rDateTime
)
506 memcpy( aGUID
, pGUID
, 16 );
509 XclExpChTrInfo::~XclExpChTrInfo()
513 void XclExpChTrInfo::SaveCont( XclExpStream
& rStrm
)
515 rStrm
<< sal_uInt32(0xFFFFFFFF)
516 << sal_uInt32(0x00000000)
517 << sal_uInt32(0x00000020)
518 << sal_uInt16(0xFFFF);
519 lcl_WriteGUID( rStrm
, aGUID
);
520 rStrm
<< sal_uInt16(0x04B0);
521 lcl_WriteFixedString( rStrm
, sUsername
, 113 );
522 lcl_WriteDateTime( rStrm
, aDateTime
);
523 rStrm
<< sal_uInt8(0x0000)
524 << sal_uInt16(0x0002);
527 sal_uInt16
XclExpChTrInfo::GetNum() const
532 std::size_t XclExpChTrInfo::GetLen() const
537 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount
) :
541 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
542 memset( pBuffer
.get(), 0, sizeof(sal_uInt16
) * nBufSize
);
543 pLast
= pBuffer
.get() + nBufSize
- 1;
546 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( const XclExpChTrTabIdBuffer
& rCopy
) :
547 nBufSize( rCopy
.nBufSize
),
548 nLastId( rCopy
.nLastId
)
550 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
551 memcpy( pBuffer
.get(), rCopy
.pBuffer
.get(), sizeof(sal_uInt16
) * nBufSize
);
552 pLast
= pBuffer
.get() + nBufSize
- 1;
555 XclExpChTrTabIdBuffer::~XclExpChTrTabIdBuffer()
559 void XclExpChTrTabIdBuffer::InitFill( sal_uInt16 nIndex
)
561 OSL_ENSURE( nIndex
< nLastId
, "XclExpChTrTabIdBuffer::Insert - out of range" );
563 sal_uInt16 nFreeCount
= 0;
564 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
568 if( nFreeCount
> nIndex
)
576 void XclExpChTrTabIdBuffer::InitFillup()
578 sal_uInt16 nFreeCount
= 1;
579 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
581 *pElem
= nFreeCount
++;
585 sal_uInt16
XclExpChTrTabIdBuffer::GetId( sal_uInt16 nIndex
) const
587 assert(nIndex
< nBufSize
&& "XclExpChTrTabIdBuffer::GetId - out of range");
588 return pBuffer
[ nIndex
];
591 bool XclExpChTrTabIdBuffer::HasId( sal_uInt16 nIndex
) const
593 return nIndex
< nBufSize
;
596 void XclExpChTrTabIdBuffer::Remove()
598 OSL_ENSURE( pBuffer
.get() <= pLast
, "XclExpChTrTabIdBuffer::Remove - buffer empty" );
599 sal_uInt16
* pElem
= pBuffer
.get();
600 while( (pElem
<= pLast
) && (*pElem
!= nLastId
) )
602 while( pElem
< pLast
)
604 *pElem
= *(pElem
+ 1);
611 XclExpChTrTabId::XclExpChTrTabId( const XclExpChTrTabIdBuffer
& rBuffer
)
612 : nTabCount( rBuffer
.GetBufferCount() )
614 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
615 rBuffer
.GetBufferCopy( pBuffer
.get() );
618 XclExpChTrTabId::~XclExpChTrTabId()
623 void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer
& rBuffer
)
626 nTabCount
= rBuffer
.GetBufferCount();
627 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
628 rBuffer
.GetBufferCopy( pBuffer
.get() );
631 void XclExpChTrTabId::SaveCont( XclExpStream
& rStrm
)
633 rStrm
.EnableEncryption();
635 rStrm
.Write(pBuffer
.get(), nTabCount
);
637 for( sal_uInt16 nIndex
= 1; nIndex
<= nTabCount
; nIndex
++ )
641 sal_uInt16
XclExpChTrTabId::GetNum() const
646 std::size_t XclExpChTrTabId::GetLen() const
648 return nTabCount
<< 1;
651 // ! does not copy additional actions
652 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction
& rCopy
) :
654 sUsername( rCopy
.sUsername
),
655 aDateTime( rCopy
.aDateTime
),
657 bAccepted( rCopy
.bAccepted
),
658 rTabInfo( rCopy
.rTabInfo
),
659 rIdBuffer( rCopy
.rIdBuffer
),
660 nLength( rCopy
.nLength
),
661 nOpCode( rCopy
.nOpCode
),
662 bForceInfo( rCopy
.bForceInfo
)
666 XclExpChTrAction::XclExpChTrAction(
667 const ScChangeAction
& rAction
,
668 const XclExpRoot
& rRoot
,
669 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
670 sal_uInt16 nNewOpCode
) :
671 sUsername( rAction
.GetUser() ),
672 aDateTime( rAction
.GetDateTime() ),
674 bAccepted( rAction
.IsAccepted() ),
675 rTabInfo( rRoot
.GetTabInfo() ),
676 rIdBuffer( rTabIdBuffer
),
678 nOpCode( nNewOpCode
),
681 aDateTime
.SetSec( 0 );
682 aDateTime
.SetNanoSec( 0 );
685 XclExpChTrAction::~XclExpChTrAction()
689 void XclExpChTrAction::SetAddAction( XclExpChTrAction
* pAction
)
692 pAddAction
->SetAddAction( pAction
);
694 pAddAction
.reset( pAction
);
697 void XclExpChTrAction::AddDependentContents(
698 const ScChangeAction
& rAction
,
699 const XclExpRoot
& rRoot
,
700 const ScChangeTrack
& rChangeTrack
)
702 ScChangeActionMap aActionMap
;
704 rChangeTrack
.GetDependents( const_cast<ScChangeAction
*>(&rAction
), aActionMap
);
705 for( const auto& rEntry
: aActionMap
)
706 if( rEntry
.second
->GetType() == SC_CAT_CONTENT
)
707 SetAddAction( new XclExpChTrCellContent(
708 *static_cast<const ScChangeActionContent
*>(rEntry
.second
), rRoot
, rIdBuffer
) );
711 void XclExpChTrAction::SetIndex( sal_uInt32
& rIndex
)
716 void XclExpChTrAction::SaveCont( XclExpStream
& rStrm
)
718 OSL_ENSURE( nOpCode
!= EXC_CHTR_OP_UNKNOWN
, "XclExpChTrAction::SaveCont - unknown action" );
722 << static_cast<sal_uInt16
>(bAccepted
? EXC_CHTR_ACCEPT
: EXC_CHTR_NOTHING
);
723 SaveActionData( rStrm
);
726 void XclExpChTrAction::PrepareSaveAction( XclExpStream
& /*rStrm*/ ) const
730 void XclExpChTrAction::CompleteSaveAction( XclExpStream
& /*rStrm*/ ) const
734 void XclExpChTrAction::Save( XclExpStream
& rStrm
)
736 if (UsesDeletedTab())
738 SAL_WARN("sc", "XclExpChTrAction : unable to export position with tab of EXC_TAB_DELETED");
741 PrepareSaveAction( rStrm
);
742 ExcRecord::Save( rStrm
);
744 pAddAction
->Save( rStrm
);
745 CompleteSaveAction( rStrm
);
748 std::size_t XclExpChTrAction::GetLen() const
750 return GetHeaderByteCount() + GetActionByteCount();
753 XclExpChTrData::XclExpChTrData() :
754 mpFormulaCell( nullptr ),
757 nType( EXC_CHTR_TYPE_EMPTY
),
762 XclExpChTrData::~XclExpChTrData()
767 void XclExpChTrData::Clear()
770 mpFormulaCell
= nullptr;
775 nType
= EXC_CHTR_TYPE_EMPTY
;
779 void XclExpChTrData::WriteFormula( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
781 OSL_ENSURE( mxTokArr
&& !mxTokArr
->Empty(), "XclExpChTrData::Write - no formula" );
784 for( const auto& rLogEntry
: maRefLog
)
786 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
788 rStrm
<< *rLogEntry
.mpUrl
<< sal_uInt8(0x01) << *rLogEntry
.mpFirstTab
<< sal_uInt8(0x02);
792 bool bSingleTab
= rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
;
793 rStrm
.SetSliceSize( bSingleTab
? 6 : 8 );
794 rStrm
<< sal_uInt8(0x01) << sal_uInt8(0x02) << sal_uInt8(0x00);
795 rStrm
<< rTabIdBuffer
.GetId( rLogEntry
.mnFirstXclTab
);
797 rStrm
<< sal_uInt8(0x02);
799 rStrm
<< sal_uInt8(0x00) << rTabIdBuffer
.GetId( rLogEntry
.mnLastXclTab
);
802 rStrm
.SetSliceSize( 0 );
803 rStrm
<< sal_uInt8(0x00);
806 void XclExpChTrData::Write( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
810 case EXC_CHTR_TYPE_RK
:
813 case EXC_CHTR_TYPE_DOUBLE
:
816 case EXC_CHTR_TYPE_STRING
:
817 OSL_ENSURE( pString
, "XclExpChTrData::Write - no string" );
820 case EXC_CHTR_TYPE_FORMULA
:
821 WriteFormula( rStrm
, rTabIdBuffer
);
826 static bool lcl_IsDeletedTab(const XclExpChTrTabIdBuffer
& rTabIdBuffer
, sal_uInt16 nIndex
)
828 return !rTabIdBuffer
.HasId(nIndex
);
831 bool XclExpChTrData::UsesDeletedTab(const XclExpChTrTabIdBuffer
& rTabIdBuffer
) const
833 if (nType
!= EXC_CHTR_TYPE_FORMULA
)
836 for( const auto& rLogEntry
: maRefLog
)
838 if (rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
840 if (lcl_IsDeletedTab(rTabIdBuffer
, rLogEntry
.mnFirstXclTab
))
842 bool bSingleTab
= rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
;
845 if (lcl_IsDeletedTab(rTabIdBuffer
, rLogEntry
.mnLastXclTab
))
851 XclExpChTrCellContent::XclExpChTrCellContent(
852 const ScChangeActionContent
& rAction
,
853 const XclExpRoot
& rRoot
,
854 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
855 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_CELL
),
857 aPosition( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()).aStart
)
861 GetCellData( rRoot
, rAction
.GetOldCell(), pOldData
, nDummy32
, nOldLength
);
862 GetCellData( rRoot
, rAction
.GetNewCell(), pNewData
, nLength
, nDummy16
);
865 XclExpChTrCellContent::~XclExpChTrCellContent()
871 void XclExpChTrCellContent::MakeEmptyChTrData( std::unique_ptr
<XclExpChTrData
>& rpData
)
876 rpData
.reset( new XclExpChTrData
);
879 void XclExpChTrCellContent::GetCellData(
880 const XclExpRoot
& rRoot
, const ScCellValue
& rScCell
,
881 std::unique_ptr
<XclExpChTrData
>& rpData
, sal_uInt32
& rXclLength1
, sal_uInt16
& rXclLength2
)
883 MakeEmptyChTrData( rpData
);
884 rXclLength1
= 0x0000003A;
885 rXclLength2
= 0x0000;
887 if (rScCell
.isEmpty())
893 switch (rScCell
.getType())
897 rpData
->fValue
= rScCell
.getDouble();
898 if( XclTools::GetRKFromDouble( rpData
->nRKValue
, rpData
->fValue
) )
900 rpData
->nType
= EXC_CHTR_TYPE_RK
;
902 rXclLength1
= 0x0000003E;
903 rXclLength2
= 0x0004;
907 rpData
->nType
= EXC_CHTR_TYPE_DOUBLE
;
909 rXclLength1
= 0x00000042;
910 rXclLength2
= 0x0008;
914 case CELLTYPE_STRING
:
918 if (rScCell
.getType() == CELLTYPE_STRING
)
920 sCellStr
= rScCell
.getSharedString()->getString();
921 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
922 rRoot
, sCellStr
, nullptr);
926 XclExpHyperlinkHelper
aLinkHelper( rRoot
, aPosition
);
927 if (rScCell
.getEditText())
929 sCellStr
= ScEditUtil::GetString(*rScCell
.getEditText(), &GetDoc());
930 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
931 rRoot
, *rScCell
.getEditText(), nullptr, aLinkHelper
);
935 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
936 rRoot
, OUString(), nullptr);
939 rpData
->pString
.reset( new XclExpString( sCellStr
, XclStrFlags::NONE
, 32766 ) );
940 rpData
->nType
= EXC_CHTR_TYPE_STRING
;
941 rpData
->nSize
= 3 + rpData
->pString
->GetSize();
942 rXclLength1
= 64 + (sCellStr
.getLength() << 1);
943 rXclLength2
= 6 + static_cast<sal_uInt16
>(sCellStr
.getLength() << 1);
946 case CELLTYPE_FORMULA
:
948 const ScFormulaCell
* pFmlCell
= rScCell
.getFormula();
949 rpData
->mpFormulaCell
= pFmlCell
;
951 const ScTokenArray
* pTokenArray
= pFmlCell
->GetCode();
954 XclExpRefLog
& rRefLog
= rpData
->maRefLog
;
955 rpData
->mxTokArr
= GetFormulaCompiler().CreateFormula(
956 EXC_FMLATYPE_CELL
, *pTokenArray
, &pFmlCell
->aPos
, &rRefLog
);
957 rpData
->nType
= EXC_CHTR_TYPE_FORMULA
;
958 std::size_t nSize
= std::accumulate(rRefLog
.begin(), rRefLog
.end(),
959 static_cast<std::size_t>(rpData
->mxTokArr
->GetSize() + 3),
960 [](const std::size_t& rSum
, const XclExpRefLogEntry
& rLogEntry
) {
961 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
962 return rSum
+ rLogEntry
.mpUrl
->GetSize() + rLogEntry
.mpFirstTab
->GetSize() + 2;
964 return rSum
+ ((rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
) ? 6 : 8);
966 rpData
->nSize
= ::std::min
< std::size_t >( nSize
, 0xFFFF );
967 rXclLength1
= 0x00000052;
968 rXclLength2
= 0x0018;
976 bool XclExpChTrCellContent::UsesDeletedTab() const
978 if (IsDeletedTab(aPosition
.Tab()))
980 if (pOldData
&& pOldData
->UsesDeletedTab(rIdBuffer
))
982 return pNewData
&& pNewData
->UsesDeletedTab(rIdBuffer
);
985 void XclExpChTrCellContent::SaveActionData( XclExpStream
& rStrm
) const
987 WriteTabId( rStrm
, aPosition
.Tab() );
988 rStrm
<< static_cast<sal_uInt16
>((pOldData
? (pOldData
->nType
<< 3) : 0x0000) | (pNewData
? pNewData
->nType
: 0x0000))
989 << sal_uInt16(0x0000);
990 Write2DAddress( rStrm
, aPosition
);
992 << sal_uInt32(0x00000000);
994 pOldData
->Write( rStrm
, rIdBuffer
);
996 pNewData
->Write( rStrm
, rIdBuffer
);
999 sal_uInt16
XclExpChTrCellContent::GetNum() const
1004 std::size_t XclExpChTrCellContent::GetActionByteCount() const
1006 std::size_t nLen
= 16;
1008 nLen
+= pOldData
->nSize
;
1010 nLen
+= pNewData
->nSize
;
1014 static const char* lcl_GetType( XclExpChTrData
* pData
)
1016 switch( pData
->nType
)
1018 case EXC_CHTR_TYPE_RK
:
1019 case EXC_CHTR_TYPE_DOUBLE
:
1021 case EXC_CHTR_TYPE_FORMULA
:
1023 ScFormulaCell
* pFormulaCell
= const_cast< ScFormulaCell
* >( pData
->mpFormulaCell
);
1026 XclXmlUtils::GetFormulaTypeAndValue( *pFormulaCell
, sType
, sValue
);
1030 case EXC_CHTR_TYPE_STRING
:
1038 static void lcl_WriteCell( XclExpXmlStream
& rStrm
, sal_Int32 nElement
, const ScAddress
& rPosition
, XclExpChTrData
* pData
)
1040 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1042 pStream
->startElement(nElement
,
1043 XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), ScRange(rPosition
)),
1044 XML_s
, nullptr, // OOXTODO: not supported
1045 XML_t
, lcl_GetType(pData
),
1046 XML_cm
, nullptr, // OOXTODO: not supported
1047 XML_vm
, nullptr, // OOXTODO: not supported
1048 XML_ph
, nullptr); // OOXTODO: not supported
1049 switch( pData
->nType
)
1051 case EXC_CHTR_TYPE_RK
:
1052 case EXC_CHTR_TYPE_DOUBLE
:
1053 pStream
->startElement(XML_v
);
1054 pStream
->write( pData
->fValue
);
1055 pStream
->endElement( XML_v
);
1057 case EXC_CHTR_TYPE_FORMULA
:
1058 pStream
->startElement( XML_f
1059 // OOXTODO: other attributes? see XclExpFormulaCell::SaveXml()
1061 pStream
->writeEscaped( XclXmlUtils::ToOUString(
1062 rStrm
.GetRoot().GetCompileFormulaContext(),
1063 pData
->mpFormulaCell
->aPos
, pData
->mpFormulaCell
->GetCode()));
1064 pStream
->endElement( XML_f
);
1066 case EXC_CHTR_TYPE_STRING
:
1067 pStream
->startElement(XML_is
);
1068 if( pData
->mpFormattedString
)
1069 pData
->mpFormattedString
->WriteXml( rStrm
);
1071 pData
->pString
->WriteXml( rStrm
);
1072 pStream
->endElement( XML_is
);
1078 pStream
->endElement( nElement
);
1081 void XclExpChTrCellContent::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1083 if (IsDeletedTab(aPosition
.Tab()))
1085 // seen on attempt to export tdf66241-1.ods to xlsx
1086 SAL_WARN("sc", "XclExpChTrCellContent: unable to export position with tab of EXC_TAB_DELETED");
1090 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1091 pStream
->startElement( XML_rcc
,
1092 XML_rId
, OString::number(GetActionNumber()),
1093 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1094 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1095 XML_sId
, OString::number(GetTabId(aPosition
.Tab())),
1096 XML_odxf
, nullptr, // OOXTODO: not supported
1097 XML_xfDxf
, nullptr, // OOXTODO: not supported
1098 XML_s
, nullptr, // OOXTODO: not supported
1099 XML_dxf
, nullptr, // OOXTODO: not supported
1100 XML_numFmtId
, nullptr, // OOXTODO: not supported
1101 XML_quotePrefix
, nullptr, // OOXTODO: not supported
1102 XML_oldQuotePrefix
, nullptr, // OOXTODO: not supported
1103 XML_ph
, nullptr, // OOXTODO: not supported
1104 XML_oldPh
, nullptr, // OOXTODO: not supported
1105 XML_endOfListFormulaUpdate
, nullptr); // OOXTODO: not supported
1108 lcl_WriteCell( rRevisionLogStrm
, XML_oc
, aPosition
, pOldData
.get() );
1111 pStream
->singleElement(XML_nc
, XML_r
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), ScRange(aPosition
)));
1116 lcl_WriteCell( rRevisionLogStrm
, XML_nc
, aPosition
, pNewData
.get() );
1118 // OOXTODO: XML_odxf, XML_ndxf, XML_extLst elements
1119 pStream
->endElement( XML_rcc
);
1122 XclExpChTrInsert::XclExpChTrInsert( const XclExpChTrInsert
& rCopy
) :
1123 XclExpChTrAction(rCopy
),
1124 mbEndOfList(rCopy
.mbEndOfList
),
1125 aRange(rCopy
.aRange
) {}
1127 XclExpChTrInsert::XclExpChTrInsert(
1128 const ScChangeAction
& rAction
,
1129 const XclExpRoot
& rRoot
,
1130 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1131 const ScChangeTrack
& rChangeTrack
) :
1132 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
),
1134 aRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()) )
1136 nLength
= 0x00000030;
1137 switch( rAction
.GetType() )
1139 case SC_CAT_INSERT_COLS
: nOpCode
= EXC_CHTR_OP_INSCOL
; break;
1140 case SC_CAT_INSERT_ROWS
:
1142 const ScChangeActionIns
& rIns
= static_cast<const ScChangeActionIns
&>(rAction
);
1143 mbEndOfList
= rIns
.IsEndOfList();
1144 nOpCode
= EXC_CHTR_OP_INSROW
;
1147 case SC_CAT_DELETE_COLS
: nOpCode
= EXC_CHTR_OP_DELCOL
; break;
1148 case SC_CAT_DELETE_ROWS
: nOpCode
= EXC_CHTR_OP_DELROW
; break;
1150 OSL_FAIL( "XclExpChTrInsert::XclExpChTrInsert - unknown action" );
1153 if( nOpCode
& EXC_CHTR_OP_COLFLAG
)
1155 aRange
.aStart
.SetRow( 0 );
1156 aRange
.aEnd
.SetRow( rRoot
.GetXclMaxPos().Row() );
1160 aRange
.aStart
.SetCol( 0 );
1161 aRange
.aEnd
.SetCol( rRoot
.GetXclMaxPos().Col() );
1164 if( nOpCode
& EXC_CHTR_OP_DELFLAG
)
1166 SetAddAction( new XclExpChTr0x014A( *this ) );
1167 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1171 XclExpChTrInsert::~XclExpChTrInsert()
1175 bool XclExpChTrInsert::UsesDeletedTab() const
1177 return IsDeletedTab(aRange
.aStart
.Tab());
1180 void XclExpChTrInsert::SaveActionData( XclExpStream
& rStrm
) const
1182 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1183 sal_uInt16 nFlagVal
= mbEndOfList
? 0x0001 : 0x0000;
1185 Write2DRange( rStrm
, aRange
);
1186 rStrm
<< sal_uInt32(0x00000000);
1189 void XclExpChTrInsert::PrepareSaveAction( XclExpStream
& rStrm
) const
1191 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1192 XclExpChTrEmpty( 0x0150 ).Save( rStrm
);
1195 void XclExpChTrInsert::CompleteSaveAction( XclExpStream
& rStrm
) const
1197 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1198 XclExpChTrEmpty( 0x0151 ).Save( rStrm
);
1201 sal_uInt16
XclExpChTrInsert::GetNum() const
1206 std::size_t XclExpChTrInsert::GetActionByteCount() const
1211 static const char* lcl_GetAction( sal_uInt16 nOpCode
)
1215 case EXC_CHTR_OP_INSCOL
: return "insertCol";
1216 case EXC_CHTR_OP_INSROW
: return "insertRow";
1217 case EXC_CHTR_OP_DELCOL
: return "deleteCol";
1218 case EXC_CHTR_OP_DELROW
: return "deleteRow";
1219 default: return "*unknown*";
1223 void XclExpChTrInsert::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1225 if (IsDeletedTab(aRange
.aStart
.Tab()))
1227 // seen on attempt to export tdf66241-1.ods to xlsx
1228 SAL_WARN("sc", "XclExpChTrCellContent: unable to export position with tab of EXC_TAB_DELETED");
1232 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1233 pStream
->startElement( XML_rrc
,
1234 XML_rId
, OString::number(GetActionNumber()),
1235 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1236 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1237 XML_sId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1238 XML_eol
, ToPsz10(mbEndOfList
),
1239 XML_ref
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aRange
),
1240 XML_action
, lcl_GetAction( nOpCode
),
1241 XML_edge
, nullptr); // OOXTODO: ???
1243 // OOXTODO: does this handle XML_rfmt, XML_undo?
1244 XclExpChTrAction
* pAction
= GetAddAction();
1245 while( pAction
!= nullptr )
1247 pAction
->SaveXml( rRevisionLogStrm
);
1248 pAction
= pAction
->GetAddAction();
1250 pStream
->endElement( XML_rrc
);
1253 XclExpChTrInsertTab::XclExpChTrInsertTab(
1254 const ScChangeAction
& rAction
,
1255 const XclExpRoot
& rRoot
,
1256 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
1257 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_INSTAB
),
1258 XclExpRoot( rRoot
),
1259 nTab( static_cast<SCTAB
>(rAction
.GetBigRange().aStart
.Tab()) )
1261 nLength
= 0x0000021C;
1265 XclExpChTrInsertTab::~XclExpChTrInsertTab()
1269 bool XclExpChTrInsertTab::UsesDeletedTab() const
1271 return IsDeletedTab(nTab
);
1274 void XclExpChTrInsertTab::SaveActionData( XclExpStream
& rStrm
) const
1276 WriteTabId( rStrm
, nTab
);
1277 rStrm
<< sal_uInt32( 0 );
1278 lcl_WriteFixedString( rStrm
, XclExpString( GetTabInfo().GetScTabName( nTab
) ), 127 );
1279 lcl_WriteDateTime( rStrm
, GetDateTime() );
1280 rStrm
.WriteZeroBytes( 133 );
1283 sal_uInt16
XclExpChTrInsertTab::GetNum() const
1288 std::size_t XclExpChTrInsertTab::GetActionByteCount() const
1293 void XclExpChTrInsertTab::SaveXml( XclExpXmlStream
& rStrm
)
1295 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1296 pStream
->singleElement( XML_ris
,
1297 XML_rId
, OString::number(GetActionNumber()),
1298 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1299 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1300 XML_sheetId
, OString::number(GetTabId(nTab
)),
1301 XML_name
, GetTabInfo().GetScTabName(nTab
).toUtf8(),
1302 XML_sheetPosition
, OString::number(nTab
) );
1305 XclExpChTrMoveRange::XclExpChTrMoveRange(
1306 const ScChangeActionMove
& rAction
,
1307 const XclExpRoot
& rRoot
,
1308 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1309 const ScChangeTrack
& rChangeTrack
) :
1310 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_MOVE
),
1311 aDestRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc() ) )
1313 nLength
= 0x00000042;
1314 aSourceRange
= aDestRange
;
1315 sal_Int32 nDCols
, nDRows
, nDTabs
;
1316 rAction
.GetDelta( nDCols
, nDRows
, nDTabs
);
1317 aSourceRange
.aStart
.IncRow( static_cast<SCROW
>(-nDRows
) );
1318 aSourceRange
.aStart
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1319 aSourceRange
.aStart
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1320 aSourceRange
.aEnd
.IncRow( static_cast<SCROW
>(-nDRows
) );
1321 aSourceRange
.aEnd
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1322 aSourceRange
.aEnd
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1323 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1326 XclExpChTrMoveRange::~XclExpChTrMoveRange()
1330 bool XclExpChTrMoveRange::UsesDeletedTab() const
1332 return IsDeletedTab(aDestRange
.aStart
.Tab()) ||
1333 IsDeletedTab(aSourceRange
.aStart
.Tab());
1336 void XclExpChTrMoveRange::SaveActionData( XclExpStream
& rStrm
) const
1338 WriteTabId( rStrm
, aDestRange
.aStart
.Tab() );
1339 Write2DRange( rStrm
, aSourceRange
);
1340 Write2DRange( rStrm
, aDestRange
);
1341 WriteTabId( rStrm
, aSourceRange
.aStart
.Tab() );
1342 rStrm
<< sal_uInt32(0x00000000);
1345 void XclExpChTrMoveRange::PrepareSaveAction( XclExpStream
& rStrm
) const
1347 XclExpChTrEmpty( 0x014E ).Save( rStrm
);
1350 void XclExpChTrMoveRange::CompleteSaveAction( XclExpStream
& rStrm
) const
1352 XclExpChTrEmpty( 0x014F ).Save( rStrm
);
1355 sal_uInt16
XclExpChTrMoveRange::GetNum() const
1360 std::size_t XclExpChTrMoveRange::GetActionByteCount() const
1365 void XclExpChTrMoveRange::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1367 if (IsDeletedTab(aDestRange
.aStart
.Tab()) || IsDeletedTab(aSourceRange
.aStart
.Tab()))
1369 // seen on attempt to export tdf66241-1.ods to xlsx
1370 SAL_WARN("sc", "XclExpChTrCellContent: unable to export position with tab of EXC_TAB_DELETED");
1374 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1376 pStream
->startElement( XML_rm
,
1377 XML_rId
, OString::number(GetActionNumber()),
1378 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1379 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1380 XML_sheetId
, OString::number(GetTabId(aDestRange
.aStart
.Tab())),
1381 XML_source
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aSourceRange
),
1382 XML_destination
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aDestRange
),
1383 XML_sourceSheetId
, OString::number(GetTabId(aSourceRange
.aStart
.Tab())) );
1384 // OOXTODO: does this handle XML_rfmt, XML_undo?
1385 XclExpChTrAction
* pAction
= GetAddAction();
1386 while( pAction
!= nullptr )
1388 pAction
->SaveXml( rRevisionLogStrm
);
1389 pAction
= pAction
->GetAddAction();
1391 pStream
->endElement( XML_rm
);
1394 XclExpChTr0x014A::XclExpChTr0x014A( const XclExpChTrInsert
& rAction
) :
1395 XclExpChTrInsert( rAction
)
1397 nLength
= 0x00000026;
1398 nOpCode
= EXC_CHTR_OP_FORMAT
;
1401 XclExpChTr0x014A::~XclExpChTr0x014A()
1405 void XclExpChTr0x014A::SaveActionData( XclExpStream
& rStrm
) const
1407 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1408 rStrm
<< sal_uInt16(0x0003)
1409 << sal_uInt16(0x0001);
1410 Write2DRange( rStrm
, aRange
);
1413 sal_uInt16
XclExpChTr0x014A::GetNum() const
1418 std::size_t XclExpChTr0x014A::GetActionByteCount() const
1423 void XclExpChTr0x014A::SaveXml( XclExpXmlStream
& rStrm
)
1425 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1427 pStream
->startElement( XML_rfmt
,
1428 XML_sheetId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1429 XML_xfDxf
, nullptr, // OOXTODO: not supported
1430 XML_s
, nullptr, // OOXTODO: style
1431 XML_sqref
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aRange
),
1432 XML_start
, nullptr, // OOXTODO: for string changes
1433 XML_length
, nullptr); // OOXTODO: for string changes
1434 // OOXTODO: XML_dxf, XML_extLst
1436 pStream
->endElement( XML_rfmt
);
1439 std::size_t ExcXmlRecord::GetLen() const
1444 sal_uInt16
ExcXmlRecord::GetNum() const
1449 void ExcXmlRecord::Save( XclExpStream
& )
1451 // Do nothing; ignored for BIFF output.
1456 class EndXmlElement
: public ExcXmlRecord
1458 sal_Int32 mnElement
;
1460 explicit EndXmlElement( sal_Int32 nElement
) : mnElement( nElement
) {}
1461 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
1466 void EndXmlElement::SaveXml( XclExpXmlStream
& rStrm
)
1468 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1469 pStream
->write("</")->writeId(mnElement
)->write(">");
1472 XclExpChangeTrack::XclExpChangeTrack( const XclExpRoot
& rRoot
) :
1473 XclExpRoot( rRoot
),
1474 pTabIdBuffer( nullptr )
1476 OSL_ENSURE( GetOldRoot().pTabId
, "XclExpChangeTrack::XclExpChangeTrack - root data incomplete" );
1477 if( !GetOldRoot().pTabId
)
1480 ScChangeTrack
* pTempChangeTrack
= CreateTempChangeTrack();
1481 if (!pTempChangeTrack
)
1484 pTabIdBuffer
= new XclExpChTrTabIdBuffer( GetTabInfo().GetXclTabCount() );
1485 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pTabIdBuffer
) );
1487 // calculate final table order (tab id list)
1488 const ScChangeAction
* pScAction
;
1489 for( pScAction
= pTempChangeTrack
->GetLast(); pScAction
; pScAction
= pScAction
->GetPrev() )
1491 if( pScAction
->GetType() == SC_CAT_INSERT_TABS
)
1493 SCTAB nScTab
= static_cast< SCTAB
>( pScAction
->GetBigRange().aStart
.Tab() );
1494 pTabIdBuffer
->InitFill( GetTabInfo().GetXclTab( nScTab
) );
1497 pTabIdBuffer
->InitFillup();
1498 GetOldRoot().pTabId
->Copy( *pTabIdBuffer
);
1500 // get actions in reverse order
1501 pScAction
= pTempChangeTrack
->GetLast();
1504 PushActionRecord( *pScAction
);
1505 const ScChangeAction
* pPrevAction
= pScAction
->GetPrev();
1506 pScAction
= pPrevAction
;
1509 // build record list
1510 if (GetOutput() == EXC_OUTPUT_BINARY
)
1512 XclExpChTrHeader
* pHeader
= new XclExpChTrHeader
; // header record for last GUID
1513 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeader
) );
1514 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0195
) );
1515 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0194( *pTempChangeTrack
) ) );
1517 OUString sLastUsername
;
1518 DateTime
aLastDateTime( DateTime::EMPTY
);
1519 sal_uInt32 nIndex
= 1;
1520 sal_uInt8 aGUID
[ 16 ]; // GUID for action info records
1521 bool bValidGUID
= false;
1522 while( !aActionStack
.empty() )
1524 XclExpChTrAction
* pAction
= aActionStack
.top();
1527 if( (nIndex
== 1) || pAction
->ForceInfoRecord() ||
1528 (pAction
->GetUsername() != sLastUsername
) ||
1529 (pAction
->GetDateTime() != aLastDateTime
) )
1531 lcl_GenerateGUID( aGUID
, bValidGUID
);
1532 sLastUsername
= pAction
->GetUsername();
1533 aLastDateTime
= pAction
->GetDateTime();
1535 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrInfo(sLastUsername
, aLastDateTime
, aGUID
)) );
1536 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrTabId(pAction
->GetTabIdBuffer())) );
1537 pHeader
->SetGUID( aGUID
);
1539 pAction
->SetIndex( nIndex
);
1540 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pAction
) );
1543 pHeader
->SetGUID( aGUID
);
1544 pHeader
->SetCount( nIndex
- 1 );
1545 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new ExcEof
) );
1549 XclExpXmlChTrHeaders
* pHeaders
= new XclExpXmlChTrHeaders
;
1550 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeaders
));
1552 OUString sLastUsername
;
1553 DateTime
aLastDateTime(DateTime::EMPTY
);
1554 sal_uInt32 nIndex
= 1;
1555 sal_Int32 nLogNumber
= 1;
1556 XclExpXmlChTrHeader
* pCurHeader
= nullptr;
1557 sal_uInt8 aGUID
[ 16 ]; // GUID for action info records
1558 bool bValidGUID
= false;
1560 while (!aActionStack
.empty())
1562 XclExpChTrAction
* pAction
= aActionStack
.top();
1565 if( (nIndex
== 1) || pAction
->ForceInfoRecord() ||
1566 (pAction
->GetUsername() != sLastUsername
) ||
1567 (pAction
->GetDateTime() != aLastDateTime
) )
1569 lcl_GenerateGUID( aGUID
, bValidGUID
);
1570 sLastUsername
= pAction
->GetUsername();
1571 aLastDateTime
= pAction
->GetDateTime();
1573 pCurHeader
= new XclExpXmlChTrHeader(sLastUsername
, aLastDateTime
, aGUID
, nLogNumber
, pAction
->GetTabIdBuffer());
1574 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pCurHeader
));
1576 pHeaders
->SetGUID(aGUID
);
1578 pAction
->SetIndex(nIndex
);
1579 pCurHeader
->AppendAction(std::unique_ptr
<XclExpChTrAction
>(pAction
));
1582 pHeaders
->SetGUID(aGUID
);
1583 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new EndXmlElement(XML_headers
)));
1587 XclExpChangeTrack::~XclExpChangeTrack()
1589 while( !aActionStack
.empty() )
1591 delete aActionStack
.top();
1596 ScChangeTrack
* XclExpChangeTrack::CreateTempChangeTrack()
1598 // get original change track
1599 ScChangeTrack
* pOrigChangeTrack
= GetDoc().GetChangeTrack();
1600 OSL_ENSURE( pOrigChangeTrack
, "XclExpChangeTrack::CreateTempChangeTrack - no change track data" );
1601 if( !pOrigChangeTrack
)
1605 // create empty document
1606 xTempDoc
.reset(new ScDocument
);
1608 // adjust table count
1609 SCTAB nOrigCount
= GetDoc().GetTableCount();
1611 for( sal_Int32 nIndex
= 0; nIndex
< nOrigCount
; nIndex
++ )
1613 xTempDoc
->CreateValidTabName(sTabName
);
1614 xTempDoc
->InsertTab(SC_TAB_APPEND
, sTabName
);
1616 OSL_ENSURE(nOrigCount
== xTempDoc
->GetTableCount(),
1617 "XclExpChangeTrack::CreateTempChangeTrack - table count mismatch");
1618 if(nOrigCount
!= xTempDoc
->GetTableCount())
1621 return pOrigChangeTrack
->Clone(xTempDoc
.get());
1624 void XclExpChangeTrack::PushActionRecord( const ScChangeAction
& rAction
)
1626 XclExpChTrAction
* pXclAction
= nullptr;
1627 ScChangeTrack
* pTempChangeTrack
= xTempDoc
->GetChangeTrack();
1628 switch( rAction
.GetType() )
1630 case SC_CAT_CONTENT
:
1631 pXclAction
= new XclExpChTrCellContent( static_cast<const ScChangeActionContent
&>(rAction
), GetRoot(), *pTabIdBuffer
);
1633 case SC_CAT_INSERT_ROWS
:
1634 case SC_CAT_INSERT_COLS
:
1635 case SC_CAT_DELETE_ROWS
:
1636 case SC_CAT_DELETE_COLS
:
1637 if (pTempChangeTrack
)
1638 pXclAction
= new XclExpChTrInsert( rAction
, GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1640 case SC_CAT_INSERT_TABS
:
1642 pXclAction
= new XclExpChTrInsertTab( rAction
, GetRoot(), *pTabIdBuffer
);
1643 XclExpChTrTabIdBuffer
* pNewBuffer
= new XclExpChTrTabIdBuffer( *pTabIdBuffer
);
1644 pNewBuffer
->Remove();
1645 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pNewBuffer
) );
1646 pTabIdBuffer
= pNewBuffer
;
1650 if (pTempChangeTrack
)
1651 pXclAction
= new XclExpChTrMoveRange( static_cast<const ScChangeActionMove
&>(rAction
), GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1656 aActionStack
.push( pXclAction
);
1659 bool XclExpChangeTrack::WriteUserNamesStream()
1662 rtl::Reference
<SotStorageStream
> xSvStrm
= OpenStream(EXC_STREAM_USERNAMES
);
1663 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::WriteUserNamesStream - no stream" );
1666 XclExpStream
aXclStrm( *xSvStrm
, GetRoot() );
1667 XclExpChTr0x0191().Save( aXclStrm
);
1668 XclExpChTr0x0198().Save( aXclStrm
);
1669 XclExpChTr0x0192().Save( aXclStrm
);
1670 XclExpChTr0x0197().Save( aXclStrm
);
1677 void XclExpChangeTrack::Write()
1679 if (maRecList
.empty())
1682 if( !WriteUserNamesStream() )
1685 rtl::Reference
<SotStorageStream
> xSvStrm
= OpenStream(EXC_STREAM_REVLOG
);
1686 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::Write - no stream" );
1689 XclExpStream
aXclStrm( *xSvStrm
, GetRoot(), EXC_MAXRECSIZE_BIFF8
+ 8 );
1691 for(const auto& rxRec
: maRecList
)
1692 rxRec
->Save(aXclStrm
);
1698 static void lcl_WriteUserNamesXml( XclExpXmlStream
& rWorkbookStrm
)
1700 sax_fastparser::FSHelperPtr pUserNames
= rWorkbookStrm
.CreateOutputStream(
1701 u
"xl/revisions/userNames.xml"_ustr
,
1702 u
"revisions/userNames.xml",
1703 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1704 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml",
1705 CREATE_OFFICEDOC_RELATION_TYPE("usernames"));
1706 pUserNames
->startElement( XML_users
,
1707 XML_xmlns
, rWorkbookStrm
.getNamespaceURL(OOX_NS(xls
)).toUtf8(),
1708 FSNS( XML_xmlns
, XML_r
), rWorkbookStrm
.getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
1710 // OOXTODO: XML_userinfo elements for each user editing the file
1711 // Doesn't seem to be supported by .xls output either (based on
1712 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1713 pUserNames
->endElement( XML_users
);
1716 void XclExpChangeTrack::WriteXml( XclExpXmlStream
& rWorkbookStrm
)
1718 if (maRecList
.empty())
1721 lcl_WriteUserNamesXml( rWorkbookStrm
);
1723 sax_fastparser::FSHelperPtr pRevisionHeaders
= rWorkbookStrm
.CreateOutputStream(
1724 u
"xl/revisions/revisionHeaders.xml"_ustr
,
1725 u
"revisions/revisionHeaders.xml",
1726 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1727 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml",
1728 CREATE_OFFICEDOC_RELATION_TYPE("revisionHeaders"));
1729 // OOXTODO: XML_userinfo elements for each user editing the file
1730 // Doesn't seem to be supported by .xls output either (based on
1731 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1732 rWorkbookStrm
.PushStream( pRevisionHeaders
);
1734 for (const auto& rxRec
: maRecList
)
1735 rxRec
->SaveXml(rWorkbookStrm
);
1737 rWorkbookStrm
.PopStream();
1740 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */