summaryrefslogtreecommitdiffstats
path: root/sc/source/filter/excel/xihelper.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/filter/excel/xihelper.cxx')
-rw-r--r--sc/source/filter/excel/xihelper.cxx896
1 files changed, 896 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xihelper.cxx b/sc/source/filter/excel/xihelper.cxx
new file mode 100644
index 000000000..ef38c5b65
--- /dev/null
+++ b/sc/source/filter/excel/xihelper.cxx
@@ -0,0 +1,896 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <memory>
+#include <xihelper.hxx>
+#include <svl/itemset.hxx>
+#include <svl/sharedstringpool.hxx>
+#include <editeng/editobj.hxx>
+#include <tools/urlobj.hxx>
+#include <editeng/eeitem.hxx>
+#include <editeng/flditem.hxx>
+#include <document.hxx>
+#include <rangelst.hxx>
+#include <editutil.hxx>
+#include <attrib.hxx>
+#include <xltracer.hxx>
+#include <xistream.hxx>
+#include <xistring.hxx>
+#include <xistyle.hxx>
+#include <excform.hxx>
+#include <scmatrix.hxx>
+#include <documentimport.hxx>
+#include <sal/log.hxx>
+
+// Excel->Calc cell address/range conversion ==================================
+
+namespace {
+
+/** Fills the passed Calc address with the passed Excel cell coordinates without checking any limits. */
+void lclFillAddress( ScAddress& rScPos, sal_uInt16 nXclCol, sal_uInt32 nXclRow, SCTAB nScTab )
+{
+ rScPos.SetCol( static_cast< SCCOL >( nXclCol ) );
+ rScPos.SetRow( static_cast< SCROW >( nXclRow ) );
+ rScPos.SetTab( nScTab );
+}
+
+} // namespace
+
+XclImpAddressConverter::XclImpAddressConverter( const XclImpRoot& rRoot ) :
+ XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetScMaxPos() )
+{
+}
+
+// cell address ---------------------------------------------------------------
+
+bool XclImpAddressConverter::CheckAddress( const XclAddress& rXclPos, bool bWarn )
+{
+ bool bValidCol = rXclPos.mnCol <= mnMaxCol;
+ bool bValidRow = rXclPos.mnRow <= mnMaxRow;
+ bool bValid = bValidCol && bValidRow;
+ if( !bValid && bWarn )
+ {
+ mbColTrunc |= !bValidCol;
+ mbRowTrunc |= !bValidRow;
+ mrTracer.TraceInvalidAddress( ScAddress(
+ static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), 0 ), maMaxPos );
+ }
+ return bValid;
+}
+
+bool XclImpAddressConverter::ConvertAddress( ScAddress& rScPos,
+ const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
+{
+ bool bValid = CheckAddress( rXclPos, bWarn );
+ if( bValid )
+ lclFillAddress( rScPos, rXclPos.mnCol, rXclPos.mnRow, nScTab );
+ return bValid;
+}
+
+ScAddress XclImpAddressConverter::CreateValidAddress(
+ const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
+{
+ ScAddress aScPos( ScAddress::UNINITIALIZED );
+ if( !ConvertAddress( aScPos, rXclPos, nScTab, bWarn ) )
+ {
+ aScPos.SetCol( static_cast< SCCOL >( ::std::min( rXclPos.mnCol, mnMaxCol ) ) );
+ aScPos.SetRow( static_cast< SCROW >( ::std::min( rXclPos.mnRow, mnMaxRow ) ) );
+ aScPos.SetTab( limit_cast< SCTAB >( nScTab, 0, maMaxPos.Tab() ) );
+ }
+ return aScPos;
+}
+
+// cell range -----------------------------------------------------------------
+
+bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
+ const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
+{
+ // check start position
+ bool bValidStart = CheckAddress( rXclRange.maFirst, bWarn );
+ if( bValidStart )
+ {
+ lclFillAddress( rScRange.aStart, rXclRange.maFirst.mnCol, rXclRange.maFirst.mnRow, nScTab1 );
+
+ // check & correct end position
+ sal_uInt16 nXclCol2 = rXclRange.maLast.mnCol;
+ sal_uInt32 nXclRow2 = rXclRange.maLast.mnRow;
+ if( !CheckAddress( rXclRange.maLast, bWarn ) )
+ {
+ nXclCol2 = ::std::min( nXclCol2, mnMaxCol );
+ nXclRow2 = ::std::min( nXclRow2, mnMaxRow );
+ }
+ lclFillAddress( rScRange.aEnd, nXclCol2, nXclRow2, nScTab2 );
+ }
+ return bValidStart;
+}
+
+// cell range list ------------------------------------------------------------
+
+void XclImpAddressConverter::ConvertRangeList( ScRangeList& rScRanges,
+ const XclRangeList& rXclRanges, SCTAB nScTab, bool bWarn )
+{
+ rScRanges.RemoveAll();
+ for( const auto& rXclRange : rXclRanges )
+ {
+ ScRange aScRange( ScAddress::UNINITIALIZED );
+ if( ConvertRange( aScRange, rXclRange, nScTab, nScTab, bWarn ) )
+ rScRanges.push_back( aScRange );
+ }
+}
+
+// String->EditEngine conversion ==============================================
+
+namespace {
+
+std::unique_ptr<EditTextObject> lclCreateTextObject( const XclImpRoot& rRoot,
+ const XclImpString& rString, XclFontItemType eType, sal_uInt16 nXFIndex )
+{
+ std::unique_ptr<EditTextObject> pTextObj;
+
+ const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
+ const XclImpFont* pFirstFont = rXFBuffer.GetFont( nXFIndex );
+ bool bFirstEscaped = pFirstFont && pFirstFont->HasEscapement();
+
+ if( rString.IsRich() || bFirstEscaped )
+ {
+ const XclImpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
+ const XclFormatRunVec& rFormats = rString.GetFormats();
+
+ ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
+ rEE.SetTextCurrentDefaults( rString.GetText() );
+
+ SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
+ if( bFirstEscaped )
+ rFontBuffer.FillToItemSet( aItemSet, eType, rXFBuffer.GetFontIndex( nXFIndex ) );
+ ESelection aSelection;
+
+ XclFormatRun aNextRun;
+ XclFormatRunVec::const_iterator aIt = rFormats.begin();
+ XclFormatRunVec::const_iterator aEnd = rFormats.end();
+
+ if( aIt != aEnd )
+ aNextRun = *aIt++;
+ else
+ aNextRun.mnChar = 0xFFFF;
+
+ sal_Int32 nLen = rString.GetText().getLength();
+ for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
+ {
+ // reached new different formatted text portion
+ if( nChar >= aNextRun.mnChar )
+ {
+ // send items to edit engine
+ rEE.QuickSetAttribs( aItemSet, aSelection );
+
+ // start new item set
+ aItemSet.ClearItem();
+ rFontBuffer.FillToItemSet( aItemSet, eType, aNextRun.mnFontIdx );
+
+ // read new formatting information
+ if( aIt != aEnd )
+ aNextRun = *aIt++;
+ else
+ aNextRun.mnChar = 0xFFFF;
+
+ // reset selection start to current position
+ aSelection.nStartPara = aSelection.nEndPara;
+ aSelection.nStartPos = aSelection.nEndPos;
+ }
+
+ // set end of selection to current position
+ if( rString.GetText()[ nChar ] == '\n' )
+ {
+ ++aSelection.nEndPara;
+ aSelection.nEndPos = 0;
+ }
+ else
+ ++aSelection.nEndPos;
+ }
+
+ // send items of last text portion to edit engine
+ rEE.QuickSetAttribs( aItemSet, aSelection );
+
+ pTextObj = rEE.CreateTextObject();
+ }
+
+ return pTextObj;
+}
+
+} // namespace
+
+std::unique_ptr<EditTextObject> XclImpStringHelper::CreateTextObject(
+ const XclImpRoot& rRoot, const XclImpString& rString )
+{
+ return lclCreateTextObject( rRoot, rString, XclFontItemType::Editeng, 0 );
+}
+
+void XclImpStringHelper::SetToDocument(
+ ScDocumentImport& rDoc, const ScAddress& rPos, const XclImpRoot& rRoot,
+ const XclImpString& rString, sal_uInt16 nXFIndex )
+{
+ if (rString.GetText().isEmpty())
+ return;
+
+ ::std::unique_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, XclFontItemType::Editeng, nXFIndex ) );
+
+ if (pTextObj)
+ {
+ rDoc.setEditCell(rPos, std::move(pTextObj));
+ }
+ else
+ {
+ const OUString& aStr = rString.GetText();
+ if (aStr.indexOf('\n') != -1 || aStr.indexOf('\r') != -1)
+ {
+ // Multiline content.
+ ScFieldEditEngine& rEngine = rDoc.getDoc().GetEditEngine();
+ rEngine.SetTextCurrentDefaults(aStr);
+ rDoc.setEditCell(rPos, rEngine.CreateTextObject());
+ }
+ else
+ {
+ // Normal text cell.
+ rDoc.setStringCell(rPos, aStr);
+ }
+ }
+}
+
+// Header/footer conversion ===================================================
+
+XclImpHFConverter::XclImpHFPortionInfo::XclImpHFPortionInfo() :
+ mnHeight( 0 ),
+ mnMaxLineHt( 0 )
+{
+ maSel.nStartPara = maSel.nEndPara = 0;
+ maSel.nStartPos = maSel.nEndPos = 0;
+}
+
+XclImpHFConverter::XclImpHFConverter( const XclImpRoot& rRoot ) :
+ XclImpRoot( rRoot ),
+ mrEE( rRoot.GetHFEditEngine() ),
+ mxFontData( new XclFontData ),
+ meCurrObj( EXC_HF_CENTER )
+{
+}
+
+XclImpHFConverter::~XclImpHFConverter()
+{
+}
+
+void XclImpHFConverter::ParseString( const OUString& rHFString )
+{
+ // edit engine objects
+ mrEE.SetText( OUString() );
+ maInfos.clear();
+ maInfos.resize( EXC_HF_PORTION_COUNT );
+ meCurrObj = EXC_HF_CENTER;
+
+ // parser temporaries
+ maCurrText.truncate();
+ OUStringBuffer aReadFont; // current font name
+ OUStringBuffer aReadStyle; // current font style
+ sal_uInt16 nReadHeight = 0; // current font height
+ ResetFontData();
+
+ /** State of the parser. */
+ enum XclHFParserState
+ {
+ xlPSText, /// Read text, search for functions.
+ xlPSFunc, /// Read function (token following a '&').
+ xlPSFont, /// Read font name ('&' is followed by '"', reads until next '"' or ',').
+ xlPSFontStyle, /// Read font style name (font part after ',', reads until next '"').
+ xlPSHeight /// Read font height ('&' is followed by num. digits, reads until non-digit).
+ } eState = xlPSText;
+
+ const sal_Unicode* pChar = rHFString.getStr();
+ const sal_Unicode* pNull = pChar + rHFString.getLength(); // pointer to terminating null char
+ while( *pChar )
+ {
+ switch( eState )
+ {
+
+// --- read text character ---
+
+ case xlPSText:
+ {
+ switch( *pChar )
+ {
+ case '&': // new command
+ InsertText();
+ eState = xlPSFunc;
+ break;
+ case '\n': // line break
+ InsertText();
+ InsertLineBreak();
+ break;
+ default:
+ maCurrText.append(OUStringChar(*pChar));
+ }
+ }
+ break;
+
+// --- read control sequence ---
+
+ case xlPSFunc:
+ {
+ eState = xlPSText;
+ switch( *pChar )
+ {
+ case '&': maCurrText.append("&"); break; // the '&' character
+
+ case 'L': SetNewPortion( EXC_HF_LEFT ); break; // Left portion
+ case 'C': SetNewPortion( EXC_HF_CENTER ); break; // Center portion
+ case 'R': SetNewPortion( EXC_HF_RIGHT ); break; // Right portion
+
+ case 'P': InsertField( SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ) ); break; // page
+ case 'N': InsertField( SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ) ); break; // page count
+ case 'D': InsertField( SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ) ); break; // date
+ case 'T': InsertField( SvxFieldItem( SvxTimeField(), EE_FEATURE_FIELD ) ); break; // time
+ case 'A': InsertField( SvxFieldItem( SvxTableField(), EE_FEATURE_FIELD ) ); break; // table name
+
+ case 'Z': // file path
+ InsertField( SvxFieldItem( SvxExtFileField(), EE_FEATURE_FIELD ) ); // convert to full name
+ if( (pNull - pChar >= 2) && (*(pChar + 1) == '&') && (*(pChar + 2) == 'F') )
+ {
+ // &Z&F found - ignore the &F part
+ pChar += 2;
+ }
+ break;
+ case 'F': // file name
+ InsertField( SvxFieldItem( SvxExtFileField( OUString(), SvxFileType::Var, SvxFileFormat::NameAndExt ), EE_FEATURE_FIELD ) );
+ break;
+
+ case 'U': // underline
+ SetAttribs();
+ mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_SINGLE) ?
+ EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_SINGLE;
+ break;
+ case 'E': // double underline
+ SetAttribs();
+ mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_DOUBLE) ?
+ EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_DOUBLE;
+ break;
+ case 'S': // strikeout
+ SetAttribs();
+ mxFontData->mbStrikeout = !mxFontData->mbStrikeout;
+ break;
+ case 'X': // superscript
+ SetAttribs();
+ mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUPER) ?
+ EXC_FONTESC_NONE : EXC_FONTESC_SUPER;
+ break;
+ case 'Y': // subscript
+ SetAttribs();
+ mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUB) ?
+ EXC_FONTESC_NONE : EXC_FONTESC_SUB;
+ break;
+
+ case '\"': // font name
+ aReadFont.setLength(0);
+ aReadStyle.setLength(0);
+ eState = xlPSFont;
+ break;
+ default:
+ if( ('0' <= *pChar) && (*pChar <= '9') ) // font size
+ {
+ nReadHeight = *pChar - '0';
+ eState = xlPSHeight;
+ }
+ }
+ }
+ break;
+
+// --- read font name ---
+
+ case xlPSFont:
+ {
+ switch( *pChar )
+ {
+ case '\"':
+ --pChar;
+ [[fallthrough]];
+ case ',':
+ eState = xlPSFontStyle;
+ break;
+ default:
+ aReadFont.append(*pChar);
+ }
+ }
+ break;
+
+// --- read font style ---
+
+ case xlPSFontStyle:
+ {
+ switch( *pChar )
+ {
+ case '\"':
+ SetAttribs();
+ if( !aReadFont.isEmpty() )
+ mxFontData->maName = aReadFont.toString();
+ mxFontData->maStyle = aReadStyle.toString();
+ eState = xlPSText;
+ break;
+ default:
+ aReadStyle.append(*pChar);
+ }
+ }
+ break;
+
+// --- read font height ---
+
+ case xlPSHeight:
+ {
+ if( ('0' <= *pChar) && (*pChar <= '9') )
+ {
+ if( nReadHeight != 0xFFFF )
+ {
+ nReadHeight *= 10;
+ nReadHeight += (*pChar - '0');
+ if( nReadHeight > 1600 ) // max 1600pt = 32000twips
+ nReadHeight = 0xFFFF;
+ }
+ }
+ else
+ {
+ if( (nReadHeight != 0) && (nReadHeight != 0xFFFF) )
+ {
+ SetAttribs();
+ mxFontData->mnHeight = nReadHeight * 20;
+ }
+ --pChar;
+ eState = xlPSText;
+ }
+ }
+ break;
+ }
+ ++pChar;
+ }
+
+ // finalize
+ CreateCurrObject();
+ maInfos[ EXC_HF_LEFT ].mnHeight += GetMaxLineHeight( EXC_HF_LEFT );
+ maInfos[ EXC_HF_CENTER ].mnHeight += GetMaxLineHeight( EXC_HF_CENTER );
+ maInfos[ EXC_HF_RIGHT ].mnHeight += GetMaxLineHeight( EXC_HF_RIGHT );
+}
+
+void XclImpHFConverter::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nWhichId ) const
+{
+ ScPageHFItem aHFItem( nWhichId );
+ if( maInfos[ EXC_HF_LEFT ].mxObj )
+ aHFItem.SetLeftArea( *maInfos[ EXC_HF_LEFT ].mxObj );
+ if( maInfos[ EXC_HF_CENTER ].mxObj )
+ aHFItem.SetCenterArea( *maInfos[ EXC_HF_CENTER ].mxObj );
+ if( maInfos[ EXC_HF_RIGHT ].mxObj )
+ aHFItem.SetRightArea( *maInfos[ EXC_HF_RIGHT ].mxObj );
+ rItemSet.Put( aHFItem );
+}
+
+sal_Int32 XclImpHFConverter::GetTotalHeight() const
+{
+ return ::std::max( maInfos[ EXC_HF_LEFT ].mnHeight,
+ ::std::max( maInfos[ EXC_HF_CENTER ].mnHeight, maInfos[ EXC_HF_RIGHT ].mnHeight ) );
+}
+
+// private --------------------------------------------------------------------
+
+sal_uInt16 XclImpHFConverter::GetMaxLineHeight( XclImpHFPortion ePortion ) const
+{
+ sal_uInt16 nMaxHt = maInfos[ ePortion ].mnMaxLineHt;
+ return (nMaxHt == 0) ? mxFontData->mnHeight : nMaxHt;
+}
+
+void XclImpHFConverter::UpdateMaxLineHeight( XclImpHFPortion ePortion )
+{
+ sal_uInt16& rnMaxHt = maInfos[ ePortion ].mnMaxLineHt;
+ rnMaxHt = ::std::max( rnMaxHt, mxFontData->mnHeight );
+}
+
+void XclImpHFConverter::UpdateCurrMaxLineHeight()
+{
+ UpdateMaxLineHeight( meCurrObj );
+}
+
+void XclImpHFConverter::SetAttribs()
+{
+ ESelection& rSel = GetCurrSel();
+ if( (rSel.nStartPara != rSel.nEndPara) || (rSel.nStartPos != rSel.nEndPos) )
+ {
+ SfxItemSet aItemSet( mrEE.GetEmptyItemSet() );
+ XclImpFont aFont( GetRoot(), *mxFontData );
+ aFont.FillToItemSet( aItemSet, XclFontItemType::HeaderFooter );
+ mrEE.QuickSetAttribs( aItemSet, rSel );
+ rSel.nStartPara = rSel.nEndPara;
+ rSel.nStartPos = rSel.nEndPos;
+ }
+}
+
+void XclImpHFConverter::ResetFontData()
+{
+ if( const XclImpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
+ *mxFontData = pFirstFont->GetFontData();
+ else
+ {
+ mxFontData->Clear();
+ mxFontData->mnHeight = 200;
+ }
+}
+
+void XclImpHFConverter::InsertText()
+{
+ if( !maCurrText.isEmpty() )
+ {
+ ESelection& rSel = GetCurrSel();
+ OUString sString(maCurrText.makeStringAndClear());
+ mrEE.QuickInsertText( sString, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ rSel.nEndPos = rSel.nEndPos + sString.getLength();
+ UpdateCurrMaxLineHeight();
+ }
+}
+
+void XclImpHFConverter::InsertField( const SvxFieldItem& rFieldItem )
+{
+ ESelection& rSel = GetCurrSel();
+ mrEE.QuickInsertField( rFieldItem, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ ++rSel.nEndPos;
+ UpdateCurrMaxLineHeight();
+}
+
+void XclImpHFConverter::InsertLineBreak()
+{
+ ESelection& rSel = GetCurrSel();
+ mrEE.QuickInsertText( OUString('\n'), ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
+ ++rSel.nEndPara;
+ rSel.nEndPos = 0;
+ GetCurrInfo().mnHeight += GetMaxLineHeight( meCurrObj );
+ GetCurrInfo().mnMaxLineHt = 0;
+}
+
+void XclImpHFConverter::CreateCurrObject()
+{
+ InsertText();
+ SetAttribs();
+ GetCurrObj() = mrEE.CreateTextObject();
+}
+
+void XclImpHFConverter::SetNewPortion( XclImpHFPortion eNew )
+{
+ if( eNew != meCurrObj )
+ {
+ CreateCurrObject();
+ meCurrObj = eNew;
+ if( GetCurrObj() )
+ mrEE.SetText( *GetCurrObj() );
+ else
+ mrEE.SetText( OUString() );
+ ResetFontData();
+ }
+}
+
+// URL conversion =============================================================
+
+namespace {
+
+void lclAppendUrlChar( OUString& rUrl, sal_Unicode cChar )
+{
+ // encode special characters
+ switch( cChar )
+ {
+ case '#': rUrl += "%23"; break;
+ case '%': rUrl += "%25"; break;
+ default: rUrl += OUStringChar( cChar );
+ }
+}
+
+} // namespace
+
+void XclImpUrlHelper::DecodeUrl(
+ OUString& rUrl, OUString& rTabName, bool& rbSameWb,
+ const XclImpRoot& rRoot, const OUString& rEncodedUrl )
+{
+ enum
+ {
+ xlUrlInit, /// Initial state, read string mode character.
+ xlUrlPath, /// Read URL path.
+ xlUrlFileName, /// Read file name.
+ xlUrlSheetName, /// Read sheet name.
+ xlUrlRaw /// Raw mode. No control characters will occur.
+ } eState = xlUrlInit;
+
+ bool bEncoded = true;
+ rbSameWb = false;
+
+ sal_Unicode cCurrDrive = 0;
+ OUString aDosBase( INetURLObject( rRoot.GetBasePath() ).getFSysPath( FSysStyle::Dos ) );
+ if (!aDosBase.isEmpty() && aDosBase.match(":\\", 1))
+ cCurrDrive = aDosBase[0];
+
+ const sal_Unicode* pChar = rEncodedUrl.getStr();
+ while( *pChar )
+ {
+ switch( eState )
+ {
+
+// --- first character ---
+
+ case xlUrlInit:
+ {
+ switch( *pChar )
+ {
+ case EXC_URLSTART_ENCODED:
+ eState = xlUrlPath;
+ break;
+ case EXC_URLSTART_SELF:
+ case EXC_URLSTART_SELFENCODED:
+ rbSameWb = true;
+ eState = xlUrlSheetName;
+ break;
+ case '[':
+ bEncoded = false;
+ eState = xlUrlFileName;
+ break;
+ default:
+ bEncoded = false;
+ lclAppendUrlChar( rUrl, *pChar );
+ eState = xlUrlPath;
+ }
+ }
+ break;
+
+// --- URL path ---
+
+ case xlUrlPath:
+ {
+ switch( *pChar )
+ {
+ case EXC_URL_DOSDRIVE:
+ {
+ if( *(pChar + 1) )
+ {
+ ++pChar;
+ if( *pChar == '@' )
+ rUrl += "\\\\";
+ else
+ {
+ lclAppendUrlChar( rUrl, *pChar );
+ rUrl += ":\\";
+ }
+ }
+ else
+ rUrl += "<NULL-DRIVE!>";
+ }
+ break;
+ case EXC_URL_DRIVEROOT:
+ if( cCurrDrive )
+ {
+ lclAppendUrlChar( rUrl, cCurrDrive );
+ rUrl += ":";
+ }
+ [[fallthrough]];
+ case EXC_URL_SUBDIR:
+ if( bEncoded )
+ rUrl += "\\";
+ else // control character in raw name -> DDE link
+ {
+ rUrl += OUStringChar(EXC_DDE_DELIM);
+ eState = xlUrlRaw;
+ }
+ break;
+ case EXC_URL_PARENTDIR:
+ rUrl += "..\\";
+ break;
+ case EXC_URL_RAW:
+ {
+ if( *(pChar + 1) )
+ {
+ sal_Int32 nLen = *++pChar;
+ for( sal_Int32 nChar = 0; (nChar < nLen) && *(pChar + 1); ++nChar )
+ lclAppendUrlChar( rUrl, *++pChar );
+// rUrl.Append( ':' );
+ }
+ }
+ break;
+ case '[':
+ eState = xlUrlFileName;
+ break;
+ default:
+ lclAppendUrlChar( rUrl, *pChar );
+ }
+ }
+ break;
+
+// --- file name ---
+
+ case xlUrlFileName:
+ {
+ switch( *pChar )
+ {
+ case ']': eState = xlUrlSheetName; break;
+ default: lclAppendUrlChar( rUrl, *pChar );
+ }
+ }
+ break;
+
+// --- sheet name ---
+
+ case xlUrlSheetName:
+ rTabName += OUStringChar( *pChar );
+ break;
+
+// --- raw read mode ---
+
+ case xlUrlRaw:
+ lclAppendUrlChar( rUrl, *pChar );
+ break;
+ }
+
+ ++pChar;
+ }
+}
+
+void XclImpUrlHelper::DecodeUrl(
+ OUString& rUrl, bool& rbSameWb, const XclImpRoot& rRoot, const OUString& rEncodedUrl )
+{
+ OUString aTabName;
+ OUString aUrl;
+ DecodeUrl( aUrl, aTabName, rbSameWb, rRoot, rEncodedUrl );
+ rUrl = aUrl;
+ OSL_ENSURE( aTabName.isEmpty(), "XclImpUrlHelper::DecodeUrl - sheet name ignored" );
+}
+
+bool XclImpUrlHelper::DecodeLink( OUString& rApplic, OUString& rTopic, const OUString& rEncUrl )
+{
+ sal_Int32 nPos = rEncUrl.indexOf( EXC_DDE_DELIM );
+ if( (nPos > 0) && (nPos + 1 < rEncUrl.getLength()) )
+ {
+ rApplic = rEncUrl.copy( 0, nPos );
+ rTopic = rEncUrl.copy( nPos + 1 );
+ return true;
+ }
+ return false;
+}
+
+// Cached Values ==============================================================
+
+XclImpCachedValue::XclImpCachedValue( XclImpStream& rStrm ) :
+ mfValue( 0.0 ),
+ mnBoolErr( 0 )
+{
+ mnType = rStrm.ReaduInt8();
+ switch( mnType )
+ {
+ case EXC_CACHEDVAL_EMPTY:
+ rStrm.Ignore( 8 );
+ break;
+ case EXC_CACHEDVAL_DOUBLE:
+ mfValue = rStrm.ReadDouble();
+ break;
+ case EXC_CACHEDVAL_STRING:
+ maStr = rStrm.ReadUniString();
+ break;
+ case EXC_CACHEDVAL_BOOL:
+ case EXC_CACHEDVAL_ERROR:
+ {
+ double fVal;
+ mnBoolErr = rStrm.ReaduInt8();
+ rStrm.Ignore( 7 );
+
+ std::unique_ptr<ScTokenArray> pScTokArr = rStrm.GetRoot().GetOldFmlaConverter().GetBoolErr(
+ XclTools::ErrorToEnum( fVal, mnType == EXC_CACHEDVAL_ERROR, mnBoolErr ) );
+ if( pScTokArr )
+ mxTokArr = std::move( pScTokArr );
+ }
+ break;
+ default:
+ OSL_FAIL( "XclImpCachedValue::XclImpCachedValue - unknown data type" );
+ }
+}
+
+XclImpCachedValue::~XclImpCachedValue()
+{
+}
+
+FormulaError XclImpCachedValue::GetScError() const
+{
+ return (mnType == EXC_CACHEDVAL_ERROR) ? XclTools::GetScErrorCode( mnBoolErr ) : FormulaError::NONE;
+}
+
+// Matrix Cached Values ==============================================================
+
+XclImpCachedMatrix::XclImpCachedMatrix( XclImpStream& rStrm ) :
+ mnScCols( 0 ),
+ mnScRows( 0 )
+{
+ mnScCols = rStrm.ReaduInt8();
+ mnScRows = rStrm.ReaduInt16();
+
+ if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
+ {
+ // in BIFF2-BIFF7: 256 columns represented by 0 columns
+ if( mnScCols == 0 )
+ mnScCols = 256;
+ }
+ else
+ {
+ // in BIFF8: columns and rows decreased by 1
+ ++mnScCols;
+ ++mnScRows;
+ }
+
+ //assuming worst case scenario of unknown types
+ const size_t nMinRecordSize = 1;
+ const size_t nMaxRows = rStrm.GetRecLeft() / (nMinRecordSize * mnScCols);
+ if (mnScRows > nMaxRows)
+ {
+ SAL_WARN("sc", "Parsing error: " << nMaxRows <<
+ " max possible rows, but " << mnScRows << " claimed, truncating");
+ mnScRows = nMaxRows;
+ }
+
+ for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
+ for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
+ maValueList.push_back( std::make_unique<XclImpCachedValue>( rStrm ) );
+}
+
+XclImpCachedMatrix::~XclImpCachedMatrix()
+{
+}
+
+ScMatrixRef XclImpCachedMatrix::CreateScMatrix( svl::SharedStringPool& rPool ) const
+{
+ ScMatrixRef xScMatrix;
+ OSL_ENSURE( mnScCols * mnScRows == maValueList.size(), "XclImpCachedMatrix::CreateScMatrix - element count mismatch" );
+ if( mnScCols && mnScRows && static_cast< sal_uLong >( mnScCols * mnScRows ) <= maValueList.size() )
+ {
+ xScMatrix = new ScMatrix(mnScCols, mnScRows, 0.0);
+ XclImpValueList::const_iterator itValue = maValueList.begin();
+ for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
+ {
+ for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
+ {
+ switch( (*itValue)->GetType() )
+ {
+ case EXC_CACHEDVAL_EMPTY:
+ // Excel shows 0.0 here, not an empty cell
+ xScMatrix->PutEmpty( nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_DOUBLE:
+ xScMatrix->PutDouble( (*itValue)->GetValue(), nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_STRING:
+ xScMatrix->PutString(rPool.intern((*itValue)->GetString()), nScCol, nScRow);
+ break;
+ case EXC_CACHEDVAL_BOOL:
+ xScMatrix->PutBoolean( (*itValue)->GetBool(), nScCol, nScRow );
+ break;
+ case EXC_CACHEDVAL_ERROR:
+ xScMatrix->PutError( (*itValue)->GetScError(), nScCol, nScRow );
+ break;
+ default:
+ OSL_FAIL( "XclImpCachedMatrix::CreateScMatrix - unknown value type" );
+ xScMatrix->PutEmpty( nScCol, nScRow );
+ }
+ ++itValue;
+ }
+ }
+ }
+ return xScMatrix;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */