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 #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, EE_PARA_MAX, 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, EE_PARA_MAX, 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