use insert function instead of for loop
[LibreOffice.git] / sc / source / filter / excel / xihelper.cxx
blob40dd4ba5901c09ebfc5e3cb8c73928f28504300e
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 <memory>
21 #include <xihelper.hxx>
22 #include <svl/itemset.hxx>
23 #include <svl/sharedstringpool.hxx>
24 #include <editeng/editobj.hxx>
25 #include <tools/urlobj.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 <xistring.hxx>
35 #include <xistyle.hxx>
36 #include <excform.hxx>
37 #include <scmatrix.hxx>
38 #include <documentimport.hxx>
39 #include <sal/log.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 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 void XclImpAddressConverter::FillRange(const XclRange& rXclRange, ScRange& rScRange)
103 const XclAddress aXclStartAdr = rXclRange.maFirst;
104 lclFillAddress(rScRange.aStart, aXclStartAdr.mnCol, aXclStartAdr.mnRow, rScRange.aStart.Tab());
105 const XclAddress aXclEndAdr = rXclRange.maLast;
106 lclFillAddress(rScRange.aEnd, aXclEndAdr.mnCol, aXclEndAdr.mnRow, rScRange.aEnd.Tab());
109 bool XclImpAddressConverter::ConvertRange( ScRange& rScRange,
110 const XclRange& rXclRange, SCTAB nScTab1, SCTAB nScTab2, bool bWarn )
112 // check start position
113 bool bValidStart = CheckAddress( rXclRange.maFirst, bWarn );
114 if( bValidStart )
116 lclFillAddress( rScRange.aStart, rXclRange.maFirst.mnCol, rXclRange.maFirst.mnRow, nScTab1 );
118 // check & correct end position
119 sal_uInt16 nXclCol2 = rXclRange.maLast.mnCol;
120 sal_uInt32 nXclRow2 = rXclRange.maLast.mnRow;
121 if( !CheckAddress( rXclRange.maLast, bWarn ) )
123 nXclCol2 = ::std::min( nXclCol2, mnMaxCol );
124 nXclRow2 = ::std::min( nXclRow2, mnMaxRow );
126 lclFillAddress( rScRange.aEnd, nXclCol2, nXclRow2, nScTab2 );
128 return bValidStart;
131 // cell range list ------------------------------------------------------------
133 void XclImpAddressConverter::ConvertRangeList( ScRangeList& rScRanges,
134 const XclRangeList& rXclRanges, SCTAB nScTab, bool bWarn )
136 rScRanges.RemoveAll();
137 for( const auto& rXclRange : rXclRanges )
139 ScRange aScRange( ScAddress::UNINITIALIZED );
140 if( ConvertRange( aScRange, rXclRange, nScTab, nScTab, bWarn ) )
141 rScRanges.push_back( aScRange );
145 // String->EditEngine conversion ==============================================
147 namespace {
149 std::unique_ptr<EditTextObject> lclCreateTextObject( const XclImpRoot& rRoot,
150 const XclImpString& rString, XclFontItemType eType, sal_uInt16 nXFIndex )
152 std::unique_ptr<EditTextObject> pTextObj;
154 const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
155 const XclImpFont* pFirstFont = rXFBuffer.GetFont( nXFIndex );
156 bool bFirstEscaped = pFirstFont && pFirstFont->HasEscapement();
158 if( rString.IsRich() || bFirstEscaped )
160 const XclImpFontBuffer& rFontBuffer = rRoot.GetFontBuffer();
161 const XclFormatRunVec& rFormats = rString.GetFormats();
163 ScEditEngineDefaulter& rEE = rRoot.GetEditEngine();
164 rEE.SetTextCurrentDefaults( rString.GetText() );
166 SfxItemSet aItemSet( rEE.GetEmptyItemSet() );
167 if( bFirstEscaped )
168 rFontBuffer.FillToItemSet( aItemSet, eType, rXFBuffer.GetFontIndex( nXFIndex ) );
169 ESelection aSelection;
171 XclFormatRun aNextRun;
172 XclFormatRunVec::const_iterator aIt = rFormats.begin();
173 XclFormatRunVec::const_iterator aEnd = rFormats.end();
175 if( aIt != aEnd )
176 aNextRun = *aIt++;
177 else
178 aNextRun.mnChar = 0xFFFF;
180 sal_Int32 nLen = rString.GetText().getLength();
181 for( sal_Int32 nChar = 0; nChar < nLen; ++nChar )
183 // reached new different formatted text portion
184 if( nChar >= aNextRun.mnChar )
186 // send items to edit engine
187 rEE.QuickSetAttribs( aItemSet, aSelection );
189 // start new item set
190 aItemSet.ClearItem();
191 rFontBuffer.FillToItemSet( aItemSet, eType, aNextRun.mnFontIdx );
193 // read new formatting information
194 if( aIt != aEnd )
195 aNextRun = *aIt++;
196 else
197 aNextRun.mnChar = 0xFFFF;
199 // reset selection start to current position
200 aSelection.CollapseToEnd();
203 // set end of selection to current position
204 if( rString.GetText()[ nChar ] == '\n' )
206 ++aSelection.end.nPara;
207 aSelection.end.nIndex = 0;
209 else
210 ++aSelection.end.nIndex;
213 // send items of last text portion to edit engine
214 rEE.QuickSetAttribs( aItemSet, aSelection );
216 pTextObj = rEE.CreateTextObject();
219 return pTextObj;
222 } // namespace
224 std::unique_ptr<EditTextObject> XclImpStringHelper::CreateTextObject(
225 const XclImpRoot& rRoot, const XclImpString& rString )
227 return lclCreateTextObject( rRoot, rString, XclFontItemType::Editeng, 0 );
230 void XclImpStringHelper::SetToDocument(
231 ScDocumentImport& rDoc, const ScAddress& rPos, const XclImpRoot& rRoot,
232 const XclImpString& rString, sal_uInt16 nXFIndex )
234 if (rString.GetText().isEmpty())
235 return;
237 ::std::unique_ptr< EditTextObject > pTextObj( lclCreateTextObject( rRoot, rString, XclFontItemType::Editeng, nXFIndex ) );
239 if (pTextObj)
241 rDoc.setEditCell(rPos, std::move(pTextObj));
243 else
245 const OUString& aStr = rString.GetText();
246 if (aStr.indexOf('\n') != -1 || aStr.indexOf('\r') != -1)
248 const XclImpXFBuffer& rXFBuffer = rRoot.GetXFBuffer();
249 const XclImpXF* pXF = rXFBuffer.GetXF( nXFIndex );
250 bool bSingleLine = pXF ? !pXF->GetLineBreak() : false;
252 // Multiline content.
253 ScFieldEditEngine& rEngine = rDoc.getDoc().GetEditEngine();
254 rEngine.SetSingleLine(bSingleLine);
255 rEngine.SetTextCurrentDefaults(aStr);
256 rDoc.setEditCell(rPos, rEngine.CreateTextObject());
257 rEngine.SetSingleLine(false);
259 else
261 // Normal text cell.
262 rDoc.setStringCell(rPos, aStr);
267 // Header/footer conversion ===================================================
269 XclImpHFConverter::XclImpHFPortionInfo::XclImpHFPortionInfo() :
270 mnHeight( 0 ),
271 mnMaxLineHt( 0 )
275 XclImpHFConverter::XclImpHFConverter( const XclImpRoot& rRoot ) :
276 XclImpRoot( rRoot ),
277 mrEE( rRoot.GetHFEditEngine() ),
278 mxFontData( new XclFontData ),
279 meCurrObj( EXC_HF_CENTER )
283 XclImpHFConverter::~XclImpHFConverter()
287 void XclImpHFConverter::ParseString( const OUString& rHFString )
289 // edit engine objects
290 mrEE.SetText( OUString() );
291 maInfos.clear();
292 maInfos.resize( EXC_HF_PORTION_COUNT );
293 meCurrObj = EXC_HF_CENTER;
295 // parser temporaries
296 maCurrText.truncate();
297 OUStringBuffer aReadFont; // current font name
298 OUStringBuffer aReadStyle; // current font style
299 sal_uInt16 nReadHeight = 0; // current font height
300 ResetFontData();
302 /** State of the parser. */
303 enum XclHFParserState
305 xlPSText, /// Read text, search for functions.
306 xlPSFunc, /// Read function (token following a '&').
307 xlPSFont, /// Read font name ('&' is followed by '"', reads until next '"' or ',').
308 xlPSFontStyle, /// Read font style name (font part after ',', reads until next '"').
309 xlPSHeight /// Read font height ('&' is followed by num. digits, reads until non-digit).
310 } eState = xlPSText;
312 const sal_Unicode* pChar = rHFString.getStr();
313 const sal_Unicode* pNull = pChar + rHFString.getLength(); // pointer to terminating null char
314 while( *pChar )
316 switch( eState )
319 // --- read text character ---
321 case xlPSText:
323 switch( *pChar )
325 case '&': // new command
326 InsertText();
327 eState = xlPSFunc;
328 break;
329 case '\n': // line break
330 InsertText();
331 InsertLineBreak();
332 break;
333 default:
334 maCurrText.append(OUStringChar(*pChar));
337 break;
339 // --- read control sequence ---
341 case xlPSFunc:
343 eState = xlPSText;
344 switch( *pChar )
346 case '&': maCurrText.append("&"); break; // the '&' character
348 case 'L': SetNewPortion( EXC_HF_LEFT ); break; // Left portion
349 case 'C': SetNewPortion( EXC_HF_CENTER ); break; // Center portion
350 case 'R': SetNewPortion( EXC_HF_RIGHT ); break; // Right portion
352 case 'P': InsertField( SvxFieldItem( SvxPageField(), EE_FEATURE_FIELD ) ); break; // page
353 case 'N': InsertField( SvxFieldItem( SvxPagesField(), EE_FEATURE_FIELD ) ); break; // page count
354 case 'D': InsertField( SvxFieldItem( SvxDateField(), EE_FEATURE_FIELD ) ); break; // date
355 case 'T': InsertField( SvxFieldItem( SvxTimeField(), EE_FEATURE_FIELD ) ); break; // time
356 case 'A': InsertField( SvxFieldItem( SvxTableField(), EE_FEATURE_FIELD ) ); break; // table name
358 case 'Z': // file path
359 InsertField( SvxFieldItem( SvxExtFileField(), EE_FEATURE_FIELD ) ); // convert to full name
360 if( (pNull - pChar >= 2) && (*(pChar + 1) == '&') && (*(pChar + 2) == 'F') )
362 // &Z&F found - ignore the &F part
363 pChar += 2;
365 break;
366 case 'F': // file name
367 InsertField( SvxFieldItem( SvxExtFileField( OUString(), SvxFileType::Var, SvxFileFormat::NameAndExt ), EE_FEATURE_FIELD ) );
368 break;
370 case 'U': // underline
371 SetAttribs();
372 mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_SINGLE) ?
373 EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_SINGLE;
374 break;
375 case 'E': // double underline
376 SetAttribs();
377 mxFontData->mnUnderline = (mxFontData->mnUnderline == EXC_FONTUNDERL_DOUBLE) ?
378 EXC_FONTUNDERL_NONE : EXC_FONTUNDERL_DOUBLE;
379 break;
380 case 'S': // strikeout
381 SetAttribs();
382 mxFontData->mbStrikeout = !mxFontData->mbStrikeout;
383 break;
384 case 'X': // superscript
385 SetAttribs();
386 mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUPER) ?
387 EXC_FONTESC_NONE : EXC_FONTESC_SUPER;
388 break;
389 case 'Y': // subscript
390 SetAttribs();
391 mxFontData->mnEscapem = (mxFontData->mnEscapem == EXC_FONTESC_SUB) ?
392 EXC_FONTESC_NONE : EXC_FONTESC_SUB;
393 break;
395 case '\"': // font name
396 aReadFont.setLength(0);
397 aReadStyle.setLength(0);
398 eState = xlPSFont;
399 break;
400 default:
401 if( ('0' <= *pChar) && (*pChar <= '9') ) // font size
403 nReadHeight = *pChar - '0';
404 eState = xlPSHeight;
408 break;
410 // --- read font name ---
412 case xlPSFont:
414 switch( *pChar )
416 case '\"':
417 --pChar;
418 [[fallthrough]];
419 case ',':
420 eState = xlPSFontStyle;
421 break;
422 default:
423 aReadFont.append(*pChar);
426 break;
428 // --- read font style ---
430 case xlPSFontStyle:
432 switch( *pChar )
434 case '\"':
435 SetAttribs();
436 if( !aReadFont.isEmpty() )
437 mxFontData->maName = aReadFont.toString();
438 mxFontData->maStyle = aReadStyle.toString();
439 eState = xlPSText;
440 break;
441 default:
442 aReadStyle.append(*pChar);
445 break;
447 // --- read font height ---
449 case xlPSHeight:
451 if( ('0' <= *pChar) && (*pChar <= '9') )
453 if( nReadHeight != 0xFFFF )
455 nReadHeight *= 10;
456 nReadHeight += (*pChar - '0');
457 if( nReadHeight > 1600 ) // max 1600pt = 32000twips
458 nReadHeight = 0xFFFF;
461 else
463 if( (nReadHeight != 0) && (nReadHeight != 0xFFFF) )
465 SetAttribs();
466 mxFontData->mnHeight = nReadHeight * 20;
468 --pChar;
469 eState = xlPSText;
472 break;
474 ++pChar;
477 // finalize
478 CreateCurrObject();
479 maInfos[ EXC_HF_LEFT ].mnHeight += GetMaxLineHeight( EXC_HF_LEFT );
480 maInfos[ EXC_HF_CENTER ].mnHeight += GetMaxLineHeight( EXC_HF_CENTER );
481 maInfos[ EXC_HF_RIGHT ].mnHeight += GetMaxLineHeight( EXC_HF_RIGHT );
484 void XclImpHFConverter::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nWhichId ) const
486 ScPageHFItem aHFItem( nWhichId );
487 if( maInfos[ EXC_HF_LEFT ].mxObj )
488 aHFItem.SetLeftArea( *maInfos[ EXC_HF_LEFT ].mxObj );
489 if( maInfos[ EXC_HF_CENTER ].mxObj )
490 aHFItem.SetCenterArea( *maInfos[ EXC_HF_CENTER ].mxObj );
491 if( maInfos[ EXC_HF_RIGHT ].mxObj )
492 aHFItem.SetRightArea( *maInfos[ EXC_HF_RIGHT ].mxObj );
493 rItemSet.Put( aHFItem );
496 sal_Int32 XclImpHFConverter::GetTotalHeight() const
498 return ::std::max( maInfos[ EXC_HF_LEFT ].mnHeight,
499 ::std::max( maInfos[ EXC_HF_CENTER ].mnHeight, maInfos[ EXC_HF_RIGHT ].mnHeight ) );
502 // private --------------------------------------------------------------------
504 sal_uInt16 XclImpHFConverter::GetMaxLineHeight( XclImpHFPortion ePortion ) const
506 sal_uInt16 nMaxHt = maInfos[ ePortion ].mnMaxLineHt;
507 return (nMaxHt == 0) ? mxFontData->mnHeight : nMaxHt;
510 void XclImpHFConverter::UpdateMaxLineHeight( XclImpHFPortion ePortion )
512 sal_uInt16& rnMaxHt = maInfos[ ePortion ].mnMaxLineHt;
513 rnMaxHt = ::std::max( rnMaxHt, mxFontData->mnHeight );
516 void XclImpHFConverter::UpdateCurrMaxLineHeight()
518 UpdateMaxLineHeight( meCurrObj );
521 void XclImpHFConverter::SetAttribs()
523 ESelection& rSel = GetCurrSel();
524 if (rSel.HasRange())
526 SfxItemSet aItemSet( mrEE.GetEmptyItemSet() );
527 XclImpFont aFont( GetRoot(), *mxFontData );
528 aFont.FillToItemSet( aItemSet, XclFontItemType::HeaderFooter );
529 mrEE.QuickSetAttribs( aItemSet, rSel );
530 rSel.CollapseToEnd();
534 void XclImpHFConverter::ResetFontData()
536 if( const XclImpFont* pFirstFont = GetFontBuffer().GetFont( EXC_FONT_APP ) )
537 *mxFontData = pFirstFont->GetFontData();
538 else
540 mxFontData->Clear();
541 mxFontData->mnHeight = 200;
545 void XclImpHFConverter::InsertText()
547 if( !maCurrText.isEmpty() )
549 ESelection& rSel = GetCurrSel();
550 OUString sString(maCurrText.makeStringAndClear());
551 mrEE.QuickInsertText(sString, ESelection(rSel.end));
552 rSel.end.nIndex += sString.getLength();
553 UpdateCurrMaxLineHeight();
557 void XclImpHFConverter::InsertField( const SvxFieldItem& rFieldItem )
559 ESelection& rSel = GetCurrSel();
560 mrEE.QuickInsertField(rFieldItem, ESelection(rSel.end));
561 ++rSel.end.nIndex;
562 UpdateCurrMaxLineHeight();
565 void XclImpHFConverter::InsertLineBreak()
567 ESelection& rSel = GetCurrSel();
568 mrEE.QuickInsertText(OUString('\n'), ESelection(rSel.end));
569 ++rSel.end.nPara;
570 rSel.end.nIndex = 0;
571 GetCurrInfo().mnHeight += GetMaxLineHeight( meCurrObj );
572 GetCurrInfo().mnMaxLineHt = 0;
575 void XclImpHFConverter::CreateCurrObject()
577 InsertText();
578 SetAttribs();
579 GetCurrObj() = mrEE.CreateTextObject();
582 void XclImpHFConverter::SetNewPortion( XclImpHFPortion eNew )
584 if( eNew != meCurrObj )
586 CreateCurrObject();
587 meCurrObj = eNew;
588 if( GetCurrObj() )
589 mrEE.SetText( *GetCurrObj() );
590 else
591 mrEE.SetText( OUString() );
592 ResetFontData();
596 // URL conversion =============================================================
598 namespace {
600 void lclAppendUrlChar( OUString& rUrl, sal_Unicode cChar )
602 // encode special characters
603 switch( cChar )
605 case '#': rUrl += "%23"; break;
606 case '%': rUrl += "%25"; break;
607 default: rUrl += OUStringChar( cChar );
611 } // namespace
613 void XclImpUrlHelper::DecodeUrl(
614 OUString& rUrl, OUString& rTabName, bool& rbSameWb,
615 const XclImpRoot& rRoot, const OUString& rEncodedUrl )
617 enum
619 xlUrlInit, /// Initial state, read string mode character.
620 xlUrlPath, /// Read URL path.
621 xlUrlFileName, /// Read file name.
622 xlUrlSheetName, /// Read sheet name.
623 xlUrlRaw /// Raw mode. No control characters will occur.
624 } eState = xlUrlInit;
626 bool bEncoded = true;
627 rbSameWb = false;
629 sal_Unicode cCurrDrive = 0;
630 OUString aDosBase( INetURLObject( rRoot.GetBasePath() ).getFSysPath( FSysStyle::Dos ) );
631 if (!aDosBase.isEmpty() && aDosBase.match(":\\", 1))
632 cCurrDrive = aDosBase[0];
634 const sal_Unicode* pChar = rEncodedUrl.getStr();
635 while( *pChar )
637 switch( eState )
640 // --- first character ---
642 case xlUrlInit:
644 switch( *pChar )
646 case EXC_URLSTART_ENCODED:
647 eState = xlUrlPath;
648 break;
649 case EXC_URLSTART_SELF:
650 case EXC_URLSTART_SELFENCODED:
651 rbSameWb = true;
652 eState = xlUrlSheetName;
653 break;
654 case '[':
655 bEncoded = false;
656 eState = xlUrlFileName;
657 break;
658 default:
659 bEncoded = false;
660 lclAppendUrlChar( rUrl, *pChar );
661 eState = xlUrlPath;
664 break;
666 // --- URL path ---
668 case xlUrlPath:
670 switch( *pChar )
672 case EXC_URL_DOSDRIVE:
674 if( *(pChar + 1) )
676 ++pChar;
677 if( *pChar == '@' )
678 rUrl += "\\\\";
679 else
681 lclAppendUrlChar( rUrl, *pChar );
682 rUrl += ":\\";
685 else
686 rUrl += "<NULL-DRIVE!>";
688 break;
689 case EXC_URL_DRIVEROOT:
690 if( cCurrDrive )
692 lclAppendUrlChar( rUrl, cCurrDrive );
693 rUrl += ":";
695 [[fallthrough]];
696 case EXC_URL_SUBDIR:
697 if( bEncoded )
698 rUrl += "\\";
699 else // control character in raw name -> DDE link
701 rUrl += OUStringChar(EXC_DDE_DELIM);
702 eState = xlUrlRaw;
704 break;
705 case EXC_URL_PARENTDIR:
706 rUrl += "..\\";
707 break;
708 case EXC_URL_RAW:
710 if( *(pChar + 1) )
712 sal_Int32 nLen = *++pChar;
713 for( sal_Int32 nChar = 0; (nChar < nLen) && *(pChar + 1); ++nChar )
714 lclAppendUrlChar( rUrl, *++pChar );
715 // rUrl.Append( ':' );
718 break;
719 case '[':
720 eState = xlUrlFileName;
721 break;
722 default:
723 lclAppendUrlChar( rUrl, *pChar );
726 break;
728 // --- file name ---
730 case xlUrlFileName:
732 switch( *pChar )
734 case ']': eState = xlUrlSheetName; break;
735 default: lclAppendUrlChar( rUrl, *pChar );
738 break;
740 // --- sheet name ---
742 case xlUrlSheetName:
743 rTabName += OUStringChar( *pChar );
744 break;
746 // --- raw read mode ---
748 case xlUrlRaw:
749 lclAppendUrlChar( rUrl, *pChar );
750 break;
753 ++pChar;
757 void XclImpUrlHelper::DecodeUrl(
758 OUString& rUrl, bool& rbSameWb, const XclImpRoot& rRoot, const OUString& rEncodedUrl )
760 OUString aTabName;
761 OUString aUrl;
762 DecodeUrl( aUrl, aTabName, rbSameWb, rRoot, rEncodedUrl );
763 rUrl = aUrl;
764 OSL_ENSURE( aTabName.isEmpty(), "XclImpUrlHelper::DecodeUrl - sheet name ignored" );
767 bool XclImpUrlHelper::DecodeLink( OUString& rApplic, OUString& rTopic, std::u16string_view aEncUrl )
769 size_t nPos = aEncUrl.find( EXC_DDE_DELIM );
770 if( nPos != std::u16string_view::npos && (nPos > 0) && (nPos + 1 < aEncUrl.size()) )
772 rApplic = aEncUrl.substr( 0, nPos );
773 rTopic = aEncUrl.substr( nPos + 1 );
774 return true;
776 return false;
779 // Cached Values ==============================================================
781 XclImpCachedValue::XclImpCachedValue( XclImpStream& rStrm ) :
782 mfValue( 0.0 ),
783 mnBoolErr( 0 )
785 mnType = rStrm.ReaduInt8();
786 switch( mnType )
788 case EXC_CACHEDVAL_EMPTY:
789 rStrm.Ignore( 8 );
790 break;
791 case EXC_CACHEDVAL_DOUBLE:
792 mfValue = rStrm.ReadDouble();
793 break;
794 case EXC_CACHEDVAL_STRING:
795 maStr = rStrm.ReadUniString();
796 break;
797 case EXC_CACHEDVAL_BOOL:
798 case EXC_CACHEDVAL_ERROR:
800 double fVal;
801 mnBoolErr = rStrm.ReaduInt8();
802 rStrm.Ignore( 7 );
804 std::unique_ptr<ScTokenArray> pScTokArr = rStrm.GetRoot().GetOldFmlaConverter().GetBoolErr(
805 XclTools::ErrorToEnum( fVal, mnType == EXC_CACHEDVAL_ERROR, mnBoolErr ) );
806 if( pScTokArr )
807 mxTokArr = std::move( pScTokArr );
809 break;
810 default:
811 OSL_FAIL( "XclImpCachedValue::XclImpCachedValue - unknown data type" );
815 XclImpCachedValue::~XclImpCachedValue()
819 FormulaError XclImpCachedValue::GetScError() const
821 return (mnType == EXC_CACHEDVAL_ERROR) ? XclTools::GetScErrorCode( mnBoolErr ) : FormulaError::NONE;
824 // Matrix Cached Values ==============================================================
826 XclImpCachedMatrix::XclImpCachedMatrix( XclImpStream& rStrm ) :
827 mnScCols( 0 ),
828 mnScRows( 0 )
830 mnScCols = rStrm.ReaduInt8();
831 mnScRows = rStrm.ReaduInt16();
833 if( rStrm.GetRoot().GetBiff() <= EXC_BIFF5 )
835 // in BIFF2-BIFF7: 256 columns represented by 0 columns
836 if( mnScCols == 0 )
837 mnScCols = 256;
839 else
841 // in BIFF8: columns and rows decreased by 1
842 ++mnScCols;
843 ++mnScRows;
846 //assuming worst case scenario of unknown types
847 const size_t nMinRecordSize = 1;
848 const size_t nMaxRows = rStrm.GetRecLeft() / (nMinRecordSize * mnScCols);
849 if (mnScRows > nMaxRows)
851 SAL_WARN("sc", "Parsing error: " << nMaxRows <<
852 " max possible rows, but " << mnScRows << " claimed, truncating");
853 mnScRows = nMaxRows;
856 for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
857 for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
858 maValueList.push_back( std::make_unique<XclImpCachedValue>( rStrm ) );
861 XclImpCachedMatrix::~XclImpCachedMatrix()
865 ScMatrixRef XclImpCachedMatrix::CreateScMatrix( svl::SharedStringPool& rPool ) const
867 ScMatrixRef xScMatrix;
868 OSL_ENSURE( mnScCols * mnScRows == maValueList.size(), "XclImpCachedMatrix::CreateScMatrix - element count mismatch" );
869 if( mnScCols && mnScRows && static_cast< sal_uLong >( mnScCols * mnScRows ) <= maValueList.size() )
871 xScMatrix = new ScMatrix(mnScCols, mnScRows, 0.0);
872 XclImpValueList::const_iterator itValue = maValueList.begin();
873 for( SCSIZE nScRow = 0; nScRow < mnScRows; ++nScRow )
875 for( SCSIZE nScCol = 0; nScCol < mnScCols; ++nScCol )
877 switch( (*itValue)->GetType() )
879 case EXC_CACHEDVAL_EMPTY:
880 // Excel shows 0.0 here, not an empty cell
881 xScMatrix->PutEmpty( nScCol, nScRow );
882 break;
883 case EXC_CACHEDVAL_DOUBLE:
884 xScMatrix->PutDouble( (*itValue)->GetValue(), nScCol, nScRow );
885 break;
886 case EXC_CACHEDVAL_STRING:
887 xScMatrix->PutString(rPool.intern((*itValue)->GetString()), nScCol, nScRow);
888 break;
889 case EXC_CACHEDVAL_BOOL:
890 xScMatrix->PutBoolean( (*itValue)->GetBool(), nScCol, nScRow );
891 break;
892 case EXC_CACHEDVAL_ERROR:
893 xScMatrix->PutError( (*itValue)->GetScError(), nScCol, nScRow );
894 break;
895 default:
896 OSL_FAIL( "XclImpCachedMatrix::CreateScMatrix - unknown value type" );
897 xScMatrix->PutEmpty( nScCol, nScRow );
899 ++itValue;
903 return xScMatrix;
906 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */