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>
25 #include <xeformula.hxx>
26 #include <xehelper.hxx>
27 #include <xltools.hxx>
28 #include <formulacell.hxx>
29 #include <document.hxx>
30 #include <editutil.hxx>
32 #include <tools/Guid.hxx>
34 #include <oox/export/utils.hxx>
35 #include <oox/token/namespaces.hxx>
36 #include <oox/token/tokens.hxx>
38 #include <svl/sharedstring.hxx>
42 static OString
lcl_DateTimeToOString( const DateTime
& rDateTime
)
45 snprintf( sBuf
, sizeof( sBuf
),
46 "%d-%02d-%02dT%02d:%02d:%02d.%09" SAL_PRIuUINT32
"Z",
47 rDateTime
.GetYear(), rDateTime
.GetMonth(), rDateTime
.GetDay(),
48 rDateTime
.GetHour(), rDateTime
.GetMin(), rDateTime
.GetSec(),
49 rDateTime
.GetNanoSec() );
55 static void lcl_WriteDateTime( XclExpStream
& rStrm
, const DateTime
& rDateTime
)
57 rStrm
.SetSliceSize( 7 );
58 rStrm
<< static_cast<sal_uInt16
>(rDateTime
.GetYear())
59 << static_cast<sal_uInt8
>(rDateTime
.GetMonth())
60 << static_cast<sal_uInt8
>(rDateTime
.GetDay())
61 << static_cast<sal_uInt8
>(rDateTime
.GetHour())
62 << static_cast<sal_uInt8
>(rDateTime
.GetMin())
63 << static_cast<sal_uInt8
>(rDateTime
.GetSec());
64 rStrm
.SetSliceSize( 0 );
67 // write string and fill rest of <nLength> with zero bytes
68 // <nLength> is without string header
69 static void lcl_WriteFixedString( XclExpStream
& rStrm
, const XclExpString
& rString
, std::size_t nLength
)
71 std::size_t nStrBytes
= rString
.GetBufferSize();
72 OSL_ENSURE( nLength
>= nStrBytes
, "lcl_WriteFixedString - String too long" );
73 if( rString
.Len() > 0 )
75 if( nLength
> nStrBytes
)
76 rStrm
.WriteZeroBytes( nLength
- nStrBytes
);
79 static void lcl_GenerateGUID( sal_uInt8
* pGUID
, bool& rValidGUID
)
81 rtl_createUuid( pGUID
, rValidGUID
? pGUID
: nullptr, false );
85 static void lcl_WriteGUID( XclExpStream
& rStrm
, const sal_uInt8
* pGUID
)
87 rStrm
.SetSliceSize( 16 );
88 for( std::size_t nIndex
= 0; nIndex
< 16; nIndex
++ )
89 rStrm
<< pGUID
[ nIndex
];
90 rStrm
.SetSliceSize( 0 );
93 XclExpUserBView::XclExpUserBView( const OUString
& rUsername
, const sal_uInt8
* pGUID
) :
94 sUsername( rUsername
)
96 memcpy( aGUID
, pGUID
, 16 );
99 void XclExpUserBView::SaveCont( XclExpStream
& rStrm
)
101 rStrm
<< sal_uInt32(0xFF078014)
102 << sal_uInt32(0x00000001);
103 lcl_WriteGUID( rStrm
, aGUID
);
104 rStrm
.WriteZeroBytes( 8 );
105 rStrm
<< sal_uInt32(1200)
108 << sal_uInt16(0x0CF7)
109 << sal_uInt16(0x0000)
110 << sal_uInt16(0x0001)
111 << sal_uInt16(0x0000);
112 if( sUsername
.Len() > 0 )
116 sal_uInt16
XclExpUserBView::GetNum() const
121 std::size_t XclExpUserBView::GetLen() const
123 return 50 + ((sUsername
.Len() > 0) ? sUsername
.GetSize() : 0);
126 XclExpUserBViewList::XclExpUserBViewList( const ScChangeTrack
& rChangeTrack
)
128 sal_uInt8 aGUID
[ 16 ];
129 bool bValidGUID
= false;
130 const std::set
<OUString
>& rStrColl
= rChangeTrack
.GetUserCollection();
131 aViews
.reserve(rStrColl
.size());
132 for (const auto& rStr
: rStrColl
)
134 lcl_GenerateGUID( aGUID
, bValidGUID
);
135 aViews
.emplace_back( rStr
, aGUID
);
139 XclExpUserBViewList::~XclExpUserBViewList()
143 void XclExpUserBViewList::Save( XclExpStream
& rStrm
)
145 for( XclExpUserBView
& rView
: aViews
)
149 XclExpUsersViewBegin::XclExpUsersViewBegin( const sal_uInt8
* pGUID
, sal_uInt32 nTab
) :
152 memcpy( aGUID
, pGUID
, 16 );
155 void XclExpUsersViewBegin::SaveCont( XclExpStream
& rStrm
)
157 lcl_WriteGUID( rStrm
, aGUID
);
162 << sal_uInt32(0x0000003C)
173 sal_uInt16
XclExpUsersViewBegin::GetNum() const
178 std::size_t XclExpUsersViewBegin::GetLen() const
183 void XclExpUsersViewEnd::SaveCont( XclExpStream
& rStrm
)
185 rStrm
<< sal_uInt16(0x0001);
188 sal_uInt16
XclExpUsersViewEnd::GetNum() const
193 std::size_t XclExpUsersViewEnd::GetLen() const
198 void XclExpChTr0x0191::SaveCont( XclExpStream
& rStrm
)
200 rStrm
<< sal_uInt16(0x0000);
203 sal_uInt16
XclExpChTr0x0191::GetNum() const
208 std::size_t XclExpChTr0x0191::GetLen() const
213 void XclExpChTr0x0198::SaveCont( XclExpStream
& rStrm
)
215 rStrm
<< sal_uInt16(0x0006)
216 << sal_uInt16(0x0000);
219 sal_uInt16
XclExpChTr0x0198::GetNum() const
224 std::size_t XclExpChTr0x0198::GetLen() const
229 void XclExpChTr0x0192::SaveCont( XclExpStream
& rStrm
)
231 rStrm
<< sal_uInt16( 0x0022 );
232 rStrm
.WriteZeroBytes( 510 );
235 sal_uInt16
XclExpChTr0x0192::GetNum() const
240 std::size_t XclExpChTr0x0192::GetLen() const
245 void XclExpChTr0x0197::SaveCont( XclExpStream
& rStrm
)
247 rStrm
<< sal_uInt16(0x0000);
250 sal_uInt16
XclExpChTr0x0197::GetNum() const
255 std::size_t XclExpChTr0x0197::GetLen() const
260 XclExpChTrEmpty::~XclExpChTrEmpty()
264 sal_uInt16
XclExpChTrEmpty::GetNum() const
269 std::size_t XclExpChTrEmpty::GetLen() const
274 XclExpChTr0x0195::~XclExpChTr0x0195()
278 void XclExpChTr0x0195::SaveCont( XclExpStream
& rStrm
)
280 rStrm
.WriteZeroBytes( 162 );
283 sal_uInt16
XclExpChTr0x0195::GetNum() const
288 std::size_t XclExpChTr0x0195::GetLen() const
293 XclExpChTr0x0194::~XclExpChTr0x0194()
297 void XclExpChTr0x0194::SaveCont( XclExpStream
& rStrm
)
299 rStrm
<< sal_uInt32(0);
300 lcl_WriteDateTime( rStrm
, aDateTime
);
301 rStrm
<< sal_uInt8(0);
302 lcl_WriteFixedString( rStrm
, sUsername
, 147 );
305 sal_uInt16
XclExpChTr0x0194::GetNum() const
310 std::size_t XclExpChTr0x0194::GetLen() const
315 XclExpChTrHeader::~XclExpChTrHeader()
319 void XclExpChTrHeader::SaveCont( XclExpStream
& rStrm
)
321 rStrm
<< sal_uInt16(0x0006)
322 << sal_uInt16(0x0000)
323 << sal_uInt16(0x000D);
324 lcl_WriteGUID( rStrm
, aGUID
);
325 lcl_WriteGUID( rStrm
, aGUID
);
327 << sal_uInt16(0x0001)
328 << sal_uInt32(0x00000000)
329 << sal_uInt16(0x001E);
332 sal_uInt16
XclExpChTrHeader::GetNum() const
337 std::size_t XclExpChTrHeader::GetLen() const
342 void XclExpChTrHeader::SaveXml( XclExpXmlStream
& rRevisionHeadersStrm
)
344 sax_fastparser::FSHelperPtr pHeaders
= rRevisionHeadersStrm
.GetCurrentStream();
345 tools::Guid
aGuid(aGUID
);
346 rRevisionHeadersStrm
.WriteAttributes(
347 XML_guid
, aGuid
.getString(),
348 XML_lastGuid
, nullptr, // OOXTODO
349 XML_shared
, nullptr, // OOXTODO
350 XML_diskRevisions
, nullptr, // OOXTODO
351 XML_history
, nullptr, // OOXTODO
352 XML_trackRevisions
, nullptr, // OOXTODO
353 XML_exclusive
, nullptr, // OOXTODO
354 XML_revisionId
, nullptr, // OOXTODO
355 XML_version
, nullptr, // OOXTODO
356 XML_keepChangeHistory
, nullptr, // OOXTODO
357 XML_protected
, nullptr, // OOXTODO
358 XML_preserveHistory
, nullptr); // OOXTODO
359 pHeaders
->write( ">" );
362 void XclExpXmlChTrHeaders::SetGUID( const sal_uInt8
* pGUID
)
364 memcpy(maGUID
, pGUID
, 16);
367 void XclExpXmlChTrHeaders::SaveXml( XclExpXmlStream
& rStrm
)
369 sax_fastparser::FSHelperPtr pHeaders
= rStrm
.GetCurrentStream();
371 pHeaders
->write("<")->writeId(XML_headers
);
373 tools::Guid
aGuid(maGUID
);
374 rStrm
.WriteAttributes(
375 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
376 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)),
377 XML_guid
, aGuid
.getString(),
378 XML_lastGuid
, nullptr, // OOXTODO
379 XML_shared
, nullptr, // OOXTODO
380 XML_diskRevisions
, nullptr, // OOXTODO
381 XML_history
, nullptr, // OOXTODO
382 XML_trackRevisions
, nullptr, // OOXTODO
383 XML_exclusive
, nullptr, // OOXTODO
384 XML_revisionId
, nullptr, // OOXTODO
385 XML_version
, nullptr, // OOXTODO
386 XML_keepChangeHistory
, nullptr, // OOXTODO
387 XML_protected
, nullptr, // OOXTODO
388 XML_preserveHistory
, nullptr); // OOXTODO
390 pHeaders
->write(">");
393 XclExpXmlChTrHeader::XclExpXmlChTrHeader(
394 const OUString
& rUserName
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
,
395 sal_Int32 nLogNumber
, const XclExpChTrTabIdBuffer
& rBuf
) :
396 maUserName(rUserName
), maDateTime(rDateTime
), mnLogNumber(nLogNumber
),
397 mnMinAction(0), mnMaxAction(0)
399 memcpy(maGUID
, pGUID
, 16);
400 if (rBuf
.GetBufferCount())
402 maTabBuffer
.resize(rBuf
.GetBufferCount());
403 rBuf
.GetBufferCopy(maTabBuffer
.data());
407 void XclExpXmlChTrHeader::SaveXml( XclExpXmlStream
& rStrm
)
409 sax_fastparser::FSHelperPtr pHeader
= rStrm
.GetCurrentStream();
411 pHeader
->write("<")->writeId(XML_header
);
414 sax_fastparser::FSHelperPtr pRevLogStrm
= rStrm
.CreateOutputStream(
415 XclXmlUtils::GetStreamName("xl/revisions/", "revisionLog", mnLogNumber
),
416 XclXmlUtils::GetStreamName(nullptr, "revisionLog", mnLogNumber
),
417 rStrm
.GetCurrentStream()->getOutputStream(),
418 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml",
419 CREATE_OFFICEDOC_RELATION_TYPE("revisionLog"),
422 tools::Guid
aGuid(maGUID
);
423 rStrm
.WriteAttributes(
424 XML_guid
, aGuid
.getString(),
425 XML_dateTime
, lcl_DateTimeToOString(maDateTime
),
426 XML_userName
, maUserName
,
427 FSNS(XML_r
, XML_id
), aRelId
);
430 rStrm
.WriteAttributes(XML_minRId
, OUString::number(mnMinAction
));
433 rStrm
.WriteAttributes(XML_maxRId
, OUString::number(mnMaxAction
));
435 if (!maTabBuffer
.empty())
436 // next available sheet index.
437 rStrm
.WriteAttributes(XML_maxSheetId
, OUString::number(maTabBuffer
.back()+1));
441 if (!maTabBuffer
.empty())
443 // Write sheet index map.
444 size_t n
= maTabBuffer
.size();
445 pHeader
->startElement(XML_sheetIdMap
, XML_count
, OString::number(n
));
447 for (size_t i
= 0; i
< n
; ++i
)
449 pHeader
->singleElement(XML_sheetId
, XML_val
, OString::number(maTabBuffer
[i
]));
451 pHeader
->endElement(XML_sheetIdMap
);
454 // Write all revision logs in a separate stream.
456 rStrm
.PushStream(pRevLogStrm
);
458 pRevLogStrm
->write("<")->writeId(XML_revisions
);
460 rStrm
.WriteAttributes(
461 XML_xmlns
, rStrm
.getNamespaceURL(OOX_NS(xls
)),
462 FSNS(XML_xmlns
, XML_r
), rStrm
.getNamespaceURL(OOX_NS(officeRel
)));
464 pRevLogStrm
->write(">");
466 for (const auto& rxAction
: maActions
)
468 rxAction
->SaveXml(rStrm
);
471 pRevLogStrm
->write("</")->writeId(XML_revisions
)->write(">");
475 pHeader
->write("</")->writeId(XML_header
)->write(">");
478 void XclExpXmlChTrHeader::AppendAction( std::unique_ptr
<XclExpChTrAction
> pAction
)
480 sal_uInt32 nActionNum
= pAction
->GetActionNumber();
481 if (!mnMinAction
|| mnMinAction
> nActionNum
)
482 mnMinAction
= nActionNum
;
484 if (!mnMaxAction
|| mnMaxAction
< nActionNum
)
485 mnMaxAction
= nActionNum
;
487 maActions
.push_back(std::move(pAction
));
490 XclExpChTrInfo::XclExpChTrInfo( const OUString
& rUsername
, const DateTime
& rDateTime
, const sal_uInt8
* pGUID
) :
491 sUsername( rUsername
),
492 aDateTime( rDateTime
)
494 memcpy( aGUID
, pGUID
, 16 );
497 XclExpChTrInfo::~XclExpChTrInfo()
501 void XclExpChTrInfo::SaveCont( XclExpStream
& rStrm
)
503 rStrm
<< sal_uInt32(0xFFFFFFFF)
504 << sal_uInt32(0x00000000)
505 << sal_uInt32(0x00000020)
506 << sal_uInt16(0xFFFF);
507 lcl_WriteGUID( rStrm
, aGUID
);
508 rStrm
<< sal_uInt16(0x04B0);
509 lcl_WriteFixedString( rStrm
, sUsername
, 113 );
510 lcl_WriteDateTime( rStrm
, aDateTime
);
511 rStrm
<< sal_uInt8(0x0000)
512 << sal_uInt16(0x0002);
515 sal_uInt16
XclExpChTrInfo::GetNum() const
520 std::size_t XclExpChTrInfo::GetLen() const
525 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount
) :
529 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
530 memset( pBuffer
.get(), 0, sizeof(sal_uInt16
) * nBufSize
);
531 pLast
= pBuffer
.get() + nBufSize
- 1;
534 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( const XclExpChTrTabIdBuffer
& rCopy
) :
535 nBufSize( rCopy
.nBufSize
),
536 nLastId( rCopy
.nLastId
)
538 pBuffer
.reset( new sal_uInt16
[ nBufSize
] );
539 memcpy( pBuffer
.get(), rCopy
.pBuffer
.get(), sizeof(sal_uInt16
) * nBufSize
);
540 pLast
= pBuffer
.get() + nBufSize
- 1;
543 XclExpChTrTabIdBuffer::~XclExpChTrTabIdBuffer()
547 void XclExpChTrTabIdBuffer::InitFill( sal_uInt16 nIndex
)
549 OSL_ENSURE( nIndex
< nLastId
, "XclExpChTrTabIdBuffer::Insert - out of range" );
551 sal_uInt16 nFreeCount
= 0;
552 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
556 if( nFreeCount
> nIndex
)
564 void XclExpChTrTabIdBuffer::InitFillup()
566 sal_uInt16 nFreeCount
= 1;
567 for( sal_uInt16
* pElem
= pBuffer
.get(); pElem
<= pLast
; pElem
++ )
569 *pElem
= nFreeCount
++;
573 sal_uInt16
XclExpChTrTabIdBuffer::GetId( sal_uInt16 nIndex
) const
575 OSL_ENSURE( nIndex
< nBufSize
, "XclExpChTrTabIdBuffer::GetId - out of range" );
576 return pBuffer
[ nIndex
];
579 void XclExpChTrTabIdBuffer::Remove()
581 OSL_ENSURE( pBuffer
.get() <= pLast
, "XclExpChTrTabIdBuffer::Remove - buffer empty" );
582 sal_uInt16
* pElem
= pBuffer
.get();
583 while( (pElem
<= pLast
) && (*pElem
!= nLastId
) )
585 while( pElem
< pLast
)
587 *pElem
= *(pElem
+ 1);
594 XclExpChTrTabId::XclExpChTrTabId( const XclExpChTrTabIdBuffer
& rBuffer
)
595 : nTabCount( rBuffer
.GetBufferCount() )
597 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
598 rBuffer
.GetBufferCopy( pBuffer
.get() );
601 XclExpChTrTabId::~XclExpChTrTabId()
606 void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer
& rBuffer
)
609 nTabCount
= rBuffer
.GetBufferCount();
610 pBuffer
.reset( new sal_uInt16
[ nTabCount
] );
611 rBuffer
.GetBufferCopy( pBuffer
.get() );
614 void XclExpChTrTabId::SaveCont( XclExpStream
& rStrm
)
616 rStrm
.EnableEncryption();
618 rStrm
.Write(pBuffer
.get(), nTabCount
);
620 for( sal_uInt16 nIndex
= 1; nIndex
<= nTabCount
; nIndex
++ )
624 sal_uInt16
XclExpChTrTabId::GetNum() const
629 std::size_t XclExpChTrTabId::GetLen() const
631 return nTabCount
<< 1;
634 // ! does not copy additional actions
635 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction
& rCopy
) :
637 sUsername( rCopy
.sUsername
),
638 aDateTime( rCopy
.aDateTime
),
640 bAccepted( rCopy
.bAccepted
),
641 rTabInfo( rCopy
.rTabInfo
),
642 rIdBuffer( rCopy
.rIdBuffer
),
643 nLength( rCopy
.nLength
),
644 nOpCode( rCopy
.nOpCode
),
645 bForceInfo( rCopy
.bForceInfo
)
649 XclExpChTrAction::XclExpChTrAction(
650 const ScChangeAction
& rAction
,
651 const XclExpRoot
& rRoot
,
652 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
653 sal_uInt16 nNewOpCode
) :
654 sUsername( rAction
.GetUser() ),
655 aDateTime( rAction
.GetDateTime() ),
657 bAccepted( rAction
.IsAccepted() ),
658 rTabInfo( rRoot
.GetTabInfo() ),
659 rIdBuffer( rTabIdBuffer
),
661 nOpCode( nNewOpCode
),
664 aDateTime
.SetSec( 0 );
665 aDateTime
.SetNanoSec( 0 );
668 XclExpChTrAction::~XclExpChTrAction()
672 void XclExpChTrAction::SetAddAction( XclExpChTrAction
* pAction
)
675 pAddAction
->SetAddAction( pAction
);
677 pAddAction
.reset( pAction
);
680 void XclExpChTrAction::AddDependentContents(
681 const ScChangeAction
& rAction
,
682 const XclExpRoot
& rRoot
,
683 const ScChangeTrack
& rChangeTrack
)
685 ScChangeActionMap aActionMap
;
687 rChangeTrack
.GetDependents( const_cast<ScChangeAction
*>(&rAction
), aActionMap
);
688 for( const auto& rEntry
: aActionMap
)
689 if( rEntry
.second
->GetType() == SC_CAT_CONTENT
)
690 SetAddAction( new XclExpChTrCellContent(
691 *static_cast<const ScChangeActionContent
*>(rEntry
.second
), rRoot
, rIdBuffer
) );
694 void XclExpChTrAction::SetIndex( sal_uInt32
& rIndex
)
699 void XclExpChTrAction::SaveCont( XclExpStream
& rStrm
)
701 OSL_ENSURE( nOpCode
!= EXC_CHTR_OP_UNKNOWN
, "XclExpChTrAction::SaveCont - unknown action" );
705 << static_cast<sal_uInt16
>(bAccepted
? EXC_CHTR_ACCEPT
: EXC_CHTR_NOTHING
);
706 SaveActionData( rStrm
);
709 void XclExpChTrAction::PrepareSaveAction( XclExpStream
& /*rStrm*/ ) const
713 void XclExpChTrAction::CompleteSaveAction( XclExpStream
& /*rStrm*/ ) const
717 void XclExpChTrAction::Save( XclExpStream
& rStrm
)
719 PrepareSaveAction( rStrm
);
720 ExcRecord::Save( rStrm
);
722 pAddAction
->Save( rStrm
);
723 CompleteSaveAction( rStrm
);
726 std::size_t XclExpChTrAction::GetLen() const
728 return GetHeaderByteCount() + GetActionByteCount();
731 XclExpChTrData::XclExpChTrData() :
732 mpFormulaCell( nullptr ),
735 nType( EXC_CHTR_TYPE_EMPTY
),
740 XclExpChTrData::~XclExpChTrData()
745 void XclExpChTrData::Clear()
748 mpFormulaCell
= nullptr;
753 nType
= EXC_CHTR_TYPE_EMPTY
;
757 void XclExpChTrData::WriteFormula( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
759 OSL_ENSURE( mxTokArr
&& !mxTokArr
->Empty(), "XclExpChTrData::Write - no formula" );
762 for( const auto& rLogEntry
: maRefLog
)
764 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
766 rStrm
<< *rLogEntry
.mpUrl
<< sal_uInt8(0x01) << *rLogEntry
.mpFirstTab
<< sal_uInt8(0x02);
770 bool bSingleTab
= rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
;
771 rStrm
.SetSliceSize( bSingleTab
? 6 : 8 );
772 rStrm
<< sal_uInt8(0x01) << sal_uInt8(0x02) << sal_uInt8(0x00);
773 rStrm
<< rTabIdBuffer
.GetId( rLogEntry
.mnFirstXclTab
);
775 rStrm
<< sal_uInt8(0x02);
777 rStrm
<< sal_uInt8(0x00) << rTabIdBuffer
.GetId( rLogEntry
.mnLastXclTab
);
780 rStrm
.SetSliceSize( 0 );
781 rStrm
<< sal_uInt8(0x00);
784 void XclExpChTrData::Write( XclExpStream
& rStrm
, const XclExpChTrTabIdBuffer
& rTabIdBuffer
)
788 case EXC_CHTR_TYPE_RK
:
791 case EXC_CHTR_TYPE_DOUBLE
:
794 case EXC_CHTR_TYPE_STRING
:
795 OSL_ENSURE( pString
, "XclExpChTrData::Write - no string" );
798 case EXC_CHTR_TYPE_FORMULA
:
799 WriteFormula( rStrm
, rTabIdBuffer
);
804 XclExpChTrCellContent::XclExpChTrCellContent(
805 const ScChangeActionContent
& rAction
,
806 const XclExpRoot
& rRoot
,
807 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
808 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_CELL
),
810 aPosition( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()).aStart
)
814 GetCellData( rRoot
, rAction
.GetOldCell(), pOldData
, nDummy32
, nOldLength
);
815 GetCellData( rRoot
, rAction
.GetNewCell(), pNewData
, nLength
, nDummy16
);
818 XclExpChTrCellContent::~XclExpChTrCellContent()
824 void XclExpChTrCellContent::MakeEmptyChTrData( std::unique_ptr
<XclExpChTrData
>& rpData
)
829 rpData
.reset( new XclExpChTrData
);
832 void XclExpChTrCellContent::GetCellData(
833 const XclExpRoot
& rRoot
, const ScCellValue
& rScCell
,
834 std::unique_ptr
<XclExpChTrData
>& rpData
, sal_uInt32
& rXclLength1
, sal_uInt16
& rXclLength2
)
836 MakeEmptyChTrData( rpData
);
837 rXclLength1
= 0x0000003A;
838 rXclLength2
= 0x0000;
840 if (rScCell
.isEmpty())
846 switch (rScCell
.meType
)
850 rpData
->fValue
= rScCell
.mfValue
;
851 if( XclTools::GetRKFromDouble( rpData
->nRKValue
, rpData
->fValue
) )
853 rpData
->nType
= EXC_CHTR_TYPE_RK
;
855 rXclLength1
= 0x0000003E;
856 rXclLength2
= 0x0004;
860 rpData
->nType
= EXC_CHTR_TYPE_DOUBLE
;
862 rXclLength1
= 0x00000042;
863 rXclLength2
= 0x0008;
867 case CELLTYPE_STRING
:
871 if (rScCell
.meType
== CELLTYPE_STRING
)
873 sCellStr
= rScCell
.mpString
->getString();
874 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
875 rRoot
, sCellStr
, nullptr);
879 XclExpHyperlinkHelper
aLinkHelper( rRoot
, aPosition
);
880 if (rScCell
.mpEditText
)
882 sCellStr
= ScEditUtil::GetString(*rScCell
.mpEditText
, &GetDoc());
883 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
884 rRoot
, *rScCell
.mpEditText
, nullptr, aLinkHelper
);
888 rpData
->mpFormattedString
= XclExpStringHelper::CreateCellString(
889 rRoot
, OUString(), nullptr);
892 rpData
->pString
.reset( new XclExpString( sCellStr
, XclStrFlags::NONE
, 32766 ) );
893 rpData
->nType
= EXC_CHTR_TYPE_STRING
;
894 rpData
->nSize
= 3 + rpData
->pString
->GetSize();
895 rXclLength1
= 64 + (sCellStr
.getLength() << 1);
896 rXclLength2
= 6 + static_cast<sal_uInt16
>(sCellStr
.getLength() << 1);
899 case CELLTYPE_FORMULA
:
901 const ScFormulaCell
* pFmlCell
= rScCell
.mpFormula
;
902 rpData
->mpFormulaCell
= pFmlCell
;
904 const ScTokenArray
* pTokenArray
= pFmlCell
->GetCode();
907 XclExpRefLog
& rRefLog
= rpData
->maRefLog
;
908 rpData
->mxTokArr
= GetFormulaCompiler().CreateFormula(
909 EXC_FMLATYPE_CELL
, *pTokenArray
, &pFmlCell
->aPos
, &rRefLog
);
910 rpData
->nType
= EXC_CHTR_TYPE_FORMULA
;
911 std::size_t nSize
= std::accumulate(rRefLog
.begin(), rRefLog
.end(),
912 static_cast<std::size_t>(rpData
->mxTokArr
->GetSize() + 3),
913 [](const std::size_t& rSum
, const XclExpRefLogEntry
& rLogEntry
) {
914 if( rLogEntry
.mpUrl
&& rLogEntry
.mpFirstTab
)
915 return rSum
+ rLogEntry
.mpUrl
->GetSize() + rLogEntry
.mpFirstTab
->GetSize() + 2;
917 return rSum
+ ((rLogEntry
.mnFirstXclTab
== rLogEntry
.mnLastXclTab
) ? 6 : 8);
919 rpData
->nSize
= ::std::min
< std::size_t >( nSize
, 0xFFFF );
920 rXclLength1
= 0x00000052;
921 rXclLength2
= 0x0018;
929 void XclExpChTrCellContent::SaveActionData( XclExpStream
& rStrm
) const
931 WriteTabId( rStrm
, aPosition
.Tab() );
932 rStrm
<< static_cast<sal_uInt16
>((pOldData
? (pOldData
->nType
<< 3) : 0x0000) | (pNewData
? pNewData
->nType
: 0x0000))
933 << sal_uInt16(0x0000);
934 Write2DAddress( rStrm
, aPosition
);
936 << sal_uInt32(0x00000000);
938 pOldData
->Write( rStrm
, rIdBuffer
);
940 pNewData
->Write( rStrm
, rIdBuffer
);
943 sal_uInt16
XclExpChTrCellContent::GetNum() const
948 std::size_t XclExpChTrCellContent::GetActionByteCount() const
950 std::size_t nLen
= 16;
952 nLen
+= pOldData
->nSize
;
954 nLen
+= pNewData
->nSize
;
958 static const char* lcl_GetType( XclExpChTrData
* pData
)
960 switch( pData
->nType
)
962 case EXC_CHTR_TYPE_RK
:
963 case EXC_CHTR_TYPE_DOUBLE
:
965 case EXC_CHTR_TYPE_FORMULA
:
967 ScFormulaCell
* pFormulaCell
= const_cast< ScFormulaCell
* >( pData
->mpFormulaCell
);
970 XclXmlUtils::GetFormulaTypeAndValue( *pFormulaCell
, sType
, sValue
);
974 case EXC_CHTR_TYPE_STRING
:
982 static void lcl_WriteCell( XclExpXmlStream
& rStrm
, sal_Int32 nElement
, const ScAddress
& rPosition
, XclExpChTrData
* pData
)
984 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
986 pStream
->startElement(nElement
,
987 XML_r
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), rPosition
),
988 XML_s
, nullptr, // OOXTODO: not supported
989 XML_t
, lcl_GetType(pData
),
990 XML_cm
, nullptr, // OOXTODO: not supported
991 XML_vm
, nullptr, // OOXTODO: not supported
992 XML_ph
, nullptr); // OOXTODO: not supported
993 switch( pData
->nType
)
995 case EXC_CHTR_TYPE_RK
:
996 case EXC_CHTR_TYPE_DOUBLE
:
997 pStream
->startElement(XML_v
);
998 pStream
->write( pData
->fValue
);
999 pStream
->endElement( XML_v
);
1001 case EXC_CHTR_TYPE_FORMULA
:
1002 pStream
->startElement( XML_f
1003 // OOXTODO: other attributes? see XclExpFormulaCell::SaveXml()
1005 pStream
->writeEscaped( XclXmlUtils::ToOUString(
1006 rStrm
.GetRoot().GetCompileFormulaContext(),
1007 pData
->mpFormulaCell
->aPos
, pData
->mpFormulaCell
->GetCode()));
1008 pStream
->endElement( XML_f
);
1010 case EXC_CHTR_TYPE_STRING
:
1011 pStream
->startElement(XML_is
);
1012 if( pData
->mpFormattedString
)
1013 pData
->mpFormattedString
->WriteXml( rStrm
);
1015 pData
->pString
->WriteXml( rStrm
);
1016 pStream
->endElement( XML_is
);
1022 pStream
->endElement( nElement
);
1025 void XclExpChTrCellContent::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1027 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1028 pStream
->startElement( XML_rcc
,
1029 XML_rId
, OString::number(GetActionNumber()),
1030 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1031 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1032 XML_sId
, OString::number(GetTabId(aPosition
.Tab())),
1033 XML_odxf
, nullptr, // OOXTODO: not supported
1034 XML_xfDxf
, nullptr, // OOXTODO: not supported
1035 XML_s
, nullptr, // OOXTODO: not supported
1036 XML_dxf
, nullptr, // OOXTODO: not supported
1037 XML_numFmtId
, nullptr, // OOXTODO: not supported
1038 XML_quotePrefix
, nullptr, // OOXTODO: not supported
1039 XML_oldQuotePrefix
, nullptr, // OOXTODO: not supported
1040 XML_ph
, nullptr, // OOXTODO: not supported
1041 XML_oldPh
, nullptr, // OOXTODO: not supported
1042 XML_endOfListFormulaUpdate
, nullptr); // OOXTODO: not supported
1045 lcl_WriteCell( rRevisionLogStrm
, XML_oc
, aPosition
, pOldData
.get() );
1048 pStream
->singleElement(XML_nc
, XML_r
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aPosition
));
1053 lcl_WriteCell( rRevisionLogStrm
, XML_nc
, aPosition
, pNewData
.get() );
1055 // OOXTODO: XML_odxf, XML_ndxf, XML_extLst elements
1056 pStream
->endElement( XML_rcc
);
1059 XclExpChTrInsert::XclExpChTrInsert( const XclExpChTrInsert
& rCopy
) :
1060 XclExpChTrAction(rCopy
),
1061 mbEndOfList(rCopy
.mbEndOfList
),
1062 aRange(rCopy
.aRange
) {}
1064 XclExpChTrInsert::XclExpChTrInsert(
1065 const ScChangeAction
& rAction
,
1066 const XclExpRoot
& rRoot
,
1067 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1068 const ScChangeTrack
& rChangeTrack
) :
1069 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
),
1071 aRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc()) )
1073 nLength
= 0x00000030;
1074 switch( rAction
.GetType() )
1076 case SC_CAT_INSERT_COLS
: nOpCode
= EXC_CHTR_OP_INSCOL
; break;
1077 case SC_CAT_INSERT_ROWS
:
1079 const ScChangeActionIns
& rIns
= static_cast<const ScChangeActionIns
&>(rAction
);
1080 mbEndOfList
= rIns
.IsEndOfList();
1081 nOpCode
= EXC_CHTR_OP_INSROW
;
1084 case SC_CAT_DELETE_COLS
: nOpCode
= EXC_CHTR_OP_DELCOL
; break;
1085 case SC_CAT_DELETE_ROWS
: nOpCode
= EXC_CHTR_OP_DELROW
; break;
1087 OSL_FAIL( "XclExpChTrInsert::XclExpChTrInsert - unknown action" );
1090 if( nOpCode
& EXC_CHTR_OP_COLFLAG
)
1092 aRange
.aStart
.SetRow( 0 );
1093 aRange
.aEnd
.SetRow( rRoot
.GetXclMaxPos().Row() );
1097 aRange
.aStart
.SetCol( 0 );
1098 aRange
.aEnd
.SetCol( rRoot
.GetXclMaxPos().Col() );
1101 if( nOpCode
& EXC_CHTR_OP_DELFLAG
)
1103 SetAddAction( new XclExpChTr0x014A( *this ) );
1104 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1108 XclExpChTrInsert::~XclExpChTrInsert()
1112 void XclExpChTrInsert::SaveActionData( XclExpStream
& rStrm
) const
1114 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1115 sal_uInt16 nFlagVal
= mbEndOfList
? 0x0001 : 0x0000;
1117 Write2DRange( rStrm
, aRange
);
1118 rStrm
<< sal_uInt32(0x00000000);
1121 void XclExpChTrInsert::PrepareSaveAction( XclExpStream
& rStrm
) const
1123 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1124 XclExpChTrEmpty( 0x0150 ).Save( rStrm
);
1127 void XclExpChTrInsert::CompleteSaveAction( XclExpStream
& rStrm
) const
1129 if( (nOpCode
== EXC_CHTR_OP_DELROW
) || (nOpCode
== EXC_CHTR_OP_DELCOL
) )
1130 XclExpChTrEmpty( 0x0151 ).Save( rStrm
);
1133 sal_uInt16
XclExpChTrInsert::GetNum() const
1138 std::size_t XclExpChTrInsert::GetActionByteCount() const
1143 static const char* lcl_GetAction( sal_uInt16 nOpCode
)
1147 case EXC_CHTR_OP_INSCOL
: return "insertCol";
1148 case EXC_CHTR_OP_INSROW
: return "insertRow";
1149 case EXC_CHTR_OP_DELCOL
: return "deleteCol";
1150 case EXC_CHTR_OP_DELROW
: return "deleteRow";
1151 default: return "*unknown*";
1155 void XclExpChTrInsert::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1157 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1158 pStream
->startElement( XML_rrc
,
1159 XML_rId
, OString::number(GetActionNumber()),
1160 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1161 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1162 XML_sId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1163 XML_eol
, ToPsz10(mbEndOfList
),
1164 XML_ref
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aRange
),
1165 XML_action
, lcl_GetAction( nOpCode
),
1166 XML_edge
, nullptr); // OOXTODO: ???
1168 // OOXTODO: does this handle XML_rfmt, XML_undo?
1169 XclExpChTrAction
* pAction
= GetAddAction();
1170 while( pAction
!= nullptr )
1172 pAction
->SaveXml( rRevisionLogStrm
);
1173 pAction
= pAction
->GetAddAction();
1175 pStream
->endElement( XML_rrc
);
1178 XclExpChTrInsertTab::XclExpChTrInsertTab(
1179 const ScChangeAction
& rAction
,
1180 const XclExpRoot
& rRoot
,
1181 const XclExpChTrTabIdBuffer
& rTabIdBuffer
) :
1182 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_INSTAB
),
1183 XclExpRoot( rRoot
),
1184 nTab( static_cast<SCTAB
>(rAction
.GetBigRange().aStart
.Tab()) )
1186 nLength
= 0x0000021C;
1190 XclExpChTrInsertTab::~XclExpChTrInsertTab()
1194 void XclExpChTrInsertTab::SaveActionData( XclExpStream
& rStrm
) const
1196 WriteTabId( rStrm
, nTab
);
1197 rStrm
<< sal_uInt32( 0 );
1198 lcl_WriteFixedString( rStrm
, XclExpString( GetTabInfo().GetScTabName( nTab
) ), 127 );
1199 lcl_WriteDateTime( rStrm
, GetDateTime() );
1200 rStrm
.WriteZeroBytes( 133 );
1203 sal_uInt16
XclExpChTrInsertTab::GetNum() const
1208 std::size_t XclExpChTrInsertTab::GetActionByteCount() const
1213 void XclExpChTrInsertTab::SaveXml( XclExpXmlStream
& rStrm
)
1215 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1216 pStream
->singleElement( XML_ris
,
1217 XML_rId
, OString::number(GetActionNumber()),
1218 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1219 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1220 XML_sheetId
, OString::number(GetTabId(nTab
)),
1221 XML_name
, GetTabInfo().GetScTabName(nTab
).toUtf8(),
1222 XML_sheetPosition
, OString::number(nTab
) );
1225 XclExpChTrMoveRange::XclExpChTrMoveRange(
1226 const ScChangeActionMove
& rAction
,
1227 const XclExpRoot
& rRoot
,
1228 const XclExpChTrTabIdBuffer
& rTabIdBuffer
,
1229 const ScChangeTrack
& rChangeTrack
) :
1230 XclExpChTrAction( rAction
, rRoot
, rTabIdBuffer
, EXC_CHTR_OP_MOVE
),
1231 aDestRange( rAction
.GetBigRange().MakeRange( rRoot
.GetDoc() ) )
1233 nLength
= 0x00000042;
1234 aSourceRange
= aDestRange
;
1235 sal_Int32 nDCols
, nDRows
, nDTabs
;
1236 rAction
.GetDelta( nDCols
, nDRows
, nDTabs
);
1237 aSourceRange
.aStart
.IncRow( static_cast<SCROW
>(-nDRows
) );
1238 aSourceRange
.aStart
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1239 aSourceRange
.aStart
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1240 aSourceRange
.aEnd
.IncRow( static_cast<SCROW
>(-nDRows
) );
1241 aSourceRange
.aEnd
.IncCol( static_cast<SCCOL
>(-nDCols
) );
1242 aSourceRange
.aEnd
.IncTab( static_cast<SCTAB
>(-nDTabs
) );
1243 AddDependentContents( rAction
, rRoot
, rChangeTrack
);
1246 XclExpChTrMoveRange::~XclExpChTrMoveRange()
1250 void XclExpChTrMoveRange::SaveActionData( XclExpStream
& rStrm
) const
1252 WriteTabId( rStrm
, aDestRange
.aStart
.Tab() );
1253 Write2DRange( rStrm
, aSourceRange
);
1254 Write2DRange( rStrm
, aDestRange
);
1255 WriteTabId( rStrm
, aSourceRange
.aStart
.Tab() );
1256 rStrm
<< sal_uInt32(0x00000000);
1259 void XclExpChTrMoveRange::PrepareSaveAction( XclExpStream
& rStrm
) const
1261 XclExpChTrEmpty( 0x014E ).Save( rStrm
);
1264 void XclExpChTrMoveRange::CompleteSaveAction( XclExpStream
& rStrm
) const
1266 XclExpChTrEmpty( 0x014F ).Save( rStrm
);
1269 sal_uInt16
XclExpChTrMoveRange::GetNum() const
1274 std::size_t XclExpChTrMoveRange::GetActionByteCount() const
1279 void XclExpChTrMoveRange::SaveXml( XclExpXmlStream
& rRevisionLogStrm
)
1281 sax_fastparser::FSHelperPtr pStream
= rRevisionLogStrm
.GetCurrentStream();
1283 pStream
->startElement( XML_rm
,
1284 XML_rId
, OString::number(GetActionNumber()),
1285 XML_ua
, ToPsz( GetAccepted () ), // OOXTODO? bAccepted == ua or ra; not sure.
1286 XML_ra
, nullptr, // OOXTODO: RRD.fUndoAction? Or RRD.fAccepted?
1287 XML_sheetId
, OString::number(GetTabId(aDestRange
.aStart
.Tab())),
1288 XML_source
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aSourceRange
),
1289 XML_destination
, XclXmlUtils::ToOString(rRevisionLogStrm
.GetRoot().GetDoc(), aDestRange
),
1290 XML_sourceSheetId
, OString::number(GetTabId(aSourceRange
.aStart
.Tab())) );
1291 // OOXTODO: does this handle XML_rfmt, XML_undo?
1292 XclExpChTrAction
* pAction
= GetAddAction();
1293 while( pAction
!= nullptr )
1295 pAction
->SaveXml( rRevisionLogStrm
);
1296 pAction
= pAction
->GetAddAction();
1298 pStream
->endElement( XML_rm
);
1301 XclExpChTr0x014A::XclExpChTr0x014A( const XclExpChTrInsert
& rAction
) :
1302 XclExpChTrInsert( rAction
)
1304 nLength
= 0x00000026;
1305 nOpCode
= EXC_CHTR_OP_FORMAT
;
1308 XclExpChTr0x014A::~XclExpChTr0x014A()
1312 void XclExpChTr0x014A::SaveActionData( XclExpStream
& rStrm
) const
1314 WriteTabId( rStrm
, aRange
.aStart
.Tab() );
1315 rStrm
<< sal_uInt16(0x0003)
1316 << sal_uInt16(0x0001);
1317 Write2DRange( rStrm
, aRange
);
1320 sal_uInt16
XclExpChTr0x014A::GetNum() const
1325 std::size_t XclExpChTr0x014A::GetActionByteCount() const
1330 void XclExpChTr0x014A::SaveXml( XclExpXmlStream
& rStrm
)
1332 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1334 pStream
->startElement( XML_rfmt
,
1335 XML_sheetId
, OString::number(GetTabId(aRange
.aStart
.Tab())),
1336 XML_xfDxf
, nullptr, // OOXTODO: not supported
1337 XML_s
, nullptr, // OOXTODO: style
1338 XML_sqref
, XclXmlUtils::ToOString(rStrm
.GetRoot().GetDoc(), aRange
),
1339 XML_start
, nullptr, // OOXTODO: for string changes
1340 XML_length
, nullptr); // OOXTODO: for string changes
1341 // OOXTODO: XML_dxf, XML_extLst
1343 pStream
->endElement( XML_rfmt
);
1346 std::size_t ExcXmlRecord::GetLen() const
1351 sal_uInt16
ExcXmlRecord::GetNum() const
1356 void ExcXmlRecord::Save( XclExpStream
& )
1358 // Do nothing; ignored for BIFF output.
1363 class EndXmlElement
: public ExcXmlRecord
1365 sal_Int32 mnElement
;
1367 explicit EndXmlElement( sal_Int32 nElement
) : mnElement( nElement
) {}
1368 virtual void SaveXml( XclExpXmlStream
& rStrm
) override
;
1373 void EndXmlElement::SaveXml( XclExpXmlStream
& rStrm
)
1375 sax_fastparser::FSHelperPtr pStream
= rStrm
.GetCurrentStream();
1376 pStream
->write("</")->writeId(mnElement
)->write(">");
1379 XclExpChangeTrack::XclExpChangeTrack( const XclExpRoot
& rRoot
) :
1380 XclExpRoot( rRoot
),
1381 pTabIdBuffer( nullptr )
1383 OSL_ENSURE( GetOldRoot().pTabId
, "XclExpChangeTrack::XclExpChangeTrack - root data incomplete" );
1384 if( !GetOldRoot().pTabId
)
1387 ScChangeTrack
* pTempChangeTrack
= CreateTempChangeTrack();
1388 if (!pTempChangeTrack
)
1391 pTabIdBuffer
= new XclExpChTrTabIdBuffer( GetTabInfo().GetXclTabCount() );
1392 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pTabIdBuffer
) );
1394 // calculate final table order (tab id list)
1395 const ScChangeAction
* pScAction
;
1396 for( pScAction
= pTempChangeTrack
->GetLast(); pScAction
; pScAction
= pScAction
->GetPrev() )
1398 if( pScAction
->GetType() == SC_CAT_INSERT_TABS
)
1400 SCTAB nScTab
= static_cast< SCTAB
>( pScAction
->GetBigRange().aStart
.Tab() );
1401 pTabIdBuffer
->InitFill( GetTabInfo().GetXclTab( nScTab
) );
1404 pTabIdBuffer
->InitFillup();
1405 GetOldRoot().pTabId
->Copy( *pTabIdBuffer
);
1407 // get actions in reverse order
1408 pScAction
= pTempChangeTrack
->GetLast();
1411 PushActionRecord( *pScAction
);
1412 const ScChangeAction
* pPrevAction
= pScAction
->GetPrev();
1413 pScAction
= pPrevAction
;
1416 // build record list
1417 if (GetOutput() == EXC_OUTPUT_BINARY
)
1419 XclExpChTrHeader
* pHeader
= new XclExpChTrHeader
; // header record for last GUID
1420 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeader
) );
1421 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0195
) );
1422 maRecList
.push_back( std::unique_ptr
<ExcRecord
>( new XclExpChTr0x0194( *pTempChangeTrack
) ) );
1424 OUString sLastUsername
;
1425 DateTime
aLastDateTime( DateTime::EMPTY
);
1426 sal_uInt32 nIndex
= 1;
1427 sal_Int32 nLogNumber
= 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();
1444 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrInfo(sLastUsername
, aLastDateTime
, aGUID
)) );
1445 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new XclExpChTrTabId(pAction
->GetTabIdBuffer())) );
1446 pHeader
->SetGUID( aGUID
);
1448 pAction
->SetIndex( nIndex
);
1449 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pAction
) );
1452 pHeader
->SetGUID( aGUID
);
1453 pHeader
->SetCount( nIndex
- 1 );
1454 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new ExcEof
) );
1458 XclExpXmlChTrHeaders
* pHeaders
= new XclExpXmlChTrHeaders
;
1459 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pHeaders
));
1461 OUString sLastUsername
;
1462 DateTime
aLastDateTime(DateTime::EMPTY
);
1463 sal_uInt32 nIndex
= 1;
1464 sal_Int32 nLogNumber
= 1;
1465 XclExpXmlChTrHeader
* pCurHeader
= nullptr;
1466 sal_uInt8 aGUID
[ 16 ]; // GUID for action info records
1467 bool bValidGUID
= false;
1469 while (!aActionStack
.empty())
1471 XclExpChTrAction
* pAction
= aActionStack
.top();
1474 if( (nIndex
== 1) || pAction
->ForceInfoRecord() ||
1475 (pAction
->GetUsername() != sLastUsername
) ||
1476 (pAction
->GetDateTime() != aLastDateTime
) )
1478 lcl_GenerateGUID( aGUID
, bValidGUID
);
1479 sLastUsername
= pAction
->GetUsername();
1480 aLastDateTime
= pAction
->GetDateTime();
1482 pCurHeader
= new XclExpXmlChTrHeader(sLastUsername
, aLastDateTime
, aGUID
, nLogNumber
, pAction
->GetTabIdBuffer());
1483 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(pCurHeader
));
1485 pHeaders
->SetGUID(aGUID
);
1487 pAction
->SetIndex(nIndex
);
1488 pCurHeader
->AppendAction(std::unique_ptr
<XclExpChTrAction
>(pAction
));
1491 pHeaders
->SetGUID(aGUID
);
1492 maRecList
.push_back( std::unique_ptr
<ExcRecord
>(new EndXmlElement(XML_headers
)));
1496 XclExpChangeTrack::~XclExpChangeTrack()
1498 while( !aActionStack
.empty() )
1500 delete aActionStack
.top();
1505 ScChangeTrack
* XclExpChangeTrack::CreateTempChangeTrack()
1507 // get original change track
1508 ScChangeTrack
* pOrigChangeTrack
= GetDoc().GetChangeTrack();
1509 OSL_ENSURE( pOrigChangeTrack
, "XclExpChangeTrack::CreateTempChangeTrack - no change track data" );
1510 if( !pOrigChangeTrack
)
1514 // create empty document
1515 xTempDoc
.reset(new ScDocument
);
1517 // adjust table count
1518 SCTAB nOrigCount
= GetDoc().GetTableCount();
1520 for( sal_Int32 nIndex
= 0; nIndex
< nOrigCount
; nIndex
++ )
1522 xTempDoc
->CreateValidTabName(sTabName
);
1523 xTempDoc
->InsertTab(SC_TAB_APPEND
, sTabName
);
1525 OSL_ENSURE(nOrigCount
== xTempDoc
->GetTableCount(),
1526 "XclExpChangeTrack::CreateTempChangeTrack - table count mismatch");
1527 if(nOrigCount
!= xTempDoc
->GetTableCount())
1530 return pOrigChangeTrack
->Clone(xTempDoc
.get());
1533 void XclExpChangeTrack::PushActionRecord( const ScChangeAction
& rAction
)
1535 XclExpChTrAction
* pXclAction
= nullptr;
1536 ScChangeTrack
* pTempChangeTrack
= xTempDoc
->GetChangeTrack();
1537 switch( rAction
.GetType() )
1539 case SC_CAT_CONTENT
:
1540 pXclAction
= new XclExpChTrCellContent( static_cast<const ScChangeActionContent
&>(rAction
), GetRoot(), *pTabIdBuffer
);
1542 case SC_CAT_INSERT_ROWS
:
1543 case SC_CAT_INSERT_COLS
:
1544 case SC_CAT_DELETE_ROWS
:
1545 case SC_CAT_DELETE_COLS
:
1546 if (pTempChangeTrack
)
1547 pXclAction
= new XclExpChTrInsert( rAction
, GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1549 case SC_CAT_INSERT_TABS
:
1551 pXclAction
= new XclExpChTrInsertTab( rAction
, GetRoot(), *pTabIdBuffer
);
1552 XclExpChTrTabIdBuffer
* pNewBuffer
= new XclExpChTrTabIdBuffer( *pTabIdBuffer
);
1553 pNewBuffer
->Remove();
1554 maBuffers
.push_back( std::unique_ptr
<XclExpChTrTabIdBuffer
>(pNewBuffer
) );
1555 pTabIdBuffer
= pNewBuffer
;
1559 if (pTempChangeTrack
)
1560 pXclAction
= new XclExpChTrMoveRange( static_cast<const ScChangeActionMove
&>(rAction
), GetRoot(), *pTabIdBuffer
, *pTempChangeTrack
);
1565 aActionStack
.push( pXclAction
);
1568 bool XclExpChangeTrack::WriteUserNamesStream()
1571 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( EXC_STREAM_USERNAMES
);
1572 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::WriteUserNamesStream - no stream" );
1575 XclExpStream
aXclStrm( *xSvStrm
, GetRoot() );
1576 XclExpChTr0x0191().Save( aXclStrm
);
1577 XclExpChTr0x0198().Save( aXclStrm
);
1578 XclExpChTr0x0192().Save( aXclStrm
);
1579 XclExpChTr0x0197().Save( aXclStrm
);
1586 void XclExpChangeTrack::Write()
1588 if (maRecList
.empty())
1591 if( !WriteUserNamesStream() )
1594 tools::SvRef
<SotStorageStream
> xSvStrm
= OpenStream( EXC_STREAM_REVLOG
);
1595 OSL_ENSURE( xSvStrm
.is(), "XclExpChangeTrack::Write - no stream" );
1598 XclExpStream
aXclStrm( *xSvStrm
, GetRoot(), EXC_MAXRECSIZE_BIFF8
+ 8 );
1600 for(const auto& rxRec
: maRecList
)
1601 rxRec
->Save(aXclStrm
);
1607 static void lcl_WriteUserNamesXml( XclExpXmlStream
& rWorkbookStrm
)
1609 sax_fastparser::FSHelperPtr pUserNames
= rWorkbookStrm
.CreateOutputStream(
1610 "xl/revisions/userNames.xml",
1611 u
"revisions/userNames.xml",
1612 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1613 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml",
1614 CREATE_OFFICEDOC_RELATION_TYPE("usernames"));
1615 pUserNames
->startElement( XML_users
,
1616 XML_xmlns
, rWorkbookStrm
.getNamespaceURL(OOX_NS(xls
)).toUtf8(),
1617 FSNS( XML_xmlns
, XML_r
), rWorkbookStrm
.getNamespaceURL(OOX_NS(officeRel
)).toUtf8(),
1619 // OOXTODO: XML_userinfo elements for each user editing the file
1620 // Doesn't seem to be supported by .xls output either (based on
1621 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1622 pUserNames
->endElement( XML_users
);
1625 void XclExpChangeTrack::WriteXml( XclExpXmlStream
& rWorkbookStrm
)
1627 if (maRecList
.empty())
1630 lcl_WriteUserNamesXml( rWorkbookStrm
);
1632 sax_fastparser::FSHelperPtr pRevisionHeaders
= rWorkbookStrm
.CreateOutputStream(
1633 "xl/revisions/revisionHeaders.xml",
1634 u
"revisions/revisionHeaders.xml",
1635 rWorkbookStrm
.GetCurrentStream()->getOutputStream(),
1636 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml",
1637 CREATE_OFFICEDOC_RELATION_TYPE("revisionHeaders"));
1638 // OOXTODO: XML_userinfo elements for each user editing the file
1639 // Doesn't seem to be supported by .xls output either (based on
1640 // contents of XclExpChangeTrack::WriteUserNamesStream()).
1641 rWorkbookStrm
.PushStream( pRevisionHeaders
);
1643 for (const auto& rxRec
: maRecList
)
1644 rxRec
->SaveXml(rWorkbookStrm
);
1646 rWorkbookStrm
.PopStream();
1649 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */