Version 5.2.6.1, tag libreoffice-5.2.6.1
[LibreOffice.git] / sc / source / filter / excel / xihelper.cxx
blob6a9c78c00a0f0def806e93f6aaf8fd2649ad6aa9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "xihelper.hxx"
21 #include <svl/itemset.hxx>
22 #include <svl/sharedstringpool.hxx>
23 #include <editeng/editobj.hxx>
24 #include <tools/urlobj.hxx>
25 #include "scitems.hxx"
26 #include <editeng/eeitem.hxx>
27 #include <editeng/flditem.hxx>
28 #include "document.hxx"
29 #include "rangelst.hxx"
30 #include "editutil.hxx"
31 #include "attrib.hxx"
32 #include "xltracer.hxx"
33 #include "xistream.hxx"
34 #include "xistyle.hxx"
35 #include "excform.hxx"
36 #include "stringutil.hxx"
37 #include "scmatrix.hxx"
38 #include "documentimport.hxx"
39 #include <o3tl/make_unique.hxx>
41 // Excel->Calc cell address/range conversion ==================================
43 namespace {
45 /** Fills the passed Calc address with the passed Excel cell coordinates without checking any limits. */
46 inline void lclFillAddress( ScAddress& rScPos, sal_uInt16 nXclCol, sal_uInt32 nXclRow, SCTAB nScTab )
48 rScPos.SetCol( static_cast< SCCOL >( nXclCol ) );
49 rScPos.SetRow( static_cast< SCROW >( nXclRow ) );
50 rScPos.SetTab( nScTab );
53 } // namespace
55 XclImpAddressConverter::XclImpAddressConverter( const XclImpRoot& rRoot ) :
56 XclAddressConverterBase( rRoot.GetTracer(), rRoot.GetScMaxPos() )
60 // cell address ---------------------------------------------------------------
62 bool XclImpAddressConverter::CheckAddress( const XclAddress& rXclPos, bool bWarn )
64 bool bValidCol = rXclPos.mnCol <= mnMaxCol;
65 bool bValidRow = rXclPos.mnRow <= mnMaxRow;
66 bool bValid = bValidCol && bValidRow;
67 if( !bValid && bWarn )
69 mbColTrunc |= !bValidCol;
70 mbRowTrunc |= !bValidRow;
71 mrTracer.TraceInvalidAddress( ScAddress(
72 static_cast< SCCOL >( rXclPos.mnCol ), static_cast< SCROW >( rXclPos.mnRow ), 0 ), maMaxPos );
74 return bValid;
77 bool XclImpAddressConverter::ConvertAddress( ScAddress& rScPos,
78 const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
80 bool bValid = CheckAddress( rXclPos, bWarn );
81 if( bValid )
82 lclFillAddress( rScPos, rXclPos.mnCol, rXclPos.mnRow, nScTab );
83 return bValid;
86 ScAddress XclImpAddressConverter::CreateValidAddress(
87 const XclAddress& rXclPos, SCTAB nScTab, bool bWarn )
89 ScAddress aScPos( ScAddress::UNINITIALIZED );
90 if( !ConvertAddress( aScPos, rXclPos, nScTab, bWarn ) )
92 aScPos.SetCol( static_cast< SCCOL >( ::std::min( rXclPos.mnCol, mnMaxCol ) ) );
93 aScPos.SetRow( static_cast< SCROW >( ::std::min( rXclPos.mnRow, mnMaxRow ) ) );
94 aScPos.SetTab( limit_cast< SCTAB >( nScTab, 0, maMaxPos.Tab() ) );
96 return aScPos;
99 // cell range -----------------------------------------------------------------
101 bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
102 const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
104 // check start position
105 bool bValidStart = CheckAddress( rXclRange.maFirst, bWarn );
106 if( bValidStart )
108 lclFillAddress( rScRange.aStart, rXclRange.maFirst.mnCol, rXclRange.maFirst.mnRow, nScTab1 );
110 // check & correct end position
111 sal_uInt16 nXclCol2 = rXclRange.maLast.mnCol;
112 sal_uInt32 nXclRow2 = rXclRange.maLast.mnRow;
113 if( !CheckAddress( rXclRange.maLast, bWarn ) )
115 nXclCol2 = ::std::min( nXclCol2, mnMaxCol );
116 nXclRow2 = ::std::min( nXclRow2, mnMaxRow );
118 lclFillAddress( rScRange.aEnd, nXclCol2, nXclRow2, nScTab2 );
120 return bValidStart;
123 // cell range list ------------------------------------------------------------
125 void XclImpAddressConverter::ConvertRangeList( ScRangeList& rScRanges,
126 const XclRangeList& rXclRanges, SCTAB nScTab, bool bWarn )
128 rScRanges.RemoveAll();
129 for( XclRangeVector::const_iterator aIt = rXclRanges.begin(), aEnd = rXclRanges.end(); aIt != aEnd; ++aIt )
131 ScRange aScRange( ScAddress::UNINITIALIZED );
132 if( ConvertRange( aScRange, *aIt, nScTab, nScTab, bWarn ) )
133 rScRanges.Append( aScRange );
137 // String->EditEngine conversion ==============================================
139 namespace {
141 EditTextObject* lclCreateTextObject( const XclImpRoot& rRoot,
142 const XclImpString& rString, XclFontItemType eType, sal_uInt16 nXFIndex )
144 EditTextObject* pTextObj = nullptr;
146 const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
147 const XclImpFont* pFirstFont = rXFBuffer.GetFont( nXFIndex );
148 bool bFirstEscaped = pFirstFont && pFirstFont->HasEscapement();
150 if( rString.IsRich() || bFirstEscaped )
152 const XclImpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
153 const XclFormatRunVec& rFormats = rString.GetFormats();
155 ScEditEngineDefaulter& rEE = (eType == EXC_FONTITEM_NOTE) ?
156 static_cast< ScEditEngineDefaulter& >( rRoot.GetDoc().GetNoteEngine() ) : rRoot.GetEditEngine();
157 rEE.SetText( rString.GetText() );
159 SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
160 if( bFirstEscaped )
161 rFontBuffer.FillToItemSet( aItemSet, eType, rXFBuffer.GetFontIndex( nXFIndex ) );
162 ESelection aSelection;
164 XclFormatRun aNextRun;
165 XclFormatRunVec::const_iterator aIt = rFormats.begin();
166 XclFormatRunVec::const_iterator aEnd = rFormats.end();
168 if( aIt != aEnd )
169 aNextRun = *aIt++;
170 else
171 aNextRun.mnChar = 0xFFFF;
173 sal_Int32 nLen = rString.GetText().getLength();
174 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
176 // reached new different formatted text portion
177 if( nChar >= aNextRun.mnChar )
179 // send items to edit engine
180 rEE.QuickSetAttribs( aItemSet, aSelection );
182 // start new item set
183 aItemSet.ClearItem();
184 rFontBuffer.FillToItemSet( aItemSet, eType, aNextRun.mnFontIdx );
186 // read new formatting information
187 if( aIt != aEnd )
188 aNextRun = *aIt++;
189 else
190 aNextRun.mnChar = 0xFFFF;
192 // reset selection start to current position
193 aSelection.nStartPara = aSelection.nEndPara;
194 aSelection.nStartPos = aSelection.nEndPos;
197 // set end of selection to current position
198 if( rString.GetText()[ nChar ] == '\n' )
200 ++aSelection.nEndPara;
201 aSelection.nEndPos = 0;
203 else
204 ++aSelection.nEndPos;
207 // send items of last text portion to edit engine
208 rEE.QuickSetAttribs( aItemSet, aSelection );
210 pTextObj = rEE.CreateTextObject();
213 return pTextObj;
216 } // namespace
218 EditTextObject* XclImpStringHelper::CreateTextObject(
219 const XclImpRoot& rRoot, const XclImpString& rString )
221 return lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, 0 );
224 void XclImpStringHelper::SetToDocument(
225 ScDocumentImport& rDoc, const ScAddress& rPos, const XclImpRoot& rRoot,
226 const XclImpString& rString, sal_uInt16 nXFIndex )
228 if (rString.GetText().isEmpty())
229 return;
231 ::std::unique_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, EXC_FONTITEM_EDITENG, nXFIndex ) );
233 if (pTextObj.get())
235 rDoc.setEditCell(rPos, pTextObj.release());
237 else
239 const OUString& aStr = rString.GetText();
240 if (aStr.indexOf('\n') != -1 || aStr.indexOf(CHAR_CR) != -1)
242 // Multiline content.
243 ScFieldEditEngine& rEngine = rDoc.getDoc().GetEditEngine();
244 rEngine.SetText(aStr);
245 rDoc.setEditCell(rPos, rEngine.CreateTextObject());
247 else
249 // Normal text cell.
250 rDoc.setStringCell(rPos, aStr);
255 // Header/footer conversion ===================================================
257 XclImpHFConverter::XclImpHFPortionInfo::XclImpHFPortionInfo() :
258 mnHeight( 0 ),
259 mnMaxLineHt( 0 )
261 maSel.nStartPara = maSel.nEndPara = 0;
262 maSel.nStartPos = maSel.nEndPos = 0;
265 XclImpHFConverter::XclImpHFConverter( const XclImpRoot& rRoot ) :
266 XclImpRoot( rRoot ),
267 mrEE( rRoot.GetHFEditEngine() ),
268 mxFontData( new XclFontData ),
269 meCurrObj( EXC_HF_CENTER )
273 XclImpHFConverter::~XclImpHFConverter()
277 void XclImpHFConverter::ParseString( const OUString& rHFString )
279 // edit engine objects
280 mrEE.SetText( EMPTY_OUSTRING );
281 maInfos.clear();
282 maInfos.resize( EXC_HF_PORTION_COUNT );
283 meCurrObj = EXC_HF_CENTER;
285 // parser temporaries
286 maCurrText.clear();
287 OUString aReadFont; // current font name
288 OUString aReadStyle; // current font style
289 sal_uInt16 nReadHeight = 0; // current font height
290 ResetFontData();
292 /** State of the parser. */
293 enum XclHFParserState
295 xlPSText, /// Read text, search for functions.
296 xlPSFunc, /// Read function (token following a '&').
297 xlPSFont, /// Read font name ('&' is followed by '"', reads until next '"' or ',').
298 xlPSFontStyle, /// Read font style name (font part after ',', reads until next '"').
299 xlPSHeight /// Read font height ('&' is followed by num. digits, reads until non-digit).
300 } eState = xlPSText;
302 const sal_Unicode* pChar = rHFString.getStr();
303 const sal_Unicode* pNull = pChar + rHFString.getLength(); // pointer to teminating null char
304 while( *pChar )
306 switch( eState )
309 // --- read text character ---
311 case xlPSText:
313 switch( *pChar )
315 case '&': // new command
316 InsertText();
317 eState = xlPSFunc;
318 break;
319 case '\n': // line break
320 InsertText();
321 InsertLineBreak();
322 break;
323 default:
324 maCurrText += OUString(*pChar);
327 break;
329 // --- read control sequence ---
331 case xlPSFunc:
333 eState = xlPSText;
334 switch( *pChar )
336 case '&': maCurrText += "&"; break; // the '&' character
338 case 'L': SetNewPortion( EXC_HF_LEFT ); break; // Left portion
339 case 'C': SetNewPortion( EXC_HF_CENTER ); break; // Center portion
340 case 'R': SetNewPortion( EXC_HF_RIGHT ); break; // Right portion
342 case 'P': InsertField( SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ) ); break; // page
343 case 'N': InsertField( SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ) ); break; // page count
344 case 'D': InsertField( SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ) ); break; // date
345 case 'T': InsertField( SvxFieldItem( SvxTimeField(), EE_FEATURE_FIELD ) ); break; // time
346 case 'A': InsertField( SvxFieldItem( SvxTableField(), EE_FEATURE_FIELD ) ); break; // table name
348 case 'Z': // file path
349 InsertField( SvxFieldItem( SvxExtFileField(), EE_FEATURE_FIELD ) ); // convert to full name
350 if( (pNull - pChar >= 2) && (*(pChar + 1) == '&') && (*(pChar + 2) == 'F') )
352 // &Z&F found - ignore the &F part
353 pChar += 2;
355 break;
356 case 'F': // file name
357 InsertField( SvxFieldItem( SvxExtFileField( EMPTY_OUSTRING, SVXFILETYPE_VAR, SVXFILEFORMAT_NAME_EXT ), EE_FEATURE_FIELD ) );
358 break;
360 case 'U': // underline
361 SetAttribs();
362 mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_SINGLE) ?
363 EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_SINGLE;
364 break;
365 case 'E': // double underline
366 SetAttribs();
367 mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_DOUBLE) ?
368 EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_DOUBLE;
369 break;
370 case 'S': // strikeout
371 SetAttribs();
372 mxFontData->mbStrikeout = !mxFontData->mbStrikeout;
373 break;
374 case 'X': // superscript
375 SetAttribs();
376 mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUPER) ?
377 EXC_FONTESC_NONE : EXC_FONTESC_SUPER;
378 break;
379 case 'Y': // subsrcipt
380 SetAttribs();
381 mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUB) ?
382 EXC_FONTESC_NONE : EXC_FONTESC_SUB;
383 break;
385 case '\"': // font name
386 aReadFont.clear();
387 aReadStyle.clear();
388 eState = xlPSFont;
389 break;
390 default:
391 if( ('0' <= *pChar) && (*pChar <= '9') ) // font size
393 nReadHeight = *pChar - '0';
394 eState = xlPSHeight;
398 break;
400 // --- read font name ---
402 case xlPSFont:
404 switch( *pChar )
406 case '\"':
407 --pChar;
408 SAL_FALLTHROUGH;
409 case ',':
410 eState = xlPSFontStyle;
411 break;
412 default:
413 aReadFont += OUString(*pChar);
416 break;
418 // --- read font style ---
420 case xlPSFontStyle:
422 switch( *pChar )
424 case '\"':
425 SetAttribs();
426 if( !aReadFont.isEmpty() )
427 mxFontData->maName = aReadFont;
428 mxFontData->maStyle = aReadStyle;
429 eState = xlPSText;
430 break;
431 default:
432 aReadStyle += OUString(*pChar);
435 break;
437 // --- read font height ---
439 case xlPSHeight:
441 if( ('0' <= *pChar) && (*pChar <= '9') )
443 if( nReadHeight != 0xFFFF )
445 nReadHeight *= 10;
446 nReadHeight += (*pChar - '0');
447 if( nReadHeight > 1600 ) // max 1600pt = 32000twips
448 nReadHeight = 0xFFFF;
451 else
453 if( (nReadHeight != 0) && (nReadHeight != 0xFFFF) )
455 SetAttribs();
456 mxFontData->mnHeight = nReadHeight * 20;
458 --pChar;
459 eState = xlPSText;
462 break;
464 ++pChar;
467 // finalize
468 CreateCurrObject();
469 maInfos[ EXC_HF_LEFT ].mnHeight += GetMaxLineHeight( EXC_HF_LEFT );
470 maInfos[ EXC_HF_CENTER ].mnHeight += GetMaxLineHeight( EXC_HF_CENTER );
471 maInfos[ EXC_HF_RIGHT ].mnHeight += GetMaxLineHeight( EXC_HF_RIGHT );
474 void XclImpHFConverter::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nWhichId ) const
476 ScPageHFItem aHFItem( nWhichId );
477 if( maInfos[ EXC_HF_LEFT ].mxObj.get() )
478 aHFItem.SetLeftArea( *maInfos[ EXC_HF_LEFT ].mxObj );
479 if( maInfos[ EXC_HF_CENTER ].mxObj.get() )
480 aHFItem.SetCenterArea( *maInfos[ EXC_HF_CENTER ].mxObj );
481 if( maInfos[ EXC_HF_RIGHT ].mxObj.get() )
482 aHFItem.SetRightArea( *maInfos[ EXC_HF_RIGHT ].mxObj );
483 rItemSet.Put( aHFItem );
486 sal_Int32 XclImpHFConverter::GetTotalHeight() const
488 return ::std::max( maInfos[ EXC_HF_LEFT ].mnHeight,
489 ::std::max( maInfos[ EXC_HF_CENTER ].mnHeight, maInfos[ EXC_HF_RIGHT ].mnHeight ) );
492 // private --------------------------------------------------------------------
494 sal_uInt16 XclImpHFConverter::GetMaxLineHeight( XclImpHFPortion ePortion ) const
496 sal_uInt16 nMaxHt = maInfos[ ePortion ].mnMaxLineHt;
497 return (nMaxHt == 0) ? mxFontData->mnHeight : nMaxHt;
500 sal_uInt16 XclImpHFConverter::GetCurrMaxLineHeight() const
502 return GetMaxLineHeight( meCurrObj );
505 void XclImpHFConverter::UpdateMaxLineHeight( XclImpHFPortion ePortion )
507 sal_uInt16& rnMaxHt = maInfos[ ePortion ].mnMaxLineHt;
508 rnMaxHt = ::std::max( rnMaxHt, mxFontData->mnHeight );
511 void XclImpHFConverter::UpdateCurrMaxLineHeight()
513 UpdateMaxLineHeight( meCurrObj );
516 void XclImpHFConverter::SetAttribs()
518 ESelection& rSel = GetCurrSel();
519 if( (rSel.nStartPara != rSel.nEndPara) || (rSel.nStartPos != rSel.nEndPos) )
521 SfxItemSet aItemSet( mrEE.GetEmptyItemSet() );
522 XclImpFont aFont( GetRoot(), *mxFontData );
523 aFont.FillToItemSet( aItemSet, EXC_FONTITEM_HF );
524 mrEE.QuickSetAttribs( aItemSet, rSel );
525 rSel.nStartPara = rSel.nEndPara;
526 rSel.nStartPos = rSel.nEndPos;
530 void XclImpHFConverter::ResetFontData()
532 if( const XclImpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
533 *mxFontData = pFirstFont->GetFontData();
534 else
536 mxFontData->Clear();
537 mxFontData->mnHeight = 200;
541 void XclImpHFConverter::InsertText()
543 if( !maCurrText.isEmpty() )
545 ESelection& rSel = GetCurrSel();
546 mrEE.QuickInsertText( maCurrText, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
547 rSel.nEndPos = rSel.nEndPos + maCurrText.getLength();
548 maCurrText.clear();
549 UpdateCurrMaxLineHeight();
553 void XclImpHFConverter::InsertField( const SvxFieldItem& rFieldItem )
555 ESelection& rSel = GetCurrSel();
556 mrEE.QuickInsertField( rFieldItem, ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
557 ++rSel.nEndPos;
558 UpdateCurrMaxLineHeight();
561 void XclImpHFConverter::InsertLineBreak()
563 ESelection& rSel = GetCurrSel();
564 mrEE.QuickInsertText( OUString('\n'), ESelection( rSel.nEndPara, rSel.nEndPos, rSel.nEndPara, rSel.nEndPos ) );
565 ++rSel.nEndPara;
566 rSel.nEndPos = 0;
567 GetCurrInfo().mnHeight += GetCurrMaxLineHeight();
568 GetCurrInfo().mnMaxLineHt = 0;
571 void XclImpHFConverter::CreateCurrObject()
573 InsertText();
574 SetAttribs();
575 GetCurrObj().reset( mrEE.CreateTextObject() );
578 void XclImpHFConverter::SetNewPortion( XclImpHFPortion eNew )
580 if( eNew != meCurrObj )
582 CreateCurrObject();
583 meCurrObj = eNew;
584 if( GetCurrObj().get() )
585 mrEE.SetText( *GetCurrObj() );
586 else
587 mrEE.SetText( EMPTY_OUSTRING );
588 ResetFontData();
592 // URL conversion =============================================================
594 namespace {
596 void lclAppendUrlChar( OUString& rUrl, sal_Unicode cChar )
598 // encode special characters
599 switch( cChar )
601 case '#': rUrl += "%23"; break;
602 case '%': rUrl += "%25"; break;
603 default: rUrl += OUString( cChar );
607 } // namespace
609 void XclImpUrlHelper::DecodeUrl(
610 OUString& rUrl, OUString& rTabName, bool& rbSameWb,
611 const XclImpRoot& rRoot, const OUString& rEncodedUrl )
613 enum
615 xlUrlInit, /// Initial state, read string mode character.
616 xlUrlPath, /// Read URL path.
617 xlUrlFileName, /// Read file name.
618 xlUrlSheetName, /// Read sheet name.
619 xlUrlRaw /// Raw mode. No control characters will occur.
620 } eState = xlUrlInit;
622 bool bEncoded = true;
623 rbSameWb = false;
625 sal_Unicode cCurrDrive = 0;
626 OUString aDosBase( INetURLObject( rRoot.GetBasePath() ).getFSysPath( INetURLObject::FSYS_DOS ) );
627 if (!aDosBase.isEmpty() && aDosBase.match(":\\", 1))
628 cCurrDrive = aDosBase[0];
630 const sal_Unicode* pChar = rEncodedUrl.getStr();
631 while( *pChar )
633 switch( eState )
636 // --- first character ---
638 case xlUrlInit:
640 switch( *pChar )
642 case EXC_URLSTART_ENCODED:
643 eState = xlUrlPath;
644 break;
645 case EXC_URLSTART_SELF:
646 case EXC_URLSTART_SELFENCODED:
647 rbSameWb = true;
648 eState = xlUrlSheetName;
649 break;
650 case '[':
651 bEncoded = false;
652 eState = xlUrlFileName;
653 break;
654 default:
655 bEncoded = false;
656 lclAppendUrlChar( rUrl, *pChar );
657 eState = xlUrlPath;
660 break;
662 // --- URL path ---
664 case xlUrlPath:
666 switch( *pChar )
668 case EXC_URL_DOSDRIVE:
670 if( *(pChar + 1) )
672 ++pChar;
673 if( *pChar == '@' )
674 rUrl += "\\\\";
675 else
677 lclAppendUrlChar( rUrl, *pChar );
678 rUrl += ":\\";
681 else
682 rUrl += "<NULL-DRIVE!>";
684 break;
685 case EXC_URL_DRIVEROOT:
686 if( cCurrDrive )
688 lclAppendUrlChar( rUrl, cCurrDrive );
689 rUrl += ":";
691 SAL_FALLTHROUGH;
692 case EXC_URL_SUBDIR:
693 if( bEncoded )
694 rUrl += "\\";
695 else // control character in raw name -> DDE link
697 rUrl += OUStringLiteral1<EXC_DDE_DELIM>();
698 eState = xlUrlRaw;
700 break;
701 case EXC_URL_PARENTDIR:
702 rUrl += "..\\";
703 break;
704 case EXC_URL_RAW:
706 if( *(pChar + 1) )
708 sal_Int32 nLen = *++pChar;
709 for( sal_Int32 nChar = 0; (nChar < nLen) && *(pChar + 1); ++nChar )
710 lclAppendUrlChar( rUrl, *++pChar );
711 // rUrl.Append( ':' );
714 break;
715 case '[':
716 eState = xlUrlFileName;
717 break;
718 default:
719 lclAppendUrlChar( rUrl, *pChar );
722 break;
724 // --- file name ---
726 case xlUrlFileName:
728 switch( *pChar )
730 case ']': eState = xlUrlSheetName; break;
731 default: lclAppendUrlChar( rUrl, *pChar );
734 break;
736 // --- sheet name ---
738 case xlUrlSheetName:
739 rTabName += OUString( *pChar );
740 break;
742 // --- raw read mode ---
744 case xlUrlRaw:
745 lclAppendUrlChar( rUrl, *pChar );
746 break;
749 ++pChar;
753 void XclImpUrlHelper::DecodeUrl(
754 OUString& rUrl, bool& rbSameWb, const XclImpRoot& rRoot, const OUString& rEncodedUrl )
756 OUString aTabName;
757 OUString aUrl;
758 DecodeUrl( aUrl, aTabName, rbSameWb, rRoot, rEncodedUrl );
759 rUrl = aUrl;
760 OSL_ENSURE( aTabName.isEmpty(), "XclImpUrlHelper::DecodeUrl - sheet name ignored" );
763 bool XclImpUrlHelper::DecodeLink( OUString& rApplic, OUString& rTopic, const OUString& rEncUrl )
765 sal_Int32 nPos = rEncUrl.indexOf( EXC_DDE_DELIM );
766 if( (nPos > 0) && (nPos + 1 < rEncUrl.getLength()) )
768 rApplic = rEncUrl.copy( 0, nPos );
769 rTopic = rEncUrl.copy( nPos + 1 );
770 return true;
772 return false;
775 // Cached Values ==============================================================
777 XclImpCachedValue::XclImpCachedValue( XclImpStream& rStrm ) :
778 mfValue( 0.0 ),
779 mnBoolErr( 0 )
781 mnType = rStrm.ReaduInt8();
782 switch( mnType )
784 case EXC_CACHEDVAL_EMPTY:
785 rStrm.Ignore( 8 );
786 break;
787 case EXC_CACHEDVAL_DOUBLE:
788 mfValue = rStrm.ReadDouble();
789 break;
790 case EXC_CACHEDVAL_STRING:
791 maStr = rStrm.ReadUniString();
792 break;
793 case EXC_CACHEDVAL_BOOL:
794 case EXC_CACHEDVAL_ERROR:
796 double fVal;
797 mnBoolErr = rStrm.ReaduInt8();
798 rStrm.Ignore( 7 );
800 const ScTokenArray* pScTokArr = rStrm.GetRoot().GetOldFmlaConverter().GetBoolErr(
801 XclTools::ErrorToEnum( fVal, mnType == EXC_CACHEDVAL_ERROR, mnBoolErr ) );
802 if( pScTokArr )
803 mxTokArr.reset( pScTokArr->Clone() );
805 break;
806 default:
807 OSL_FAIL( "XclImpCachedValue::XclImpCachedValue - unknown data type" );
811 XclImpCachedValue::~XclImpCachedValue()
815 sal_uInt16 XclImpCachedValue::GetScError() const
817 return (mnType == EXC_CACHEDVAL_ERROR) ? XclTools::GetScErrorCode( mnBoolErr ) : 0;
820 // Matrix Cached Values ==============================================================
822 XclImpCachedMatrix::XclImpCachedMatrix( XclImpStream& rStrm ) :
823 mnScCols( 0 ),
824 mnScRows( 0 )
826 mnScCols = rStrm.ReaduInt8();
827 mnScRows = rStrm.ReaduInt16();
829 if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
831 // in BIFF2-BIFF7: 256 columns represented by 0 columns
832 if( mnScCols == 0 )
833 mnScCols = 256;
835 else
837 // in BIFF8: columns and rows decreaed by 1
838 ++mnScCols;
839 ++mnScRows;
842 //assuming worse case scenario of unknown types
843 const size_t nMinRecordSize = 1;
844 const size_t nMaxRows = rStrm.GetRecLeft() / (nMinRecordSize * mnScCols);
845 if (mnScRows > nMaxRows)
847 SAL_WARN("sc", "Parsing error: " << nMaxRows <<
848 " max possible rows, but " << mnScRows << " claimed, truncating");
849 mnScRows = nMaxRows;
852 for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
853 for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
854 maValueList.push_back( o3tl::make_unique<XclImpCachedValue>( rStrm ) );
857 XclImpCachedMatrix::~XclImpCachedMatrix()
861 ScMatrixRef XclImpCachedMatrix::CreateScMatrix( svl::SharedStringPool& rPool ) const
863 ScMatrixRef xScMatrix;
864 OSL_ENSURE( mnScCols * mnScRows == maValueList.size(), "XclImpCachedMatrix::CreateScMatrix - element count mismatch" );
865 if( mnScCols && mnScRows && static_cast< sal_uLong >( mnScCols * mnScRows ) <= maValueList.size() )
867 xScMatrix = new ScFullMatrix(mnScCols, mnScRows, 0.0);
868 XclImpValueList::const_iterator itValue = maValueList.begin();
869 for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
871 for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
873 switch( (*itValue)->GetType() )
875 case EXC_CACHEDVAL_EMPTY:
876 // Excel shows 0.0 here, not an empty cell
877 xScMatrix->PutEmpty( nScCol, nScRow );
878 break;
879 case EXC_CACHEDVAL_DOUBLE:
880 xScMatrix->PutDouble( (*itValue)->GetValue(), nScCol, nScRow );
881 break;
882 case EXC_CACHEDVAL_STRING:
883 xScMatrix->PutString(rPool.intern((*itValue)->GetString()), nScCol, nScRow);
884 break;
885 case EXC_CACHEDVAL_BOOL:
886 xScMatrix->PutBoolean( (*itValue)->GetBool(), nScCol, nScRow );
887 break;
888 case EXC_CACHEDVAL_ERROR:
889 xScMatrix->PutError( (*itValue)->GetScError(), nScCol, nScRow );
890 break;
891 default:
892 OSL_FAIL( "XclImpCachedMatrix::CreateScMatrix - unknown value type" );
893 xScMatrix->PutEmpty( nScCol, nScRow );
895 ++itValue;
899 return xScMatrix;
902 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */