Version 7.5.1.1, tag libreoffice-7.5.1.1
[LibreOffice.git] / sc / source / filter / xcl97 / XclExpChangeTrack.cxx
blob57fd143bf659c728f539ab3ca585e2e8ab9c1ad6
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <memory>
21 #include <numeric>
22 #include <stdio.h>
23 #include <sot/storage.hxx>
24 #include <XclExpChangeTrack.hxx>
25 #include <utility>
26 #include <xeformula.hxx>
27 #include <xehelper.hxx>
28 #include <xltools.hxx>
29 #include <formulacell.hxx>
30 #include <document.hxx>
31 #include <editutil.hxx>
32 #include <root.hxx>
33 #include <tools/Guid.hxx>
35 #include <oox/export/utils.hxx>
36 #include <oox/token/namespaces.hxx>
37 #include <oox/token/tokens.hxx>
38 #include <rtl/uuid.h>
39 #include <svl/sharedstring.hxx>
41 using namespace oox;
43 static OString lcl_DateTimeToOString( const DateTime& rDateTime )
45 char sBuf[ 200 ];
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() );
51 return sBuf;
54 // local functions
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 )
75 rStrm << rString;
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 );
83 rValidGUID = true;
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)
107 << sal_uInt32(1000)
108 << sal_uInt16(1000)
109 << sal_uInt16(0x0CF7)
110 << sal_uInt16(0x0000)
111 << sal_uInt16(0x0001)
112 << sal_uInt16(0x0000);
113 if( sUsername.Len() > 0 )
114 rStrm << sUsername;
117 sal_uInt16 XclExpUserBView::GetNum() const
119 return 0x01A9;
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 )
147 rView.Save( rStrm );
150 XclExpUsersViewBegin::XclExpUsersViewBegin( const sal_uInt8* pGUID, sal_uInt32 nTab ) :
151 nCurrTab( nTab )
153 memcpy( aGUID, pGUID, 16 );
156 void XclExpUsersViewBegin::SaveCont( XclExpStream& rStrm )
158 lcl_WriteGUID( rStrm, aGUID );
159 rStrm << nCurrTab
160 << sal_uInt32(100)
161 << sal_uInt32(64)
162 << sal_uInt32(3)
163 << sal_uInt32(0x0000003C)
164 << sal_uInt16(0)
165 << sal_uInt16(3)
166 << sal_uInt16(0)
167 << sal_uInt16(3)
168 << double(0)
169 << double(0)
170 << sal_Int16(-1)
171 << sal_Int16(-1);
174 sal_uInt16 XclExpUsersViewBegin::GetNum() const
176 return 0x01AA;
179 std::size_t XclExpUsersViewBegin::GetLen() const
181 return 64;
184 void XclExpUsersViewEnd::SaveCont( XclExpStream& rStrm )
186 rStrm << sal_uInt16(0x0001);
189 sal_uInt16 XclExpUsersViewEnd::GetNum() const
191 return 0x01AB;
194 std::size_t XclExpUsersViewEnd::GetLen() const
196 return 2;
199 void XclExpChTr0x0191::SaveCont( XclExpStream& rStrm )
201 rStrm << sal_uInt16(0x0000);
204 sal_uInt16 XclExpChTr0x0191::GetNum() const
206 return 0x0191;
209 std::size_t XclExpChTr0x0191::GetLen() const
211 return 2;
214 void XclExpChTr0x0198::SaveCont( XclExpStream& rStrm )
216 rStrm << sal_uInt16(0x0006)
217 << sal_uInt16(0x0000);
220 sal_uInt16 XclExpChTr0x0198::GetNum() const
222 return 0x0198;
225 std::size_t XclExpChTr0x0198::GetLen() const
227 return 4;
230 void XclExpChTr0x0192::SaveCont( XclExpStream& rStrm )
232 rStrm << sal_uInt16( 0x0022 );
233 rStrm.WriteZeroBytes( 510 );
236 sal_uInt16 XclExpChTr0x0192::GetNum() const
238 return 0x0192;
241 std::size_t XclExpChTr0x0192::GetLen() const
243 return 512;
246 void XclExpChTr0x0197::SaveCont( XclExpStream& rStrm )
248 rStrm << sal_uInt16(0x0000);
251 sal_uInt16 XclExpChTr0x0197::GetNum() const
253 return 0x0197;
256 std::size_t XclExpChTr0x0197::GetLen() const
258 return 2;
261 XclExpChTrEmpty::~XclExpChTrEmpty()
265 sal_uInt16 XclExpChTrEmpty::GetNum() const
267 return nRecNum;
270 std::size_t XclExpChTrEmpty::GetLen() const
272 return 0;
275 XclExpChTr0x0195::~XclExpChTr0x0195()
279 void XclExpChTr0x0195::SaveCont( XclExpStream& rStrm )
281 rStrm.WriteZeroBytes( 162 );
284 sal_uInt16 XclExpChTr0x0195::GetNum() const
286 return 0x0195;
289 std::size_t XclExpChTr0x0195::GetLen() const
291 return 162;
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
308 return 0x0194;
311 std::size_t XclExpChTr0x0194::GetLen() const
313 return 162;
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 );
327 rStrm << nCount
328 << sal_uInt16(0x0001)
329 << sal_uInt32(0x00000000)
330 << sal_uInt16(0x001E);
333 sal_uInt16 XclExpChTrHeader::GetNum() const
335 return 0x0196;
338 std::size_t XclExpChTrHeader::GetLen() const
340 return 50;
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);
414 OUString aRelId;
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"),
421 &aRelId);
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);
430 if (mnMinAction)
431 rStrm.WriteAttributes(XML_minRId, OUString::number(mnMinAction));
433 if (mnMaxAction)
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));
440 pHeader->write(">");
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(">");
474 rStrm.PopStream();
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
518 return 0x0138;
521 std::size_t XclExpChTrInfo::GetLen() const
523 return 158;
526 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount ) :
527 nBufSize( nCount ),
528 nLastId( 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++ )
555 if( !*pElem )
556 nFreeCount++;
557 if( nFreeCount > nIndex )
559 *pElem = nLastId--;
560 return;
565 void XclExpChTrTabIdBuffer::InitFillup()
567 sal_uInt16 nFreeCount = 1;
568 for( sal_uInt16* pElem = pBuffer.get(); pElem <= pLast; pElem++ )
569 if( !*pElem )
570 *pElem = nFreeCount++;
571 nLastId = nBufSize;
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) )
585 pElem++;
586 while( pElem < pLast )
588 *pElem = *(pElem + 1);
589 pElem++;
591 pLast--;
592 nLastId--;
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()
604 Clear();
607 void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer& rBuffer )
609 Clear();
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();
618 if( pBuffer )
619 rStrm.Write(pBuffer.get(), nTabCount);
620 else
621 for( sal_uInt16 nIndex = 1; nIndex <= nTabCount; nIndex++ )
622 rStrm << nIndex;
625 sal_uInt16 XclExpChTrTabId::GetNum() const
627 return 0x013D;
630 std::size_t XclExpChTrTabId::GetLen() const
632 return nTabCount << 1;
635 // ! does not copy additional actions
636 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction& rCopy ) :
637 ExcRecord( rCopy ),
638 sUsername( rCopy.sUsername ),
639 aDateTime( rCopy.aDateTime ),
640 nIndex( 0 ),
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() ),
657 nIndex( 0 ),
658 bAccepted( rAction.IsAccepted() ),
659 rTabInfo( rRoot.GetTabInfo() ),
660 rIdBuffer( rTabIdBuffer ),
661 nLength( 0 ),
662 nOpCode( nNewOpCode ),
663 bForceInfo( false )
665 aDateTime.SetSec( 0 );
666 aDateTime.SetNanoSec( 0 );
669 XclExpChTrAction::~XclExpChTrAction()
673 void XclExpChTrAction::SetAddAction( XclExpChTrAction* pAction )
675 if( pAddAction )
676 pAddAction->SetAddAction( pAction );
677 else
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 )
697 nIndex = rIndex++;
700 void XclExpChTrAction::SaveCont( XclExpStream& rStrm )
702 OSL_ENSURE( nOpCode != EXC_CHTR_OP_UNKNOWN, "XclExpChTrAction::SaveCont - unknown action" );
703 rStrm << nLength
704 << nIndex
705 << nOpCode
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 );
722 if( pAddAction )
723 pAddAction->Save( rStrm );
724 CompleteSaveAction( rStrm );
727 std::size_t XclExpChTrAction::GetLen() const
729 return GetHeaderByteCount() + GetActionByteCount();
732 XclExpChTrData::XclExpChTrData() :
733 mpFormulaCell( nullptr ),
734 fValue( 0.0 ),
735 nRKValue( 0 ),
736 nType( EXC_CHTR_TYPE_EMPTY ),
737 nSize( 0 )
741 XclExpChTrData::~XclExpChTrData()
743 Clear();
746 void XclExpChTrData::Clear()
748 pString.reset();
749 mpFormulaCell = nullptr;
750 mxTokArr.reset();
751 maRefLog.clear();
752 fValue = 0.0;
753 nRKValue = 0;
754 nType = EXC_CHTR_TYPE_EMPTY;
755 nSize = 0;
758 void XclExpChTrData::WriteFormula( XclExpStream& rStrm, const XclExpChTrTabIdBuffer& rTabIdBuffer )
760 OSL_ENSURE( mxTokArr && !mxTokArr->Empty(), "XclExpChTrData::Write - no formula" );
761 rStrm << *mxTokArr;
763 for( const auto& rLogEntry : maRefLog )
765 if( rLogEntry.mpUrl && rLogEntry.mpFirstTab )
767 rStrm << *rLogEntry.mpUrl << sal_uInt8(0x01) << *rLogEntry.mpFirstTab << sal_uInt8(0x02);
769 else
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 );
775 if( bSingleTab )
776 rStrm << sal_uInt8(0x02);
777 else
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 )
787 switch( nType )
789 case EXC_CHTR_TYPE_RK:
790 rStrm << nRKValue;
791 break;
792 case EXC_CHTR_TYPE_DOUBLE:
793 rStrm << fValue;
794 break;
795 case EXC_CHTR_TYPE_STRING:
796 OSL_ENSURE( pString, "XclExpChTrData::Write - no string" );
797 rStrm << *pString;
798 break;
799 case EXC_CHTR_TYPE_FORMULA:
800 WriteFormula( rStrm, rTabIdBuffer );
801 break;
805 XclExpChTrCellContent::XclExpChTrCellContent(
806 const ScChangeActionContent& rAction,
807 const XclExpRoot& rRoot,
808 const XclExpChTrTabIdBuffer& rTabIdBuffer ) :
809 XclExpChTrAction( rAction, rRoot, rTabIdBuffer, EXC_CHTR_OP_CELL ),
810 XclExpRoot( rRoot ),
811 aPosition( rAction.GetBigRange().MakeRange( rRoot.GetDoc()).aStart )
813 sal_uInt32 nDummy32;
814 sal_uInt16 nDummy16;
815 GetCellData( rRoot, rAction.GetOldCell(), pOldData, nDummy32, nOldLength );
816 GetCellData( rRoot, rAction.GetNewCell(), pNewData, nLength, nDummy16 );
819 XclExpChTrCellContent::~XclExpChTrCellContent()
821 pOldData.reset();
822 pNewData.reset();
825 void XclExpChTrCellContent::MakeEmptyChTrData( std::unique_ptr<XclExpChTrData>& rpData )
827 if( rpData )
828 rpData->Clear();
829 else
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())
843 rpData.reset();
844 return;
847 switch (rScCell.getType())
849 case CELLTYPE_VALUE:
851 rpData->fValue = rScCell.getDouble();
852 if( XclTools::GetRKFromDouble( rpData->nRKValue, rpData->fValue ) )
854 rpData->nType = EXC_CHTR_TYPE_RK;
855 rpData->nSize = 4;
856 rXclLength1 = 0x0000003E;
857 rXclLength2 = 0x0004;
859 else
861 rpData->nType = EXC_CHTR_TYPE_DOUBLE;
862 rpData->nSize = 8;
863 rXclLength1 = 0x00000042;
864 rXclLength2 = 0x0008;
867 break;
868 case CELLTYPE_STRING:
869 case CELLTYPE_EDIT:
871 OUString sCellStr;
872 if (rScCell.getType() == CELLTYPE_STRING)
874 sCellStr = rScCell.getSharedString()->getString();
875 rpData->mpFormattedString = XclExpStringHelper::CreateCellString(
876 rRoot, sCellStr, nullptr);
878 else
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);
887 else
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);
899 break;
900 case CELLTYPE_FORMULA:
902 const ScFormulaCell* pFmlCell = rScCell.getFormula();
903 rpData->mpFormulaCell = pFmlCell;
905 const ScTokenArray* pTokenArray = pFmlCell->GetCode();
906 if( pTokenArray )
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;
917 else
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;
925 break;
926 default:;
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 );
936 rStrm << nOldLength
937 << sal_uInt32(0x00000000);
938 if( pOldData )
939 pOldData->Write( rStrm, rIdBuffer );
940 if( pNewData )
941 pNewData->Write( rStrm, rIdBuffer );
944 sal_uInt16 XclExpChTrCellContent::GetNum() const
946 return 0x013B;
949 std::size_t XclExpChTrCellContent::GetActionByteCount() const
951 std::size_t nLen = 16;
952 if( pOldData )
953 nLen += pOldData->nSize;
954 if( pNewData )
955 nLen += pNewData->nSize;
956 return nLen;
959 static const char* lcl_GetType( XclExpChTrData* pData )
961 switch( pData->nType )
963 case EXC_CHTR_TYPE_RK:
964 case EXC_CHTR_TYPE_DOUBLE:
965 return "n";
966 case EXC_CHTR_TYPE_FORMULA:
968 ScFormulaCell* pFormulaCell = const_cast< ScFormulaCell* >( pData->mpFormulaCell );
969 const char* sType;
970 OUString sValue;
971 XclXmlUtils::GetFormulaTypeAndValue( *pFormulaCell, sType, sValue );
972 return sType;
974 break;
975 case EXC_CHTR_TYPE_STRING:
976 return "inlineStr";
977 default:
978 break;
980 return "*unknown*";
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 );
1001 break;
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 );
1010 break;
1011 case EXC_CHTR_TYPE_STRING:
1012 pStream->startElement(XML_is);
1013 if( pData->mpFormattedString )
1014 pData->mpFormattedString->WriteXml( rStrm );
1015 else
1016 pData->pString->WriteXml( rStrm );
1017 pStream->endElement( XML_is );
1018 break;
1019 default:
1020 // ignore
1021 break;
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
1044 if( pOldData )
1046 lcl_WriteCell( rRevisionLogStrm, XML_oc, aPosition, pOldData.get() );
1047 if (!pNewData)
1049 pStream->singleElement(XML_nc, XML_r, XclXmlUtils::ToOString(rRevisionLogStrm.GetRoot().GetDoc(), aPosition));
1052 if( pNewData )
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 ),
1071 mbEndOfList(false),
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;
1084 break;
1085 case SC_CAT_DELETE_COLS: nOpCode = EXC_CHTR_OP_DELCOL; break;
1086 case SC_CAT_DELETE_ROWS: nOpCode = EXC_CHTR_OP_DELROW; break;
1087 default:
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() );
1096 else
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;
1117 rStrm << nFlagVal;
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
1136 return 0x0137;
1139 std::size_t XclExpChTrInsert::GetActionByteCount() const
1141 return 16;
1144 static const char* lcl_GetAction( sal_uInt16 nOpCode )
1146 switch( 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;
1188 bForceInfo = true;
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
1206 return 0x014D;
1209 std::size_t XclExpChTrInsertTab::GetActionByteCount() const
1211 return 276;
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
1272 return 0x0140;
1275 std::size_t XclExpChTrMoveRange::GetActionByteCount() const
1277 return 24;
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
1323 return 0x014A;
1326 std::size_t XclExpChTr0x014A::GetActionByteCount() const
1328 return 14;
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
1349 return 0;
1352 sal_uInt16 ExcXmlRecord::GetNum() const
1354 return 0;
1357 void ExcXmlRecord::Save( XclExpStream& )
1359 // Do nothing; ignored for BIFF output.
1362 namespace {
1364 class EndXmlElement : public ExcXmlRecord
1366 sal_Int32 mnElement;
1367 public:
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 )
1386 return;
1388 ScChangeTrack* pTempChangeTrack = CreateTempChangeTrack();
1389 if (!pTempChangeTrack)
1390 return;
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();
1410 while( pScAction )
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();
1433 aActionStack.pop();
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) );
1455 else
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();
1471 aActionStack.pop();
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));
1483 nLogNumber++;
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();
1500 aActionStack.pop();
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 )
1510 return nullptr;
1512 assert(!xTempDoc);
1513 // create empty document
1514 xTempDoc.reset(new ScDocument);
1516 // adjust table count
1517 SCTAB nOrigCount = GetDoc().GetTableCount();
1518 OUString sTabName;
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())
1527 return nullptr;
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 );
1540 break;
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 );
1547 break;
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;
1556 break;
1557 case SC_CAT_MOVE:
1558 if (pTempChangeTrack)
1559 pXclAction = new XclExpChTrMoveRange( static_cast<const ScChangeActionMove&>(rAction), GetRoot(), *pTabIdBuffer, *pTempChangeTrack );
1560 break;
1561 default:;
1563 if( pXclAction )
1564 aActionStack.push( pXclAction );
1567 bool XclExpChangeTrack::WriteUserNamesStream()
1569 bool bRet = false;
1570 tools::SvRef<SotStorageStream> xSvStrm = OpenStream( EXC_STREAM_USERNAMES );
1571 OSL_ENSURE( xSvStrm.is(), "XclExpChangeTrack::WriteUserNamesStream - no stream" );
1572 if( xSvStrm.is() )
1574 XclExpStream aXclStrm( *xSvStrm, GetRoot() );
1575 XclExpChTr0x0191().Save( aXclStrm );
1576 XclExpChTr0x0198().Save( aXclStrm );
1577 XclExpChTr0x0192().Save( aXclStrm );
1578 XclExpChTr0x0197().Save( aXclStrm );
1579 xSvStrm->Commit();
1580 bRet = true;
1582 return bRet;
1585 void XclExpChangeTrack::Write()
1587 if (maRecList.empty())
1588 return;
1590 if( !WriteUserNamesStream() )
1591 return;
1593 tools::SvRef<SotStorageStream> xSvStrm = OpenStream( EXC_STREAM_REVLOG );
1594 OSL_ENSURE( xSvStrm.is(), "XclExpChangeTrack::Write - no stream" );
1595 if( xSvStrm.is() )
1597 XclExpStream aXclStrm( *xSvStrm, GetRoot(), EXC_MAXRECSIZE_BIFF8 + 8 );
1599 for(const auto& rxRec : maRecList)
1600 rxRec->Save(aXclStrm);
1602 xSvStrm->Commit();
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(),
1617 XML_count, "0" );
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())
1627 return;
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: */