LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sc / source / filter / xcl97 / XclExpChangeTrack.cxx
blob89891f7a617ac4e851b9917d69cf191412a1fcf6
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 <xeformula.hxx>
26 #include <xehelper.hxx>
27 #include <xltools.hxx>
28 #include <formulacell.hxx>
29 #include <document.hxx>
30 #include <editutil.hxx>
31 #include <root.hxx>
32 #include <tools/Guid.hxx>
34 #include <oox/export/utils.hxx>
35 #include <oox/token/namespaces.hxx>
36 #include <oox/token/tokens.hxx>
37 #include <rtl/uuid.h>
38 #include <svl/sharedstring.hxx>
40 using namespace oox;
42 static OString lcl_DateTimeToOString( const DateTime& rDateTime )
44 char sBuf[ 200 ];
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() );
50 return OString(sBuf);
53 // local functions
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 )
74 rStrm << rString;
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 );
82 rValidGUID = true;
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)
106 << sal_uInt32(1000)
107 << sal_uInt16(1000)
108 << sal_uInt16(0x0CF7)
109 << sal_uInt16(0x0000)
110 << sal_uInt16(0x0001)
111 << sal_uInt16(0x0000);
112 if( sUsername.Len() > 0 )
113 rStrm << sUsername;
116 sal_uInt16 XclExpUserBView::GetNum() const
118 return 0x01A9;
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 )
146 rView.Save( rStrm );
149 XclExpUsersViewBegin::XclExpUsersViewBegin( const sal_uInt8* pGUID, sal_uInt32 nTab ) :
150 nCurrTab( nTab )
152 memcpy( aGUID, pGUID, 16 );
155 void XclExpUsersViewBegin::SaveCont( XclExpStream& rStrm )
157 lcl_WriteGUID( rStrm, aGUID );
158 rStrm << nCurrTab
159 << sal_uInt32(100)
160 << sal_uInt32(64)
161 << sal_uInt32(3)
162 << sal_uInt32(0x0000003C)
163 << sal_uInt16(0)
164 << sal_uInt16(3)
165 << sal_uInt16(0)
166 << sal_uInt16(3)
167 << double(0)
168 << double(0)
169 << sal_Int16(-1)
170 << sal_Int16(-1);
173 sal_uInt16 XclExpUsersViewBegin::GetNum() const
175 return 0x01AA;
178 std::size_t XclExpUsersViewBegin::GetLen() const
180 return 64;
183 void XclExpUsersViewEnd::SaveCont( XclExpStream& rStrm )
185 rStrm << sal_uInt16(0x0001);
188 sal_uInt16 XclExpUsersViewEnd::GetNum() const
190 return 0x01AB;
193 std::size_t XclExpUsersViewEnd::GetLen() const
195 return 2;
198 void XclExpChTr0x0191::SaveCont( XclExpStream& rStrm )
200 rStrm << sal_uInt16(0x0000);
203 sal_uInt16 XclExpChTr0x0191::GetNum() const
205 return 0x0191;
208 std::size_t XclExpChTr0x0191::GetLen() const
210 return 2;
213 void XclExpChTr0x0198::SaveCont( XclExpStream& rStrm )
215 rStrm << sal_uInt16(0x0006)
216 << sal_uInt16(0x0000);
219 sal_uInt16 XclExpChTr0x0198::GetNum() const
221 return 0x0198;
224 std::size_t XclExpChTr0x0198::GetLen() const
226 return 4;
229 void XclExpChTr0x0192::SaveCont( XclExpStream& rStrm )
231 rStrm << sal_uInt16( 0x0022 );
232 rStrm.WriteZeroBytes( 510 );
235 sal_uInt16 XclExpChTr0x0192::GetNum() const
237 return 0x0192;
240 std::size_t XclExpChTr0x0192::GetLen() const
242 return 512;
245 void XclExpChTr0x0197::SaveCont( XclExpStream& rStrm )
247 rStrm << sal_uInt16(0x0000);
250 sal_uInt16 XclExpChTr0x0197::GetNum() const
252 return 0x0197;
255 std::size_t XclExpChTr0x0197::GetLen() const
257 return 2;
260 XclExpChTrEmpty::~XclExpChTrEmpty()
264 sal_uInt16 XclExpChTrEmpty::GetNum() const
266 return nRecNum;
269 std::size_t XclExpChTrEmpty::GetLen() const
271 return 0;
274 XclExpChTr0x0195::~XclExpChTr0x0195()
278 void XclExpChTr0x0195::SaveCont( XclExpStream& rStrm )
280 rStrm.WriteZeroBytes( 162 );
283 sal_uInt16 XclExpChTr0x0195::GetNum() const
285 return 0x0195;
288 std::size_t XclExpChTr0x0195::GetLen() const
290 return 162;
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
307 return 0x0194;
310 std::size_t XclExpChTr0x0194::GetLen() const
312 return 162;
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 );
326 rStrm << nCount
327 << sal_uInt16(0x0001)
328 << sal_uInt32(0x00000000)
329 << sal_uInt16(0x001E);
332 sal_uInt16 XclExpChTrHeader::GetNum() const
334 return 0x0196;
337 std::size_t XclExpChTrHeader::GetLen() const
339 return 50;
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);
413 OUString aRelId;
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"),
420 &aRelId);
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);
429 if (mnMinAction)
430 rStrm.WriteAttributes(XML_minRId, OUString::number(mnMinAction));
432 if (mnMaxAction)
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));
439 pHeader->write(">");
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(">");
473 rStrm.PopStream();
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
517 return 0x0138;
520 std::size_t XclExpChTrInfo::GetLen() const
522 return 158;
525 XclExpChTrTabIdBuffer::XclExpChTrTabIdBuffer( sal_uInt16 nCount ) :
526 nBufSize( nCount ),
527 nLastId( 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++ )
554 if( !*pElem )
555 nFreeCount++;
556 if( nFreeCount > nIndex )
558 *pElem = nLastId--;
559 return;
564 void XclExpChTrTabIdBuffer::InitFillup()
566 sal_uInt16 nFreeCount = 1;
567 for( sal_uInt16* pElem = pBuffer.get(); pElem <= pLast; pElem++ )
568 if( !*pElem )
569 *pElem = nFreeCount++;
570 nLastId = nBufSize;
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) )
584 pElem++;
585 while( pElem < pLast )
587 *pElem = *(pElem + 1);
588 pElem++;
590 pLast--;
591 nLastId--;
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()
603 Clear();
606 void XclExpChTrTabId::Copy( const XclExpChTrTabIdBuffer& rBuffer )
608 Clear();
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();
617 if( pBuffer )
618 rStrm.Write(pBuffer.get(), nTabCount);
619 else
620 for( sal_uInt16 nIndex = 1; nIndex <= nTabCount; nIndex++ )
621 rStrm << nIndex;
624 sal_uInt16 XclExpChTrTabId::GetNum() const
626 return 0x013D;
629 std::size_t XclExpChTrTabId::GetLen() const
631 return nTabCount << 1;
634 // ! does not copy additional actions
635 XclExpChTrAction::XclExpChTrAction( const XclExpChTrAction& rCopy ) :
636 ExcRecord( rCopy ),
637 sUsername( rCopy.sUsername ),
638 aDateTime( rCopy.aDateTime ),
639 nIndex( 0 ),
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() ),
656 nIndex( 0 ),
657 bAccepted( rAction.IsAccepted() ),
658 rTabInfo( rRoot.GetTabInfo() ),
659 rIdBuffer( rTabIdBuffer ),
660 nLength( 0 ),
661 nOpCode( nNewOpCode ),
662 bForceInfo( false )
664 aDateTime.SetSec( 0 );
665 aDateTime.SetNanoSec( 0 );
668 XclExpChTrAction::~XclExpChTrAction()
672 void XclExpChTrAction::SetAddAction( XclExpChTrAction* pAction )
674 if( pAddAction )
675 pAddAction->SetAddAction( pAction );
676 else
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 )
696 nIndex = rIndex++;
699 void XclExpChTrAction::SaveCont( XclExpStream& rStrm )
701 OSL_ENSURE( nOpCode != EXC_CHTR_OP_UNKNOWN, "XclExpChTrAction::SaveCont - unknown action" );
702 rStrm << nLength
703 << nIndex
704 << nOpCode
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 );
721 if( pAddAction )
722 pAddAction->Save( rStrm );
723 CompleteSaveAction( rStrm );
726 std::size_t XclExpChTrAction::GetLen() const
728 return GetHeaderByteCount() + GetActionByteCount();
731 XclExpChTrData::XclExpChTrData() :
732 mpFormulaCell( nullptr ),
733 fValue( 0.0 ),
734 nRKValue( 0 ),
735 nType( EXC_CHTR_TYPE_EMPTY ),
736 nSize( 0 )
740 XclExpChTrData::~XclExpChTrData()
742 Clear();
745 void XclExpChTrData::Clear()
747 pString.reset();
748 mpFormulaCell = nullptr;
749 mxTokArr.reset();
750 maRefLog.clear();
751 fValue = 0.0;
752 nRKValue = 0;
753 nType = EXC_CHTR_TYPE_EMPTY;
754 nSize = 0;
757 void XclExpChTrData::WriteFormula( XclExpStream& rStrm, const XclExpChTrTabIdBuffer& rTabIdBuffer )
759 OSL_ENSURE( mxTokArr && !mxTokArr->Empty(), "XclExpChTrData::Write - no formula" );
760 rStrm << *mxTokArr;
762 for( const auto& rLogEntry : maRefLog )
764 if( rLogEntry.mpUrl && rLogEntry.mpFirstTab )
766 rStrm << *rLogEntry.mpUrl << sal_uInt8(0x01) << *rLogEntry.mpFirstTab << sal_uInt8(0x02);
768 else
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 );
774 if( bSingleTab )
775 rStrm << sal_uInt8(0x02);
776 else
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 )
786 switch( nType )
788 case EXC_CHTR_TYPE_RK:
789 rStrm << nRKValue;
790 break;
791 case EXC_CHTR_TYPE_DOUBLE:
792 rStrm << fValue;
793 break;
794 case EXC_CHTR_TYPE_STRING:
795 OSL_ENSURE( pString, "XclExpChTrData::Write - no string" );
796 rStrm << *pString;
797 break;
798 case EXC_CHTR_TYPE_FORMULA:
799 WriteFormula( rStrm, rTabIdBuffer );
800 break;
804 XclExpChTrCellContent::XclExpChTrCellContent(
805 const ScChangeActionContent& rAction,
806 const XclExpRoot& rRoot,
807 const XclExpChTrTabIdBuffer& rTabIdBuffer ) :
808 XclExpChTrAction( rAction, rRoot, rTabIdBuffer, EXC_CHTR_OP_CELL ),
809 XclExpRoot( rRoot ),
810 aPosition( rAction.GetBigRange().MakeRange( rRoot.GetDoc()).aStart )
812 sal_uInt32 nDummy32;
813 sal_uInt16 nDummy16;
814 GetCellData( rRoot, rAction.GetOldCell(), pOldData, nDummy32, nOldLength );
815 GetCellData( rRoot, rAction.GetNewCell(), pNewData, nLength, nDummy16 );
818 XclExpChTrCellContent::~XclExpChTrCellContent()
820 pOldData.reset();
821 pNewData.reset();
824 void XclExpChTrCellContent::MakeEmptyChTrData( std::unique_ptr<XclExpChTrData>& rpData )
826 if( rpData )
827 rpData->Clear();
828 else
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())
842 rpData.reset();
843 return;
846 switch (rScCell.meType)
848 case CELLTYPE_VALUE:
850 rpData->fValue = rScCell.mfValue;
851 if( XclTools::GetRKFromDouble( rpData->nRKValue, rpData->fValue ) )
853 rpData->nType = EXC_CHTR_TYPE_RK;
854 rpData->nSize = 4;
855 rXclLength1 = 0x0000003E;
856 rXclLength2 = 0x0004;
858 else
860 rpData->nType = EXC_CHTR_TYPE_DOUBLE;
861 rpData->nSize = 8;
862 rXclLength1 = 0x00000042;
863 rXclLength2 = 0x0008;
866 break;
867 case CELLTYPE_STRING:
868 case CELLTYPE_EDIT:
870 OUString sCellStr;
871 if (rScCell.meType == CELLTYPE_STRING)
873 sCellStr = rScCell.mpString->getString();
874 rpData->mpFormattedString = XclExpStringHelper::CreateCellString(
875 rRoot, sCellStr, nullptr);
877 else
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);
886 else
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);
898 break;
899 case CELLTYPE_FORMULA:
901 const ScFormulaCell* pFmlCell = rScCell.mpFormula;
902 rpData->mpFormulaCell = pFmlCell;
904 const ScTokenArray* pTokenArray = pFmlCell->GetCode();
905 if( pTokenArray )
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;
916 else
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;
924 break;
925 default:;
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 );
935 rStrm << nOldLength
936 << sal_uInt32(0x00000000);
937 if( pOldData )
938 pOldData->Write( rStrm, rIdBuffer );
939 if( pNewData )
940 pNewData->Write( rStrm, rIdBuffer );
943 sal_uInt16 XclExpChTrCellContent::GetNum() const
945 return 0x013B;
948 std::size_t XclExpChTrCellContent::GetActionByteCount() const
950 std::size_t nLen = 16;
951 if( pOldData )
952 nLen += pOldData->nSize;
953 if( pNewData )
954 nLen += pNewData->nSize;
955 return nLen;
958 static const char* lcl_GetType( XclExpChTrData* pData )
960 switch( pData->nType )
962 case EXC_CHTR_TYPE_RK:
963 case EXC_CHTR_TYPE_DOUBLE:
964 return "n";
965 case EXC_CHTR_TYPE_FORMULA:
967 ScFormulaCell* pFormulaCell = const_cast< ScFormulaCell* >( pData->mpFormulaCell );
968 const char* sType;
969 OUString sValue;
970 XclXmlUtils::GetFormulaTypeAndValue( *pFormulaCell, sType, sValue );
971 return sType;
973 break;
974 case EXC_CHTR_TYPE_STRING:
975 return "inlineStr";
976 default:
977 break;
979 return "*unknown*";
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 );
1000 break;
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 );
1009 break;
1010 case EXC_CHTR_TYPE_STRING:
1011 pStream->startElement(XML_is);
1012 if( pData->mpFormattedString )
1013 pData->mpFormattedString->WriteXml( rStrm );
1014 else
1015 pData->pString->WriteXml( rStrm );
1016 pStream->endElement( XML_is );
1017 break;
1018 default:
1019 // ignore
1020 break;
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
1043 if( pOldData )
1045 lcl_WriteCell( rRevisionLogStrm, XML_oc, aPosition, pOldData.get() );
1046 if (!pNewData)
1048 pStream->singleElement(XML_nc, XML_r, XclXmlUtils::ToOString(rRevisionLogStrm.GetRoot().GetDoc(), aPosition));
1051 if( pNewData )
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 ),
1070 mbEndOfList(false),
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;
1083 break;
1084 case SC_CAT_DELETE_COLS: nOpCode = EXC_CHTR_OP_DELCOL; break;
1085 case SC_CAT_DELETE_ROWS: nOpCode = EXC_CHTR_OP_DELROW; break;
1086 default:
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() );
1095 else
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;
1116 rStrm << nFlagVal;
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
1135 return 0x0137;
1138 std::size_t XclExpChTrInsert::GetActionByteCount() const
1140 return 16;
1143 static const char* lcl_GetAction( sal_uInt16 nOpCode )
1145 switch( 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;
1187 bForceInfo = true;
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
1205 return 0x014D;
1208 std::size_t XclExpChTrInsertTab::GetActionByteCount() const
1210 return 276;
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
1271 return 0x0140;
1274 std::size_t XclExpChTrMoveRange::GetActionByteCount() const
1276 return 24;
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
1322 return 0x014A;
1325 std::size_t XclExpChTr0x014A::GetActionByteCount() const
1327 return 14;
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
1348 return 0;
1351 sal_uInt16 ExcXmlRecord::GetNum() const
1353 return 0;
1356 void ExcXmlRecord::Save( XclExpStream& )
1358 // Do nothing; ignored for BIFF output.
1361 namespace {
1363 class EndXmlElement : public ExcXmlRecord
1365 sal_Int32 mnElement;
1366 public:
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 )
1385 return;
1387 ScChangeTrack* pTempChangeTrack = CreateTempChangeTrack();
1388 if (!pTempChangeTrack)
1389 return;
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();
1409 while( pScAction )
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();
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 nLogNumber++;
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) );
1456 else
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();
1472 aActionStack.pop();
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));
1484 nLogNumber++;
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();
1501 aActionStack.pop();
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 )
1511 return nullptr;
1513 assert(!xTempDoc);
1514 // create empty document
1515 xTempDoc.reset(new ScDocument);
1517 // adjust table count
1518 SCTAB nOrigCount = GetDoc().GetTableCount();
1519 OUString sTabName;
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())
1528 return nullptr;
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 );
1541 break;
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 );
1548 break;
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;
1557 break;
1558 case SC_CAT_MOVE:
1559 if (pTempChangeTrack)
1560 pXclAction = new XclExpChTrMoveRange( static_cast<const ScChangeActionMove&>(rAction), GetRoot(), *pTabIdBuffer, *pTempChangeTrack );
1561 break;
1562 default:;
1564 if( pXclAction )
1565 aActionStack.push( pXclAction );
1568 bool XclExpChangeTrack::WriteUserNamesStream()
1570 bool bRet = false;
1571 tools::SvRef<SotStorageStream> xSvStrm = OpenStream( EXC_STREAM_USERNAMES );
1572 OSL_ENSURE( xSvStrm.is(), "XclExpChangeTrack::WriteUserNamesStream - no stream" );
1573 if( xSvStrm.is() )
1575 XclExpStream aXclStrm( *xSvStrm, GetRoot() );
1576 XclExpChTr0x0191().Save( aXclStrm );
1577 XclExpChTr0x0198().Save( aXclStrm );
1578 XclExpChTr0x0192().Save( aXclStrm );
1579 XclExpChTr0x0197().Save( aXclStrm );
1580 xSvStrm->Commit();
1581 bRet = true;
1583 return bRet;
1586 void XclExpChangeTrack::Write()
1588 if (maRecList.empty())
1589 return;
1591 if( !WriteUserNamesStream() )
1592 return;
1594 tools::SvRef<SotStorageStream> xSvStrm = OpenStream( EXC_STREAM_REVLOG );
1595 OSL_ENSURE( xSvStrm.is(), "XclExpChangeTrack::Write - no stream" );
1596 if( xSvStrm.is() )
1598 XclExpStream aXclStrm( *xSvStrm, GetRoot(), EXC_MAXRECSIZE_BIFF8 + 8 );
1600 for(const auto& rxRec : maRecList)
1601 rxRec->Save(aXclStrm);
1603 xSvStrm->Commit();
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(),
1618 XML_count, "0" );
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())
1628 return;
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: */