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_scfilt.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