1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 #include "XclImpChangeTrack.hxx"
28 #include <tools/debug.hxx>
29 #include <sot/storage.hxx>
30 #include <svl/zforlist.hxx>
31 #include "chgviset.hxx"
32 #include "cell.hxx"
33 #include "chgtrack.hxx"
34 #include "xihelper.hxx"
35 #include "xilink.hxx"
36 #include "externalrefmgr.hxx"
37 
38 //___________________________________________________________________
39 // class XclImpChangeTrack
40 
XclImpChangeTrack(const XclImpRoot & rRoot,const XclImpStream & rBookStrm)41 XclImpChangeTrack::XclImpChangeTrack( const XclImpRoot& rRoot, const XclImpStream& rBookStrm ) :
42     XclImpRoot( rRoot ),
43 	aRecHeader(),
44 	sOldUsername(),
45 	pChangeTrack( NULL ),
46 	pStrm( NULL ),
47 	nTabIdCount( 0 ),
48 	bGlobExit( sal_False ),
49 	eNestedMode( nmBase )
50 {
51 	// Verify that the User Names stream exists before going any further. Excel adds both
52 	// "Revision Log" and "User Names" streams when Change Tracking is active but the Revision log
53 	// remains if Change Tracking is turned off.
54     SotStorageStreamRef xUserStrm = OpenStream( EXC_STREAM_USERNAMES );
55     if( !xUserStrm.Is() )
56 		return;
57 
58     xInStrm = OpenStream( EXC_STREAM_REVLOG );
59     if( xInStrm.Is() )
60 	{
61         xInStrm->Seek( STREAM_SEEK_TO_END );
62         sal_uLong nStreamLen = xInStrm->Tell();
63         if( (xInStrm->GetErrorCode() == ERRCODE_NONE) && (nStreamLen != STREAM_SEEK_TO_END) )
64 		{
65             xInStrm->Seek( STREAM_SEEK_TO_BEGIN );
66             pStrm = new XclImpStream( *xInStrm, GetRoot() );
67             pStrm->CopyDecrypterFrom( rBookStrm );
68             pChangeTrack = new ScChangeTrack( GetDocPtr() );
69 
70             sOldUsername = pChangeTrack->GetUser();
71             pChangeTrack->SetUseFixDateTime( sal_True );
72 
73             ReadRecords();
74 		}
75 	}
76 }
77 
~XclImpChangeTrack()78 XclImpChangeTrack::~XclImpChangeTrack()
79 {
80     delete pChangeTrack;
81     delete pStrm;
82 }
83 
DoAcceptRejectAction(ScChangeAction * pAction)84 void XclImpChangeTrack::DoAcceptRejectAction( ScChangeAction* pAction )
85 {
86 	if( !pAction ) return;
87 	switch( aRecHeader.nAccept )
88 	{
89 		case EXC_CHTR_ACCEPT:
90 			pChangeTrack->Accept( pAction );
91 		break;
92 		case EXC_CHTR_REJECT:
93 		break;
94 	}
95 }
96 
DoAcceptRejectAction(sal_uInt32 nFirst,sal_uInt32 nLast)97 void XclImpChangeTrack::DoAcceptRejectAction( sal_uInt32 nFirst, sal_uInt32 nLast )
98 {
99 	for( sal_uInt32 nIndex = nFirst; nIndex <= nLast; nIndex++ )
100 		DoAcceptRejectAction( pChangeTrack->GetAction( nIndex ) );
101 }
102 
DoInsertRange(const ScRange & rRange)103 void XclImpChangeTrack::DoInsertRange( const ScRange& rRange )
104 {
105 	sal_uInt32 nFirst = pChangeTrack->GetActionMax() + 1;
106 	pChangeTrack->AppendInsert( rRange );
107 	sal_uInt32 nLast = pChangeTrack->GetActionMax();
108 	DoAcceptRejectAction( nFirst, nLast );
109 }
110 
DoDeleteRange(const ScRange & rRange)111 void XclImpChangeTrack::DoDeleteRange( const ScRange& rRange )
112 {
113 	sal_uLong nFirst, nLast;
114 	pChangeTrack->AppendDeleteRange( rRange, NULL, nFirst, nLast );
115 	DoAcceptRejectAction( nFirst, nLast );
116 }
117 
ReadTabNum()118 SCTAB XclImpChangeTrack::ReadTabNum()
119 {
120     return static_cast<SCTAB>(GetTabInfo().GetCurrentIndex(
121                 pStrm->ReaduInt16(), nTabIdCount ));
122 }
123 
ReadDateTime(DateTime & rDateTime)124 void XclImpChangeTrack::ReadDateTime( DateTime& rDateTime )
125 {
126 	sal_uInt16 nYear;
127 	sal_uInt8 nMonth, nDay, nHour, nMin, nSec;
128 
129 	*pStrm >> nYear >> nMonth >> nDay >> nHour >> nMin >> nSec;
130 
131 	rDateTime.SetYear( nYear );
132 	rDateTime.SetMonth( nMonth );
133 	rDateTime.SetDay( nDay );
134 	rDateTime.SetHour( nHour );
135 	rDateTime.SetMin( nMin );
136 	rDateTime.SetSec( nSec );
137 	rDateTime.Set100Sec( 0 );
138 }
139 
CheckRecord(sal_uInt16 nOpCode)140 sal_Bool XclImpChangeTrack::CheckRecord( sal_uInt16 nOpCode )
141 {
142 	if( (nOpCode != EXC_CHTR_OP_UNKNOWN) && (aRecHeader.nOpCode != nOpCode) )
143 	{
144 		DBG_ERROR( "XclImpChangeTrack::CheckRecord - unknown action" );
145 		return sal_False;
146 	}
147 	return aRecHeader.nIndex != 0;
148 }
149 
Read3DTabRefInfo(SCTAB & rFirstTab,SCTAB & rLastTab,ExcelToSc8::ExternalTabInfo & rExtInfo)150 sal_Bool XclImpChangeTrack::Read3DTabRefInfo( SCTAB& rFirstTab, SCTAB& rLastTab, ExcelToSc8::ExternalTabInfo& rExtInfo )
151 {
152 	if( LookAtuInt8() == 0x01 )
153 	{
154         rExtInfo.mbExternal = false;
155 		// internal ref - read tab num and return sc tab num (position in TABID list)
156         pStrm->Ignore( 3 );
157         rFirstTab = static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) );
158 		sal_uInt8 nFillByte = pStrm->ReaduInt8();
159 		rLastTab = (nFillByte == 0x00) ?
160             static_cast< SCTAB >( GetTabInfo().GetCurrentIndex( pStrm->ReaduInt16(), nTabIdCount ) ) : rFirstTab;
161 	}
162 	else
163 	{
164 		// external ref - read doc and tab name and find sc tab num
165         // - URL
166         String aEncUrl( pStrm->ReadUniString() );
167         String aUrl;
168         bool bSelf;
169         XclImpUrlHelper::DecodeUrl( aUrl, bSelf, GetRoot(), aEncUrl );
170         pStrm->Ignore( 1 );
171         // - sheet name, always separated from URL
172         String aTabName( pStrm->ReadUniString() );
173         pStrm->Ignore( 1 );
174 
175         rExtInfo.mbExternal = true;
176         ScExternalRefManager* pRefMgr = GetDoc().GetExternalRefManager();
177         pRefMgr->convertToAbsName(aUrl);
178         rExtInfo.mnFileId = pRefMgr->getExternalFileId(aUrl);
179         rExtInfo.maTabName = aTabName;
180         rFirstTab = rLastTab = 0;
181 	}
182 	return sal_True;
183 }
184 
ReadFormula(ScTokenArray * & rpTokenArray,const ScAddress & rPosition)185 void XclImpChangeTrack::ReadFormula( ScTokenArray*& rpTokenArray, const ScAddress& rPosition )
186 {
187 	sal_uInt16 nFmlSize;
188 	*pStrm >> nFmlSize;
189 
190 	// create a memory stream and copy the formula to be able to read simultaneously
191 	// the formula and the additional 3D tab ref data following the formula
192 	// here we have to simulate an Excel record to be able to use an XclImpStream...
193 	// 2do: remove the stream member from formula converter and add it as a parameter
194 	// to the Convert() routine (to prevent the construction/destruction of the
195 	// converter in each formula)
196 	SvMemoryStream aMemStrm;
197 	aMemStrm << (sal_uInt16) 0x0001 << nFmlSize;
198     pStrm->CopyToStream( aMemStrm, nFmlSize );
199     XclImpStream aFmlaStrm( aMemStrm, GetRoot() );
200 	aFmlaStrm.StartNextRecord();
201     XclImpChTrFmlConverter aFmlConv( GetRoot(), *this );
202 
203 	// read the formula, 3D tab refs from extended data
204 	const ScTokenArray* pArray = NULL;
205 	aFmlConv.Reset( rPosition );
206     sal_Bool bOK = (aFmlConv.Convert( pArray, aFmlaStrm, nFmlSize, false, FT_CellFormula) == ConvOK);	// JEG : Check This
207 	rpTokenArray = (bOK && pArray) ? new ScTokenArray( *pArray ) : NULL;
208     pStrm->Ignore( 1 );
209 }
210 
ReadCell(ScBaseCell * & rpCell,sal_uInt32 & rFormat,sal_uInt16 nFlags,const ScAddress & rPosition)211 void XclImpChangeTrack::ReadCell(
212 		ScBaseCell*& rpCell,
213 		sal_uInt32& rFormat,
214 		sal_uInt16 nFlags,
215 		const ScAddress& rPosition )
216 {
217 	rpCell = NULL;
218 	rFormat = 0;
219 	switch( nFlags & EXC_CHTR_TYPE_MASK )
220 	{
221 		case EXC_CHTR_TYPE_EMPTY:
222 		break;
223 		case EXC_CHTR_TYPE_RK:
224 		{
225 			double fValue = ReadRK();
226 			if( pStrm->IsValid() )
227 				rpCell = new ScValueCell( fValue );
228 		}
229 		break;
230 		case EXC_CHTR_TYPE_DOUBLE:
231 		{
232 			double fValue;
233 			*pStrm >> fValue;
234 			if( pStrm->IsValid() )
235 				rpCell = new ScValueCell( fValue );
236 		}
237 		break;
238 		case EXC_CHTR_TYPE_STRING:
239 		{
240             String sString( pStrm->ReadUniString() );
241 			if( pStrm->IsValid() )
242 				rpCell = new ScStringCell( sString );
243 		}
244 		break;
245 		case EXC_CHTR_TYPE_BOOL:
246 		{
247 			double fValue = (double) ReadBool();
248 			if( pStrm->IsValid() )
249 			{
250 				rpCell = new ScValueCell( fValue );
251                 rFormat = GetFormatter().GetStandardFormat( NUMBERFORMAT_LOGICAL, ScGlobal::eLnge );
252 			}
253 		}
254 		break;
255 		case EXC_CHTR_TYPE_FORMULA:
256 		{
257 			ScTokenArray* pTokenArray = NULL;
258 			ReadFormula( pTokenArray, rPosition );
259 			if( pStrm->IsValid() && pTokenArray )
260                 rpCell = new ScFormulaCell( GetDocPtr(), rPosition, pTokenArray );
261 		}
262 		break;
263 		default:
264 			DBG_ERROR( "XclImpChangeTrack::ReadCell - unknown data type" );
265 	}
266 }
267 
ReadChTrInsert()268 void XclImpChangeTrack::ReadChTrInsert()
269 {
270 	*pStrm >> aRecHeader;
271 	if( CheckRecord( EXC_CHTR_OP_UNKNOWN ) )
272 	{
273         if( (aRecHeader.nOpCode != EXC_CHTR_OP_INSROW) &&
274             (aRecHeader.nOpCode != EXC_CHTR_OP_INSCOL) &&
275             (aRecHeader.nOpCode != EXC_CHTR_OP_DELROW) &&
276             (aRecHeader.nOpCode != EXC_CHTR_OP_DELCOL) )
277 		{
278 			DBG_ERROR( "XclImpChangeTrack::ReadChTrInsert - unknown action" );
279 			return;
280 		}
281 
282 		ScRange aRange;
283 		aRange.aStart.SetTab( ReadTabNum() );
284 		aRange.aEnd.SetTab( aRange.aStart.Tab() );
285         pStrm->Ignore( 2 );
286 		Read2DRange( aRange );
287 
288 		if( aRecHeader.nOpCode & EXC_CHTR_OP_COLFLAG )
289 			aRange.aEnd.SetRow( MAXROW );
290 		else
291 			aRange.aEnd.SetCol( MAXCOL );
292 
293 		sal_Bool bValid = pStrm->IsValid();
294 		if( FoundNestedMode() )
295 			ReadNestedRecords();
296 
297 		if( bValid )
298 		{
299 			if( aRecHeader.nOpCode & EXC_CHTR_OP_DELFLAG )
300 				DoDeleteRange( aRange );
301 			else
302 				DoInsertRange( aRange );
303 		}
304 	}
305 }
306 
ReadChTrInfo()307 void XclImpChangeTrack::ReadChTrInfo()
308 {
309     pStrm->DisableDecryption();
310     pStrm->Ignore( 32 );
311     String sUsername( pStrm->ReadUniString() );
312 	if( !pStrm->IsValid() ) return;
313 
314 	if( sUsername.Len() )
315 		pChangeTrack->SetUser( sUsername );
316     pStrm->Seek( 148 );
317 	if( !pStrm->IsValid() ) return;
318 
319 	DateTime aDateTime;
320 	ReadDateTime( aDateTime );
321 	if( pStrm->IsValid() )
322 		pChangeTrack->SetFixDateTimeLocal( aDateTime );
323 }
324 
ReadChTrCellContent()325 void XclImpChangeTrack::ReadChTrCellContent()
326 {
327 	*pStrm >> aRecHeader;
328 	if( CheckRecord( EXC_CHTR_OP_CELL ) )
329 	{
330 		ScAddress aPosition;
331 		SCTAB nTab = ReadTabNum();
332 		aPosition.SetTab( nTab );
333 		sal_uInt16 nValueType;
334 		*pStrm >> nValueType;
335 		sal_uInt16 nOldValueType = (nValueType >> 3) & EXC_CHTR_TYPE_MASK;
336 		sal_uInt16 nNewValueType = nValueType & EXC_CHTR_TYPE_MASK;
337         pStrm->Ignore( 2 );
338 		Read2DAddress( aPosition );
339 		sal_uInt16 nOldSize;
340 		*pStrm >> nOldSize;
341 		DBG_ASSERT( (nOldSize == 0) == (nOldValueType == EXC_CHTR_TYPE_EMPTY),
342 			"XclImpChangeTrack::ReadChTrCellContent - old value mismatch" );
343         pStrm->Ignore( 4 );
344 		switch( nValueType & EXC_CHTR_TYPE_FORMATMASK )
345 		{
346 			case 0x0000:							break;
347             case 0x1100:    pStrm->Ignore( 16 );    break;
348             case 0x1300:    pStrm->Ignore( 8 );     break;
349 			default:		DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - unknown format info" );
350 		}
351 
352 		ScBaseCell* pOldCell;
353 		ScBaseCell* pNewCell;
354 		sal_uInt32 nOldFormat;
355 		sal_uInt32 nNewFormat;
356 		ReadCell( pOldCell, nOldFormat, nOldValueType, aPosition );
357 		ReadCell( pNewCell, nNewFormat, nNewValueType, aPosition );
358         if( !pStrm->IsValid() || (pStrm->GetRecLeft() > 0) )
359 		{
360 			DBG_ERROR( "XclImpChangeTrack::ReadChTrCellContent - bytes left, action ignored" );
361 			if( pOldCell )
362 				pOldCell->Delete();
363 			if( pNewCell )
364 				pNewCell->Delete();
365 		}
366 		else
367 		{
368 			ScChangeActionContent* pNewAction =
369 				pChangeTrack->AppendContentOnTheFly( aPosition, pOldCell, pNewCell, nOldFormat, nNewFormat );
370 			DoAcceptRejectAction( pNewAction );
371 		}
372 	}
373 }
374 
ReadChTrTabId()375 void XclImpChangeTrack::ReadChTrTabId()
376 {
377     if( nTabIdCount == 0 )  // read only 1st time, otherwise calculated by <ReadChTrInsertTab()>
378         nTabIdCount = static_cast< sal_uInt16 >( pStrm->GetRecLeft() >> 1 );
379 }
380 
ReadChTrMoveRange()381 void XclImpChangeTrack::ReadChTrMoveRange()
382 {
383 	*pStrm >> aRecHeader;
384 	if( CheckRecord( EXC_CHTR_OP_MOVE ) )
385 	{
386 		ScRange aSourceRange;
387 		ScRange aDestRange;
388 		aDestRange.aStart.SetTab( ReadTabNum() );
389 		aDestRange.aEnd.SetTab( aDestRange.aStart.Tab() );
390 		Read2DRange( aSourceRange );
391 		Read2DRange( aDestRange );
392 		aSourceRange.aStart.SetTab( ReadTabNum() );
393 		aSourceRange.aEnd.SetTab( aSourceRange.aStart.Tab() );
394 
395 		sal_Bool bValid = pStrm->IsValid();
396 		if( FoundNestedMode() )
397 			ReadNestedRecords();
398 
399 		if( bValid )
400 		{
401 			pChangeTrack->AppendMove( aSourceRange, aDestRange, NULL );
402 			DoAcceptRejectAction( pChangeTrack->GetLast() );
403 		}
404 	}
405 }
406 
ReadChTrInsertTab()407 void XclImpChangeTrack::ReadChTrInsertTab()
408 {
409 	*pStrm >> aRecHeader;
410 	if( CheckRecord( EXC_CHTR_OP_INSTAB ) )
411 	{
412 		SCTAB nTab = ReadTabNum();
413 		if( pStrm->IsValid() )
414 		{
415 			nTabIdCount++;
416 			DoInsertRange( ScRange( 0, 0, nTab, MAXCOL, MAXROW, nTab ) );
417 		}
418 	}
419 }
420 
InitNestedMode()421 void XclImpChangeTrack::InitNestedMode()
422 {
423 	DBG_ASSERT( eNestedMode == nmBase, "XclImpChangeTrack::InitNestedMode - unexpected nested mode" );
424 	if( eNestedMode == nmBase )
425 		eNestedMode = nmFound;
426 }
427 
ReadNestedRecords()428 void XclImpChangeTrack::ReadNestedRecords()
429 {
430 	DBG_ASSERT( eNestedMode == nmFound, "XclImpChangeTrack::StartNestedMode - missing nested mode" );
431 	if( eNestedMode == nmFound )
432 	{
433 		eNestedMode = nmNested;
434 		ReadRecords();
435 	}
436 }
437 
EndNestedMode()438 sal_Bool XclImpChangeTrack::EndNestedMode()
439 {
440 	DBG_ASSERT( eNestedMode != nmBase, "XclImpChangeTrack::EndNestedMode - missing nested mode" );
441 	sal_Bool bReturn = (eNestedMode == nmNested);
442 	eNestedMode = nmBase;
443 	return bReturn;
444 }
445 
ReadRecords()446 void XclImpChangeTrack::ReadRecords()
447 {
448 	sal_Bool bExitLoop = sal_False;
449 
450 	while( !bExitLoop && !bGlobExit && pStrm->StartNextRecord() )
451 	{
452         switch( pStrm->GetRecId() )
453 		{
454 			case 0x000A:	bGlobExit = sal_True;			break;
455 			case 0x0137:	ReadChTrInsert();				break;
456 			case 0x0138:	ReadChTrInfo();					break;
457 			case 0x013B:	ReadChTrCellContent();			break;
458 			case 0x013D:	ReadChTrTabId();				break;
459 			case 0x0140:	ReadChTrMoveRange();			break;
460 			case 0x014D:	ReadChTrInsertTab();			break;
461 			case 0x014E:
462 			case 0x0150:	InitNestedMode();				break;
463 			case 0x014F:
464 			case 0x0151:	bExitLoop = EndNestedMode();	break;
465 		}
466 	}
467 }
468 
Apply()469 void XclImpChangeTrack::Apply()
470 {
471     if( pChangeTrack )
472 	{
473 		pChangeTrack->SetUser( sOldUsername );
474 		pChangeTrack->SetUseFixDateTime( sal_False );
475 
476         GetDoc().SetChangeTrack( pChangeTrack );
477 		pChangeTrack = NULL;
478 
479 		ScChangeViewSettings aSettings;
480 		aSettings.SetShowChanges( sal_True );
481         GetDoc().SetChangeViewSettings( aSettings );
482 	}
483 }
484 
485 //___________________________________________________________________
486 // class XclImpChTrFmlConverter
487 
~XclImpChTrFmlConverter()488 XclImpChTrFmlConverter::~XclImpChTrFmlConverter()
489 {
490 }
491 
492 // virtual, called from ExcToSc8::Convert()
Read3DTabReference(sal_uInt16,SCTAB & rFirstTab,SCTAB & rLastTab,ExternalTabInfo & rExtInfo)493 bool XclImpChTrFmlConverter::Read3DTabReference( sal_uInt16 /*nIxti*/, SCTAB& rFirstTab, SCTAB& rLastTab,
494 												 ExternalTabInfo& rExtInfo )
495 {
496 	return rChangeTrack.Read3DTabRefInfo( rFirstTab, rLastTab, rExtInfo );
497 }
498 
499