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>
43 static OString
lcl_DateTimeToOString( const DateTime
& rDateTime
)
46 snprintf( sBuf
, sizeof( sBuf
),
47 "%d-%02d-%02dT%02d:%02d:%02d.%09" SAL_PRIuUINT32
"Z",
48 rDateTime
.GetYear(), rDateTime
.GetMonth(), rDateTime
.GetDay(),
49 rDateTime
.GetHour(), rDateTime
.GetMin(), rDateTime
.GetSec(),
50 rDateTime
.GetNanoSec() );
56 static void lcl_WriteDateTime( XclExpStream
& rStrm
, const DateTime
& rDateTime
)
58 rStrm
.SetSliceSize( 7 );
59 rStrm
<< static_cast<sal_uInt16
>(rDateTime
.GetYear())
60 << static_cast<sal_uInt8
>(rDateTime
.GetMonth())
61 << static_cast<sal_uInt8
>(rDateTime
.GetDay())
62 << static_cast<sal_uInt8
>(rDateTime
.GetHour())
63 << static_cast<sal_uInt8
>(rDateTime
.GetMin())
64 << static_cast<sal_uInt8
>(rDateTime
.GetSec());
65 rStrm
.SetSliceSize( 0 );
68 // write string and fill rest of <nLength> with zero bytes
69 // <nLength> is without string header
70 static void lcl_WriteFixedString( XclExpStream
& rStrm
, const XclExpString
& rString
, std::size_t nLength
)
72 std::size_t nStrBytes
= rString
.GetBufferSize();
73 OSL_ENSURE( nLength
>= nStrBytes
, "lcl_WriteFixedString - String too long" );
74 if( rString
.Len() > 0 )
76 if( nLength
> nStrBytes
)
77 rStrm
.WriteZeroBytes( nLength
- nStrBytes
);
80 static void lcl_GenerateGUID( sal_uInt8
* pGUID
, bool& rValidGUID
)
82 rtl_createUuid( pGUID
, rValidGUID
? pGUID
: nullptr, false );
86 static void lcl_WriteGUID( XclExpStream
& rStrm
, const sal_uInt8
* pGUID
)
88 rStrm
.SetSliceSize( 16 );
89 for( std::size_t nIndex
= 0; nIndex
< 16; nIndex
++ )
90 rStrm
<< pGUID
[ nIndex
];
91 rStrm
.SetSliceSize( 0 );
94 XclExpUserBView::XclExpUserBView( const OUString
& rUsername
, const sal_uInt8
* pGUID
) :
95 sUsername( rUsername
)
97 memcpy( aGUID
, pGUID
, 16 );
100 void XclExpUserBView::SaveCont( XclExpStream
& rStrm
)
102 rStrm
<< sal_uInt32(0xFF078014)
103 << sal_uInt32(0x00000001);
104 lcl_WriteGUID( rStrm
, aGUID
);
105 rStrm
.WriteZeroBytes( 8 );
106 rStrm
<< sal_uInt32(1200)
109 << sal_uInt16(0x0CF7)
110 << sal_uInt16(0x0000)
111 << sal_uInt16(0x0001)
112 << sal_uInt16(0x0000);
113 if( sUsername
.Len() > 0 )
117 sal_uInt16
XclExpUserBView::GetNum() const
122 std::size_t XclExpUserBView::GetLen() const
124 return 50 + ((sUsername
.Len() > 0) ? sUsername
.GetSize() : 0);
127 XclExpUserBViewList::XclExpUserBViewList( const ScChangeTrack
& rChangeTrack
)
129 sal_uInt8 aGUID
[ 16 ];
130 bool bValidGUID
= false;
131 const std::set
<OUString
>& rStrColl
= rChangeTrack
.GetUserCollection();
132 aViews
.reserve(rStrColl
.size());
133 for (const auto& rStr
: rStrColl
)
135 lcl_GenerateGUID( aGUID
, bValidGUID
);
136 aViews
.emplace_back( rStr
, aGUID
);
140 XclExpUserBViewList::~XclExpUserBViewList()
144 void XclExpUserBViewList::Save( XclExpStream
& rStrm
)
146 for( XclExpUserBView
& rView
: aViews
)
150 XclExpUsersViewBegin::XclExpUsersViewBegin( const sal_uInt8
* pGUID
, sal_uInt32 nTab
) :
153 memcpy( aGUID
, pGUID
, 16 );
156 void XclExpUsersViewBegin::SaveCont( XclExpStream
& rStrm
)
158 lcl_WriteGUID( rStrm
, aGUID
);
163 << sal_uInt32(0x0000003C)
174 sal_uInt16
XclExpUsersViewBegin::GetNum() const
179 std::size_t XclExpUsersViewBegin::GetLen() const
184 void XclExpUsersViewEnd::SaveCont( XclExpStream
& rStrm
)
186 rStrm
<< sal_uInt16(0x0001);
189 sal_uInt16
XclExpUsersViewEnd::GetNum() const
194 std::size_t XclExpUsersViewEnd::GetLen() const
199 void XclExpChTr0x0191::SaveCont( XclExpStream
& rStrm
)
201 rStrm
<< sal_uInt16(0x0000);
204 sal_uInt16
XclExpChTr0x0191::GetNum() const
209 std::size_t XclExpChTr0x0191::GetLen() const
214 void XclExpChTr0x0198::SaveCont( XclExpStream
& rStrm
)
216 rStrm
<< sal_uInt16(0x0006)
217 << sal_uInt16(0x0000);
220 sal_uInt16
XclExpChTr0x0198::GetNum() const
225 std::size_t XclExpChTr0x0198::GetLen() const
230 void XclExpChTr0x0192::SaveCont( XclExpStream
& rStrm
)
232 rStrm
<< sal_uInt16( 0x0022 );
233 rStrm
.WriteZeroBytes( 510 );
236 sal_uInt16
XclExpChTr0x0192::GetNum() const
241 std::size_t XclExpChTr0x0192::GetLen() const
246 void XclExpChTr0x0197::SaveCont( XclExpStream
& rStrm
)
248 rStrm
<< sal_uInt16(0x0000);
251 sal_uInt16
XclExpChTr0x0197::GetNum() const
256 std::size_t XclExpChTr0x0197::GetLen() const
261 XclExpChTrEmpty::~XclExpChTrEmpty()
265 sal_uInt16
XclExpChTrEmpty::GetNum() const
270 std::size_t XclExpChTrEmpty::GetLen() const
275 XclExpChTr0x0195::~XclExpChTr0x0195()
279 void XclExpChTr0x0195::SaveCont( XclExpStream
& rStrm
)
281 rStrm
.WriteZeroBytes( 162 );
284 sal_uInt16
XclExpChTr0x0195::GetNum() const
289 std::size_t XclExpChTr0x0195::GetLen() const
294 XclExpChTr0x0194::~XclExpChTr0x0194()
298 void XclExpChTr0x0194::SaveCont( XclExpStream
& rStrm
)
300 rStrm
<< sal_uInt32(0);
301 lcl_WriteDateTime( rStrm
, aDateTime
);
302 rStrm
<< sal_uInt8(0);
303 lcl_WriteFixedString( rStrm
, sUsername
, 147 );
306 sal_uInt16
XclExpChTr0x0194::GetNum() const
311 std::size_t XclExpChTr0x0194::GetLen() const
316 XclExpChTrHeader::~XclExpChTrHeader()
320 void XclExpChTrHeader::SaveCont( XclExpStream
& rStrm
)
322 rStrm
<< sal_uInt16(0x0006)
323 << sal_uInt16(0x0000)
324 << sal_uInt16(0x000D);
325 lcl_WriteGUID( rStrm
, aGUID
);
326 lcl_WriteGUID( rStrm
, aGUID
);
328 << sal_uInt16(0x0001)
329 << sal_uInt32(0x00000000)
330 << sal_uInt16(0x001E);
333 sal_uInt16
XclExpChTrHeader::GetNum() const
338 std::size_t XclExpChTrHeader::GetLen() const
343 void XclExpChTrHeader::SaveXml( XclExpXmlStream
& rRevisionHeadersStrm
)
345 sax_fastparser::FSHelperPtr pHeaders
= rRevisionHeadersStrm
.GetCurrentStream();
346 tools::Guid
aGuid(aGUID
);
347 rRevisionHeadersStrm
.WriteAttributes(
348 XML_guid
, aGuid
.getString(),
349 XML_lastGuid
, nullptr, // OOXTODO
350 XML_shared
, nullptr, // OOXTODO
351 XML_diskRevisions
, nullptr, // OOXTODO
352 XML_history
, nullptr, // OOXTODO
353 XML_trackRevisions
, nullptr, // OOXTODO
354 XML_exclusive
, nullptr, // OOXTODO
355 XML_revisionId
, nullptr, // OOXTODO
356 XML_version
, nullptr, // OOXTODO
357 XML_keepChangeHistory
, nullptr, // OOXTODO
358 XML_protected
, nullptr, // OOXTODO
359 XML_preserveHistory
, nullptr); // OOXTODO
360 pHeaders
->write( ">" );
363 void XclExpXmlChTrHeaders::SetGUID( const sal_uInt8
* pGUID
)
365 memcpy(maGUID
, pGUID
, 16);
368 void XclExpXmlChTrHeaders::SaveXml( XclExpXmlStream
& rStrm
)
370 sax_fastparser::FSHelperPtr pHeaders
= rStrm
.GetCurrentStream();
372 pHeaders
->write("<")->writeId(XML_headers
);
374 tools::Guid
aGuid(maGUID
);
375 rStrm
.WriteAttributes(
376 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
377 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)),
378 XML_guid
, aGuid
.getString(),
379 XML_lastGuid
, nullptr, // OOXTODO
380 XML_shared
, nullptr, // OOXTODO
381 XML_diskRevisions
, nullptr, // OOXTODO
382 XML_history
, nullptr, // OOXTODO
383 XML_trackRevisions
, nullptr, // OOXTODO
384 XML_exclusive
, nullptr, // OOXTODO
385 XML_revisionId
, nullptr, // OOXTODO
386 XML_version
, nullptr, // OOXTODO
387 XML_keepChangeHistory
, nullptr, // OOXTODO
388 XML_protected
, nullptr, // OOXTODO
389 XML_preserveHistory
, nullptr); // OOXTODO
391 pHeaders
->write(">");
394 XclExpXmlChTrHeader::XclExpXmlChTrHeader(
395 OUString aUserName
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
,
396 sal_Int32 nLogNumber
, const XclExpChTrTabIdBuffer
& rBuf
) :
397 maUserName(std::move(aUserName
)), maDateTime(rDateTime
), mnLogNumber(nLogNumber
),
398 mnMinAction(0), mnMaxAction(0)
400 memcpy(maGUID
, pGUID
, 16);
401 if (rBuf
.GetBufferCount())
403 maTabBuffer
.resize(rBuf
.GetBufferCount());
404 rBuf
.GetBufferCopy(maTabBuffer
.data());
408 void XclExpXmlChTrHeader::SaveXml( XclExpXmlStream
& rStrm
)
410 sax_fastparser::FSHelperPtr pHeader
= rStrm
.GetCurrentStream();
412 pHeader
->write("<")->writeId(XML_header
);
415 sax_fastparser::FSHelperPtr pRevLogStrm
= rStrm
.CreateOutputStream(
416 XclXmlUtils::GetStreamName("xl/revisions/", "revisionLog", mnLogNumber
),
417 XclXmlUtils::GetStreamName(nullptr, "revisionLog", mnLogNumber
),
418 rStrm
.GetCurrentStream()->getOutputStream(),
419 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
420 CREATE_OFFICEDOC_RELATION_TYPE("revisionLog"),
423 tools::Guid
aGuid(maGUID
);
424 rStrm
.WriteAttributes(
425 XML_guid
, aGuid
.getString(),
426 XML_dateTime
, lcl_DateTimeToOString(maDateTime
),
427 XML_userName
, maUserName
,
428 FSNS(XML_r
, XML_id
), aRelId
);
431 rStrm
.WriteAttributes(XML_minRId
, OUString::number(mnMinAction
));
434 rStrm
.WriteAttributes(XML_maxRId
, OUString::number(mnMaxAction
));
436 if (!maTabBuffer
.empty())
437 // next available sheet index.
438 rStrm
.WriteAttributes(XML_maxSheetId
, OUString::number(maTabBuffer
.back()+1));
442 if (!maTabBuffer
.empty())
444 // Write sheet index map.
445 size_t n
= maTabBuffer
.size();
446 pHeader
->startElement(XML_sheetIdMap
, XML_count
, OString::number(n
));
448 for (size_t i
= 0; i
< n
; ++i
)
450 pHeader
->singleElement(XML_sheetId
, XML_val
, OString::number(maTabBuffer
[i
]));
452 pHeader
->endElement(XML_sheetIdMap
);
455 // Write all revision logs in a separate stream.
457 rStrm
.PushStream(pRevLogStrm
);
459 pRevLogStrm
->write("<")->writeId(XML_revisions
);
461 rStrm
.WriteAttributes(
462 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
463 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)));
465 pRevLogStrm
->write(">");
467 for (const auto& rxAction
: maActions
)
469 rxAction
->SaveXml(rStrm
);
472 pRevLogStrm
->write("</")->writeId(XML_revisions
)->write(">");
476 pHeader
->write("</")->writeId(XML_header
)->write(">");
479 void XclExpXmlChTrHeader::AppendAction( std::unique_ptr
<XclExpChTrAction
> pAction
)
481 sal_uInt32 nActionNum
= pAction
->GetActionNumber();
482 if (!mnMinAction
|| mnMinAction
> nActionNum
)
483 mnMinAction
= nActionNum
;
485 if (!mnMaxAction
|| mnMaxAction
< nActionNum
)
486 mnMaxAction
= nActionNum
;
488 maActions
.push_back(std::move(pAction
));
491 XclExpChTrInfo::XclExpChTrInfo( const OUString
& rUsername
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
) :
492 sUsername( rUsername
),
493 aDateTime( rDateTime
)
495 memcpy( aGUID
, pGUID
, 16 );
498 XclExpChTrInfo::~XclExpChTrInfo()
502 void XclExpChTrInfo::SaveCont( XclExpStream
& rStrm
)
504 rStrm
<< sal_uInt32(0xFFFFFFFF)
505 << sal_uInt32(0x00000000)
506 << sal_uInt32(0x00000020)
507 << sal_uInt16(0xFFFF);
508 lcl_WriteGUID( rStrm
, aGUID
);
509 rStrm
<< sal_uInt16(0x04B0);
510 lcl_WriteFixedString( rStrm
, sUsername
, 113 );
511 lcl_WriteDateTime( rStrm
, aDateTime
);
512 rStrm
<< sal_uInt8(0x0000)
513 << sal_uInt16(0x0002);
516 sal_uInt16
XclExpChTrInfo::GetNum() const
521 std::size_t XclExpChTrInfo::GetLen() const
526 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount
) :
530 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
531 memset( pBuffer
.get(), 0, sizeof(sal_uInt16
) * nBufSize
);
532 pLast
= pBuffer
.get() + nBufSize
- 1;
535 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( const XclExpChTrTabIdBuffer
& rCopy
) :
536 nBufSize( rCopy
.nBufSize
),
537 nLastId( rCopy
.nLastId
)
539 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
540 memcpy( pBuffer
.get(), rCopy
.pBuffer
.get(), sizeof(sal_uInt16
) * nBufSize
);
541 pLast
= pBuffer
.get() + nBufSize
- 1;
544 XclExpChTrTabIdBuffer::~XclExpChTrTabIdBuffer()
548 void XclExpChTrTabIdBuffer::InitFill( sal_uInt16 nIndex
)
550 OSL_ENSURE( nIndex
< nLastId
, "XclExpChTrTabIdBuffer::Insert - out of range" );
552 sal_uInt16 nFreeCount
= 0;
553 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
557 if( nFreeCount
> nIndex
)
565 void XclExpChTrTabIdBuffer::InitFillup()
567 sal_uInt16 nFreeCount
= 1;
568 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
570 *pElem
= nFreeCount
++;
574 sal_uInt16
XclExpChTrTabIdBuffer::GetId( sal_uInt16 nIndex
) const
576 OSL_ENSURE( nIndex
< nBufSize
, "XclExpChTrTabIdBuffer::GetId - out of range" );
577 return pBuffer
[ nIndex
];
580 void XclExpChTrTabIdBuffer::Remove()
582 OSL_ENSURE( pBuffer
.get() <= pLast
, "XclExpChTrTabIdBuffer::Remove - buffer empty" );
583 sal_uInt16
* pElem
= pBuffer
.get();
584 while( (pElem
<= pLast
) && (*pElem
!= nLastId
) )
586 while( pElem
< pLast
)
588 *pElem
= *(pElem
+ 1);
595 XclExpChTrTabId::XclExpChTrTabId( const XclExpChTrTabIdBuffer
& rBuffer
)
596 : nTabCount( rBuffer
.GetBufferCount() )
598 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
599 rBuffer
.GetBufferCopy( pBuffer
.get() );
602 XclExpChTrTabId::~XclExpChTrTabId()
607 void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer
& rBuffer
)
610 nTabCount
= rBuffer
.GetBufferCount();
611 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
612 rBuffer
.GetBufferCopy( pBuffer
.get() );
615 void XclExpChTrTabId::SaveCont( XclExpStream
& rStrm
)
617 rStrm
.EnableEncryption();
619 rStrm
.Write(pBuffer
.get(), nTabCount
);
621 for( sal_uInt16 nIndex
= 1; nIndex
<= nTabCount
; nIndex
++ )
625 sal_uInt16
XclExpChTrTabId::GetNum() const
630 std::size_t XclExpChTrTabId::GetLen() const
632 return nTabCount
<< 1;
635 // ! does not copy additional actions
636 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction
& rCopy
) :
638 sUsername( rCopy
.sUsername
),
639 aDateTime( rCopy
.aDateTime
),
641 bAccepted( rCopy
.bAccepted
),
642 rTabInfo( rCopy
.rTabInfo
),
643 rIdBuffer( rCopy
.rIdBuffer
),
644 nLength( rCopy
.nLength
),
645 nOpCode( rCopy
.nOpCode
),
646 bForceInfo( rCopy
.bForceInfo
)
650 XclExpChTrAction::XclExpChTrAction(
651 const ScChangeAction
& rAction
,
652 const XclExpRoot
& rRoot
,
653 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
654 sal_uInt16 nNewOpCode
) :
655 sUsername( rAction
.GetUser() ),
656 aDateTime( rAction
.GetDateTime() ),
658 bAccepted( rAction
.IsAccepted() ),
659 rTabInfo( rRoot
.GetTabInfo() ),
660 rIdBuffer( rTabIdBuffer
),
662 nOpCode( nNewOpCode
),
665 aDateTime
.SetSec( 0 );
666 aDateTime
.SetNanoSec( 0 );
669 XclExpChTrAction::~XclExpChTrAction()
673 void XclExpChTrAction::SetAddAction( XclExpChTrAction
* pAction
)
676 pAddAction
->SetAddAction( pAction
);
678 pAddAction
.reset( pAction
);
681 void XclExpChTrAction::AddDependentContents(
682 const ScChangeAction
& rAction
,
683 const XclExpRoot
& rRoot
,
684 const ScChangeTrack
& rChangeTrack
)
686 ScChangeActionMap aActionMap
;
688 rChangeTrack
.GetDependents( const_cast<ScChangeAction
*>(&rAction
), aActionMap
);
689 for( const auto& rEntry
: aActionMap
)
690 if( rEntry
.second
->GetType() == SC_CAT_CONTENT
)
691 SetAddAction( new XclExpChTrCellContent(
692 *static_cast<const ScChangeActionContent
*>(rEntry
.second
), rRoot
, rIdBuffer
) );
695 void XclExpChTrAction::SetIndex( sal_uInt32
& rIndex
)
700 void XclExpChTrAction::SaveCont( XclExpStream
& rStrm
)
702 OSL_ENSURE( nOpCode
!= EXC_CHTR_OP_UNKNOWN
, "XclExpChTrAction::SaveCont - unknown action" );
706 << static_cast<sal_uInt16
>(bAccepted
? EXC_CHTR_ACCEPT
: EXC_CHTR_NOTHING
);
707 SaveActionData( rStrm
);
710 void XclExpChTrAction::PrepareSaveAction( XclExpStream
& /*rStrm*/ ) const
714 void XclExpChTrAction::CompleteSaveAction( XclExpStream
& /*rStrm*/ ) const
718 void XclExpChTrAction::Save( XclExpStream
& rStrm
)
720 PrepareSaveAction( rStrm
);
721 ExcRecord::Save( rStrm
);
723 pAddAction
->Save( rStrm
);
724 CompleteSaveAction( rStrm
);
727 std::size_t XclExpChTrAction::GetLen() const
729 return GetHeaderByteCount() + GetActionByteCount();
732 XclExpChTrData::XclExpChTrData() :
733 mpFormulaCell( nullptr ),
736 nType( EXC_CHTR_TYPE_EMPTY
),
741 XclExpChTrData::~XclExpChTrData()
746 void XclExpChTrData::Clear()
749 mpFormulaCell
= nullptr;
754 nType
= EXC_CHTR_TYPE_EMPTY
;
758 void XclExpChTrData::WriteFormula( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
760 OSL_ENSURE( mxTokArr
&& !mxTokArr
->Empty(), "XclExpChTrData::Write - no formula" );
763 for( const auto& rLogEntry
: maRefLog
)
765 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
767 rStrm
<< *rLogEntry
.mpUrl
<< sal_uInt8(0x01) << *rLogEntry
.mpFirstTab
<< sal_uInt8(0x02);
771 bool bSingleTab
= rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
;
772 rStrm
.SetSliceSize( bSingleTab
? 6 : 8 );
773 rStrm
<< sal_uInt8(0x01) << sal_uInt8(0x02) << sal_uInt8(0x00);
774 rStrm
<< rTabIdBuffer
.GetId( rLogEntry
.mnFirstXclTab
);
776 rStrm
<< sal_uInt8(0x02);
778 rStrm
<< sal_uInt8(0x00) << rTabIdBuffer
.GetId( rLogEntry
.mnLastXclTab
);
781 rStrm
.SetSliceSize( 0 );
782 rStrm
<< sal_uInt8(0x00);
785 void XclExpChTrData::Write( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
789 case EXC_CHTR_TYPE_RK
:
792 case EXC_CHTR_TYPE_DOUBLE
:
795 case EXC_CHTR_TYPE_STRING
:
796 OSL_ENSURE( pString
, "XclExpChTrData::Write - no string" );
799 case EXC_CHTR_TYPE_FORMULA
:
800 WriteFormula( rStrm
, rTabIdBuffer
);
805 XclExpChTrCellContent::XclExpChTrCellContent(
806 const ScChangeActionContent
& rAction
,
807 const XclExpRoot
& rRoot
,
808 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
809 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_CELL
),
811 aPosition( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()).aStart
)
815 GetCellData( rRoot
, rAction
.GetOldCell(), pOldData
, nDummy32
, nOldLength
);
816 GetCellData( rRoot
, rAction
.GetNewCell(), pNewData
, nLength
, nDummy16
);
819 XclExpChTrCellContent::~XclExpChTrCellContent()
825 void XclExpChTrCellContent::MakeEmptyChTrData( std::unique_ptr
<XclExpChTrData
>& rpData
)
830 rpData
.reset( new XclExpChTrData
);
833 void XclExpChTrCellContent::GetCellData(
834 const XclExpRoot
& rRoot
, const ScCellValue
& rScCell
,
835 std::unique_ptr
<XclExpChTrData
>& rpData
, sal_uInt32
& rXclLength1
, sal_uInt16
& rXclLength2
)
837 MakeEmptyChTrData( rpData
);
838 rXclLength1
= 0x0000003A;
839 rXclLength2
= 0x0000;
841 if (rScCell
.isEmpty())
847 switch (rScCell
.getType())
851 rpData
->fValue
= rScCell
.getDouble();
852 if( XclTools::GetRKFromDouble( rpData
->nRKValue
, rpData
->fValue
) )
854 rpData
->nType
= EXC_CHTR_TYPE_RK
;
856 rXclLength1
= 0x0000003E;
857 rXclLength2
= 0x0004;
861 rpData
->nType
= EXC_CHTR_TYPE_DOUBLE
;
863 rXclLength1
= 0x00000042;
864 rXclLength2
= 0x0008;
868 case CELLTYPE_STRING
:
872 if (rScCell
.getType() == CELLTYPE_STRING
)
874 sCellStr
= rScCell
.getSharedString()->getString();
875 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
876 rRoot
, sCellStr
, nullptr);
880 XclExpHyperlinkHelper
aLinkHelper( rRoot
, aPosition
);
881 if (rScCell
.getEditText())
883 sCellStr
= ScEditUtil::GetString(*rScCell
.getEditText(), &GetDoc());
884 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
885 rRoot
, *rScCell
.getEditText(), nullptr, aLinkHelper
);
889 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
890 rRoot
, OUString(), nullptr);
893 rpData
->pString
.reset( new XclExpString( sCellStr
, XclStrFlags::NONE
, 32766 ) );
894 rpData
->nType
= EXC_CHTR_TYPE_STRING
;
895 rpData
->nSize
= 3 + rpData
->pString
->GetSize();
896 rXclLength1
= 64 + (sCellStr
.getLength() << 1);
897 rXclLength2
= 6 + static_cast<sal_uInt16
>(sCellStr
.getLength() << 1);
900 case CELLTYPE_FORMULA
:
902 const ScFormulaCell
* pFmlCell
= rScCell
.getFormula();
903 rpData
->mpFormulaCell
= pFmlCell
;
905 const ScTokenArray
* pTokenArray
= pFmlCell
->GetCode();
908 XclExpRefLog
& rRefLog
= rpData
->maRefLog
;
909 rpData
->mxTokArr
= GetFormulaCompiler().CreateFormula(
910 EXC_FMLATYPE_CELL
, *pTokenArray
, &pFmlCell
->aPos
, &rRefLog
);
911 rpData
->nType
= EXC_CHTR_TYPE_FORMULA
;
912 std::size_t nSize
= std::accumulate(rRefLog
.begin(), rRefLog
.end(),
913 static_cast<std::size_t>(rpData
->mxTokArr
->GetSize() + 3),
914 [](const std::size_t& rSum
, const XclExpRefLogEntry
& rLogEntry
) {
915 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
916 return rSum
+ rLogEntry
.mpUrl
->GetSize() + rLogEntry
.mpFirstTab
->GetSize() + 2;
918 return rSum
+ ((rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
) ? 6 : 8);
920 rpData
->nSize
= ::std::min
< std::size_t >( nSize
, 0xFFFF );
921 rXclLength1
= 0x00000052;
922 rXclLength2
= 0x0018;
930 void XclExpChTrCellContent::SaveActionData( XclExpStream
& rStrm
) const
932 WriteTabId( rStrm
, aPosition
.Tab() );
933 rStrm
<< static_cast<sal_uInt16
>((pOldData
? (pOldData
->nType
<< 3) : 0x0000) | (pNewData
? pNewData
->nType
: 0x0000))
934 << sal_uInt16(0x0000);
935 Write2DAddress( rStrm
, aPosition
);
937 << sal_uInt32(0x00000000);
939 pOldData
->Write( rStrm
, rIdBuffer
);
941 pNewData
->Write( rStrm
, rIdBuffer
);
944 sal_uInt16
XclExpChTrCellContent::GetNum() const
949 std::size_t XclExpChTrCellContent::GetActionByteCount() const
951 std::size_t nLen
= 16;
953 nLen
+= pOldData
->nSize
;
955 nLen
+= pNewData
->nSize
;
959 static const char* lcl_GetType( XclExpChTrData
* pData
)
961 switch( pData
->nType
)
963 case EXC_CHTR_TYPE_RK
:
964 case EXC_CHTR_TYPE_DOUBLE
:
966 case EXC_CHTR_TYPE_FORMULA
:
968 ScFormulaCell
* pFormulaCell
= const_cast< ScFormulaCell
* >( pData
->mpFormulaCell
);
971 XclXmlUtils::GetFormulaTypeAndValue( *pFormulaCell
, sType
, sValue
);
975 case EXC_CHTR_TYPE_STRING
:
983 static void lcl_WriteCell( XclExpXmlStream
& rStrm
, sal_Int32 nElement
, const ScAddress
& rPosition
, XclExpChTrData
* pData
)
985 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
987 pStream
->startElement(nElement
,
988 XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), rPosition
),
989 XML_s
, nullptr, // OOXTODO: not supported
990 XML_t
, lcl_GetType(pData
),
991 XML_cm
, nullptr, // OOXTODO: not supported
992 XML_vm
, nullptr, // OOXTODO: not supported
993 XML_ph
, nullptr); // OOXTODO: not supported
994 switch( pData
->nType
)
996 case EXC_CHTR_TYPE_RK
:
997 case EXC_CHTR_TYPE_DOUBLE
:
998 pStream
->startElement(XML_v
);
999 pStream
->write( pData
->fValue
);
1000 pStream
->endElement( XML_v
);
1002 case EXC_CHTR_TYPE_FORMULA
:
1003 pStream
->startElement( XML_f
1004 // OOXTODO: other attributes? see XclExpFormulaCell::SaveXml()
1006 pStream
->writeEscaped( XclXmlUtils::ToOUString(
1007 rStrm
.GetRoot().GetCompileFormulaContext(),
1008 pData
->mpFormulaCell
->aPos
, pData
->mpFormulaCell
->GetCode()));
1009 pStream
->endElement( XML_f
);
1011 case EXC_CHTR_TYPE_STRING
:
1012 pStream
->startElement(XML_is
);
1013 if( pData
->mpFormattedString
)
1014 pData
->mpFormattedString
->WriteXml( rStrm
);
1016 pData
->pString
->WriteXml( rStrm
);
1017 pStream
->endElement( XML_is
);
1023 pStream
->endElement( nElement
);
1026 void XclExpChTrCellContent::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1028 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1029 pStream
->startElement( XML_rcc
,
1030 XML_rId
, OString::number(GetActionNumber()),
1031 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1032 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1033 XML_sId
, OString::number(GetTabId(aPosition
.Tab())),
1034 XML_odxf
, nullptr, // OOXTODO: not supported
1035 XML_xfDxf
, nullptr, // OOXTODO: not supported
1036 XML_s
, nullptr, // OOXTODO: not supported
1037 XML_dxf
, nullptr, // OOXTODO: not supported
1038 XML_numFmtId
, nullptr, // OOXTODO: not supported
1039 XML_quotePrefix
, nullptr, // OOXTODO: not supported
1040 XML_oldQuotePrefix
, nullptr, // OOXTODO: not supported
1041 XML_ph
, nullptr, // OOXTODO: not supported
1042 XML_oldPh
, nullptr, // OOXTODO: not supported
1043 XML_endOfListFormulaUpdate
, nullptr); // OOXTODO: not supported
1046 lcl_WriteCell( rRevisionLogStrm
, XML_oc
, aPosition
, pOldData
.get() );
1049 pStream
->singleElement(XML_nc
, XML_r
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aPosition
));
1054 lcl_WriteCell( rRevisionLogStrm
, XML_nc
, aPosition
, pNewData
.get() );
1056 // OOXTODO: XML_odxf, XML_ndxf, XML_extLst elements
1057 pStream
->endElement( XML_rcc
);
1060 XclExpChTrInsert::XclExpChTrInsert( const XclExpChTrInsert
& rCopy
) :
1061 XclExpChTrAction(rCopy
),
1062 mbEndOfList(rCopy
.mbEndOfList
),
1063 aRange(rCopy
.aRange
) {}
1065 XclExpChTrInsert::XclExpChTrInsert(
1066 const ScChangeAction
& rAction
,
1067 const XclExpRoot
& rRoot
,
1068 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1069 const ScChangeTrack
& rChangeTrack
) :
1070 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
),
1072 aRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()) )
1074 nLength
= 0x00000030;
1075 switch( rAction
.GetType() )
1077 case SC_CAT_INSERT_COLS
: nOpCode
= EXC_CHTR_OP_INSCOL
; break;
1078 case SC_CAT_INSERT_ROWS
:
1080 const ScChangeActionIns
& rIns
= static_cast<const ScChangeActionIns
&>(rAction
);
1081 mbEndOfList
= rIns
.IsEndOfList();
1082 nOpCode
= EXC_CHTR_OP_INSROW
;
1085 case SC_CAT_DELETE_COLS
: nOpCode
= EXC_CHTR_OP_DELCOL
; break;
1086 case SC_CAT_DELETE_ROWS
: nOpCode
= EXC_CHTR_OP_DELROW
; break;
1088 OSL_FAIL( "XclExpChTrInsert::XclExpChTrInsert - unknown action" );
1091 if( nOpCode
& EXC_CHTR_OP_COLFLAG
)
1093 aRange
.aStart
.SetRow( 0 );
1094 aRange
.aEnd
.SetRow( rRoot
.GetXclMaxPos().Row() );
1098 aRange
.aStart
.SetCol( 0 );
1099 aRange
.aEnd
.SetCol( rRoot
.GetXclMaxPos().Col() );
1102 if( nOpCode
& EXC_CHTR_OP_DELFLAG
)
1104 SetAddAction( new XclExpChTr0x014A( *this ) );
1105 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1109 XclExpChTrInsert::~XclExpChTrInsert()
1113 void XclExpChTrInsert::SaveActionData( XclExpStream
& rStrm
) const
1115 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1116 sal_uInt16 nFlagVal
= mbEndOfList
? 0x0001 : 0x0000;
1118 Write2DRange( rStrm
, aRange
);
1119 rStrm
<< sal_uInt32(0x00000000);
1122 void XclExpChTrInsert::PrepareSaveAction( XclExpStream
& rStrm
) const
1124 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1125 XclExpChTrEmpty( 0x0150 ).Save( rStrm
);
1128 void XclExpChTrInsert::CompleteSaveAction( XclExpStream
& rStrm
) const
1130 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1131 XclExpChTrEmpty( 0x0151 ).Save( rStrm
);
1134 sal_uInt16
XclExpChTrInsert::GetNum() const
1139 std::size_t XclExpChTrInsert::GetActionByteCount() const
1144 static const char* lcl_GetAction( sal_uInt16 nOpCode
)
1148 case EXC_CHTR_OP_INSCOL
: return "insertCol";
1149 case EXC_CHTR_OP_INSROW
: return "insertRow";
1150 case EXC_CHTR_OP_DELCOL
: return "deleteCol";
1151 case EXC_CHTR_OP_DELROW
: return "deleteRow";
1152 default: return "*unknown*";
1156 void XclExpChTrInsert::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1158 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1159 pStream
->startElement( XML_rrc
,
1160 XML_rId
, OString::number(GetActionNumber()),
1161 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1162 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1163 XML_sId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1164 XML_eol
, ToPsz10(mbEndOfList
),
1165 XML_ref
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aRange
),
1166 XML_action
, lcl_GetAction( nOpCode
),
1167 XML_edge
, nullptr); // OOXTODO: ???
1169 // OOXTODO: does this handle XML_rfmt, XML_undo?
1170 XclExpChTrAction
* pAction
= GetAddAction();
1171 while( pAction
!= nullptr )
1173 pAction
->SaveXml( rRevisionLogStrm
);
1174 pAction
= pAction
->GetAddAction();
1176 pStream
->endElement( XML_rrc
);
1179 XclExpChTrInsertTab::XclExpChTrInsertTab(
1180 const ScChangeAction
& rAction
,
1181 const XclExpRoot
& rRoot
,
1182 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
1183 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_INSTAB
),
1184 XclExpRoot( rRoot
),
1185 nTab( static_cast<SCTAB
>(rAction
.GetBigRange().aStart
.Tab()) )
1187 nLength
= 0x0000021C;
1191 XclExpChTrInsertTab::~XclExpChTrInsertTab()
1195 void XclExpChTrInsertTab::SaveActionData( XclExpStream
& rStrm
) const
1197 WriteTabId( rStrm
, nTab
);
1198 rStrm
<< sal_uInt32( 0 );
1199 lcl_WriteFixedString( rStrm
, XclExpString( GetTabInfo().GetScTabName( nTab
) ), 127 );
1200 lcl_WriteDateTime( rStrm
, GetDateTime() );
1201 rStrm
.WriteZeroBytes( 133 );
1204 sal_uInt16
XclExpChTrInsertTab::GetNum() const
1209 std::size_t XclExpChTrInsertTab::GetActionByteCount() const
1214 void XclExpChTrInsertTab::SaveXml( XclExpXmlStream
& rStrm
)
1216 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1217 pStream
->singleElement( XML_ris
,
1218 XML_rId
, OString::number(GetActionNumber()),
1219 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1220 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1221 XML_sheetId
, OString::number(GetTabId(nTab
)),
1222 XML_name
, GetTabInfo().GetScTabName(nTab
).toUtf8(),
1223 XML_sheetPosition
, OString::number(nTab
) );
1226 XclExpChTrMoveRange::XclExpChTrMoveRange(
1227 const ScChangeActionMove
& rAction
,
1228 const XclExpRoot
& rRoot
,
1229 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1230 const ScChangeTrack
& rChangeTrack
) :
1231 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_MOVE
),
1232 aDestRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc() ) )
1234 nLength
= 0x00000042;
1235 aSourceRange
= aDestRange
;
1236 sal_Int32 nDCols
, nDRows
, nDTabs
;
1237 rAction
.GetDelta( nDCols
, nDRows
, nDTabs
);
1238 aSourceRange
.aStart
.IncRow( static_cast<SCROW
>(-nDRows
) );
1239 aSourceRange
.aStart
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1240 aSourceRange
.aStart
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1241 aSourceRange
.aEnd
.IncRow( static_cast<SCROW
>(-nDRows
) );
1242 aSourceRange
.aEnd
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1243 aSourceRange
.aEnd
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1244 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1247 XclExpChTrMoveRange::~XclExpChTrMoveRange()
1251 void XclExpChTrMoveRange::SaveActionData( XclExpStream
& rStrm
) const
1253 WriteTabId( rStrm
, aDestRange
.aStart
.Tab() );
1254 Write2DRange( rStrm
, aSourceRange
);
1255 Write2DRange( rStrm
, aDestRange
);
1256 WriteTabId( rStrm
, aSourceRange
.aStart
.Tab() );
1257 rStrm
<< sal_uInt32(0x00000000);
1260 void XclExpChTrMoveRange::PrepareSaveAction( XclExpStream
& rStrm
) const
1262 XclExpChTrEmpty( 0x014E ).Save( rStrm
);
1265 void XclExpChTrMoveRange::CompleteSaveAction( XclExpStream
& rStrm
) const
1267 XclExpChTrEmpty( 0x014F ).Save( rStrm
);
1270 sal_uInt16
XclExpChTrMoveRange::GetNum() const
1275 std::size_t XclExpChTrMoveRange::GetActionByteCount() const
1280 void XclExpChTrMoveRange::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1282 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1284 pStream
->startElement( XML_rm
,
1285 XML_rId
, OString::number(GetActionNumber()),
1286 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1287 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1288 XML_sheetId
, OString::number(GetTabId(aDestRange
.aStart
.Tab())),
1289 XML_source
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aSourceRange
),
1290 XML_destination
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aDestRange
),
1291 XML_sourceSheetId
, OString::number(GetTabId(aSourceRange
.aStart
.Tab())) );
1292 // OOXTODO: does this handle XML_rfmt, XML_undo?
1293 XclExpChTrAction
* pAction
= GetAddAction();
1294 while( pAction
!= nullptr )
1296 pAction
->SaveXml( rRevisionLogStrm
);
1297 pAction
= pAction
->GetAddAction();
1299 pStream
->endElement( XML_rm
);
1302 XclExpChTr0x014A::XclExpChTr0x014A( const XclExpChTrInsert
& rAction
) :
1303 XclExpChTrInsert( rAction
)
1305 nLength
= 0x00000026;
1306 nOpCode
= EXC_CHTR_OP_FORMAT
;
1309 XclExpChTr0x014A::~XclExpChTr0x014A()
1313 void XclExpChTr0x014A::SaveActionData( XclExpStream
& rStrm
) const
1315 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1316 rStrm
<< sal_uInt16(0x0003)
1317 << sal_uInt16(0x0001);
1318 Write2DRange( rStrm
, aRange
);
1321 sal_uInt16
XclExpChTr0x014A::GetNum() const
1326 std::size_t XclExpChTr0x014A::GetActionByteCount() const
1331 void XclExpChTr0x014A::SaveXml( XclExpXmlStream
& rStrm
)
1333 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1335 pStream
->startElement( XML_rfmt
,
1336 XML_sheetId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1337 XML_xfDxf
, nullptr, // OOXTODO: not supported
1338 XML_s
, nullptr, // OOXTODO: style
1339 XML_sqref
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aRange
),
1340 XML_start
, nullptr, // OOXTODO: for string changes
1341 XML_length
, nullptr); // OOXTODO: for string changes
1342 // OOXTODO: XML_dxf, XML_extLst
1344 pStream
->endElement( XML_rfmt
);
1347 std::size_t ExcXmlRecord::GetLen() const
1352 sal_uInt16
ExcXmlRecord::GetNum() const
1357 void ExcXmlRecord::Save( XclExpStream
& )
1359 // Do nothing; ignored for BIFF output.
1364 class EndXmlElement
: public ExcXmlRecord
1366 sal_Int32 mnElement
;
1368 explicit EndXmlElement( sal_Int32 nElement
) : mnElement( nElement
) {}
1369 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
1374 void EndXmlElement::SaveXml( XclExpXmlStream
& rStrm
)
1376 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1377 pStream
->write("</")->writeId(mnElement
)->write(">");
1380 XclExpChangeTrack::XclExpChangeTrack( const XclExpRoot
& rRoot
) :
1381 XclExpRoot( rRoot
),
1382 pTabIdBuffer( nullptr )
1384 OSL_ENSURE( GetOldRoot().pTabId
, "XclExpChangeTrack::XclExpChangeTrack - root data incomplete" );
1385 if( !GetOldRoot().pTabId
)
1388 ScChangeTrack
* pTempChangeTrack
= CreateTempChangeTrack();
1389 if (!pTempChangeTrack
)
1392 pTabIdBuffer
= new XclExpChTrTabIdBuffer( GetTabInfo().GetXclTabCount() );
1393 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pTabIdBuffer
) );
1395 // calculate final table order (tab id list)
1396 const ScChangeAction
* pScAction
;
1397 for( pScAction
= pTempChangeTrack
->GetLast(); pScAction
; pScAction
= pScAction
->GetPrev() )
1399 if( pScAction
->GetType() == SC_CAT_INSERT_TABS
)
1401 SCTAB nScTab
= static_cast< SCTAB
>( pScAction
->GetBigRange().aStart
.Tab() );
1402 pTabIdBuffer
->InitFill( GetTabInfo().GetXclTab( nScTab
) );
1405 pTabIdBuffer
->InitFillup();
1406 GetOldRoot().pTabId
->Copy( *pTabIdBuffer
);
1408 // get actions in reverse order
1409 pScAction
= pTempChangeTrack
->GetLast();
1412 PushActionRecord( *pScAction
);
1413 const ScChangeAction
* pPrevAction
= pScAction
->GetPrev();
1414 pScAction
= pPrevAction
;
1417 // build record list
1418 if (GetOutput() == EXC_OUTPUT_BINARY
)
1420 XclExpChTrHeader
* pHeader
= new XclExpChTrHeader
; // header record for last GUID
1421 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeader
) );
1422 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0195
) );
1423 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0194( *pTempChangeTrack
) ) );
1425 OUString sLastUsername
;
1426 DateTime
aLastDateTime( DateTime::EMPTY
);
1427 sal_uInt32 nIndex
= 1;
1428 sal_uInt8 aGUID
[ 16 ]; // GUID for action info records
1429 bool bValidGUID
= false;
1430 while( !aActionStack
.empty() )
1432 XclExpChTrAction
* pAction
= aActionStack
.top();
1435 if( (nIndex
== 1) || pAction
->ForceInfoRecord() ||
1436 (pAction
->GetUsername() != sLastUsername
) ||
1437 (pAction
->GetDateTime() != aLastDateTime
) )
1439 lcl_GenerateGUID( aGUID
, bValidGUID
);
1440 sLastUsername
= pAction
->GetUsername();
1441 aLastDateTime
= pAction
->GetDateTime();
1443 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrInfo(sLastUsername
, aLastDateTime
, aGUID
)) );
1444 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrTabId(pAction
->GetTabIdBuffer())) );
1445 pHeader
->SetGUID( aGUID
);
1447 pAction
->SetIndex( nIndex
);
1448 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pAction
) );
1451 pHeader
->SetGUID( aGUID
);
1452 pHeader
->SetCount( nIndex
- 1 );
1453 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new ExcEof
) );
1457 XclExpXmlChTrHeaders
* pHeaders
= new XclExpXmlChTrHeaders
;
1458 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeaders
));
1460 OUString sLastUsername
;
1461 DateTime
aLastDateTime(DateTime::EMPTY
);
1462 sal_uInt32 nIndex
= 1;
1463 sal_Int32 nLogNumber
= 1;
1464 XclExpXmlChTrHeader
* pCurHeader
= nullptr;
1465 sal_uInt8 aGUID
[ 16 ]; // GUID for action info records
1466 bool bValidGUID
= false;
1468 while (!aActionStack
.empty())
1470 XclExpChTrAction
* pAction
= aActionStack
.top();
1473 if( (nIndex
== 1) || pAction
->ForceInfoRecord() ||
1474 (pAction
->GetUsername() != sLastUsername
) ||
1475 (pAction
->GetDateTime() != aLastDateTime
) )
1477 lcl_GenerateGUID( aGUID
, bValidGUID
);
1478 sLastUsername
= pAction
->GetUsername();
1479 aLastDateTime
= pAction
->GetDateTime();
1481 pCurHeader
= new XclExpXmlChTrHeader(sLastUsername
, aLastDateTime
, aGUID
, nLogNumber
, pAction
->GetTabIdBuffer());
1482 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pCurHeader
));
1484 pHeaders
->SetGUID(aGUID
);
1486 pAction
->SetIndex(nIndex
);
1487 pCurHeader
->AppendAction(std::unique_ptr
<XclExpChTrAction
>(pAction
));
1490 pHeaders
->SetGUID(aGUID
);
1491 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new EndXmlElement(XML_headers
)));
1495 XclExpChangeTrack::~XclExpChangeTrack()
1497 while( !aActionStack
.empty() )
1499 delete aActionStack
.top();
1504 ScChangeTrack
* XclExpChangeTrack::CreateTempChangeTrack()
1506 // get original change track
1507 ScChangeTrack
* pOrigChangeTrack
= GetDoc().GetChangeTrack();
1508 OSL_ENSURE( pOrigChangeTrack
, "XclExpChangeTrack::CreateTempChangeTrack - no change track data" );
1509 if( !pOrigChangeTrack
)
1513 // create empty document
1514 xTempDoc
.reset(new ScDocument
);
1516 // adjust table count
1517 SCTAB nOrigCount
= GetDoc().GetTableCount();
1519 for( sal_Int32 nIndex
= 0; nIndex
< nOrigCount
; nIndex
++ )
1521 xTempDoc
->CreateValidTabName(sTabName
);
1522 xTempDoc
->InsertTab(SC_TAB_APPEND
, sTabName
);
1524 OSL_ENSURE(nOrigCount
== xTempDoc
->GetTableCount(),
1525 "XclExpChangeTrack::CreateTempChangeTrack - table count mismatch");
1526 if(nOrigCount
!= xTempDoc
->GetTableCount())
1529 return pOrigChangeTrack
->Clone(xTempDoc
.get());
1532 void XclExpChangeTrack::PushActionRecord( const ScChangeAction
& rAction
)
1534 XclExpChTrAction
* pXclAction
= nullptr;
1535 ScChangeTrack
* pTempChangeTrack
= xTempDoc
->GetChangeTrack();
1536 switch( rAction
.GetType() )
1538 case SC_CAT_CONTENT
:
1539 pXclAction
= new XclExpChTrCellContent( static_cast<const ScChangeActionContent
&>(rAction
), GetRoot(), *pTabIdBuffer
);
1541 case SC_CAT_INSERT_ROWS
:
1542 case SC_CAT_INSERT_COLS
:
1543 case SC_CAT_DELETE_ROWS
:
1544 case SC_CAT_DELETE_COLS
:
1545 if (pTempChangeTrack
)
1546 pXclAction
= new XclExpChTrInsert( rAction
, GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1548 case SC_CAT_INSERT_TABS
:
1550 pXclAction
= new XclExpChTrInsertTab( rAction
, GetRoot(), *pTabIdBuffer
);
1551 XclExpChTrTabIdBuffer
* pNewBuffer
= new XclExpChTrTabIdBuffer( *pTabIdBuffer
);
1552 pNewBuffer
->Remove();
1553 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pNewBuffer
) );
1554 pTabIdBuffer
= pNewBuffer
;
1558 if (pTempChangeTrack
)
1559 pXclAction
= new XclExpChTrMoveRange( static_cast<const ScChangeActionMove
&>(rAction
), GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1564 aActionStack
.push( pXclAction
);
1567 bool XclExpChangeTrack::WriteUserNamesStream()
1570 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( EXC_STREAM_USERNAMES
);
1571 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::WriteUserNamesStream - no stream" );
1574 XclExpStream
aXclStrm( *xSvStrm
, GetRoot() );
1575 XclExpChTr0x0191().Save( aXclStrm
);
1576 XclExpChTr0x0198().Save( aXclStrm
);
1577 XclExpChTr0x0192().Save( aXclStrm
);
1578 XclExpChTr0x0197().Save( aXclStrm
);
1585 void XclExpChangeTrack::Write()
1587 if (maRecList
.empty())
1590 if( !WriteUserNamesStream() )
1593 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( EXC_STREAM_REVLOG
);
1594 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::Write - no stream" );
1597 XclExpStream
aXclStrm( *xSvStrm
, GetRoot(), EXC_MAXRECSIZE_BIFF8
+ 8 );
1599 for(const auto& rxRec
: maRecList
)
1600 rxRec
->Save(aXclStrm
);
1606 static void lcl_WriteUserNamesXml( XclExpXmlStream
& rWorkbookStrm
)
1608 sax_fastparser::FSHelperPtr pUserNames
= rWorkbookStrm
.CreateOutputStream(
1609 "xl/revisions/userNames.xml",
1610 u
"revisions/userNames.xml",
1611 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1612 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml",
1613 CREATE_OFFICEDOC_RELATION_TYPE("usernames"));
1614 pUserNames
->startElement( XML_users
,
1615 XML_xmlns
, rWorkbookStrm
.getNamespaceURL(OOX_NS(xls
)).toUtf8(),
1616 FSNS( XML_xmlns
, XML_r
), rWorkbookStrm
.getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
1618 // OOXTODO: XML_userinfo elements for each user editing the file
1619 // Doesn't seem to be supported by .xls output either (based on
1620 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1621 pUserNames
->endElement( XML_users
);
1624 void XclExpChangeTrack::WriteXml( XclExpXmlStream
& rWorkbookStrm
)
1626 if (maRecList
.empty())
1629 lcl_WriteUserNamesXml( rWorkbookStrm
);
1631 sax_fastparser::FSHelperPtr pRevisionHeaders
= rWorkbookStrm
.CreateOutputStream(
1632 "xl/revisions/revisionHeaders.xml",
1633 u
"revisions/revisionHeaders.xml",
1634 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1635 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml",
1636 CREATE_OFFICEDOC_RELATION_TYPE("revisionHeaders"));
1637 // OOXTODO: XML_userinfo elements for each user editing the file
1638 // Doesn't seem to be supported by .xls output either (based on
1639 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1640 rWorkbookStrm
.PushStream( pRevisionHeaders
);
1642 for (const auto& rxRec
: maRecList
)
1643 rxRec
->SaveXml(rWorkbookStrm
);
1645 rWorkbookStrm
.PopStream();
1648 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */