LCOV - code coverage report
Current view: top level - sc/source/filter/excel - xehelper.cxx (source / functions) Hit Total Coverage
Test: commit c8344322a7af75b84dd3ca8f78b05543a976dfd5 Lines: 347 489 71.0 %
Date: 2015-06-13 12:38:46 Functions: 36 49 73.5 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11