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