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