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 #include "xicontent.hxx"
27 #include <sfx2/objsh.hxx>
28 #include <sfx2/docfile.hxx>
29 #include <tools/urlobj.hxx>
30 #include <editeng/editeng.hxx>
31 #include <editeng/editobj.hxx>
32 #include <sfx2/linkmgr.hxx>
33 #include <svl/itemset.hxx>
34 #include "scitems.hxx"
35 #include <editeng/eeitem.hxx>
36 #include <svl/intitem.hxx>
37 #include <svl/stritem.hxx>
38 #include <editeng/flditem.hxx>
39 #include <editeng/fhgtitem.hxx>
40 #include <editeng/wghtitem.hxx>
41 #include <editeng/udlnitem.hxx>
42 #include <editeng/postitem.hxx>
43 #include <editeng/colritem.hxx>
44 #include <editeng/crsditem.hxx>
45 #include "document.hxx"
46 #include "editutil.hxx"
47 #include "cell.hxx"
48 #include "validat.hxx"
49 #include "patattr.hxx"
50 #include "docpool.hxx"
51 #include "rangenam.hxx"
52 #include "arealink.hxx"
53 #include "stlsheet.hxx"
54 #include "scextopt.hxx"
55 #include "xlformula.hxx"
56 #include "xltracer.hxx"
57 #include "xistream.hxx"
58 #include "xihelper.hxx"
59 #include "xistyle.hxx"
60 #include "xiescher.hxx"
61 #include "xiname.hxx"
62 
63 #include "excform.hxx"
64 #include "tabprotection.hxx"
65 
66 #include <memory>
67 
68 using ::com::sun::star::uno::Sequence;
69 using ::std::auto_ptr;
70 
71 // Shared string table ========================================================
72 
XclImpSst(const XclImpRoot & rRoot)73 XclImpSst::XclImpSst( const XclImpRoot& rRoot ) :
74     XclImpRoot( rRoot )
75 {
76 }
77 
ReadSst(XclImpStream & rStrm)78 void XclImpSst::ReadSst( XclImpStream& rStrm )
79 {
80     sal_uInt32 nStrCount;
81     rStrm.Ignore( 4 );
82     rStrm >> nStrCount;
83     maStrings.clear();
84     maStrings.reserve( static_cast< size_t >( nStrCount ) );
85     while( (nStrCount > 0) && rStrm.IsValid() )
86     {
87         XclImpString aString;
88         aString.Read( rStrm );
89         maStrings.push_back( aString );
90         --nStrCount;
91     }
92 }
93 
GetString(sal_uInt32 nSstIndex) const94 const XclImpString* XclImpSst::GetString( sal_uInt32 nSstIndex ) const
95 {
96     return (nSstIndex < maStrings.size()) ? &maStrings[ nSstIndex ] : 0;
97 }
98 
CreateCell(sal_uInt32 nSstIndex,sal_uInt16 nXFIndex) const99 ScBaseCell* XclImpSst::CreateCell( sal_uInt32 nSstIndex, sal_uInt16 nXFIndex ) const
100 {
101     ScBaseCell* pCell = 0;
102     if( const XclImpString* pString = GetString( nSstIndex ) )
103         pCell = XclImpStringHelper::CreateCell( *this, *pString, nXFIndex );
104     return pCell;
105 }
106 
107 // Hyperlinks =================================================================
108 
109 namespace {
110 
111 /** Reads character array and stores it into rString.
112     @param nChars  Number of following characters (not byte count!).
113     @param b16Bit  true = 16-bit characters, false = 8-bit characters. */
lclAppendString32(String & rString,XclImpStream & rStrm,sal_uInt32 nChars,bool b16Bit)114 void lclAppendString32( String& rString, XclImpStream& rStrm, sal_uInt32 nChars, bool b16Bit )
115 {
116     sal_uInt16 nReadChars = ulimit_cast< sal_uInt16 >( nChars );
117     rString.Append( rStrm.ReadRawUniString( nReadChars, b16Bit ) );
118     // ignore remaining chars
119     sal_Size nIgnore = nChars - nReadChars;
120     if( b16Bit )
121         nIgnore *= 2;
122     rStrm.Ignore( nIgnore );
123 }
124 
125 /** Reads 32-bit string length and the character array and stores it into rString.
126     @param b16Bit  true = 16-bit characters, false = 8-bit characters. */
lclAppendString32(String & rString,XclImpStream & rStrm,bool b16Bit)127 void lclAppendString32( String& rString, XclImpStream& rStrm, bool b16Bit )
128 {
129     lclAppendString32( rString, rStrm, rStrm.ReaduInt32(), b16Bit );
130 }
131 
132 /** Reads 32-bit string length and ignores following character array.
133     @param b16Bit  true = 16-bit characters, false = 8-bit characters. */
lclIgnoreString32(XclImpStream & rStrm,bool b16Bit)134 void lclIgnoreString32( XclImpStream& rStrm, bool b16Bit )
135 {
136     sal_uInt32 nChars;
137     rStrm >> nChars;
138     if( b16Bit )
139         nChars *= 2;
140     rStrm.Ignore( nChars );
141 }
142 
143 /** Converts a path to an absolute path.
144     @param rPath  The source path. The resulting path is returned here.
145     @param nLevel  Number of parent directories to add in front of the path. */
lclGetAbsPath(String & rPath,sal_uInt16 nLevel,SfxObjectShell * pDocShell)146 void lclGetAbsPath( String& rPath, sal_uInt16 nLevel, SfxObjectShell* pDocShell )
147 {
148     String aTmpStr;
149     while( nLevel )
150     {
151         aTmpStr.AppendAscii( "../" );
152         --nLevel;
153     }
154     aTmpStr += rPath;
155 
156     if( pDocShell )
157     {
158         bool bWasAbs = false;
159         rPath = pDocShell->GetMedium()->GetURLObject().smartRel2Abs( aTmpStr, bWasAbs ).GetMainURL( INetURLObject::NO_DECODE );
160         // full path as stored in SvxURLField must be encoded
161     }
162     else
163         rPath = aTmpStr;
164 }
165 
166 /** Inserts the URL into a text cell. Does not modify value or formula cells. */
lclInsertUrl(const XclImpRoot & rRoot,const String & rUrl,SCCOL nScCol,SCROW nScRow,SCTAB nScTab)167 void lclInsertUrl( const XclImpRoot& rRoot, const String& rUrl, SCCOL nScCol, SCROW nScRow, SCTAB nScTab )
168 {
169     ScDocument& rDoc = rRoot.GetDoc();
170     ScAddress aScPos( nScCol, nScRow, nScTab );
171     CellType eCellType = rDoc.GetCellType( aScPos );
172     switch( eCellType )
173     {
174         // #i54261# hyperlinks in string cells
175         case CELLTYPE_STRING:
176         case CELLTYPE_EDIT:
177         {
178             String aDisplText;
179             rDoc.GetString( nScCol, nScRow, nScTab, aDisplText );
180             if( !aDisplText.Len() )
181                 aDisplText = rUrl;
182 
183             ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
184             SvxURLField aUrlField( rUrl, aDisplText, SVXURLFORMAT_APPDEFAULT );
185 
186             const ScEditCell* pEditCell = (eCellType == CELLTYPE_EDIT) ? static_cast< const ScEditCell* >( rDoc.GetCell( aScPos ) ) : 0;
187             const EditTextObject* pEditObj = pEditCell ? pEditCell->GetData() : 0;
188             if( pEditObj )
189             {
190                 rEE.SetText( *pEditObj );
191                 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection( 0, 0, 0xFFFF, 0 ) );
192             }
193             else
194             {
195                 rEE.SetText( EMPTY_STRING );
196                 rEE.QuickInsertField( SvxFieldItem( aUrlField, EE_FEATURE_FIELD ), ESelection() );
197                 if( const ScPatternAttr* pPattern = rDoc.GetPattern( aScPos.Col(), aScPos.Row(), nScTab ) )
198                 {
199                     SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
200                     pPattern->FillEditItemSet( &aItemSet );
201                     rEE.QuickSetAttribs( aItemSet, ESelection( 0, 0, 0xFFFF, 0 ) );
202                 }
203             }
204             ::std::auto_ptr< EditTextObject > xTextObj( rEE.CreateTextObject() );
205 
206             ScEditCell* pCell = new ScEditCell( xTextObj.get(), &rDoc, rEE.GetEditTextObjectPool() );
207             rDoc.PutCell( aScPos, pCell );
208         }
209         break;
210 
211         // fix for #i31050# disabled, HYPERLINK is not able to return numeric value (#i91351#)
212 #if 0
213         case CELLTYPE_VALUE:
214         {
215             // #i31050# replace number with HYPERLINK function
216             ScTokenArray aTokenArray;
217             aTokenArray.AddOpCode( ocHyperLink );
218             aTokenArray.AddOpCode( ocOpen );
219             aTokenArray.AddString( rUrl );
220             aTokenArray.AddOpCode( ocSep );
221             aTokenArray.AddDouble( rDoc.GetValue( aScPos ) );
222             aTokenArray.AddOpCode( ocClose );
223             rDoc.PutCell( aScPos, new ScFormulaCell( &rDoc, aScPos, &aTokenArray ) );
224         }
225         break;
226 #endif
227 
228         default:;
229     }
230 }
231 
232 } // namespace
233 
234 // ----------------------------------------------------------------------------
235 
ReadHlink(XclImpStream & rStrm)236 void XclImpHyperlink::ReadHlink( XclImpStream& rStrm )
237 {
238     XclRange aXclRange( ScAddress::UNINITIALIZED );
239     rStrm >> aXclRange;
240     // #i80006# Excel silently ignores invalid hi-byte of column index (TODO: everywhere?)
241     aXclRange.maFirst.mnCol &= 0xFF;
242     aXclRange.maLast.mnCol &= 0xFF;
243     String aString = ReadEmbeddedData( rStrm );
244     if ( aString.Len() > 0 )
245         rStrm.GetRoot().GetXFRangeBuffer().SetHyperlink( aXclRange, aString );
246 }
247 
ReadEmbeddedData(XclImpStream & rStrm)248 String XclImpHyperlink::ReadEmbeddedData( XclImpStream& rStrm )
249 {
250     const XclImpRoot& rRoot = rStrm.GetRoot();
251     SfxObjectShell* pDocShell = rRoot.GetDocShell();
252 
253     DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
254 
255     sal_uInt32 nFlags;
256     XclGuid aGuid;
257     rStrm >> aGuid;
258     rStrm.Ignore( 4 );
259     rStrm >> nFlags;
260 
261     DBG_ASSERT( aGuid == XclTools::maGuidStdLink, "XclImpHyperlink::ReadEmbeddedData - unknown header GUID" );
262 
263     sal_uInt16 nLevel = 0;                  // counter for level to climb down in path
264     ::std::auto_ptr< String > xLongName;    // link / file name
265     ::std::auto_ptr< String > xShortName;   // 8.3-representation of file name
266     ::std::auto_ptr< String > xTextMark;    // text mark
267 
268     // description (ignore)
269     if( ::get_flag( nFlags, EXC_HLINK_DESCR ) )
270         lclIgnoreString32( rStrm, true );
271     // target frame (ignore) !! DESCR/FRAME - is this the right order? (never seen them together)
272     if( ::get_flag( nFlags, EXC_HLINK_FRAME ) )
273         lclIgnoreString32( rStrm, true );
274 
275     // URL fields are zero-terminated - do not let the stream replace them
276     // in the lclAppendString32() with the '?' character.
277     rStrm.SetNulSubstChar( '\0' );
278 
279     // UNC path
280     if( ::get_flag( nFlags, EXC_HLINK_UNC ) )
281     {
282         xLongName.reset( new String );
283         lclAppendString32( *xLongName, rStrm, true );
284         lclGetAbsPath( *xLongName, 0, pDocShell );
285     }
286     // file link or URL
287     else if( ::get_flag( nFlags, EXC_HLINK_BODY ) )
288     {
289         rStrm >> aGuid;
290 
291         if( aGuid == XclTools::maGuidFileMoniker )
292         {
293             rStrm >> nLevel;
294             xShortName.reset( new String );
295             lclAppendString32( *xShortName, rStrm, false );
296             rStrm.Ignore( 24 );
297 
298             sal_uInt32 nStrLen;
299             rStrm >> nStrLen;
300             if( nStrLen )
301             {
302                 rStrm >> nStrLen;
303                 nStrLen /= 2;       // it's byte count here...
304                 rStrm.Ignore( 2 );
305                 xLongName.reset( new String );
306                 lclAppendString32( *xLongName, rStrm, nStrLen, true );
307                 lclGetAbsPath( *xLongName, nLevel, pDocShell );
308             }
309             else
310                 lclGetAbsPath( *xShortName, nLevel, pDocShell );
311         }
312         else if( aGuid == XclTools::maGuidUrlMoniker )
313         {
314             sal_uInt32 nStrLen;
315             rStrm >> nStrLen;
316             nStrLen /= 2;       // it's byte count here...
317             xLongName.reset( new String );
318             lclAppendString32( *xLongName, rStrm, nStrLen, true );
319             if( !::get_flag( nFlags, EXC_HLINK_ABS ) )
320                 lclGetAbsPath( *xLongName, 0, pDocShell );
321         }
322         else
323         {
324             DBG_ERRORFILE( "XclImpHyperlink::ReadEmbeddedData - unknown content GUID" );
325         }
326     }
327 
328     // text mark
329     if( ::get_flag( nFlags, EXC_HLINK_MARK ) )
330     {
331         xTextMark.reset( new String );
332         lclAppendString32( *xTextMark, rStrm, true );
333     }
334 
335     rStrm.SetNulSubstChar();    // back to default
336 
337     DBG_ASSERT( rStrm.GetRecLeft() == 0, "XclImpHyperlink::ReadEmbeddedData - record size mismatch" );
338 
339     if( !xLongName.get() && xShortName.get() )
340         xLongName = xShortName;
341     else if( !xLongName.get() && xTextMark.get() )
342         xLongName.reset( new String );
343 
344     if( xLongName.get() )
345     {
346         if( xTextMark.get() )
347         {
348             if( xLongName->Len() == 0 )
349                 xTextMark->SearchAndReplaceAll( '!', '.' );
350             xLongName->Append( '#' );
351             xLongName->Append( *xTextMark );
352         }
353         return *xLongName;
354     }
355     return String::EmptyString();
356 }
357 
ConvertToValidTabName(String & rUrl)358 void XclImpHyperlink::ConvertToValidTabName(String& rUrl)
359 {
360     xub_StrLen n = rUrl.Len();
361     if (n < 4)
362         // Needs at least 4 characters.
363         return;
364 
365     sal_Unicode c = rUrl.GetChar(0);
366     if (c != sal_Unicode('#'))
367         // the 1st character must be '#'.
368         return;
369 
370     String aNewUrl(sal_Unicode('#')), aTabName;
371 
372     bool bInQuote = false;
373     bool bQuoteTabName = false;
374     for (xub_StrLen i = 1; i < n; ++i)
375     {
376         c = rUrl.GetChar(i);
377         if (c == sal_Unicode('\''))
378         {
379             if (bInQuote && i+1 < n && rUrl.GetChar(i+1) == sal_Unicode('\''))
380             {
381                 // Two consecutive single quotes ('') signify a single literal
382                 // quite.  When this occurs, the whole table name needs to be
383                 // quoted.
384                 bQuoteTabName = true;
385                 aTabName.Append(c);
386                 aTabName.Append(c);
387                 ++i;
388                 continue;
389             }
390 
391             bInQuote = !bInQuote;
392             if (!bInQuote && aTabName.Len() > 0)
393             {
394                 if (bQuoteTabName)
395                     aNewUrl.Append(sal_Unicode('\''));
396                 aNewUrl.Append(aTabName);
397                 if (bQuoteTabName)
398                     aNewUrl.Append(sal_Unicode('\''));
399             }
400         }
401         else if (bInQuote)
402             aTabName.Append(c);
403         else
404             aNewUrl.Append(c);
405     }
406 
407     if (bInQuote)
408         // It should be outside the quotes!
409         return;
410 
411     // All is good.  Pass the new URL.
412     rUrl = aNewUrl;
413 }
414 
InsertUrl(const XclImpRoot & rRoot,const XclRange & rXclRange,const String & rUrl)415 void XclImpHyperlink::InsertUrl( const XclImpRoot& rRoot, const XclRange& rXclRange, const String& rUrl )
416 {
417     String aUrl(rUrl);
418     ConvertToValidTabName(aUrl);
419 
420     SCTAB nScTab = rRoot.GetCurrScTab();
421     ScRange aScRange( ScAddress::UNINITIALIZED );
422     if( rRoot.GetAddressConverter().ConvertRange( aScRange, rXclRange, nScTab, nScTab, true ) )
423     {
424         SCCOL nScCol1, nScCol2;
425         SCROW nScRow1, nScRow2;
426         aScRange.GetVars( nScCol1, nScRow1, nScTab, nScCol2, nScRow2, nScTab );
427         for( SCCOL nScCol = nScCol1; nScCol <= nScCol2; ++nScCol )
428             for( SCROW nScRow = nScRow1; nScRow <= nScRow2; ++nScRow )
429                 lclInsertUrl( rRoot, aUrl, nScCol, nScRow, nScTab );
430     }
431 }
432 
433 // Label ranges ===============================================================
434 
ReadLabelranges(XclImpStream & rStrm)435 void XclImpLabelranges::ReadLabelranges( XclImpStream& rStrm )
436 {
437     const XclImpRoot& rRoot = rStrm.GetRoot();
438     DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
439 
440     ScDocument& rDoc = rRoot.GetDoc();
441     SCTAB nScTab = rRoot.GetCurrScTab();
442     XclImpAddressConverter& rAddrConv = rRoot.GetAddressConverter();
443     ScRangePairListRef xLabelRangesRef;
444     const ScRange* pScRange = 0;
445 
446     XclRangeList aRowXclRanges, aColXclRanges;
447     rStrm >> aRowXclRanges >> aColXclRanges;
448 
449     // row label ranges
450     ScRangeList aRowScRanges;
451     rAddrConv.ConvertRangeList( aRowScRanges, aRowXclRanges, nScTab, false );
452     xLabelRangesRef = rDoc.GetRowNameRangesRef();
453     for( pScRange = aRowScRanges.First(); pScRange; pScRange = aRowScRanges.Next() )
454     {
455         ScRange aDataRange( *pScRange );
456         if( aDataRange.aEnd.Col() < MAXCOL )
457         {
458             aDataRange.aStart.SetCol( aDataRange.aEnd.Col() + 1 );
459             aDataRange.aEnd.SetCol( MAXCOL );
460         }
461         else if( aDataRange.aStart.Col() > 0 )
462         {
463             aDataRange.aEnd.SetCol( aDataRange.aStart.Col() - 1 );
464             aDataRange.aStart.SetCol( 0 );
465         }
466         xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
467     }
468 
469     // column label ranges
470     ScRangeList aColScRanges;
471     rAddrConv.ConvertRangeList( aColScRanges, aColXclRanges, nScTab, false );
472     xLabelRangesRef = rDoc.GetColNameRangesRef();
473     for( pScRange = aColScRanges.First(); pScRange; pScRange = aColScRanges.Next() )
474     {
475         ScRange aDataRange( *pScRange );
476         if( aDataRange.aEnd.Row() < MAXROW )
477         {
478             aDataRange.aStart.SetRow( aDataRange.aEnd.Row() + 1 );
479             aDataRange.aEnd.SetRow( MAXROW );
480         }
481         else if( aDataRange.aStart.Row() > 0 )
482         {
483             aDataRange.aEnd.SetRow( aDataRange.aStart.Row() - 1 );
484             aDataRange.aStart.SetRow( 0 );
485         }
486         xLabelRangesRef->Append( ScRangePair( *pScRange, aDataRange ) );
487     }
488 }
489 
490 // Conditional formatting =====================================================
491 
XclImpCondFormat(const XclImpRoot & rRoot,sal_uInt32 nFormatIndex)492 XclImpCondFormat::XclImpCondFormat( const XclImpRoot& rRoot, sal_uInt32 nFormatIndex ) :
493     XclImpRoot( rRoot ),
494     mnFormatIndex( nFormatIndex ),
495     mnCondCount( 0 ),
496     mnCondIndex( 0 )
497 {
498 }
499 
~XclImpCondFormat()500 XclImpCondFormat::~XclImpCondFormat()
501 {
502 }
503 
ReadCondfmt(XclImpStream & rStrm)504 void XclImpCondFormat::ReadCondfmt( XclImpStream& rStrm )
505 {
506     DBG_ASSERT( !mnCondCount, "XclImpCondFormat::ReadCondfmt - already initialized" );
507     XclRangeList aXclRanges;
508     rStrm >> mnCondCount;
509     rStrm.Ignore( 10 );
510     rStrm >> aXclRanges;
511     GetAddressConverter().ConvertRangeList( maRanges, aXclRanges, GetCurrScTab(), true );
512 }
513 
ReadCF(XclImpStream & rStrm)514 void XclImpCondFormat::ReadCF( XclImpStream& rStrm )
515 {
516     if( mnCondIndex >= mnCondCount )
517     {
518         DBG_ERRORFILE( "XclImpCondFormat::ReadCF - CF without leading CONDFMT" );
519         return;
520     }
521 
522     // entire conditional format outside of valid range?
523     if( !maRanges.Count() )
524         return;
525 
526     sal_uInt8 nType, nOperator;
527     sal_uInt16 nFmlaSize1, nFmlaSize2;
528     sal_uInt32 nFlags;
529 
530     rStrm >> nType >> nOperator >> nFmlaSize1 >> nFmlaSize2 >> nFlags;
531     rStrm.Ignore( 2 );
532 
533     // *** mode and comparison operator ***
534 
535     ScConditionMode eMode = SC_COND_NONE;
536     switch( nType )
537     {
538         case EXC_CF_TYPE_CELL:
539         {
540             switch( nOperator )
541             {
542                 case EXC_CF_CMP_BETWEEN:        eMode = SC_COND_BETWEEN;    break;
543                 case EXC_CF_CMP_NOT_BETWEEN:    eMode = SC_COND_NOTBETWEEN; break;
544                 case EXC_CF_CMP_EQUAL:          eMode = SC_COND_EQUAL;      break;
545                 case EXC_CF_CMP_NOT_EQUAL:      eMode = SC_COND_NOTEQUAL;   break;
546                 case EXC_CF_CMP_GREATER:        eMode = SC_COND_GREATER;    break;
547                 case EXC_CF_CMP_LESS:           eMode = SC_COND_LESS;       break;
548                 case EXC_CF_CMP_GREATER_EQUAL:  eMode = SC_COND_EQGREATER;  break;
549                 case EXC_CF_CMP_LESS_EQUAL:     eMode = SC_COND_EQLESS;     break;
550                 default:
551                     DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF comparison 0x%02hX", nOperator );
552             }
553         }
554         break;
555 
556         case EXC_CF_TYPE_FMLA:
557             eMode = SC_COND_DIRECT;
558         break;
559 
560         default:
561             DBG_ERROR1( "XclImpCondFormat::ReadCF - unknown CF mode 0x%02hX", nType );
562             return;
563     }
564 
565     // *** create style sheet ***
566 
567     String aStyleName( XclTools::GetCondFormatStyleName( GetCurrScTab(), mnFormatIndex, mnCondIndex ) );
568     SfxItemSet& rStyleItemSet = ScfTools::MakeCellStyleSheet( GetStyleSheetPool(), aStyleName, true ).GetItemSet();
569 
570     const XclImpPalette& rPalette = GetPalette();
571 
572     // *** font block ***
573 
574     if( ::get_flag( nFlags, EXC_CF_BLOCK_FONT ) )
575     {
576         XclImpFont aFont( GetRoot() );
577         aFont.ReadCFFontBlock( rStrm );
578         aFont.FillToItemSet( rStyleItemSet, EXC_FONTITEM_CELL );
579     }
580 
581     // *** border block ***
582 
583     if( ::get_flag( nFlags, EXC_CF_BLOCK_BORDER ) )
584     {
585         sal_uInt16 nLineStyle;
586         sal_uInt32 nLineColor;
587         rStrm >> nLineStyle >> nLineColor;
588         rStrm.Ignore( 2 );
589 
590         XclImpCellBorder aBorder;
591         aBorder.FillFromCF8( nLineStyle, nLineColor, nFlags );
592         aBorder.FillToItemSet( rStyleItemSet, rPalette );
593     }
594 
595     // *** pattern block ***
596 
597     if( ::get_flag( nFlags, EXC_CF_BLOCK_AREA ) )
598     {
599         sal_uInt16 nPattern, nColor;
600         rStrm >> nPattern >> nColor;
601 
602         XclImpCellArea aArea;
603         aArea.FillFromCF8( nPattern, nColor, nFlags );
604         aArea.FillToItemSet( rStyleItemSet, rPalette );
605     }
606 
607     // *** formulas ***
608 
609     const ScAddress& rPos = maRanges.GetObject( 0 )->aStart;    // assured above that maRanges is not empty
610     ExcelToSc& rFmlaConv = GetOldFmlaConverter();
611 
612     ::std::auto_ptr< ScTokenArray > xTokArr1;
613     if( nFmlaSize1 > 0 )
614     {
615         const ScTokenArray* pTokArr = 0;
616         rFmlaConv.Reset( rPos );
617         rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize1, false, FT_Conditional );
618         // formula converter owns pTokArr -> create a copy of the token array
619         if( pTokArr )
620             xTokArr1.reset( pTokArr->Clone() );
621     }
622 
623     ::std::auto_ptr< ScTokenArray > pTokArr2;
624     if( nFmlaSize2 > 0 )
625     {
626         const ScTokenArray* pTokArr = 0;
627         rFmlaConv.Reset( rPos );
628         rFmlaConv.Convert( pTokArr, rStrm, nFmlaSize2, false, FT_Conditional );
629         // formula converter owns pTokArr -> create a copy of the token array
630         if( pTokArr )
631             pTokArr2.reset( pTokArr->Clone() );
632     }
633 
634     // *** create the Calc conditional formatting ***
635 
636     if( !mxScCondFmt.get() )
637     {
638         sal_uLong nKey = 0;
639         mxScCondFmt.reset( new ScConditionalFormat( nKey, GetDocPtr() ) );
640     }
641 
642     ScCondFormatEntry aEntry( eMode, xTokArr1.get(), pTokArr2.get(), GetDocPtr(), rPos, aStyleName );
643     mxScCondFmt->AddEntry( aEntry );
644     ++mnCondIndex;
645 }
646 
Apply()647 void XclImpCondFormat::Apply()
648 {
649     if( mxScCondFmt.get() )
650     {
651         ScDocument& rDoc = GetDoc();
652 
653         sal_uLong nKey = rDoc.AddCondFormat( *mxScCondFmt );
654         ScPatternAttr aPattern( rDoc.GetPool() );
655         aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_CONDITIONAL, nKey ) );
656 
657         // maRanges contains only valid cell ranges
658         for( const ScRange* pScRange = maRanges.First(); pScRange; pScRange = maRanges.Next() )
659         {
660             rDoc.ApplyPatternAreaTab(
661                 pScRange->aStart.Col(), pScRange->aStart.Row(),
662                 pScRange->aEnd.Col(), pScRange->aEnd.Row(),
663                 pScRange->aStart.Tab(), aPattern );
664         }
665     }
666 }
667 
668 // ----------------------------------------------------------------------------
669 
XclImpCondFormatManager(const XclImpRoot & rRoot)670 XclImpCondFormatManager::XclImpCondFormatManager( const XclImpRoot& rRoot ) :
671     XclImpRoot( rRoot )
672 {
673 }
674 
ReadCondfmt(XclImpStream & rStrm)675 void XclImpCondFormatManager::ReadCondfmt( XclImpStream& rStrm )
676 {
677     XclImpCondFormat* pFmt = new XclImpCondFormat( GetRoot(), maCondFmtList.Count() );
678     pFmt->ReadCondfmt( rStrm );
679     maCondFmtList.Append( pFmt );
680 }
681 
ReadCF(XclImpStream & rStrm)682 void XclImpCondFormatManager::ReadCF( XclImpStream& rStrm )
683 {
684     DBG_ASSERT( !maCondFmtList.Empty(), "XclImpCondFormatManager::ReadCF - CF without leading CONDFMT" );
685     if( !maCondFmtList.Empty() )
686         maCondFmtList.GetObject( maCondFmtList.Count() - 1 )->ReadCF( rStrm );
687 }
688 
Apply()689 void XclImpCondFormatManager::Apply()
690 {
691     for( XclImpCondFormat* pFmt = maCondFmtList.First(); pFmt; pFmt = maCondFmtList.Next() )
692         pFmt->Apply();
693     maCondFmtList.Clear();
694 }
695 
696 // Data Validation ============================================================
697 
ReadDval(XclImpStream & rStrm)698 void XclImpValidation::ReadDval( XclImpStream& rStrm )
699 {
700     const XclImpRoot& rRoot = rStrm.GetRoot();
701     DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
702 
703     sal_uInt32 nObjId;
704     rStrm.Ignore( 10 );
705     rStrm >> nObjId;
706     if( nObjId != EXC_DVAL_NOOBJ )
707     {
708         DBG_ASSERT( nObjId <= 0xFFFF, "XclImpValidation::ReadDval - invalid object ID" );
709         rRoot.GetCurrSheetDrawing().SetSkipObj( static_cast< sal_uInt16 >( nObjId ) );
710     }
711 }
712 
ReadDV(XclImpStream & rStrm)713 void XclImpValidation::ReadDV( XclImpStream& rStrm )
714 {
715     const XclImpRoot& rRoot = rStrm.GetRoot();
716     DBG_ASSERT_BIFF( rRoot.GetBiff() == EXC_BIFF8 );
717 
718     ScDocument& rDoc = rRoot.GetDoc();
719     SCTAB nScTab = rRoot.GetCurrScTab();
720     ExcelToSc& rFmlaConv = rRoot.GetOldFmlaConverter();
721 
722     // flags
723     sal_uInt32 nFlags;
724     rStrm >> nFlags;
725 
726     // message strings
727     /*  Empty strings are single NUL characters in Excel (string length is 1).
728         -> Do not let the stream replace them with '?' characters. */
729     rStrm.SetNulSubstChar( '\0' );
730     String aPromptTitle(   rStrm.ReadUniString() );
731     String aErrorTitle(    rStrm.ReadUniString() );
732     String aPromptMessage( rStrm.ReadUniString() );
733     String aErrorMessage(  rStrm.ReadUniString() );
734     rStrm.SetNulSubstChar();    // back to default
735 
736     // formula(s)
737     if( rStrm.GetRecLeft() > 8 )
738     {
739         sal_uInt16 nLen;
740 
741         // first formula
742         // string list is single tStr token with NUL separators -> replace them with LF
743         rStrm.SetNulSubstChar( '\n' );
744         ::std::auto_ptr< ScTokenArray > xTokArr1;
745         rStrm >> nLen;
746         rStrm.Ignore( 2 );
747         if( nLen > 0 )
748         {
749             const ScTokenArray* pTokArr = 0;
750             rFmlaConv.Reset();
751             rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_Conditional );
752             // formula converter owns pTokArr -> create a copy of the token array
753             if( pTokArr )
754                 xTokArr1.reset( pTokArr->Clone() );
755         }
756         rStrm.SetNulSubstChar();    // back to default
757 
758         // second formula
759         ::std::auto_ptr< ScTokenArray > xTokArr2;
760         rStrm >> nLen;
761         rStrm.Ignore( 2 );
762         if( nLen > 0 )
763         {
764             const ScTokenArray* pTokArr = 0;
765             rFmlaConv.Reset();
766             rFmlaConv.Convert( pTokArr, rStrm, nLen, false, FT_Conditional );
767             // formula converter owns pTokArr -> create a copy of the token array
768             if( pTokArr )
769                 xTokArr2.reset( pTokArr->Clone() );
770         }
771 
772         // read all cell ranges
773         XclRangeList aXclRanges;
774         rStrm >> aXclRanges;
775 
776         // convert to Calc range list
777         ScRangeList aScRanges;
778         rRoot.GetAddressConverter().ConvertRangeList( aScRanges, aXclRanges, nScTab, true );
779 
780         // only continue if there are valid ranges
781         if( aScRanges.Count() )
782         {
783             bool bIsValid = true;   // valid settings in flags field
784 
785             ScValidationMode eValMode = SC_VALID_ANY;
786             switch( nFlags & EXC_DV_MODE_MASK )
787             {
788                 case EXC_DV_MODE_ANY:       eValMode = SC_VALID_ANY;        break;
789                 case EXC_DV_MODE_WHOLE:     eValMode = SC_VALID_WHOLE;      break;
790                 case EXC_DV_MODE_DECIMAL:   eValMode = SC_VALID_DECIMAL;    break;
791                 case EXC_DV_MODE_LIST:      eValMode = SC_VALID_LIST;       break;
792                 case EXC_DV_MODE_DATE:      eValMode = SC_VALID_DATE;       break;
793                 case EXC_DV_MODE_TIME:      eValMode = SC_VALID_TIME;       break;
794                 case EXC_DV_MODE_TEXTLEN:   eValMode = SC_VALID_TEXTLEN;    break;
795                 case EXC_DV_MODE_CUSTOM:    eValMode = SC_VALID_CUSTOM;     break;
796                 default:                    bIsValid = false;
797             }
798             rRoot.GetTracer().TraceDVType(eValMode == SC_VALID_CUSTOM);
799 
800             ScConditionMode eCondMode = SC_COND_BETWEEN;
801             switch( nFlags & EXC_DV_COND_MASK )
802             {
803                 case EXC_DV_COND_BETWEEN:   eCondMode = SC_COND_BETWEEN;    break;
804                 case EXC_DV_COND_NOTBETWEEN:eCondMode = SC_COND_NOTBETWEEN; break;
805                 case EXC_DV_COND_EQUAL:     eCondMode = SC_COND_EQUAL;      break;
806                 case EXC_DV_COND_NOTEQUAL:  eCondMode = SC_COND_NOTEQUAL;   break;
807                 case EXC_DV_COND_GREATER:   eCondMode = SC_COND_GREATER;    break;
808                 case EXC_DV_COND_LESS:      eCondMode = SC_COND_LESS;       break;
809                 case EXC_DV_COND_EQGREATER: eCondMode = SC_COND_EQGREATER;  break;
810                 case EXC_DV_COND_EQLESS:    eCondMode = SC_COND_EQLESS;     break;
811                 default:                    bIsValid = false;
812             }
813 
814             if( bIsValid )
815             {
816                 // first range for base address for relative references
817                 const ScRange& rScRange = *aScRanges.GetObject( 0 );    // aScRanges is not empty
818 
819                 // process string list of a list validity (convert to list of string tokens)
820                 if( xTokArr1.get() && (eValMode == SC_VALID_LIST) && ::get_flag( nFlags, EXC_DV_STRINGLIST ) )
821                     XclTokenArrayHelper::ConvertStringToList( *xTokArr1, '\n', true );
822 
823                 ScValidationData aValidData( eValMode, eCondMode, xTokArr1.get(), xTokArr2.get(), &rDoc, rScRange.aStart );
824 
825                 aValidData.SetIgnoreBlank( ::get_flag( nFlags, EXC_DV_IGNOREBLANK ) );
826                 aValidData.SetListType( ::get_flagvalue( nFlags, EXC_DV_SUPPRESSDROPDOWN, ValidListType::INVISIBLE, ValidListType::UNSORTED ) );
827 
828                 // *** prompt box ***
829                 if( aPromptTitle.Len() || aPromptMessage.Len() )
830                 {
831                     // set any text stored in the record
832                     aValidData.SetInput( aPromptTitle, aPromptMessage );
833                     if( !::get_flag( nFlags, EXC_DV_SHOWPROMPT ) )
834                         aValidData.ResetInput();
835                 }
836 
837                 // *** error box ***
838                 ScValidErrorStyle eErrStyle = SC_VALERR_STOP;
839                 switch( nFlags & EXC_DV_ERROR_MASK )
840                 {
841                     case EXC_DV_ERROR_WARNING:  eErrStyle = SC_VALERR_WARNING;  break;
842                     case EXC_DV_ERROR_INFO:     eErrStyle = SC_VALERR_INFO;     break;
843                 }
844                 // set texts and error style
845                 aValidData.SetError( aErrorTitle, aErrorMessage, eErrStyle );
846                 if( !::get_flag( nFlags, EXC_DV_SHOWERROR ) )
847                     aValidData.ResetError();
848 
849                 // set the handle ID
850                 sal_uLong nHandle = rDoc.AddValidationEntry( aValidData );
851                 ScPatternAttr aPattern( rDoc.GetPool() );
852                 aPattern.GetItemSet().Put( SfxUInt32Item( ATTR_VALIDDATA, nHandle ) );
853 
854                 // apply all ranges
855                 for( const ScRange* pScRange = aScRanges.First(); pScRange; pScRange = aScRanges.Next() )
856                     rDoc.ApplyPatternAreaTab( pScRange->aStart.Col(), pScRange->aStart.Row(),
857                         pScRange->aEnd.Col(), pScRange->aEnd.Row(), nScTab, aPattern );
858             }
859         }
860     }
861 }
862 
863 // Web queries ================================================================
864 
XclImpWebQuery(const ScRange & rDestRange)865 XclImpWebQuery::XclImpWebQuery( const ScRange& rDestRange ) :
866     maDestRange( rDestRange ),
867     meMode( xlWQUnknown ),
868     mnRefresh( 0 )
869 {
870 }
871 
ReadParamqry(XclImpStream & rStrm)872 void XclImpWebQuery::ReadParamqry( XclImpStream& rStrm )
873 {
874     sal_uInt16 nFlags = rStrm.ReaduInt16();
875     sal_uInt16 nType = ::extract_value< sal_uInt16 >( nFlags, 0, 3 );
876     if( (nType == EXC_PQRYTYPE_WEBQUERY) && ::get_flag( nFlags, EXC_PQRY_WEBQUERY ) )
877     {
878         if( ::get_flag( nFlags, EXC_PQRY_TABLES ) )
879         {
880             meMode = xlWQAllTables;
881             maTables = ScfTools::GetHTMLTablesName();
882         }
883         else
884         {
885             meMode = xlWQDocument;
886             maTables = ScfTools::GetHTMLDocName();
887         }
888     }
889 }
890 
ReadWqstring(XclImpStream & rStrm)891 void XclImpWebQuery::ReadWqstring( XclImpStream& rStrm )
892 {
893     maURL = rStrm.ReadUniString();
894 }
895 
ReadWqsettings(XclImpStream & rStrm)896 void XclImpWebQuery::ReadWqsettings( XclImpStream& rStrm )
897 {
898     sal_uInt16 nFlags;
899     rStrm.Ignore( 10 );
900     rStrm >> nFlags;
901     rStrm.Ignore( 10 );
902     rStrm >> mnRefresh;
903 
904     if( ::get_flag( nFlags, EXC_WQSETT_SPECTABLES ) && (meMode == xlWQAllTables) )
905         meMode = xlWQSpecTables;
906 }
907 
ReadWqtables(XclImpStream & rStrm)908 void XclImpWebQuery::ReadWqtables( XclImpStream& rStrm )
909 {
910     if( meMode == xlWQSpecTables )
911 	{
912         rStrm.Ignore( 4 );
913         String aTables( rStrm.ReadUniString() );
914 
915         const sal_Unicode cSep = ';';
916         String aQuotedPairs( RTL_CONSTASCII_USTRINGPARAM( "\"\"" ) );
917         xub_StrLen nTokenCnt = aTables.GetQuotedTokenCount( aQuotedPairs, ',' );
918         maTables.Erase();
919         xub_StrLen nStringIx = 0;
920         for( xub_StrLen nToken = 0; nToken < nTokenCnt; ++nToken )
921         {
922             String aToken( aTables.GetQuotedToken( 0, aQuotedPairs, ',', nStringIx ) );
923             sal_Int32 nTabNum = CharClass::isAsciiNumeric( aToken ) ? aToken.ToInt32() : 0;
924             if( nTabNum > 0 )
925                 ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLIndex( static_cast< sal_uInt32 >( nTabNum ) ), cSep );
926             else
927             {
928                 ScGlobal::EraseQuotes( aToken, '"', false );
929                 if( aToken.Len() )
930                     ScGlobal::AddToken( maTables, ScfTools::GetNameFromHTMLName( aToken ), cSep );
931             }
932         }
933     }
934 }
935 
Apply(ScDocument & rDoc,const String & rFilterName)936 void XclImpWebQuery::Apply( ScDocument& rDoc, const String& rFilterName )
937 {
938     if( maURL.Len() && (meMode != xlWQUnknown) && rDoc.GetDocumentShell() )
939     {
940         ScAreaLink* pLink = new ScAreaLink( rDoc.GetDocumentShell(),
941             maURL, rFilterName, EMPTY_STRING, maTables, maDestRange, mnRefresh * 60UL );
942         rDoc.GetLinkManager()->InsertFileLink( *pLink, OBJECT_CLIENT_FILE,
943             maURL, &rFilterName, &maTables );
944     }
945 }
946 
947 // ----------------------------------------------------------------------------
948 
XclImpWebQueryBuffer(const XclImpRoot & rRoot)949 XclImpWebQueryBuffer::XclImpWebQueryBuffer( const XclImpRoot& rRoot ) :
950     XclImpRoot( rRoot )
951 {
952 }
953 
ReadQsi(XclImpStream & rStrm)954 void XclImpWebQueryBuffer::ReadQsi( XclImpStream& rStrm )
955 {
956     if( GetBiff() == EXC_BIFF8 )
957     {
958         rStrm.Ignore( 10 );
959         String aXclName( rStrm.ReadUniString() );
960 
961         // #i64794# Excel replaces spaces with underscores
962         aXclName.SearchAndReplaceAll( ' ', '_' );
963 
964         // #101529# find the defined name used in Calc
965         if( const XclImpName* pName = GetNameManager().FindName( aXclName, GetCurrScTab() ) )
966         {
967             if( const ScRangeData* pRangeData = pName->GetScRangeData() )
968             {
969                 ScRange aRange;
970                 if( pRangeData->IsReference( aRange ) )
971                     maWQList.Append( new XclImpWebQuery( aRange ) );
972             }
973         }
974     }
975     else
976     {
977         DBG_ERROR_BIFF();
978     }
979 }
980 
ReadParamqry(XclImpStream & rStrm)981 void XclImpWebQueryBuffer::ReadParamqry( XclImpStream& rStrm )
982 {
983     if( XclImpWebQuery* pQuery = maWQList.Last() )
984         pQuery->ReadParamqry( rStrm );
985 }
986 
ReadWqstring(XclImpStream & rStrm)987 void XclImpWebQueryBuffer::ReadWqstring( XclImpStream& rStrm )
988 {
989     if( XclImpWebQuery* pQuery = maWQList.Last() )
990         pQuery->ReadWqstring( rStrm );
991 }
992 
ReadWqsettings(XclImpStream & rStrm)993 void XclImpWebQueryBuffer::ReadWqsettings( XclImpStream& rStrm )
994 {
995     if( XclImpWebQuery* pQuery = maWQList.Last() )
996         pQuery->ReadWqsettings( rStrm );
997 }
998 
ReadWqtables(XclImpStream & rStrm)999 void XclImpWebQueryBuffer::ReadWqtables( XclImpStream& rStrm )
1000 {
1001     if( XclImpWebQuery* pQuery = maWQList.Last() )
1002         pQuery->ReadWqtables( rStrm );
1003 }
1004 
Apply()1005 void XclImpWebQueryBuffer::Apply()
1006 {
1007     ScDocument& rDoc = GetDoc();
1008     String aFilterName( RTL_CONSTASCII_USTRINGPARAM( EXC_WEBQRY_FILTER ) );
1009     for( XclImpWebQuery* pQuery = maWQList.First(); pQuery; pQuery = maWQList.Next() )
1010         pQuery->Apply( rDoc, aFilterName );
1011 }
1012 
1013 // Decryption =================================================================
1014 
1015 namespace {
1016 
lclReadFilepass5(XclImpStream & rStrm)1017 XclImpDecrypterRef lclReadFilepass5( XclImpStream& rStrm )
1018 {
1019     XclImpDecrypterRef xDecr;
1020     DBG_ASSERT( rStrm.GetRecLeft() == 4, "lclReadFilepass5 - wrong record size" );
1021     if( rStrm.GetRecLeft() == 4 )
1022     {
1023         sal_uInt16 nKey, nHash;
1024         rStrm >> nKey >> nHash;
1025         xDecr.reset( new XclImpBiff5Decrypter( nKey, nHash ) );
1026     }
1027     return xDecr;
1028 }
1029 
lclReadFilepass8_Standard(XclImpStream & rStrm)1030 XclImpDecrypterRef lclReadFilepass8_Standard( XclImpStream& rStrm )
1031 {
1032     XclImpDecrypterRef xDecr;
1033     DBG_ASSERT( rStrm.GetRecLeft() == 48, "lclReadFilepass8 - wrong record size" );
1034     if( rStrm.GetRecLeft() == 48 )
1035     {
1036         sal_uInt8 pnSalt[ 16 ];
1037         sal_uInt8 pnVerifier[ 16 ];
1038         sal_uInt8 pnVerifierHash[ 16 ];
1039         rStrm.Read( pnSalt, 16 );
1040         rStrm.Read( pnVerifier, 16 );
1041         rStrm.Read( pnVerifierHash, 16 );
1042         xDecr.reset( new XclImpBiff8Decrypter( pnSalt, pnVerifier, pnVerifierHash ) );
1043     }
1044     return xDecr;
1045 }
1046 
lclReadFilepass8_Strong(XclImpStream &)1047 XclImpDecrypterRef lclReadFilepass8_Strong( XclImpStream& /*rStrm*/ )
1048 {
1049     // not supported
1050     return XclImpDecrypterRef();
1051 }
1052 
lclReadFilepass8(XclImpStream & rStrm)1053 XclImpDecrypterRef lclReadFilepass8( XclImpStream& rStrm )
1054 {
1055     XclImpDecrypterRef xDecr;
1056 
1057     sal_uInt16 nMode;
1058     rStrm >> nMode;
1059     switch( nMode )
1060     {
1061         case EXC_FILEPASS_BIFF5:
1062             xDecr = lclReadFilepass5( rStrm );
1063         break;
1064 
1065         case EXC_FILEPASS_BIFF8:
1066         {
1067             rStrm.Ignore( 2 );
1068             sal_uInt16 nSubMode;
1069             rStrm >> nSubMode;
1070             switch( nSubMode )
1071             {
1072                 case EXC_FILEPASS_BIFF8_STD:
1073                     xDecr = lclReadFilepass8_Standard( rStrm );
1074                 break;
1075                 case EXC_FILEPASS_BIFF8_STRONG:
1076                     xDecr = lclReadFilepass8_Strong( rStrm );
1077                 break;
1078                 default:
1079                     DBG_ERRORFILE( "lclReadFilepass8 - unknown BIFF8 encryption sub mode" );
1080             }
1081         }
1082         break;
1083 
1084         default:
1085             DBG_ERRORFILE( "lclReadFilepass8 - unknown encryption mode" );
1086     }
1087 
1088     return xDecr;
1089 }
1090 
1091 } // namespace
1092 
1093 // ----------------------------------------------------------------------------
1094 
ReadFilepass(XclImpStream & rStrm)1095 ErrCode XclImpDecryptHelper::ReadFilepass( XclImpStream& rStrm )
1096 {
1097     XclImpDecrypterRef xDecr;
1098     rStrm.DisableDecryption();
1099 
1100     // read the FILEPASS record and create a new decrypter object
1101     switch( rStrm.GetRoot().GetBiff() )
1102     {
1103         case EXC_BIFF2:
1104         case EXC_BIFF3:
1105         case EXC_BIFF4:
1106         case EXC_BIFF5: xDecr = lclReadFilepass5( rStrm );  break;
1107         case EXC_BIFF8: xDecr = lclReadFilepass8( rStrm );  break;
1108         default:        DBG_ERROR_BIFF();
1109     };
1110 
1111     // set decrypter at import stream
1112     rStrm.SetDecrypter( xDecr );
1113 
1114     // request and verify a password (decrypter implements IDocPasswordVerifier)
1115     if( xDecr.is() )
1116         rStrm.GetRoot().RequestEncryptionData( *xDecr );
1117 
1118     // return error code (success, wrong password, etc.)
1119     return xDecr.is() ? xDecr->GetError() : EXC_ENCR_ERROR_UNSUPP_CRYPT;
1120 }
1121 
1122 // Document protection ========================================================
1123 
XclImpDocProtectBuffer(const XclImpRoot & rRoot)1124 XclImpDocProtectBuffer::XclImpDocProtectBuffer( const XclImpRoot& rRoot ) :
1125     XclImpRoot( rRoot ),
1126     mnPassHash(0x0000),
1127     mbDocProtect(false),
1128     mbWinProtect(false)
1129 {
1130 }
1131 
ReadDocProtect(XclImpStream & rStrm)1132 void XclImpDocProtectBuffer::ReadDocProtect( XclImpStream& rStrm )
1133 {
1134     mbDocProtect = rStrm.ReaduInt16() ? true : false;
1135 }
1136 
ReadWinProtect(XclImpStream & rStrm)1137 void XclImpDocProtectBuffer::ReadWinProtect( XclImpStream& rStrm )
1138 {
1139     mbWinProtect = rStrm.ReaduInt16() ? true : false;
1140 }
1141 
ReadPasswordHash(XclImpStream & rStrm)1142 void XclImpDocProtectBuffer::ReadPasswordHash( XclImpStream& rStrm )
1143 {
1144     rStrm.EnableDecryption();
1145     mnPassHash = rStrm.ReaduInt16();
1146 }
1147 
Apply() const1148 void XclImpDocProtectBuffer::Apply() const
1149 {
1150     if (!mbDocProtect && !mbWinProtect)
1151         // Excel requires either the structure or windows protection is set.
1152         // If neither is set then the document is not protected at all.
1153         return;
1154 
1155     auto_ptr<ScDocProtection> pProtect(new ScDocProtection);
1156     pProtect->setProtected(true);
1157 
1158 #if ENABLE_SHEET_PROTECTION
1159     if (mnPassHash)
1160     {
1161         // 16-bit password pash.
1162         Sequence<sal_Int8> aPass(2);
1163         aPass[0] = (mnPassHash >> 8) & 0xFF;
1164         aPass[1] = mnPassHash & 0xFF;
1165         pProtect->setPasswordHash(aPass, PASSHASH_XL);
1166     }
1167 #endif
1168 
1169     // document protection options
1170     pProtect->setOption(ScDocProtection::STRUCTURE, mbDocProtect);
1171     pProtect->setOption(ScDocProtection::WINDOWS,   mbWinProtect);
1172 
1173     GetDoc().SetDocProtection(pProtect.get());
1174 }
1175 
1176 // Sheet Protection ===========================================================
1177 
Sheet()1178 XclImpSheetProtectBuffer::Sheet::Sheet() :
1179     mbProtected(false),
1180     mnPasswordHash(0x0000),
1181     mnOptions(0x4400)
1182 {
1183 }
1184 
1185 // ----------------------------------------------------------------------------
1186 
Sheet(const Sheet & r)1187 XclImpSheetProtectBuffer::Sheet::Sheet(const Sheet& r) :
1188     mbProtected(r.mbProtected),
1189     mnPasswordHash(r.mnPasswordHash),
1190     mnOptions(r.mnOptions)
1191 {
1192 }
1193 
XclImpSheetProtectBuffer(const XclImpRoot & rRoot)1194 XclImpSheetProtectBuffer::XclImpSheetProtectBuffer( const XclImpRoot& rRoot ) :
1195     XclImpRoot( rRoot )
1196 {
1197 }
1198 
ReadProtect(XclImpStream & rStrm,SCTAB nTab)1199 void XclImpSheetProtectBuffer::ReadProtect( XclImpStream& rStrm, SCTAB nTab )
1200 {
1201     if ( rStrm.ReaduInt16() )
1202     {
1203         Sheet* pSheet = GetSheetItem(nTab);
1204         if (pSheet)
1205             pSheet->mbProtected = true;
1206     }
1207 }
1208 
ReadOptions(XclImpStream & rStrm,SCTAB nTab)1209 void XclImpSheetProtectBuffer::ReadOptions( XclImpStream& rStrm, SCTAB nTab )
1210 {
1211     rStrm.Ignore(12);
1212 
1213     // feature type can be either 2 or 4.  If 2, this record stores flag for
1214     // enhanced protection, whereas if 4 it stores flag for smart tag.
1215     sal_uInt16 nFeatureType;
1216     rStrm >> nFeatureType;
1217     if (nFeatureType != 2)
1218         // We currently only support import of enhanced protection data.
1219         return;
1220 
1221     rStrm.Ignore(1); // always 1
1222 
1223     // The flag size specifies the size of bytes that follows that stores
1224     // feature data.  If -1 it depends on the feature type imported earlier.
1225     // For enhanced protection data, the size is always 4.  For the most xls
1226     // documents out there this value is almost always -1.
1227     sal_Int32 nFlagSize;
1228     rStrm >> nFlagSize;
1229     if (nFlagSize != -1)
1230         return;
1231 
1232     // There are actually 4 bytes to read, but the upper 2 bytes currently
1233     // don't store any bits.
1234     sal_uInt16 nOptions;
1235     rStrm >> nOptions;
1236 
1237     Sheet* pSheet = GetSheetItem(nTab);
1238     if (pSheet)
1239         pSheet->mnOptions = nOptions;
1240 }
1241 
ReadPasswordHash(XclImpStream & rStrm,SCTAB nTab)1242 void XclImpSheetProtectBuffer::ReadPasswordHash( XclImpStream& rStrm, SCTAB nTab )
1243 {
1244     sal_uInt16 nHash;
1245     rStrm >> nHash;
1246     Sheet* pSheet = GetSheetItem(nTab);
1247     if (pSheet)
1248         pSheet->mnPasswordHash = nHash;
1249 }
1250 
Apply() const1251 void XclImpSheetProtectBuffer::Apply() const
1252 {
1253     for (ProtectedSheetMap::const_iterator itr = maProtectedSheets.begin(), itrEnd = maProtectedSheets.end();
1254          itr != itrEnd; ++itr)
1255     {
1256         if (!itr->second.mbProtected)
1257             // This sheet is (for whatever reason) not protected.
1258             continue;
1259 
1260         auto_ptr<ScTableProtection> pProtect(new ScTableProtection);
1261         pProtect->setProtected(true);
1262 
1263 #if ENABLE_SHEET_PROTECTION
1264         // 16-bit hash password
1265         const sal_uInt16 nHash = itr->second.mnPasswordHash;
1266         if (nHash)
1267         {
1268             Sequence<sal_Int8> aPass(2);
1269             aPass[0] = (nHash >> 8) & 0xFF;
1270             aPass[1] = nHash & 0xFF;
1271             pProtect->setPasswordHash(aPass, PASSHASH_XL);
1272         }
1273 #endif
1274 
1275         // sheet protection options
1276         const sal_uInt16 nOptions = itr->second.mnOptions;
1277         pProtect->setOption( ScTableProtection::OBJECTS,               (nOptions & 0x0001) );
1278         pProtect->setOption( ScTableProtection::SCENARIOS,             (nOptions & 0x0002) );
1279         pProtect->setOption( ScTableProtection::FORMAT_CELLS,          (nOptions & 0x0004) );
1280         pProtect->setOption( ScTableProtection::FORMAT_COLUMNS,        (nOptions & 0x0008) );
1281         pProtect->setOption( ScTableProtection::FORMAT_ROWS,           (nOptions & 0x0010) );
1282         pProtect->setOption( ScTableProtection::INSERT_COLUMNS,        (nOptions & 0x0020) );
1283         pProtect->setOption( ScTableProtection::INSERT_ROWS,           (nOptions & 0x0040) );
1284         pProtect->setOption( ScTableProtection::INSERT_HYPERLINKS,     (nOptions & 0x0080) );
1285         pProtect->setOption( ScTableProtection::DELETE_COLUMNS,        (nOptions & 0x0100) );
1286         pProtect->setOption( ScTableProtection::DELETE_ROWS,           (nOptions & 0x0200) );
1287         pProtect->setOption( ScTableProtection::SELECT_LOCKED_CELLS,   (nOptions & 0x0400) );
1288         pProtect->setOption( ScTableProtection::SORT,                  (nOptions & 0x0800) );
1289         pProtect->setOption( ScTableProtection::AUTOFILTER,            (nOptions & 0x1000) );
1290         pProtect->setOption( ScTableProtection::PIVOT_TABLES,          (nOptions & 0x2000) );
1291         pProtect->setOption( ScTableProtection::SELECT_UNLOCKED_CELLS, (nOptions & 0x4000) );
1292 
1293         // all done.  now commit.
1294         GetDoc().SetTabProtection(itr->first, pProtect.get());
1295     }
1296 }
1297 
GetSheetItem(SCTAB nTab)1298 XclImpSheetProtectBuffer::Sheet* XclImpSheetProtectBuffer::GetSheetItem( SCTAB nTab )
1299 {
1300     ProtectedSheetMap::iterator itr = maProtectedSheets.find(nTab);
1301     if (itr == maProtectedSheets.end())
1302     {
1303         // new sheet
1304         if ( !maProtectedSheets.insert( ProtectedSheetMap::value_type(nTab, Sheet()) ).second )
1305             return NULL;
1306 
1307         itr = maProtectedSheets.find(nTab);
1308     }
1309 
1310     return &itr->second;
1311 }
1312 
1313 // ============================================================================
1314 
1315