xref: /AOO41X/main/sc/source/filter/xcl97/XclImpChangeTrack.cxx (revision b3f79822e811ac3493b185030a72c3c5a51f32d8)
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