xref: /trunk/main/sc/source/filter/excel/xehelper.cxx (revision c2eaa082)
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 <com/sun/star/i18n/XBreakIterator.hpp>
27 #include <com/sun/star/i18n/ScriptType.hpp>
28 #include <sfx2/objsh.hxx>
29 #include <vcl/font.hxx>
30 #include <tools/urlobj.hxx>
31 #include <svl/itemset.hxx>
32 #include <svtools/ctrltool.hxx>
33 #include <svx/svdotext.hxx>
34 #include <editeng/outlobj.hxx>
35 #include "scitems.hxx"
36 #include <editeng/fhgtitem.hxx>
37 #include <editeng/flstitem.hxx>
38 #include <editeng/colritem.hxx>
39 #include <editeng/eeitem.hxx>
40 #include <editeng/flditem.hxx>
41 #include <editeng/escpitem.hxx>
42 #include <editeng/svxfont.hxx>
43 
44 #define _SVSTDARR_USHORTS
45 #include <svl/svstdarr.hxx>
46 #include "document.hxx"
47 #include "docpool.hxx"
48 #include "cell.hxx"
49 #include "editutil.hxx"
50 #include "patattr.hxx"
51 #include "xestyle.hxx"
52 #include "fprogressbar.hxx"
53 #include "xltracer.hxx"
54 #include "xecontent.hxx"
55 #include "xelink.hxx"
56 #include "xehelper.hxx"
57 
58 using ::rtl::OUString;
59 using ::com::sun::star::uno::Reference;
60 using ::com::sun::star::i18n::XBreakIterator;
61 
62 // Export progress bar ========================================================
63 
XclExpProgressBar(const XclExpRoot & rRoot)64 XclExpProgressBar::XclExpProgressBar( const XclExpRoot& rRoot ) :
65     XclExpRoot( rRoot ),
66     mxProgress( new ScfProgressBar( rRoot.GetDocShell(), STR_SAVE_DOC ) ),
67     mpSubProgress( 0 ),
68     mpSubRowCreate( 0 ),
69     mpSubRowFinal( 0 ),
70     mnSegRowFinal( SCF_INV_SEGMENT ),
71     mnRowCount( 0 )
72 {
73 }
74 
~XclExpProgressBar()75 XclExpProgressBar::~XclExpProgressBar()
76 {
77 }
78 
Initialize()79 void XclExpProgressBar::Initialize()
80 {
81     const ScDocument& rDoc = GetDoc();
82     const XclExpTabInfo& rTabInfo = GetTabInfo();
83     SCTAB nScTabCount = rTabInfo.GetScTabCount();
84 
85     // *** segment: creation of ROW records *** -------------------------------
86 
87     sal_Int32 nSegRowCreate = mxProgress->AddSegment( 2000 );
88     mpSubRowCreate = &mxProgress->GetSegmentProgressBar( nSegRowCreate );
89     maSubSegRowCreate.resize( nScTabCount, SCF_INV_SEGMENT );
90 
91     for( SCTAB nScTab = 0; nScTab < nScTabCount; ++nScTab )
92     {
93         if( rTabInfo.IsExportTab( nScTab ) )
94         {
95             SCCOL nLastUsedScCol;
96             SCROW nLastUsedScRow;
97             rDoc.GetTableArea( nScTab, nLastUsedScCol, nLastUsedScRow );
98             sal_Size nSegSize = static_cast< sal_Size >( nLastUsedScRow + 1 );
99             maSubSegRowCreate[ nScTab ] = mpSubRowCreate->AddSegment( nSegSize );
100         }
101     }
102 
103     // *** segment: writing all ROW records *** -------------------------------
104 
105     mnSegRowFinal = mxProgress->AddSegment( 1000 );
106     // sub progress bar and segment are created later in ActivateFinalRowsSegment()
107 }
108 
IncRowRecordCount()109 void XclExpProgressBar::IncRowRecordCount()
110 {
111     ++mnRowCount;
112 }
113 
ActivateCreateRowsSegment()114 void XclExpProgressBar::ActivateCreateRowsSegment()
115 {
116     DBG_ASSERT( (0 <= GetCurrScTab()) && (GetCurrScTab() < GetTabInfo().GetScTabCount()),
117         "XclExpProgressBar::ActivateCreateRowsSegment - invalid sheet" );
118     sal_Int32 nSeg = maSubSegRowCreate[ GetCurrScTab() ];
119     DBG_ASSERT( nSeg != SCF_INV_SEGMENT, "XclExpProgressBar::ActivateCreateRowsSegment - invalid segment" );
120     if( nSeg != SCF_INV_SEGMENT )
121     {
122         mpSubProgress = mpSubRowCreate;
123         mpSubProgress->ActivateSegment( nSeg );
124     }
125     else
126         mpSubProgress = 0;
127 }
128 
ActivateFinalRowsSegment()129 void XclExpProgressBar::ActivateFinalRowsSegment()
130 {
131     if( !mpSubRowFinal && (mnRowCount > 0) )
132     {
133         mpSubRowFinal = &mxProgress->GetSegmentProgressBar( mnSegRowFinal );
134         mpSubRowFinal->AddSegment( mnRowCount );
135     }
136     mpSubProgress = mpSubRowFinal;
137     if( mpSubProgress )
138         mpSubProgress->Activate();
139 }
140 
Progress()141 void XclExpProgressBar::Progress()
142 {
143     if( mpSubProgress && !mpSubProgress->IsFull() )
144         mpSubProgress->Progress();
145 }
146 
147 // Calc->Excel cell address/range conversion ==================================
148 
149 namespace {
150 
151 /** Fills the passed Excel address with the passed Calc cell coordinates without checking any limits. */
lclFillAddress(XclAddress & rXclPos,SCCOL nScCol,SCROW nScRow)152 inline void lclFillAddress( XclAddress& rXclPos, SCCOL nScCol, SCROW nScRow )
153 {
154     rXclPos.mnCol = static_cast< sal_uInt16 >( nScCol );
155     rXclPos.mnRow = static_cast< sal_uInt16 >( nScRow );
156 }
157 
158 } // namespace
159 
160 // ----------------------------------------------------------------------------
161 
XclExpAddressConverter(const XclExpRoot & rRoot)162 XclExpAddressConverter::XclExpAddressConverter( const XclExpRoot& rRoot ) :
163     XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetXclMaxPos() )
164 {
165 }
166 
167 // cell address ---------------------------------------------------------------
168 
CheckAddress(const ScAddress & rScPos,bool bWarn)169 bool XclExpAddressConverter::CheckAddress( const ScAddress& rScPos, bool bWarn )
170 {
171     // ScAddress::operator<=() doesn't do what we want here
172     bool bValidCol = (0 <= rScPos.Col()) && (rScPos.Col() <= maMaxPos.Col());
173     bool bValidRow = (0 <= rScPos.Row()) && (rScPos.Row() <= maMaxPos.Row());
174     bool bValidTab = (0 <= rScPos.Tab()) && (rScPos.Tab() <= maMaxPos.Tab());
175 
176     bool bValid = bValidCol && bValidRow && bValidTab;
177     if( !bValid && bWarn )
178     {
179         mbColTrunc |= !bValidCol;
180         mbRowTrunc |= !bValidRow;
181         mbTabTrunc |= (rScPos.Tab() > maMaxPos.Tab());  // do not warn for deleted refs
182         mrTracer.TraceInvalidAddress( rScPos, maMaxPos );
183     }
184     return bValid;
185 }
186 
ConvertAddress(XclAddress & rXclPos,const ScAddress & rScPos,bool bWarn)187 bool XclExpAddressConverter::ConvertAddress( XclAddress& rXclPos,
188         const ScAddress& rScPos, bool bWarn )
189 {
190     bool bValid = CheckAddress( rScPos, bWarn );
191     if( bValid )
192         lclFillAddress( rXclPos, rScPos.Col(), rScPos.Row() );
193     return bValid;
194 }
195 
CreateValidAddress(const ScAddress & rScPos,bool bWarn)196 XclAddress XclExpAddressConverter::CreateValidAddress( const ScAddress& rScPos, bool bWarn )
197 {
198     XclAddress aXclPos( ScAddress::UNINITIALIZED );
199     if( !ConvertAddress( aXclPos, rScPos, bWarn ) )
200         lclFillAddress( aXclPos, ::std::min( rScPos.Col(), maMaxPos.Col() ), ::std::min( rScPos.Row(), maMaxPos.Row() ) );
201     return aXclPos;
202 }
203 
204 // cell range -----------------------------------------------------------------
205 
CheckRange(const ScRange & rScRange,bool bWarn)206 bool XclExpAddressConverter::CheckRange( const ScRange& rScRange, bool bWarn )
207 {
208     return CheckAddress( rScRange.aStart, bWarn ) && CheckAddress( rScRange.aEnd, bWarn );
209 }
210 
ValidateRange(ScRange & rScRange,bool bWarn)211 bool XclExpAddressConverter::ValidateRange( ScRange& rScRange, bool bWarn )
212 {
213     rScRange.Justify();
214 
215     // check start position
216     bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
217     if( bValidStart )
218     {
219         // check & correct end position
220         ScAddress& rScEnd = rScRange.aEnd;
221         if( !CheckAddress( rScEnd, bWarn ) )
222         {
223             rScEnd.SetCol( ::std::min( rScEnd.Col(), maMaxPos.Col() ) );
224             rScEnd.SetRow( ::std::min( rScEnd.Row(), maMaxPos.Row() ) );
225             rScEnd.SetTab( ::std::min( rScEnd.Tab(), maMaxPos.Tab() ) );
226         }
227     }
228 
229     return bValidStart;
230 }
231 
ConvertRange(XclRange & rXclRange,const ScRange & rScRange,bool bWarn)232 bool XclExpAddressConverter::ConvertRange( XclRange& rXclRange,
233         const ScRange& rScRange, bool bWarn )
234 {
235     // check start position
236     bool bValidStart = CheckAddress( rScRange.aStart, bWarn );
237     if( bValidStart )
238     {
239         lclFillAddress( rXclRange.maFirst, rScRange.aStart.Col(), rScRange.aStart.Row() );
240 
241         // check & correct end position
242         SCCOL nScCol2 = rScRange.aEnd.Col();
243         SCROW nScRow2 = rScRange.aEnd.Row();
244         if( !CheckAddress( rScRange.aEnd, bWarn ) )
245         {
246             nScCol2 = ::std::min( nScCol2, maMaxPos.Col() );
247             nScRow2 = ::std::min( nScRow2, maMaxPos.Row() );
248         }
249         lclFillAddress( rXclRange.maLast, nScCol2, nScRow2 );
250     }
251     return bValidStart;
252 }
253 
254 //UNUSED2008-05  XclRange XclExpAddressConverter::CreateValidRange( const ScRange& rScRange, bool bWarn )
255 //UNUSED2008-05  {
256 //UNUSED2008-05      return XclRange(
257 //UNUSED2008-05          CreateValidAddress( rScRange.aStart, bWarn ),
258 //UNUSED2008-05          CreateValidAddress( rScRange.aEnd, bWarn ) );
259 //UNUSED2008-05  }
260 
261 // cell range list ------------------------------------------------------------
262 
263 //UNUSED2008-05  bool XclExpAddressConverter::CheckRangeList( const ScRangeList& rScRanges, bool bWarn )
264 //UNUSED2008-05  {
265 //UNUSED2008-05      for( sal_uLong nIdx = 0, nSize = rScRanges.Count(); nIdx < nSize; ++nIdx )
266 //UNUSED2008-05          if( const ScRange* pScRange = rScRanges.GetObject( nIdx ) )
267 //UNUSED2008-05              if( !CheckRange( *pScRange, bWarn ) )
268 //UNUSED2008-05                  return false;
269 //UNUSED2008-05      return true;
270 //UNUSED2008-05  }
271 
ValidateRangeList(ScRangeList & rScRanges,bool bWarn)272 void XclExpAddressConverter::ValidateRangeList( ScRangeList& rScRanges, bool bWarn )
273 {
274     sal_uLong nIdx = rScRanges.Count();
275     while( nIdx )
276     {
277         --nIdx; // backwards to keep nIdx valid
278         ScRange* pScRange = rScRanges.GetObject( nIdx );
279         if( pScRange && !CheckRange( *pScRange, bWarn ) )
280             delete rScRanges.Remove( nIdx );
281     }
282 }
283 
ConvertRangeList(XclRangeList & rXclRanges,const ScRangeList & rScRanges,bool bWarn)284 void XclExpAddressConverter::ConvertRangeList( XclRangeList& rXclRanges,
285         const ScRangeList& rScRanges, bool bWarn )
286 {
287     rXclRanges.clear();
288     for( sal_uLong nPos = 0, nCount = rScRanges.Count(); nPos < nCount; ++nPos )
289     {
290         if( const ScRange* pScRange = rScRanges.GetObject( nPos ) )
291         {
292             XclRange aXclRange( ScAddress::UNINITIALIZED );
293             if( ConvertRange( aXclRange, *pScRange, bWarn ) )
294                 rXclRanges.push_back( aXclRange );
295         }
296     }
297 }
298 
299 // EditEngine->String conversion ==============================================
300 
301 namespace {
302 
lclGetUrlRepresentation(const SvxURLField & rUrlField)303 String lclGetUrlRepresentation( const SvxURLField& rUrlField )
304 {
305     String aRepr( rUrlField.GetRepresentation() );
306     // no representation -> use URL
307     return aRepr.Len() ? aRepr : rUrlField.GetURL();
308 }
309 
310 } // namespace
311 
312 // ----------------------------------------------------------------------------
313 
XclExpHyperlinkHelper(const XclExpRoot & rRoot,const ScAddress & rScPos)314 XclExpHyperlinkHelper::XclExpHyperlinkHelper( const XclExpRoot& rRoot, const ScAddress& rScPos ) :
315     XclExpRoot( rRoot ),
316     maScPos( rScPos ),
317     mbMultipleUrls( false )
318 {
319 }
320 
~XclExpHyperlinkHelper()321 XclExpHyperlinkHelper::~XclExpHyperlinkHelper()
322 {
323 }
324 
ProcessUrlField(const SvxURLField & rUrlField)325 String XclExpHyperlinkHelper::ProcessUrlField( const SvxURLField& rUrlField )
326 {
327     String aUrlRepr;
328 
329     if( GetBiff() == EXC_BIFF8 )    // no HLINK records in BIFF2-BIFF7
330     {
331         // there was/is already a HLINK record
332         mbMultipleUrls = mxLinkRec.is();
333 
334         mxLinkRec.reset( new XclExpHyperlink( GetRoot(), rUrlField, maScPos ) );
335 
336         if( const String* pRepr = mxLinkRec->GetRepr() )
337             aUrlRepr = *pRepr;
338 
339         // add URL to note text
340         ScGlobal::AddToken( maUrlList, rUrlField.GetURL(), '\n' );
341     }
342 
343     // no hyperlink representation from Excel HLINK record -> use it from text field
344     return aUrlRepr.Len() ? aUrlRepr : lclGetUrlRepresentation( rUrlField );
345 }
346 
HasLinkRecord() const347 bool XclExpHyperlinkHelper::HasLinkRecord() const
348 {
349     return !mbMultipleUrls && mxLinkRec.is();
350 }
351 
GetLinkRecord()352 XclExpHyperlinkHelper::XclExpHyperlinkRef XclExpHyperlinkHelper::GetLinkRecord()
353 {
354     if( HasLinkRecord() )
355         return mxLinkRec;
356     return XclExpHyperlinkRef();
357 }
358 
359 // ----------------------------------------------------------------------------
360 
361 namespace {
362 
363 /** Creates a new formatted string from the passed unformatted string.
364 
365     Creates a Unicode string or a byte string, depending on the current BIFF
366     version contained in the passed XclExpRoot object. May create a formatted
367     string object, if the text contains different script types.
368 
369     @param pCellAttr
370         Cell attributes used for font formatting.
371     @param nFlags
372         Modifiers for string export.
373     @param nMaxLen
374         The maximum number of characters to store in this string.
375     @return
376         The new string object.
377  */
lclCreateFormattedString(const XclExpRoot & rRoot,const String & rText,const ScPatternAttr * pCellAttr,XclStrFlags nFlags,sal_uInt16 nMaxLen)378 XclExpStringRef lclCreateFormattedString(
379         const XclExpRoot& rRoot, const String& rText, const ScPatternAttr* pCellAttr,
380         XclStrFlags nFlags, sal_uInt16 nMaxLen )
381 {
382     /*  Create an empty Excel string object with correctly initialized BIFF mode,
383         because this function only uses Append() functions that require this. */
384     XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
385 
386     // script type handling
387     Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
388     namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
389     // #i63255# get script type for leading weak characters
390     sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rText );
391 
392     // font buffer and cell item set
393     XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
394     const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
395 
396     // process all script portions
397     OUString aOUText( rText );
398     sal_Int32 nPortionPos = 0;
399     sal_Int32 nTextLen = aOUText.getLength();
400     while( nPortionPos < nTextLen )
401     {
402         // get script type and end position of next script portion
403         sal_Int16 nScript = xBreakIt->getScriptType( aOUText, nPortionPos );
404         sal_Int32 nPortionEnd = xBreakIt->endOfScript( aOUText, nPortionPos, nScript );
405 
406         // reuse previous script for following weak portions
407         if( nScript == ApiScriptType::WEAK )
408             nScript = nLastScript;
409 
410         // construct font from current text portion
411         SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, rItemSet, nScript ) );
412 
413         // Excel start position of this portion
414         sal_uInt16 nXclPortionStart = xString->Len();
415         // add portion text to Excel string
416         XclExpStringHelper::AppendString( *xString, rRoot, aOUText.copy( nPortionPos, nPortionEnd - nPortionPos ) );
417         if( nXclPortionStart < xString->Len() )
418         {
419             // insert font into buffer
420             sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
421             // insert font index into format run vector
422             xString->AppendFormat( nXclPortionStart, nFontIdx );
423         }
424 
425         // go to next script portion
426         nLastScript = nScript;
427         nPortionPos = nPortionEnd;
428     }
429 
430     return xString;
431 }
432 
433 /** Creates a new formatted string from an edit engine text object.
434 
435     Creates a Unicode string or a byte string, depending on the current BIFF
436     version contained in the passed XclExpRoot object.
437 
438     @param rEE
439         The edit engine in use. The text object must already be set.
440     @param nFlags
441         Modifiers for string export.
442     @param nMaxLen
443         The maximum number of characters to store in this string.
444     @return
445         The new string object.
446  */
lclCreateFormattedString(const XclExpRoot & rRoot,EditEngine & rEE,XclExpHyperlinkHelper * pLinkHelper,XclStrFlags nFlags,sal_uInt16 nMaxLen)447 XclExpStringRef lclCreateFormattedString(
448         const XclExpRoot& rRoot, EditEngine& rEE, XclExpHyperlinkHelper* pLinkHelper,
449         XclStrFlags nFlags, sal_uInt16 nMaxLen )
450 {
451     /*  Create an empty Excel string object with correctly initialized BIFF mode,
452         because this function only uses Append() functions that require this. */
453     XclExpStringRef xString = XclExpStringHelper::CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
454 
455     // font buffer and helper item set for edit engine -> Calc item conversion
456     XclExpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
457     SfxItemSet aItemSet( *rRoot.GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
458 
459     // script type handling
460     Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
461     namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
462     // #i63255# get script type for leading weak characters
463     sal_Int16 nLastScript = XclExpStringHelper::GetLeadingScriptType( rRoot, rEE.GetText() );
464 
465     // process all paragraphs
466     sal_uInt32 nParaCount = rEE.GetParagraphCount();
467     for( sal_uInt32 nPara = 0; nPara < nParaCount; ++nPara )
468     {
469         ESelection aSel( nPara, 0 );
470         String aParaText( rEE.GetText( nPara ) );
471 
472         SvUShorts aPosList;
473         rEE.GetPortions( nPara, aPosList );
474 
475         // process all portions in the paragraph
476         sal_uInt16 nPosCount = aPosList.Count();
477         for( sal_uInt16 nPos = 0; nPos < nPosCount; ++nPos )
478         {
479             aSel.nEndPos = static_cast< xub_StrLen >( aPosList.GetObject( nPos ) );
480             String aXclPortionText( aParaText, aSel.nStartPos, aSel.nEndPos - aSel.nStartPos );
481 
482             aItemSet.ClearItem();
483             SfxItemSet aEditSet( rEE.GetAttribs( aSel ) );
484             ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
485 
486             // get escapement value
487             short nEsc = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT ).GetEsc();
488 
489             // process text fields
490             bool bIsHyperlink = false;
491             if( aSel.nStartPos + 1 == aSel.nEndPos )
492             {
493                 // test if the character is a text field
494                 const SfxPoolItem* pItem;
495                 if( aEditSet.GetItemState( EE_FEATURE_FIELD, sal_False, &pItem ) == SFX_ITEM_SET )
496                 {
497                     const SvxFieldData* pField = static_cast< const SvxFieldItem* >( pItem )->GetField();
498                     if( const SvxURLField* pUrlField = PTR_CAST( SvxURLField, pField ) )
499                     {
500                         // convert URL field to string representation
501                         aXclPortionText = pLinkHelper ?
502                             pLinkHelper->ProcessUrlField( *pUrlField ) :
503                             lclGetUrlRepresentation( *pUrlField );
504                         bIsHyperlink = true;
505                     }
506                     else
507                     {
508                         DBG_ERRORFILE( "lclCreateFormattedString - unknown text field" );
509                         aXclPortionText.Erase();
510                     }
511                 }
512             }
513 
514             // Excel start position of this portion
515             sal_uInt16 nXclPortionStart = xString->Len();
516             // add portion text to Excel string
517             XclExpStringHelper::AppendString( *xString, rRoot, aXclPortionText );
518             if( (nXclPortionStart < xString->Len()) || (aParaText.Len() == 0) )
519             {
520                 /*  Construct font from current edit engine text portion. Edit engine
521                     creates different portions for different script types, no need to loop. */
522                 sal_Int16 nScript = xBreakIt->getScriptType( aXclPortionText, 0 );
523                 if( nScript == ApiScriptType::WEAK )
524                     nScript = nLastScript;
525                 SvxFont aFont( XclExpFontHelper::GetFontFromItemSet( rRoot, aItemSet, nScript ) );
526                 nLastScript = nScript;
527 
528                 // add escapement
529                 aFont.SetEscapement( nEsc );
530                 // modify automatic font color for hyperlinks
531                 if( bIsHyperlink && (GETITEM( aItemSet, SvxColorItem, ATTR_FONT_COLOR ).GetValue().GetColor() == COL_AUTO) )
532                     aFont.SetColor( Color( COL_LIGHTBLUE ) );
533 
534                 // insert font into buffer
535                 sal_uInt16 nFontIdx = rFontBuffer.Insert( aFont, EXC_COLOR_CELLTEXT );
536                 // insert font index into format run vector
537                 xString->AppendFormat( nXclPortionStart, nFontIdx );
538             }
539 
540             aSel.nStartPos = aSel.nEndPos;
541         }
542 
543         // add trailing newline (important for correct character index calculation)
544         if( nPara + 1 < nParaCount )
545             XclExpStringHelper::AppendChar( *xString, rRoot, '\n' );
546     }
547 
548     return xString;
549 }
550 
551 } // namespace
552 
553 // ----------------------------------------------------------------------------
554 
CreateString(const XclExpRoot & rRoot,const String & rString,XclStrFlags nFlags,sal_uInt16 nMaxLen)555 XclExpStringRef XclExpStringHelper::CreateString(
556         const XclExpRoot& rRoot, const String& rString, XclStrFlags nFlags, sal_uInt16 nMaxLen )
557 {
558     XclExpStringRef xString( new XclExpString );
559     if( rRoot.GetBiff() == EXC_BIFF8 )
560         xString->Assign( rString, nFlags, nMaxLen );
561     else
562         xString->AssignByte( rString, rRoot.GetTextEncoding(), nFlags, nMaxLen );
563     return xString;
564 }
565 
CreateString(const XclExpRoot & rRoot,sal_Unicode cChar,XclStrFlags nFlags,sal_uInt16 nMaxLen)566 XclExpStringRef XclExpStringHelper::CreateString(
567         const XclExpRoot& rRoot, sal_Unicode cChar, XclStrFlags nFlags, sal_uInt16 nMaxLen )
568 {
569     XclExpStringRef xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
570     AppendChar( *xString, rRoot, cChar );
571     return xString;
572 }
573 
AppendString(XclExpString & rXclString,const XclExpRoot & rRoot,const String & rString)574 void XclExpStringHelper::AppendString( XclExpString& rXclString, const XclExpRoot& rRoot, const String& rString )
575 {
576     if( rRoot.GetBiff() == EXC_BIFF8 )
577         rXclString.Append( rString );
578     else
579         rXclString.AppendByte( rString, rRoot.GetTextEncoding() );
580 }
581 
AppendChar(XclExpString & rXclString,const XclExpRoot & rRoot,sal_Unicode cChar)582 void XclExpStringHelper::AppendChar( XclExpString& rXclString, const XclExpRoot& rRoot, sal_Unicode cChar )
583 {
584     if( rRoot.GetBiff() == EXC_BIFF8 )
585         rXclString.Append( cChar );
586     else
587         rXclString.AppendByte( cChar, rRoot.GetTextEncoding() );
588 }
589 
CreateCellString(const XclExpRoot & rRoot,const ScStringCell & rStringCell,const ScPatternAttr * pCellAttr,XclStrFlags nFlags,sal_uInt16 nMaxLen)590 XclExpStringRef XclExpStringHelper::CreateCellString(
591         const XclExpRoot& rRoot, const ScStringCell& rStringCell, const ScPatternAttr* pCellAttr,
592         XclStrFlags nFlags, sal_uInt16 nMaxLen )
593 {
594     String aCellText;
595     rStringCell.GetString( aCellText );
596     return lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
597 }
598 
CreateCellString(const XclExpRoot & rRoot,const ScEditCell & rEditCell,const ScPatternAttr * pCellAttr,XclExpHyperlinkHelper & rLinkHelper,XclStrFlags nFlags,sal_uInt16 nMaxLen)599 XclExpStringRef XclExpStringHelper::CreateCellString(
600         const XclExpRoot& rRoot, const ScEditCell& rEditCell, const ScPatternAttr* pCellAttr,
601         XclExpHyperlinkHelper& rLinkHelper, XclStrFlags nFlags, sal_uInt16 nMaxLen )
602 {
603     XclExpStringRef xString;
604     if( const EditTextObject* pEditObj = rEditCell.GetData() )
605     {
606         // formatted cell
607         ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
608         sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
609         rEE.SetUpdateMode( sal_True );
610         // default items
611         const SfxItemSet& rItemSet = pCellAttr ? pCellAttr->GetItemSet() : rRoot.GetDoc().GetDefPattern()->GetItemSet();
612         SfxItemSet* pEEItemSet = new SfxItemSet( rEE.GetEmptyItemSet() );
613         ScPatternAttr::FillToEditItemSet( *pEEItemSet, rItemSet );
614         rEE.SetDefaults( pEEItemSet );      // edit engine takes ownership
615         // create the string
616         rEE.SetText( *pEditObj );
617         xString = lclCreateFormattedString( rRoot, rEE, &rLinkHelper, nFlags, nMaxLen );
618         rEE.SetUpdateMode( bOldUpdateMode );
619     }
620     else
621     {
622         // unformatted cell
623         String aCellText;
624         rEditCell.GetString( aCellText );
625         xString = lclCreateFormattedString( rRoot, aCellText, pCellAttr, nFlags, nMaxLen );
626     }
627     return xString;
628 }
629 
CreateString(const XclExpRoot & rRoot,const SdrTextObj & rTextObj,XclStrFlags nFlags,sal_uInt16 nMaxLen)630 XclExpStringRef XclExpStringHelper::CreateString(
631         const XclExpRoot& rRoot, const SdrTextObj& rTextObj,
632         XclStrFlags nFlags, sal_uInt16 nMaxLen )
633 {
634     XclExpStringRef xString;
635     if( const OutlinerParaObject* pParaObj = rTextObj.GetOutlinerParaObject() )
636     {
637         EditEngine& rEE = rRoot.GetDrawEditEngine();
638         sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
639         rEE.SetUpdateMode( sal_True );
640         // create the string
641         rEE.SetText( pParaObj->GetTextObject() );
642         xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
643         rEE.SetUpdateMode( bOldUpdateMode );
644         // limit formats - TODO: BIFF dependent
645         if( !xString->IsEmpty() )
646         {
647             xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
648             xString->AppendTrailingFormat( EXC_FONT_APP );
649         }
650     }
651     else
652     {
653         DBG_ERRORFILE( "XclExpStringHelper::CreateString - textbox without para object" );
654         // create BIFF dependent empty Excel string
655         xString = CreateString( rRoot, EMPTY_STRING, nFlags, nMaxLen );
656     }
657     return xString;
658 }
659 
CreateString(const XclExpRoot & rRoot,const EditTextObject & rEditObj,XclStrFlags nFlags,sal_uInt16 nMaxLen)660 XclExpStringRef XclExpStringHelper::CreateString(
661         const XclExpRoot& rRoot, const EditTextObject& rEditObj,
662         XclStrFlags nFlags, sal_uInt16 nMaxLen )
663 {
664     XclExpStringRef xString;
665     EditEngine& rEE = rRoot.GetDrawEditEngine();
666     sal_Bool bOldUpdateMode = rEE.GetUpdateMode();
667     rEE.SetUpdateMode( sal_True );
668     rEE.SetText( rEditObj );
669     xString = lclCreateFormattedString( rRoot, rEE, 0, nFlags, nMaxLen );
670     rEE.SetUpdateMode( bOldUpdateMode );
671     // limit formats - TODO: BIFF dependent
672     if( !xString->IsEmpty() )
673     {
674         xString->LimitFormatCount( EXC_MAXRECSIZE_BIFF8 / 8 - 1 );
675         xString->AppendTrailingFormat( EXC_FONT_APP );
676     }
677     return xString;
678 }
679 
GetLeadingScriptType(const XclExpRoot & rRoot,const String & rString)680 sal_Int16 XclExpStringHelper::GetLeadingScriptType( const XclExpRoot& rRoot, const String& rString )
681 {
682     namespace ApiScriptType = ::com::sun::star::i18n::ScriptType;
683     Reference< XBreakIterator > xBreakIt = rRoot.GetDoc().GetBreakIterator();
684     OUString aOUString( rString );
685     sal_Int32 nStrPos = 0;
686     sal_Int32 nStrLen = aOUString.getLength();
687     sal_Int16 nScript = ApiScriptType::WEAK;
688     while( (nStrPos < nStrLen) && (nScript == ApiScriptType::WEAK) )
689     {
690         nScript = xBreakIt->getScriptType( aOUString, nStrPos );
691         nStrPos = xBreakIt->endOfScript( aOUString, nStrPos, nScript );
692     }
693     return (nScript == ApiScriptType::WEAK) ? rRoot.GetDefApiScript() : nScript;
694 }
695 
696 // Header/footer conversion ===================================================
697 
XclExpHFConverter(const XclExpRoot & rRoot)698 XclExpHFConverter::XclExpHFConverter( const XclExpRoot& rRoot ) :
699     XclExpRoot( rRoot ),
700     mrEE( rRoot.GetHFEditEngine() ),
701     mnTotalHeight( 0 )
702 {
703 }
704 
GenerateString(const EditTextObject * pLeftObj,const EditTextObject * pCenterObj,const EditTextObject * pRightObj)705 void XclExpHFConverter::GenerateString(
706         const EditTextObject* pLeftObj,
707         const EditTextObject* pCenterObj,
708         const EditTextObject* pRightObj )
709 {
710     maHFString.Erase();
711     mnTotalHeight = 0;
712     AppendPortion( pLeftObj, 'L' );
713     AppendPortion( pCenterObj, 'C' );
714     AppendPortion( pRightObj, 'R' );
715 }
716 
AppendPortion(const EditTextObject * pTextObj,sal_Unicode cPortionCode)717 void XclExpHFConverter::AppendPortion( const EditTextObject* pTextObj, sal_Unicode cPortionCode )
718 {
719     if( !pTextObj ) return;
720 
721     String aText;
722     sal_Int32 nHeight = 0;
723     SfxItemSet aItemSet( *GetDoc().GetPool(), ATTR_PATTERN_START, ATTR_PATTERN_END );
724 
725     // edit engine
726     sal_Bool bOldUpdateMode = mrEE.GetUpdateMode();
727     mrEE.SetUpdateMode( sal_True );
728     mrEE.SetText( *pTextObj );
729 
730     // font information
731     XclFontData aFontData, aNewData;
732     if( const XclExpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
733     {
734         aFontData = pFirstFont->GetFontData();
735         (aFontData.mnHeight += 10) /= 20;   // using pt here, not twips
736     }
737     else
738         aFontData.mnHeight = 10;
739 
740     const FontList* pFontList = 0;
741     if( SfxObjectShell* pDocShell = GetDocShell() )
742     {
743         if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
744                 pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
745             pFontList = pInfoItem->GetFontList();
746     }
747 
748     sal_uInt32 nParaCount = mrEE.GetParagraphCount();
749     for( sal_uInt32 nPara = 0; nPara < nParaCount; ++nPara )
750     {
751         ESelection aSel( nPara, 0 );
752         String aParaText;
753         sal_Int32 nParaHeight = 0;
754         SvUShorts aPosList;
755         mrEE.GetPortions( nPara, aPosList );
756 
757         sal_uInt16 nPosCount = aPosList.Count();
758         for( sal_uInt16 nPos = 0; nPos < nPosCount; ++nPos )
759         {
760             aSel.nEndPos = static_cast< xub_StrLen >( aPosList.GetObject( nPos ) );
761             if( aSel.nStartPos < aSel.nEndPos )
762             {
763 
764 // --- font attributes ---
765 
766                 Font aFont;
767                 aItemSet.ClearItem();
768                 SfxItemSet aEditSet( mrEE.GetAttribs( aSel ) );
769                 ScPatternAttr::GetFromEditItemSet( aItemSet, aEditSet );
770                 ScPatternAttr::GetFont( aFont, aItemSet, SC_AUTOCOL_RAW );
771 
772                 // font name and style
773                 aNewData.maName = XclTools::GetXclFontName( aFont.GetName() );
774                 aNewData.mnWeight = (aFont.GetWeight() > WEIGHT_NORMAL) ? EXC_FONTWGHT_BOLD : EXC_FONTWGHT_NORMAL;
775                 aNewData.mbItalic = (aFont.GetItalic() != ITALIC_NONE);
776                 bool bNewFont = !(aFontData.maName == aNewData.maName);
777                 bool bNewStyle = (aFontData.mnWeight != aNewData.mnWeight) ||
778                                  (aFontData.mbItalic != aNewData.mbItalic);
779                 if( bNewFont || (bNewStyle && pFontList) )
780                 {
781                     aParaText.AppendAscii( "&\"" ).Append( aNewData.maName );
782                     if( pFontList )
783                     {
784                         FontInfo aFontInfo( pFontList->Get(
785                             aNewData.maName,
786                             (aNewData.mnWeight > EXC_FONTWGHT_NORMAL) ? WEIGHT_BOLD : WEIGHT_NORMAL,
787                             aNewData.mbItalic ? ITALIC_NORMAL : ITALIC_NONE ) );
788                         aNewData.maStyle = pFontList->GetStyleName( aFontInfo );
789                         if( aNewData.maStyle.Len() )
790                             aParaText.Append( ',' ).Append( aNewData.maStyle );
791                     }
792                     aParaText.Append( '"' );
793                 }
794 
795                 // height
796                 // is calculated wrong in ScPatternAttr::GetFromEditItemSet, because already in twips and not 100thmm
797                 // -> get it directly from edit engine item set
798                 aNewData.mnHeight = ulimit_cast< sal_uInt16 >( GETITEM( aEditSet, SvxFontHeightItem, EE_CHAR_FONTHEIGHT ).GetHeight() );
799                 (aNewData.mnHeight += 10) /= 20;
800                 bool bFontHtChanged = (aFontData.mnHeight != aNewData.mnHeight);
801                 if( bFontHtChanged )
802                     aParaText.Append( '&' ).Append( String::CreateFromInt32( aNewData.mnHeight ) );
803                 // update maximum paragraph height, convert to twips
804                 nParaHeight = ::std::max< sal_Int32 >( nParaHeight, aNewData.mnHeight * 20 );
805 
806                 // underline
807                 aNewData.mnUnderline = EXC_FONTUNDERL_NONE;
808                 switch( aFont.GetUnderline() )
809                 {
810                     case UNDERLINE_NONE:    aNewData.mnUnderline = EXC_FONTUNDERL_NONE;    break;
811                     case UNDERLINE_SINGLE:  aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE;  break;
812                     case UNDERLINE_DOUBLE:  aNewData.mnUnderline = EXC_FONTUNDERL_DOUBLE;  break;
813                     default:                aNewData.mnUnderline = EXC_FONTUNDERL_SINGLE;
814                 }
815                 if( aFontData.mnUnderline != aNewData.mnUnderline )
816                 {
817                     sal_uInt8 nTmpUnderl = (aNewData.mnUnderline == EXC_FONTUNDERL_NONE) ?
818                         aFontData.mnUnderline : aNewData.mnUnderline;
819                     aParaText.AppendAscii( (nTmpUnderl == EXC_FONTUNDERL_SINGLE) ? "&U" : "&E" );
820                 }
821 
822                 // strikeout
823                 aNewData.mbStrikeout = (aFont.GetStrikeout() != STRIKEOUT_NONE);
824                 if( aFontData.mbStrikeout != aNewData.mbStrikeout )
825                     aParaText.AppendAscii( "&S" );
826 
827                 // super/sub script
828                 const SvxEscapementItem& rEscapeItem = GETITEM( aEditSet, SvxEscapementItem, EE_CHAR_ESCAPEMENT );
829                 aNewData.SetScEscapement( rEscapeItem.GetEsc() );
830                 if( aFontData.mnEscapem != aNewData.mnEscapem )
831                 {
832                     switch(aNewData.mnEscapem)
833                     {
834                         // close the previous super/sub script.
835                         case EXC_FONTESC_NONE:  aParaText.AppendAscii( (aFontData.mnEscapem == EXC_FONTESC_SUPER) ? "&X" : "&Y" ); break;
836                         case EXC_FONTESC_SUPER: aParaText.AppendAscii( "&X" );  break;
837                         case EXC_FONTESC_SUB:   aParaText.AppendAscii( "&Y" );  break;
838                         default: break;
839                     }
840                 }
841 
842                 aFontData = aNewData;
843 
844 // --- text content or text fields ---
845 
846                 const SfxPoolItem* pItem;
847                 if( (aSel.nStartPos + 1 == aSel.nEndPos) &&     // fields are single characters
848                     (aEditSet.GetItemState( EE_FEATURE_FIELD, sal_False, &pItem ) == SFX_ITEM_SET) )
849                 {
850                     if( const SvxFieldData* pFieldData = static_cast< const SvxFieldItem* >( pItem )->GetField() )
851                     {
852                         if( pFieldData->ISA( SvxPageField ) )
853                             aParaText.AppendAscii( "&P" );
854                         else if( pFieldData->ISA( SvxPagesField ) )
855                             aParaText.AppendAscii( "&N" );
856                         else if( pFieldData->ISA( SvxDateField ) )
857                             aParaText.AppendAscii( "&D" );
858                         else if( pFieldData->ISA( SvxTimeField ) || pFieldData->ISA( SvxExtTimeField ) )
859                             aParaText.AppendAscii( "&T" );
860                         else if( pFieldData->ISA( SvxTableField ) )
861                             aParaText.AppendAscii( "&A" );
862                         else if( pFieldData->ISA( SvxFileField ) )  // title -> file name
863                             aParaText.AppendAscii( "&F" );
864                         else if( const SvxExtFileField* pFileField = PTR_CAST( SvxExtFileField, pFieldData ) )
865                         {
866                             switch( pFileField->GetFormat() )
867                             {
868                                 case SVXFILEFORMAT_NAME_EXT:
869                                 case SVXFILEFORMAT_NAME:
870                                     aParaText.AppendAscii( "&F" );
871                                 break;
872                                 case SVXFILEFORMAT_PATH:
873                                     aParaText.AppendAscii( "&Z" );
874                                 break;
875                                 case SVXFILEFORMAT_FULLPATH:
876                                     aParaText.AppendAscii( "&Z&F" );
877                                 break;
878                                 default:
879                                     DBG_ERRORFILE( "XclExpHFConverter::AppendPortion - unknown file field" );
880                             }
881                         }
882                     }
883                 }
884                 else
885                 {
886                     String aPortionText( mrEE.GetText( aSel ) );
887                     aPortionText.SearchAndReplaceAll( String( '&' ), String( RTL_CONSTASCII_USTRINGPARAM( "&&" ) ) );
888                     // #i17440# space between font height and numbers in text
889                     if( bFontHtChanged && aParaText.Len() && aPortionText.Len() )
890                     {
891                         sal_Unicode cLast = aParaText.GetChar( aParaText.Len() - 1 );
892                         sal_Unicode cFirst = aPortionText.GetChar( 0 );
893                         if( ('0' <= cLast) && (cLast <= '9') && ('0' <= cFirst) && (cFirst <= '9') )
894                             aParaText.Append( ' ' );
895                     }
896                     aParaText.Append( aPortionText );
897                 }
898             }
899 
900             aSel.nStartPos = aSel.nEndPos;
901         }
902 
903         ScGlobal::AddToken( aText, aParaText, '\n' );
904         if( nParaHeight == 0 )
905             nParaHeight = aFontData.mnHeight * 20;  // points -> twips
906         nHeight += nParaHeight;
907     }
908 
909     mrEE.SetUpdateMode( bOldUpdateMode );
910 
911     if( aText.Len() )
912     {
913         maHFString.Append( '&' ).Append( cPortionCode ).Append( aText );
914         mnTotalHeight = ::std::max( mnTotalHeight, nHeight );
915     }
916 }
917 
918 // URL conversion =============================================================
919 
920 namespace {
921 
922 /** Converts the file URL passed in rUrl to a URL in DOS notation (local or UNC).
923     @param rUrl  (in/out-param) In: URL to convert; Out: Converted URL in DOS notation.
924     @param rBasePath  Base path for relative URLs.
925     @param bSaveRelUrl  Converts to a relative URL, using rBasePath.
926     @return  True = Conversion successful, rUrl contains converted file URL. */
lclConvertToDos(String & rUrl,const String & rBasePath,bool bSaveRelUrl)927 bool lclConvertToDos( String& rUrl, const String& rBasePath, bool bSaveRelUrl )
928 {
929     String aDosUrl( INetURLObject( rUrl ).getFSysPath( INetURLObject::FSYS_DOS ) );
930     bool bRet = (aDosUrl.Len() > 0);
931     if( bRet && bSaveRelUrl )
932     {
933         // try to convert to relative path
934         String aDosBase( INetURLObject( rBasePath ).getFSysPath( INetURLObject::FSYS_DOS ) );
935         if( aDosBase.Len() )
936         {
937             xub_StrLen nPos;
938 
939             // --- 1st step: delete equal subdirectories ---
940 
941             // special handling for UNC
942             xub_StrLen nStartSearch = aDosBase.EqualsAscii( "\\\\", 0, 2 ) ? 2 : 0;
943             bool bEqualBase = false;
944             bool bLoop = true;
945             while( bLoop && ((nPos = aDosBase.Search( '\\', nStartSearch )) != STRING_NOTFOUND) )
946             {
947                 bLoop = (sal_True == aDosBase.Equals( aDosUrl, 0, nPos + 1 ));
948                 if( bLoop )
949                 {
950                     aDosBase.Erase( 0, nPos + 1 );
951                     aDosUrl.Erase( 0, nPos + 1 );
952                     nStartSearch = 0;
953                     bEqualBase = true;
954                 }
955             }
956 
957             // --- 2nd step: add parent directory levels ---
958 
959             if( bEqualBase )
960             {
961                 while( (nPos = aDosBase.Search( '\\' )) != STRING_NOTFOUND )
962                 {
963                     aDosBase.Erase( 0, nPos + 1 );
964                     aDosUrl.InsertAscii( "..\\", 0 );
965                 }
966             }
967         }
968         rUrl = aDosUrl;
969     }
970     return bRet;
971 }
972 
973 /** Encodes special parts of the URL, i.e. directory separators and volume names.
974     @param pTableName  Pointer to a table name to be encoded in this URL, or 0. */
lclEncodeDosUrl(XclBiff eBiff,String & rUrl,const String * pTableName=0)975 void lclEncodeDosUrl( XclBiff eBiff, String& rUrl, const String* pTableName = 0 )
976 {
977     if( rUrl.Len() )
978     {
979         String aOldUrl( rUrl );
980         rUrl = EXC_URLSTART_ENCODED;
981 
982         if( (aOldUrl.Len() > 2) && aOldUrl.EqualsAscii( "\\\\", 0, 2 ) )
983         {
984             // UNC
985             rUrl.Append( EXC_URL_DOSDRIVE ).Append( '@' );
986             aOldUrl.Erase( 0, 2 );
987         }
988         else if( (aOldUrl.Len() > 2) && aOldUrl.EqualsAscii( ":\\", 1, 2 ) )
989         {
990             // drive letter
991             rUrl.Append( EXC_URL_DOSDRIVE ).Append( aOldUrl.GetChar( 0 ) );
992             aOldUrl.Erase( 0, 3 );
993         }
994 
995         // directories
996         xub_StrLen nPos;
997         while( (nPos = aOldUrl.Search( '\\' )) != STRING_NOTFOUND )
998         {
999             if( aOldUrl.EqualsAscii( "..", 0, 2 ) )
1000                 rUrl.Append( EXC_URL_PARENTDIR );   // parent dir
1001             else
1002                 rUrl.Append( aOldUrl.GetBuffer(), nPos ).Append( EXC_URL_SUBDIR );
1003             aOldUrl.Erase( 0, nPos + 1 );
1004         }
1005 
1006         // file name
1007         if( pTableName )    // enclose file name in brackets if table name follows
1008             rUrl.Append( '[' ).Append( aOldUrl ).Append( ']' );
1009         else
1010             rUrl.Append( aOldUrl );
1011     }
1012     else    // empty URL -> self reference
1013     {
1014         switch( eBiff )
1015         {
1016             case EXC_BIFF5:
1017                 rUrl = pTableName ? EXC_URLSTART_SELFENCODED : EXC_URLSTART_SELF;
1018             break;
1019             case EXC_BIFF8:
1020                 DBG_ASSERT( pTableName, "lclEncodeDosUrl - sheet name required for BIFF8" );
1021                 rUrl = EXC_URLSTART_SELF;
1022             break;
1023             default:
1024                 DBG_ERROR_BIFF();
1025         }
1026     }
1027 
1028     // table name
1029     if( pTableName )
1030         rUrl.Append( *pTableName );
1031 }
1032 
1033 } // namespace
1034 
1035 // ----------------------------------------------------------------------------
1036 
EncodeUrl(const XclExpRoot & rRoot,const String & rAbsUrl,const String * pTableName)1037 String XclExpUrlHelper::EncodeUrl( const XclExpRoot& rRoot, const String& rAbsUrl, const String* pTableName )
1038 {
1039     String aDosUrl( rAbsUrl );
1040     if( !aDosUrl.Len() || lclConvertToDos( aDosUrl, rRoot.GetBasePath(), rRoot.IsRelUrl() ) )
1041         lclEncodeDosUrl( rRoot.GetBiff(), aDosUrl, pTableName );
1042     return aDosUrl;
1043 }
1044 
EncodeDde(const String & rApplic,const String rTopic)1045 String XclExpUrlHelper::EncodeDde( const String& rApplic, const String rTopic )
1046 {
1047     String aDde( rApplic );
1048     aDde.Append( EXC_DDE_DELIM ).Append( rTopic );
1049     return aDde;
1050 }
1051 
1052 // Cached Value Lists =========================================================
1053 
XclExpCachedMatrix(const ScMatrix & rMatrix)1054 XclExpCachedMatrix::XclExpCachedMatrix( const ScMatrix& rMatrix )
1055     : mrMatrix( rMatrix )
1056 {
1057     mrMatrix.IncRef();
1058 }
~XclExpCachedMatrix()1059 XclExpCachedMatrix::~XclExpCachedMatrix()
1060 {
1061     mrMatrix.DecRef();
1062 }
1063 
GetDimensions(SCSIZE & nCols,SCSIZE & nRows) const1064 void XclExpCachedMatrix::GetDimensions( SCSIZE & nCols, SCSIZE & nRows ) const
1065 {
1066     mrMatrix.GetDimensions( nCols, nRows );
1067 
1068     DBG_ASSERT( nCols && nRows, "XclExpCachedMatrix::GetDimensions - empty matrix" );
1069     DBG_ASSERT( nCols <= 256, "XclExpCachedMatrix::GetDimensions - too many columns" );
1070 }
1071 
GetSize() const1072 sal_Size XclExpCachedMatrix::GetSize() const
1073 {
1074     SCSIZE nCols, nRows;
1075 
1076     GetDimensions( nCols, nRows );
1077 
1078     /*  The returned size may be wrong if the matrix contains strings. The only
1079         effect is that the export stream has to update a wrong record size which is
1080         faster than to iterate through all cached values and calculate their sizes. */
1081     return 3 + 9 * (nCols * nRows);
1082 }
1083 
Save(XclExpStream & rStrm) const1084 void XclExpCachedMatrix::Save( XclExpStream& rStrm ) const
1085 {
1086     SCSIZE nCols, nRows;
1087 
1088     GetDimensions( nCols, nRows );
1089 
1090     if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
1091         // in BIFF2-BIFF7: 256 columns represented by 0 columns
1092         rStrm << static_cast< sal_uInt8 >( nCols ) << static_cast< sal_uInt16 >( nRows );
1093     else
1094         // in BIFF8: columns and rows decreaed by 1
1095         rStrm << static_cast< sal_uInt8 >( nCols - 1 ) << static_cast< sal_uInt16 >( nRows - 1 );
1096 
1097     for( SCSIZE nRow = 0; nRow < nRows; ++nRow )
1098     {
1099         for( SCSIZE nCol = 0; nCol < nCols; ++nCol )
1100         {
1101             ScMatValType nMatValType = SC_MATVAL_VALUE;
1102             const ScMatrixValue* pMatVal = mrMatrix.Get( nCol, nRow, nMatValType );
1103 
1104             if( !pMatVal || SC_MATVAL_EMPTY == nMatValType )
1105             {
1106                 rStrm.SetSliceSize( 9 );
1107                 rStrm << EXC_CACHEDVAL_EMPTY;
1108                 rStrm.WriteZeroBytes( 8 );
1109             }
1110             else if( ScMatrix::IsNonValueType( nMatValType ) )
1111             {
1112                 XclExpString aStr( pMatVal->GetString(), EXC_STR_DEFAULT );
1113                 rStrm.SetSliceSize( 6 );
1114                 rStrm << EXC_CACHEDVAL_STRING << aStr;
1115             }
1116             else if( SC_MATVAL_BOOLEAN == nMatValType )
1117             {
1118                 sal_Int8 nBool = pMatVal->GetBoolean();
1119                 rStrm.SetSliceSize( 9 );
1120                 rStrm << EXC_CACHEDVAL_BOOL << nBool;
1121                 rStrm.WriteZeroBytes( 7 );
1122             }
1123             else if( sal_uInt16 nScError = pMatVal->GetError() )
1124             {
1125                 sal_Int8 nError ( XclTools::GetXclErrorCode( nScError ) );
1126                 rStrm.SetSliceSize( 9 );
1127                 rStrm << EXC_CACHEDVAL_ERROR << nError;
1128                 rStrm.WriteZeroBytes( 7 );
1129             }
1130             else
1131             {
1132                 rStrm.SetSliceSize( 9 );
1133                 rStrm << EXC_CACHEDVAL_DOUBLE << pMatVal->fVal;
1134             }
1135         }
1136     }
1137 }
1138 
1139 // ============================================================================
1140 
1141