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 <memory>
21 #include <xistyle.hxx>
22 #include <sfx2/objsh.hxx>
23 #include <svtools/ctrltool.hxx>
24 #include <editeng/editobj.hxx>
25 #include <scitems.hxx>
26 #include <editeng/fontitem.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <editeng/wghtitem.hxx>
29 #include <editeng/udlnitem.hxx>
30 #include <editeng/postitem.hxx>
31 #include <editeng/crossedoutitem.hxx>
32 #include <editeng/contouritem.hxx>
33 #include <editeng/shdditem.hxx>
34 #include <editeng/escapementitem.hxx>
35 #include <svx/algitem.hxx>
36 #include <editeng/borderline.hxx>
37 #include <editeng/boxitem.hxx>
38 #include <editeng/lineitem.hxx>
39 #include <svx/rotmodit.hxx>
40 #include <editeng/colritem.hxx>
41 #include <editeng/brushitem.hxx>
42 #include <editeng/frmdiritem.hxx>
43 #include <editeng/eeitem.hxx>
44 #include <editeng/flstitem.hxx>
45 #include <editeng/justifyitem.hxx>
46 #include <editeng/editids.hrc>
47 #include <sal/macros.h>
48 #include <sal/log.hxx>
49 #include <vcl/fontcharmap.hxx>
50 #include <vcl/outdev.hxx>
51 #include <document.hxx>
52 #include <documentimport.hxx>
53 #include <docpool.hxx>
54 #include <attrib.hxx>
55 #include <patattr.hxx>
56 #include <stlpool.hxx>
57 #include <stlsheet.hxx>
58 #include <globstr.hrc>
59 #include <scresid.hxx>
60 #include <attarray.hxx>
61 #include <xladdress.hxx>
62 #include <xlcontent.hxx>
63 #include <xltracer.hxx>
64 #include <xltools.hxx>
65 #include <xistream.hxx>
66 #include <xicontent.hxx>
67 
68 #include <root.hxx>
69 #include <colrowst.hxx>
70 
71 #include <vector>
72 
73 #include <cppuhelper/implbase.hxx>
74 #include <com/sun/star/container/XIndexAccess.hpp>
75 #include <com/sun/star/beans/XPropertySet.hpp>
76 
77 using ::std::vector;
78 using namespace ::com::sun::star;
79 
80 typedef ::cppu::WeakImplHelper< container::XIndexAccess > XIndexAccess_BASE;
81 typedef ::std::vector< Color > ColorVec;
82 
83 class PaletteIndex : public XIndexAccess_BASE
84 {
85 public:
PaletteIndex(const ColorVec & rColorTable)86     explicit PaletteIndex( const ColorVec& rColorTable ) : maColor( rColorTable ) {}
87 
88     // Methods XIndexAccess
getCount()89     virtual ::sal_Int32 SAL_CALL getCount() override
90     {
91          return  maColor.size();
92     }
93 
getByIndex(::sal_Int32 Index)94     virtual uno::Any SAL_CALL getByIndex( ::sal_Int32 Index ) override
95     {
96         //--Index;  // apparently the palette is already 1 based
97         return uno::makeAny( sal_Int32( maColor[ Index ] ) );
98     }
99 
100     // Methods XElementAccess
getElementType()101     virtual uno::Type SAL_CALL getElementType() override
102     {
103         return ::cppu::UnoType<sal_Int32>::get();
104     }
hasElements()105     virtual sal_Bool SAL_CALL hasElements() override
106     {
107         return (!maColor.empty());
108     }
109 
110 private:
111     ColorVec        maColor;
112 };
113 
114 void
ExportPalette()115 XclImpPalette::ExportPalette()
116 {
117     if( SfxObjectShell* pDocShell = mrRoot.GetDocShell() )
118     {
119         // copy values in color palette
120         sal_Int16 nColors =  maColorTable.size();
121         ColorVec aColors;
122         aColors.resize( nColors );
123         for( sal_uInt16 nIndex = 0; nIndex < nColors; ++nIndex )
124             aColors[ nIndex ] = GetColor( nIndex );
125 
126         uno::Reference< beans::XPropertySet > xProps( pDocShell->GetModel(), uno::UNO_QUERY );
127         if ( xProps.is() )
128         {
129             uno::Reference< container::XIndexAccess > xIndex( new PaletteIndex( aColors ) );
130             xProps->setPropertyValue( "ColorPalette", uno::makeAny( xIndex ) );
131         }
132     }
133 
134 }
135 // PALETTE record - color information =========================================
136 
XclImpPalette(const XclImpRoot & rRoot)137 XclImpPalette::XclImpPalette( const XclImpRoot& rRoot ) :
138     XclDefaultPalette( rRoot ), mrRoot( rRoot )
139 {
140 }
141 
Initialize()142 void XclImpPalette::Initialize()
143 {
144     maColorTable.clear();
145 }
146 
GetColor(sal_uInt16 nXclIndex) const147 Color XclImpPalette::GetColor( sal_uInt16 nXclIndex ) const
148 {
149     if( nXclIndex >= EXC_COLOR_USEROFFSET )
150     {
151         sal_uInt32 nIx = nXclIndex - EXC_COLOR_USEROFFSET;
152         if( nIx < maColorTable.size() )
153             return maColorTable[ nIx ];
154     }
155     return GetDefColor( nXclIndex );
156 }
157 
ReadPalette(XclImpStream & rStrm)158 void XclImpPalette::ReadPalette( XclImpStream& rStrm )
159 {
160     sal_uInt16 nCount;
161     nCount = rStrm.ReaduInt16();
162 
163     const size_t nMinRecordSize = 4;
164     const size_t nMaxRecords = rStrm.GetRecLeft() / nMinRecordSize;
165     if (nCount > nMaxRecords)
166     {
167         SAL_WARN("sc", "Parsing error: " << nMaxRecords <<
168                  " max possible entries, but " << nCount << " claimed, truncating");
169         nCount = nMaxRecords;
170     }
171 
172     maColorTable.resize( nCount );
173     Color aColor;
174     for( sal_uInt16 nIndex = 0; nIndex < nCount; ++nIndex )
175     {
176         rStrm >> aColor;
177         maColorTable[ nIndex ] = aColor;
178     }
179     ExportPalette();
180 }
181 
182 // FONT record - font information =============================================
XclImpFont(const XclImpRoot & rRoot)183 XclImpFont::XclImpFont( const XclImpRoot& rRoot ) :
184     XclImpRoot( rRoot ),
185     mbHasCharSet( false ),
186     mbHasWstrn( true ),
187     mbHasAsian( false ),
188     mbHasCmplx( false )
189 {
190     SetAllUsedFlags( false );
191 }
192 
XclImpFont(const XclImpRoot & rRoot,const XclFontData & rFontData)193 XclImpFont::XclImpFont( const XclImpRoot& rRoot, const XclFontData& rFontData ) :
194     XclImpRoot( rRoot )
195 {
196     SetFontData( rFontData, false );
197 }
198 
SetAllUsedFlags(bool bUsed)199 void XclImpFont::SetAllUsedFlags( bool bUsed )
200 {
201     mbFontNameUsed = mbHeightUsed = mbColorUsed = mbWeightUsed = mbEscapemUsed =
202         mbUnderlUsed = mbItalicUsed = mbStrikeUsed = mbOutlineUsed = mbShadowUsed = bUsed;
203 }
204 
SetFontData(const XclFontData & rFontData,bool bHasCharSet)205 void XclImpFont::SetFontData( const XclFontData& rFontData, bool bHasCharSet )
206 {
207     maData = rFontData;
208     mbHasCharSet = bHasCharSet;
209     if( !maData.maStyle.isEmpty() )
210     {
211         if( SfxObjectShell* pDocShell = GetDocShell() )
212         {
213             if( const SvxFontListItem* pInfoItem = static_cast< const SvxFontListItem* >(
214                 pDocShell->GetItem( SID_ATTR_CHAR_FONTLIST ) ) )
215             {
216                 if( const FontList* pFontList = pInfoItem->GetFontList() )
217                 {
218                     FontMetric aFontMetric( pFontList->Get( maData.maName, maData.maStyle ) );
219                     maData.SetScWeight( aFontMetric.GetWeight() );
220                     maData.SetScPosture( aFontMetric.GetItalic() );
221                 }
222             }
223         }
224         maData.maStyle.clear();
225     }
226     GuessScriptType();
227     SetAllUsedFlags( true );
228 }
229 
GetFontEncoding() const230 rtl_TextEncoding XclImpFont::GetFontEncoding() const
231 {
232     // #i63105# use text encoding from FONT record
233     // #i67768# BIFF2-BIFF4 FONT records do not contain character set
234     rtl_TextEncoding eFontEnc = mbHasCharSet ? maData.GetFontEncoding() : GetTextEncoding();
235     return (eFontEnc == RTL_TEXTENCODING_DONTKNOW) ? GetTextEncoding() : eFontEnc;
236 }
237 
ReadFont(XclImpStream & rStrm)238 void XclImpFont::ReadFont( XclImpStream& rStrm )
239 {
240     switch( GetBiff() )
241     {
242         case EXC_BIFF2:
243             ReadFontData2( rStrm );
244             ReadFontName2( rStrm );
245         break;
246         case EXC_BIFF3:
247         case EXC_BIFF4:
248             ReadFontData2( rStrm );
249             ReadFontColor( rStrm );
250             ReadFontName2( rStrm );
251         break;
252         case EXC_BIFF5:
253             ReadFontData5( rStrm );
254             ReadFontName2( rStrm );
255         break;
256         case EXC_BIFF8:
257             ReadFontData5( rStrm );
258             ReadFontName8( rStrm );
259         break;
260         default:
261             DBG_ERROR_BIFF();
262             return;
263     }
264     GuessScriptType();
265     SetAllUsedFlags( true );
266 }
267 
ReadEfont(XclImpStream & rStrm)268 void XclImpFont::ReadEfont( XclImpStream& rStrm )
269 {
270     ReadFontColor( rStrm );
271 }
272 
ReadCFFontBlock(XclImpStream & rStrm)273 void XclImpFont::ReadCFFontBlock( XclImpStream& rStrm )
274 {
275     OSL_ENSURE_BIFF( GetBiff() == EXC_BIFF8 );
276     if( GetBiff() != EXC_BIFF8 )
277         return;
278 
279     rStrm.Ignore( 64 );
280     sal_uInt32 nHeight = rStrm.ReaduInt32();
281     sal_uInt32 nStyle = rStrm.ReaduInt32();
282     sal_uInt16 nWeight = rStrm.ReaduInt16();
283     rStrm.Ignore( 2 ); //nEscapem
284     sal_uInt8 nUnderl = rStrm.ReaduInt8();
285     rStrm.Ignore( 3 );
286     sal_uInt32 nColor = rStrm.ReaduInt32();
287     rStrm.Ignore( 4 );
288     sal_uInt32 nFontFlags1 = rStrm.ReaduInt32();
289     rStrm.Ignore( 4 ); //nFontFlags2
290     sal_uInt32 nFontFlags3 = rStrm.ReaduInt32();
291     rStrm.Ignore( 18 );
292 
293     if( (mbHeightUsed = (nHeight <= 0x7FFF)) )
294         maData.mnHeight = static_cast< sal_uInt16 >( nHeight );
295     if( (mbWeightUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE ) && (nWeight < 0x7FFF)) )
296         maData.mnWeight = nWeight;
297     if( (mbItalicUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STYLE )) )
298         maData.mbItalic = ::get_flag( nStyle, EXC_CF_FONT_STYLE );
299     if( (mbUnderlUsed = !::get_flag( nFontFlags3, EXC_CF_FONT_UNDERL ) && (nUnderl <= 0x7F)) )
300         maData.mnUnderline = nUnderl;
301     if( (mbColorUsed = (nColor <= 0x7FFF)) )
302         maData.maColor = GetPalette().GetColor( static_cast< sal_uInt16 >( nColor ) );
303     if( (mbStrikeUsed = !::get_flag( nFontFlags1, EXC_CF_FONT_STRIKEOUT )) )
304         maData.mbStrikeout = ::get_flag( nStyle, EXC_CF_FONT_STRIKEOUT );
305 }
306 
FillToItemSet(SfxItemSet & rItemSet,XclFontItemType eType,bool bSkipPoolDefs) const307 void XclImpFont::FillToItemSet( SfxItemSet& rItemSet, XclFontItemType eType, bool bSkipPoolDefs ) const
308 {
309     // true = edit engine Which-IDs (EE_CHAR_*); false = Calc Which-IDs (ATTR_*)
310     bool bEE = eType != XclFontItemType::Cell;
311 
312 // item = the item to put into the item set
313 // sc_which = the Calc Which-ID of the item
314 // ee_which = the edit engine Which-ID of the item
315 #define PUTITEM( item, sc_which, ee_which ) \
316     ScfTools::PutItem( rItemSet, item, (bEE ? (static_cast<sal_uInt16>(ee_which)) : (sc_which)), bSkipPoolDefs )
317 
318 // Font item
319     if( mbFontNameUsed )
320     {
321         rtl_TextEncoding eFontEnc = maData.GetFontEncoding();
322         rtl_TextEncoding eTempTextEnc = (bEE && (eFontEnc == GetTextEncoding())) ?
323             ScfTools::GetSystemTextEncoding() : eFontEnc;
324 
325         //add corresponding pitch for FontFamily
326         FontPitch ePitch = PITCH_DONTKNOW;
327         FontFamily eFtFamily = maData.GetScFamily( GetTextEncoding() );
328         switch( eFtFamily ) //refer http://msdn.microsoft.com/en-us/library/aa246306(v=VS.60).aspx
329         {
330             case FAMILY_ROMAN:              ePitch = PITCH_VARIABLE;        break;
331             case FAMILY_SWISS:              ePitch = PITCH_VARIABLE;        break;
332             case FAMILY_MODERN:             ePitch = PITCH_FIXED;           break;
333             default:                        break;
334          }
335         SvxFontItem aFontItem( eFtFamily , maData.maName, EMPTY_OUSTRING, ePitch, eTempTextEnc, ATTR_FONT );
336 
337         // set only for valid script types
338         if( mbHasWstrn )
339             PUTITEM( aFontItem, ATTR_FONT,      EE_CHAR_FONTINFO );
340         if( mbHasAsian )
341             PUTITEM( aFontItem, ATTR_CJK_FONT,  EE_CHAR_FONTINFO_CJK );
342         if( mbHasCmplx )
343             PUTITEM( aFontItem, ATTR_CTL_FONT,  EE_CHAR_FONTINFO_CTL );
344     }
345 
346 // Font height (for all script types)
347     if( mbHeightUsed )
348     {
349         sal_Int32 nHeight = maData.mnHeight;
350         if( bEE && (eType != XclFontItemType::HeaderFooter) )     // do not convert header/footer height
351             nHeight = (nHeight * 127 + 36) / EXC_POINTS_PER_INCH;   // 1 in == 72 pt
352 
353         SvxFontHeightItem aHeightItem( nHeight, 100, ATTR_FONT_HEIGHT );
354         PUTITEM( aHeightItem,   ATTR_FONT_HEIGHT,       EE_CHAR_FONTHEIGHT );
355         PUTITEM( aHeightItem,   ATTR_CJK_FONT_HEIGHT,   EE_CHAR_FONTHEIGHT_CJK );
356         PUTITEM( aHeightItem,   ATTR_CTL_FONT_HEIGHT,   EE_CHAR_FONTHEIGHT_CTL );
357     }
358 
359 // Font color - pass AUTO_COL to item
360     if( mbColorUsed )
361         PUTITEM( SvxColorItem( maData.maColor, ATTR_FONT_COLOR  ), ATTR_FONT_COLOR, EE_CHAR_COLOR );
362 
363 // Font weight (for all script types)
364     if( mbWeightUsed )
365     {
366         SvxWeightItem aWeightItem( maData.GetScWeight(), ATTR_FONT_WEIGHT );
367         PUTITEM( aWeightItem,   ATTR_FONT_WEIGHT,       EE_CHAR_WEIGHT );
368         PUTITEM( aWeightItem,   ATTR_CJK_FONT_WEIGHT,   EE_CHAR_WEIGHT_CJK );
369         PUTITEM( aWeightItem,   ATTR_CTL_FONT_WEIGHT,   EE_CHAR_WEIGHT_CTL );
370     }
371 
372 // Font underline
373     if( mbUnderlUsed )
374     {
375         SvxUnderlineItem aUnderlItem( maData.GetScUnderline(), ATTR_FONT_UNDERLINE );
376         PUTITEM( aUnderlItem,   ATTR_FONT_UNDERLINE,    EE_CHAR_UNDERLINE );
377     }
378 
379 // Font posture (for all script types)
380     if( mbItalicUsed )
381     {
382         SvxPostureItem aPostItem( maData.GetScPosture(), ATTR_FONT_POSTURE );
383         PUTITEM( aPostItem, ATTR_FONT_POSTURE,      EE_CHAR_ITALIC );
384         PUTITEM( aPostItem, ATTR_CJK_FONT_POSTURE,  EE_CHAR_ITALIC_CJK );
385         PUTITEM( aPostItem, ATTR_CTL_FONT_POSTURE,  EE_CHAR_ITALIC_CTL );
386     }
387 
388 // Boolean attributes crossed out, contoured, shadowed
389     if( mbStrikeUsed )
390         PUTITEM( SvxCrossedOutItem( maData.GetScStrikeout(), ATTR_FONT_CROSSEDOUT ), ATTR_FONT_CROSSEDOUT, EE_CHAR_STRIKEOUT );
391     if( mbOutlineUsed )
392         PUTITEM( SvxContourItem( maData.mbOutline, ATTR_FONT_CONTOUR ), ATTR_FONT_CONTOUR, EE_CHAR_OUTLINE );
393     if( mbShadowUsed )
394         PUTITEM( SvxShadowedItem( maData.mbShadow, ATTR_FONT_SHADOWED ), ATTR_FONT_SHADOWED, EE_CHAR_SHADOW );
395 
396 // Super-/subscript: only on edit engine objects
397     if( mbEscapemUsed && bEE )
398         rItemSet.Put( SvxEscapementItem( maData.GetScEscapement(), EE_CHAR_ESCAPEMENT ) );
399 
400 #undef PUTITEM
401 }
402 
WriteFontProperties(ScfPropertySet & rPropSet,XclFontPropSetType eType,const Color * pFontColor) const403 void XclImpFont::WriteFontProperties( ScfPropertySet& rPropSet,
404         XclFontPropSetType eType, const Color* pFontColor ) const
405 {
406     GetFontPropSetHelper().WriteFontProperties(
407         rPropSet, eType, maData, mbHasWstrn, mbHasAsian, mbHasCmplx, pFontColor );
408 }
409 
ReadFontData2(XclImpStream & rStrm)410 void XclImpFont::ReadFontData2( XclImpStream& rStrm )
411 {
412     sal_uInt16 nFlags;
413     maData.mnHeight = rStrm.ReaduInt16();
414     nFlags = rStrm.ReaduInt16();
415 
416     maData.mnWeight     = ::get_flagvalue( nFlags, EXC_FONTATTR_BOLD, EXC_FONTWGHT_BOLD, EXC_FONTWGHT_NORMAL );
417     maData.mnUnderline  = ::get_flagvalue( nFlags, EXC_FONTATTR_UNDERLINE, EXC_FONTUNDERL_SINGLE, EXC_FONTUNDERL_NONE );
418     maData.mbItalic     = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
419     maData.mbStrikeout  = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
420     maData.mbOutline    = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
421     maData.mbShadow     = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
422     mbHasCharSet = false;
423 }
424 
ReadFontData5(XclImpStream & rStrm)425 void XclImpFont::ReadFontData5( XclImpStream& rStrm )
426 {
427     sal_uInt16 nFlags;
428 
429     maData.mnHeight = rStrm.ReaduInt16();
430     nFlags = rStrm.ReaduInt16();
431     ReadFontColor( rStrm );
432     maData.mnWeight  = rStrm.ReaduInt16();
433     maData.mnEscapem = rStrm.ReaduInt16();
434     maData.mnUnderline = rStrm.ReaduInt8();
435     maData.mnFamily = rStrm.ReaduInt8();
436     maData.mnCharSet = rStrm.ReaduInt8();
437     rStrm.Ignore( 1 );
438 
439     maData.mbItalic     = ::get_flag( nFlags, EXC_FONTATTR_ITALIC );
440     maData.mbStrikeout  = ::get_flag( nFlags, EXC_FONTATTR_STRIKEOUT );
441     maData.mbOutline    = ::get_flag( nFlags, EXC_FONTATTR_OUTLINE );
442     maData.mbShadow     = ::get_flag( nFlags, EXC_FONTATTR_SHADOW );
443     mbHasCharSet = true;
444 }
445 
ReadFontColor(XclImpStream & rStrm)446 void XclImpFont::ReadFontColor( XclImpStream& rStrm )
447 {
448     maData.maColor = GetPalette().GetColor( rStrm.ReaduInt16() );
449 }
450 
ReadFontName2(XclImpStream & rStrm)451 void XclImpFont::ReadFontName2( XclImpStream& rStrm )
452 {
453     maData.maName = rStrm.ReadByteString( false );
454 }
455 
ReadFontName8(XclImpStream & rStrm)456 void XclImpFont::ReadFontName8( XclImpStream& rStrm )
457 {
458     maData.maName = rStrm.ReadUniString( rStrm.ReaduInt8() );
459 }
460 
GuessScriptType()461 void XclImpFont::GuessScriptType()
462 {
463     mbHasWstrn = true;
464     mbHasAsian = mbHasCmplx = false;
465 
466     // find the script types for which the font contains characters
467     if( OutputDevice* pPrinter = GetPrinter() )
468     {
469         vcl::Font aFont( maData.maName, Size( 0, 10 ) );
470         FontCharMapRef xFontCharMap;
471 
472         pPrinter->SetFont( aFont );
473         if( pPrinter->GetFontCharMap( xFontCharMap ) )
474         {
475             // CJK fonts
476             mbHasAsian =
477                 xFontCharMap->HasChar( 0x3041 ) ||   // 3040-309F: Hiragana
478                 xFontCharMap->HasChar( 0x30A1 ) ||   // 30A0-30FF: Katakana
479                 xFontCharMap->HasChar( 0x3111 ) ||   // 3100-312F: Bopomofo
480                 xFontCharMap->HasChar( 0x3131 ) ||   // 3130-318F: Hangul Compatibility Jamo
481                 xFontCharMap->HasChar( 0x3301 ) ||   // 3300-33FF: CJK Compatibility
482                 xFontCharMap->HasChar( 0x3401 ) ||   // 3400-4DBF: CJK Unified Ideographs Extension A
483                 xFontCharMap->HasChar( 0x4E01 ) ||   // 4E00-9FFF: CJK Unified Ideographs
484                 xFontCharMap->HasChar( 0x7E01 ) ||   // 4E00-9FFF: CJK Unified Ideographs
485                 xFontCharMap->HasChar( 0xA001 ) ||   // A001-A48F: Yi Syllables
486                 xFontCharMap->HasChar( 0xAC01 ) ||   // AC00-D7AF: Hangul Syllables
487                 xFontCharMap->HasChar( 0xCC01 ) ||   // AC00-D7AF: Hangul Syllables
488                 xFontCharMap->HasChar( 0xF901 ) ||   // F900-FAFF: CJK Compatibility Ideographs
489                 xFontCharMap->HasChar( 0xFF71 );     // FF00-FFEF: Halfwidth/Fullwidth Forms
490             // CTL fonts
491             mbHasCmplx =
492                 xFontCharMap->HasChar( 0x05D1 ) ||   // 0590-05FF: Hebrew
493                 xFontCharMap->HasChar( 0x0631 ) ||   // 0600-06FF: Arabic
494                 xFontCharMap->HasChar( 0x0721 ) ||   // 0700-074F: Syriac
495                 xFontCharMap->HasChar( 0x0911 ) ||   // 0900-0DFF: Indic scripts
496                 xFontCharMap->HasChar( 0x0E01 ) ||   // 0E00-0E7F: Thai
497                 xFontCharMap->HasChar( 0xFB21 ) ||   // FB1D-FB4F: Hebrew Presentation Forms
498                 xFontCharMap->HasChar( 0xFB51 ) ||   // FB50-FDFF: Arabic Presentation Forms-A
499                 xFontCharMap->HasChar( 0xFE71 );     // FE70-FEFF: Arabic Presentation Forms-B
500             // Western fonts
501             mbHasWstrn = (!mbHasAsian && !mbHasCmplx) || xFontCharMap->HasChar( 'A' );
502         }
503     }
504 }
505 
XclImpFontBuffer(const XclImpRoot & rRoot)506 XclImpFontBuffer::XclImpFontBuffer( const XclImpRoot& rRoot ) :
507     XclImpRoot( rRoot ),
508     maFont4( rRoot ),
509     maCtrlFont( rRoot )
510 {
511     Initialize();
512 
513     // default font for form controls without own font information
514     XclFontData aCtrlFontData;
515     switch( GetBiff() )
516     {
517         case EXC_BIFF2:
518         case EXC_BIFF3:
519         case EXC_BIFF4:
520         case EXC_BIFF5:
521             aCtrlFontData.maName = "Helv";
522             aCtrlFontData.mnHeight = 160;
523             aCtrlFontData.mnWeight = EXC_FONTWGHT_BOLD;
524         break;
525         case EXC_BIFF8:
526             aCtrlFontData.maName = "Tahoma";
527             aCtrlFontData.mnHeight = 160;
528             aCtrlFontData.mnWeight = EXC_FONTWGHT_NORMAL;
529         break;
530         default:
531             DBG_ERROR_BIFF();
532     }
533     maCtrlFont.SetFontData( aCtrlFontData, false );
534 }
535 
Initialize()536 void XclImpFontBuffer::Initialize()
537 {
538     maFontList.clear();
539 
540     // application font for column width calculation, later filled with first font from font list
541     XclFontData aAppFontData;
542     aAppFontData.maName = "Arial";
543     aAppFontData.mnHeight = 200;
544     aAppFontData.mnWeight = EXC_FONTWGHT_NORMAL;
545     UpdateAppFont( aAppFontData, false );
546 }
547 
GetFont(sal_uInt16 nFontIndex) const548 const XclImpFont* XclImpFontBuffer::GetFont( sal_uInt16 nFontIndex ) const
549 {
550     /*  Font with index 4 is not stored in an Excel file, but used e.g. by
551         BIFF5 form pushbutton objects. It is the bold default font.
552         This also means that entries above 4 are out by one in the list. */
553 
554     if (nFontIndex == 4)
555         return &maFont4;
556 
557     if (nFontIndex < 4)
558     {
559         // Font ID is zero-based when it's less than 4.
560         return nFontIndex >= maFontList.size() ? nullptr : &maFontList[nFontIndex];
561     }
562 
563     // Font ID is greater than 4.  It is now 1-based.
564     return nFontIndex > maFontList.size() ? nullptr : &maFontList[nFontIndex-1];
565 }
566 
ReadFont(XclImpStream & rStrm)567 void XclImpFontBuffer::ReadFont( XclImpStream& rStrm )
568 {
569     maFontList.emplace_back( GetRoot() );
570     XclImpFont& rFont = maFontList.back();
571     rFont.ReadFont( rStrm );
572 
573     if( maFontList.size() == 1 )
574     {
575         UpdateAppFont( rFont.GetFontData(), rFont.HasCharSet() );
576         // #i71033# set text encoding from application font, if CODEPAGE is missing
577         SetAppFontEncoding( rFont.GetFontEncoding() );
578     }
579 }
580 
ReadEfont(XclImpStream & rStrm)581 void XclImpFontBuffer::ReadEfont( XclImpStream& rStrm )
582 {
583     if( !maFontList.empty() )
584         maFontList.back().ReadEfont( rStrm );
585 }
586 
FillToItemSet(SfxItemSet & rItemSet,XclFontItemType eType,sal_uInt16 nFontIdx,bool bSkipPoolDefs) const587 void XclImpFontBuffer::FillToItemSet(
588         SfxItemSet& rItemSet, XclFontItemType eType,
589         sal_uInt16 nFontIdx, bool bSkipPoolDefs ) const
590 {
591     if( const XclImpFont* pFont = GetFont( nFontIdx ) )
592         pFont->FillToItemSet( rItemSet, eType, bSkipPoolDefs );
593 }
594 
WriteFontProperties(ScfPropertySet & rPropSet,XclFontPropSetType eType,sal_uInt16 nFontIdx,const Color * pFontColor) const595 void XclImpFontBuffer::WriteFontProperties( ScfPropertySet& rPropSet,
596         XclFontPropSetType eType, sal_uInt16 nFontIdx, const Color* pFontColor ) const
597 {
598     if( const XclImpFont* pFont = GetFont( nFontIdx ) )
599         pFont->WriteFontProperties( rPropSet, eType, pFontColor );
600 }
601 
WriteDefaultCtrlFontProperties(ScfPropertySet & rPropSet) const602 void XclImpFontBuffer::WriteDefaultCtrlFontProperties( ScfPropertySet& rPropSet ) const
603 {
604     maCtrlFont.WriteFontProperties( rPropSet, EXC_FONTPROPSET_CONTROL );
605 }
606 
UpdateAppFont(const XclFontData & rFontData,bool bHasCharSet)607 void XclImpFontBuffer::UpdateAppFont( const XclFontData& rFontData, bool bHasCharSet )
608 {
609     maAppFont = rFontData;
610     // #i3006# Calculate the width of '0' from first font and current printer.
611     SetCharWidth( maAppFont );
612 
613     // font 4 is bold font 0
614     XclFontData aFont4Data( maAppFont );
615     aFont4Data.mnWeight = EXC_FONTWGHT_BOLD;
616     maFont4.SetFontData( aFont4Data, bHasCharSet );
617 }
618 
619 // FORMAT record - number formats =============================================
620 
XclImpNumFmtBuffer(const XclImpRoot & rRoot)621 XclImpNumFmtBuffer::XclImpNumFmtBuffer( const XclImpRoot& rRoot ) :
622     XclNumFmtBuffer( rRoot ),
623     XclImpRoot( rRoot ),
624     mnNextXclIdx( 0 )
625 {
626 }
627 
Initialize()628 void XclImpNumFmtBuffer::Initialize()
629 {
630     maIndexMap.clear();
631     mnNextXclIdx = 0;
632     InitializeImport();     // base class
633 }
634 
ReadFormat(XclImpStream & rStrm)635 void XclImpNumFmtBuffer::ReadFormat( XclImpStream& rStrm )
636 {
637     OUString aFormat;
638     switch( GetBiff() )
639     {
640         case EXC_BIFF2:
641         case EXC_BIFF3:
642             aFormat = rStrm.ReadByteString( false );
643         break;
644 
645         case EXC_BIFF4:
646             rStrm.Ignore( 2 );  // in BIFF4 the index field exists, but is undefined
647             aFormat = rStrm.ReadByteString( false );
648         break;
649 
650         case EXC_BIFF5:
651             mnNextXclIdx = rStrm.ReaduInt16();
652             aFormat = rStrm.ReadByteString( false );
653         break;
654 
655         case EXC_BIFF8:
656             mnNextXclIdx = rStrm.ReaduInt16();
657             aFormat = rStrm.ReadUniString();
658         break;
659 
660         default:
661             DBG_ERROR_BIFF();
662             return;
663     }
664 
665     if( mnNextXclIdx < 0xFFFF )
666     {
667         InsertFormat( mnNextXclIdx, aFormat );
668         ++mnNextXclIdx;
669     }
670 }
671 
ReadCFFormat(XclImpStream & rStrm,bool bIFmt)672 sal_uInt16 XclImpNumFmtBuffer::ReadCFFormat( XclImpStream& rStrm, bool bIFmt )
673 {
674     // internal number format ?
675     if(bIFmt)
676     {
677         rStrm.Ignore(1);
678         sal_uInt8 nIndex;
679         nIndex = rStrm.ReaduInt8();
680         return nIndex;
681     }
682     else
683     {
684         OUString aFormat = rStrm.ReadUniString();
685         InsertFormat( mnNextXclIdx, aFormat );
686         ++mnNextXclIdx;
687         return mnNextXclIdx - 1;
688     }
689 }
690 
CreateScFormats()691 void XclImpNumFmtBuffer::CreateScFormats()
692 {
693     OSL_ENSURE( maIndexMap.empty(), "XclImpNumFmtBuffer::CreateScFormats - already created" );
694 
695     SvNumberFormatter& rFormatter = GetFormatter();
696     for( const auto& [rXclNumFmt, rNumFmt] : GetFormatMap() )
697     {
698         // insert/convert the Excel number format
699         sal_Int32 nCheckPos;
700         SvNumFormatType nType = SvNumFormatType::DEFINED;
701         sal_uInt32 nKey;
702         if( !rNumFmt.maFormat.isEmpty() )
703         {
704             OUString aFormat( rNumFmt.maFormat );
705             rFormatter.PutandConvertEntry( aFormat, nCheckPos,
706                                            nType, nKey, LANGUAGE_ENGLISH_US, rNumFmt.meLanguage, false);
707         }
708         else
709             nKey = rFormatter.GetFormatIndex( rNumFmt.meOffset, rNumFmt.meLanguage );
710 
711         // insert the resulting format key into the Excel->Calc index map
712         maIndexMap[ rXclNumFmt ] = nKey;
713     }
714 }
715 
GetScFormat(sal_uInt16 nXclNumFmt) const716 sal_uInt32 XclImpNumFmtBuffer::GetScFormat( sal_uInt16 nXclNumFmt ) const
717 {
718     XclImpIndexMap::const_iterator aIt = maIndexMap.find( nXclNumFmt );
719     return (aIt != maIndexMap.end()) ? aIt->second : NUMBERFORMAT_ENTRY_NOT_FOUND;
720 }
721 
FillToItemSet(SfxItemSet & rItemSet,sal_uInt16 nXclNumFmt,bool bSkipPoolDefs) const722 void XclImpNumFmtBuffer::FillToItemSet( SfxItemSet& rItemSet, sal_uInt16 nXclNumFmt, bool bSkipPoolDefs ) const
723 {
724     sal_uInt32 nScNumFmt = GetScFormat( nXclNumFmt );
725     if( nScNumFmt == NUMBERFORMAT_ENTRY_NOT_FOUND )
726         nScNumFmt = GetStdScNumFmt();
727     FillScFmtToItemSet( rItemSet, nScNumFmt, bSkipPoolDefs );
728 }
729 
FillScFmtToItemSet(SfxItemSet & rItemSet,sal_uInt32 nScNumFmt,bool bSkipPoolDefs) const730 void XclImpNumFmtBuffer::FillScFmtToItemSet( SfxItemSet& rItemSet, sal_uInt32 nScNumFmt, bool bSkipPoolDefs ) const
731 {
732     OSL_ENSURE( nScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND, "XclImpNumFmtBuffer::FillScFmtToItemSet - invalid number format" );
733     ScfTools::PutItem( rItemSet, SfxUInt32Item( ATTR_VALUE_FORMAT, nScNumFmt ), bSkipPoolDefs );
734     if( rItemSet.GetItemState( ATTR_VALUE_FORMAT, false ) == SfxItemState::SET )
735         ScGlobal::AddLanguage( rItemSet, GetFormatter() );
736 }
737 
738 // XF, STYLE record - Cell formatting =========================================
739 
FillFromXF2(sal_uInt8 nNumFmt)740 void XclImpCellProt::FillFromXF2( sal_uInt8 nNumFmt )
741 {
742     mbLocked = ::get_flag( nNumFmt, EXC_XF2_LOCKED );
743     mbHidden = ::get_flag( nNumFmt, EXC_XF2_HIDDEN );
744 }
745 
FillFromXF3(sal_uInt16 nProt)746 void XclImpCellProt::FillFromXF3( sal_uInt16 nProt )
747 {
748     mbLocked = ::get_flag( nProt, EXC_XF_LOCKED );
749     mbHidden = ::get_flag( nProt, EXC_XF_HIDDEN );
750 }
751 
FillToItemSet(SfxItemSet & rItemSet,bool bSkipPoolDefs) const752 void XclImpCellProt::FillToItemSet( SfxItemSet& rItemSet, bool bSkipPoolDefs ) const
753 {
754     ScfTools::PutItem( rItemSet, ScProtectionAttr( mbLocked, mbHidden ), bSkipPoolDefs );
755 }
756 
FillFromXF2(sal_uInt8 nFlags)757 void XclImpCellAlign::FillFromXF2( sal_uInt8 nFlags )
758 {
759     mnHorAlign = ::extract_value< sal_uInt8 >( nFlags, 0, 3 );
760 }
761 
FillFromXF3(sal_uInt16 nAlign)762 void XclImpCellAlign::FillFromXF3( sal_uInt16 nAlign )
763 {
764     mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
765     mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );   // new in BIFF3
766 }
767 
FillFromXF4(sal_uInt16 nAlign)768 void XclImpCellAlign::FillFromXF4( sal_uInt16 nAlign )
769 {
770     FillFromXF3( nAlign );
771     mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 2 );  // new in BIFF4
772     mnOrient = ::extract_value< sal_uInt8 >( nAlign, 6, 2 );    // new in BIFF4
773 }
774 
FillFromXF5(sal_uInt16 nAlign)775 void XclImpCellAlign::FillFromXF5( sal_uInt16 nAlign )
776 {
777     mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
778     mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
779     mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
780     mnOrient = ::extract_value< sal_uInt8 >( nAlign, 8, 2 );
781 }
782 
FillFromXF8(sal_uInt16 nAlign,sal_uInt16 nMiscAttrib)783 void XclImpCellAlign::FillFromXF8( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
784 {
785     mnHorAlign = ::extract_value< sal_uInt8 >( nAlign, 0, 3 );
786     mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
787     mbLineBreak = ::get_flag( nAlign, EXC_XF_LINEBREAK );
788     mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 );      // new in BIFF8
789     mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 );   // new in BIFF8
790     mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK );           // new in BIFF8
791     mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 );  // new in BIFF8
792 }
793 
FillFromCF(sal_uInt16 nAlign,sal_uInt16 nMiscAttrib)794 void XclImpCellAlign::FillFromCF( sal_uInt16 nAlign, sal_uInt16 nMiscAttrib )
795 {
796     mnHorAlign = extract_value< sal_uInt8 >( nAlign, 0, 3 );
797     mbLineBreak = get_flag< sal_uInt8 >( nAlign, EXC_XF_LINEBREAK );
798     mnVerAlign = ::extract_value< sal_uInt8 >( nAlign, 4, 3 );
799     mnRotation = ::extract_value< sal_uInt8 >( nAlign, 8, 8 );
800     mnIndent = ::extract_value< sal_uInt8 >( nMiscAttrib, 0, 4 );
801     mbShrink = ::get_flag( nMiscAttrib, EXC_XF8_SHRINK );
802     mnTextDir = ::extract_value< sal_uInt8 >( nMiscAttrib, 6, 2 );
803 }
804 
FillToItemSet(SfxItemSet & rItemSet,const XclImpFont * pFont,bool bSkipPoolDefs) const805 void XclImpCellAlign::FillToItemSet( SfxItemSet& rItemSet, const XclImpFont* pFont, bool bSkipPoolDefs ) const
806 {
807     // horizontal alignment
808     ScfTools::PutItem( rItemSet, SvxHorJustifyItem( GetScHorAlign(), ATTR_HOR_JUSTIFY ), bSkipPoolDefs );
809     ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScHorJustifyMethod(), ATTR_HOR_JUSTIFY_METHOD ), bSkipPoolDefs );
810 
811     // text wrap (#i74508# always if vertical alignment is justified or distributed)
812     bool bLineBreak = mbLineBreak || (mnVerAlign == EXC_XF_VER_JUSTIFY) || (mnVerAlign == EXC_XF_VER_DISTRIB);
813     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_LINEBREAK, bLineBreak ), bSkipPoolDefs );
814 
815     // vertical alignment
816     ScfTools::PutItem( rItemSet, SvxVerJustifyItem( GetScVerAlign(), ATTR_VER_JUSTIFY ), bSkipPoolDefs );
817     ScfTools::PutItem( rItemSet, SvxJustifyMethodItem( GetScVerJustifyMethod(), ATTR_VER_JUSTIFY_METHOD ), bSkipPoolDefs );
818 
819     // indent
820     sal_uInt16 nScIndent = mnIndent * 200; // 1 Excel unit == 10 pt == 200 twips
821     ScfTools::PutItem( rItemSet, SfxUInt16Item( ATTR_INDENT, nScIndent ), bSkipPoolDefs );
822 
823     // shrink to fit
824     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_SHRINKTOFIT, mbShrink ), bSkipPoolDefs );
825 
826     // text orientation/rotation (BIFF2-BIFF7 sets mnOrient)
827     sal_uInt8 nXclRot = (mnOrient == EXC_ORIENT_NONE) ? mnRotation : XclTools::GetXclRotFromOrient( mnOrient );
828     bool bStacked = (nXclRot == EXC_ROT_STACKED);
829     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_STACKED, bStacked ), bSkipPoolDefs );
830     // set an angle in the range from -90 to 90 degrees
831     sal_Int32 nAngle = XclTools::GetScRotation( nXclRot, 0 );
832     ScfTools::PutItem( rItemSet, SfxInt32Item( ATTR_ROTATE_VALUE, nAngle ), bSkipPoolDefs );
833     // set "Use asian vertical layout", if cell is stacked and font contains CKJ characters
834     bool bAsianVert = bStacked && pFont && pFont->HasAsianChars();
835     ScfTools::PutItem( rItemSet, SfxBoolItem( ATTR_VERTICAL_ASIAN, bAsianVert ), bSkipPoolDefs );
836 
837     // CTL text direction
838     ScfTools::PutItem( rItemSet, SvxFrameDirectionItem( GetScFrameDir(), ATTR_WRITINGDIR ), bSkipPoolDefs );
839 }
840 
XclImpCellBorder()841 XclImpCellBorder::XclImpCellBorder()
842 {
843     SetUsedFlags( false, false );
844 }
845 
SetUsedFlags(bool bOuterUsed,bool bDiagUsed)846 void XclImpCellBorder::SetUsedFlags( bool bOuterUsed, bool bDiagUsed )
847 {
848     mbLeftUsed = mbRightUsed = mbTopUsed = mbBottomUsed = bOuterUsed;
849     mbDiagUsed = bDiagUsed;
850 }
851 
FillFromXF2(sal_uInt8 nFlags)852 void XclImpCellBorder::FillFromXF2( sal_uInt8 nFlags )
853 {
854     mnLeftLine   = ::get_flagvalue( nFlags, EXC_XF2_LEFTLINE,   EXC_LINE_THIN, EXC_LINE_NONE );
855     mnRightLine  = ::get_flagvalue( nFlags, EXC_XF2_RIGHTLINE,  EXC_LINE_THIN, EXC_LINE_NONE );
856     mnTopLine    = ::get_flagvalue( nFlags, EXC_XF2_TOPLINE,    EXC_LINE_THIN, EXC_LINE_NONE );
857     mnBottomLine = ::get_flagvalue( nFlags, EXC_XF2_BOTTOMLINE, EXC_LINE_THIN, EXC_LINE_NONE );
858     mnLeftColor = mnRightColor = mnTopColor = mnBottomColor = EXC_COLOR_BIFF2_BLACK;
859     SetUsedFlags( true, false );
860 }
861 
FillFromXF3(sal_uInt32 nBorder)862 void XclImpCellBorder::FillFromXF3( sal_uInt32 nBorder )
863 {
864     mnTopLine     = ::extract_value< sal_uInt8  >( nBorder,  0, 3 );
865     mnLeftLine    = ::extract_value< sal_uInt8  >( nBorder,  8, 3 );
866     mnBottomLine  = ::extract_value< sal_uInt8  >( nBorder, 16, 3 );
867     mnRightLine   = ::extract_value< sal_uInt8  >( nBorder, 24, 3 );
868     mnTopColor    = ::extract_value< sal_uInt16 >( nBorder,  3, 5 );
869     mnLeftColor   = ::extract_value< sal_uInt16 >( nBorder, 11, 5 );
870     mnBottomColor = ::extract_value< sal_uInt16 >( nBorder, 19, 5 );
871     mnRightColor  = ::extract_value< sal_uInt16 >( nBorder, 27, 5 );
872     SetUsedFlags( true, false );
873 }
874 
FillFromXF5(sal_uInt32 nBorder,sal_uInt32 nArea)875 void XclImpCellBorder::FillFromXF5( sal_uInt32 nBorder, sal_uInt32 nArea )
876 {
877     mnTopLine     = ::extract_value< sal_uInt8  >( nBorder,  0, 3 );
878     mnLeftLine    = ::extract_value< sal_uInt8  >( nBorder,  3, 3 );
879     mnBottomLine  = ::extract_value< sal_uInt8  >( nArea,   22, 3 );
880     mnRightLine   = ::extract_value< sal_uInt8  >( nBorder,  6, 3 );
881     mnTopColor    = ::extract_value< sal_uInt16 >( nBorder,  9, 7 );
882     mnLeftColor   = ::extract_value< sal_uInt16 >( nBorder, 16, 7 );
883     mnBottomColor = ::extract_value< sal_uInt16 >( nArea,   25, 7 );
884     mnRightColor  = ::extract_value< sal_uInt16 >( nBorder, 23, 7 );
885     SetUsedFlags( true, false );
886 }
887 
FillFromXF8(sal_uInt32 nBorder1,sal_uInt32 nBorder2)888 void XclImpCellBorder::FillFromXF8( sal_uInt32 nBorder1, sal_uInt32 nBorder2 )
889 {
890     mnLeftLine    = ::extract_value< sal_uInt8  >( nBorder1,  0, 4 );
891     mnRightLine   = ::extract_value< sal_uInt8  >( nBorder1,  4, 4 );
892     mnTopLine     = ::extract_value< sal_uInt8  >( nBorder1,  8, 4 );
893     mnBottomLine  = ::extract_value< sal_uInt8  >( nBorder1, 12, 4 );
894     mnLeftColor   = ::extract_value< sal_uInt16 >( nBorder1, 16, 7 );
895     mnRightColor  = ::extract_value< sal_uInt16 >( nBorder1, 23, 7 );
896     mnTopColor    = ::extract_value< sal_uInt16 >( nBorder2,  0, 7 );
897     mnBottomColor = ::extract_value< sal_uInt16 >( nBorder2,  7, 7 );
898     mbDiagTLtoBR  = ::get_flag( nBorder1, EXC_XF_DIAGONAL_TL_TO_BR );
899     mbDiagBLtoTR  = ::get_flag( nBorder1, EXC_XF_DIAGONAL_BL_TO_TR );
900     if( mbDiagTLtoBR || mbDiagBLtoTR )
901     {
902         mnDiagLine  = ::extract_value< sal_uInt8 >( nBorder2, 21, 4 );
903         mnDiagColor = ::extract_value< sal_uInt16 >( nBorder2, 14, 7 );
904     }
905     SetUsedFlags( true, true );
906 }
907 
FillFromCF8(sal_uInt16 nLineStyle,sal_uInt32 nLineColor,sal_uInt32 nFlags)908 void XclImpCellBorder::FillFromCF8( sal_uInt16 nLineStyle, sal_uInt32 nLineColor, sal_uInt32 nFlags )
909 {
910     mnLeftLine    = ::extract_value< sal_uInt8  >( nLineStyle,  0, 4 );
911     mnRightLine   = ::extract_value< sal_uInt8  >( nLineStyle,  4, 4 );
912     mnTopLine     = ::extract_value< sal_uInt8  >( nLineStyle,  8, 4 );
913     mnBottomLine  = ::extract_value< sal_uInt8  >( nLineStyle, 12, 4 );
914     mnLeftColor   = ::extract_value< sal_uInt16 >( nLineColor,  0, 7 );
915     mnRightColor  = ::extract_value< sal_uInt16 >( nLineColor,  7, 7 );
916     mnTopColor    = ::extract_value< sal_uInt16 >( nLineColor, 16, 7 );
917     mnBottomColor = ::extract_value< sal_uInt16 >( nLineColor, 23, 7 );
918     mbLeftUsed    = !::get_flag( nFlags, EXC_CF_BORDER_LEFT );
919     mbRightUsed   = !::get_flag( nFlags, EXC_CF_BORDER_RIGHT );
920     mbTopUsed     = !::get_flag( nFlags, EXC_CF_BORDER_TOP );
921     mbBottomUsed  = !::get_flag( nFlags, EXC_CF_BORDER_BOTTOM );
922     mbDiagUsed    = false;
923 }
924 
HasAnyOuterBorder() const925 bool XclImpCellBorder::HasAnyOuterBorder() const
926 {
927     return
928         (mbLeftUsed   && (mnLeftLine != EXC_LINE_NONE)) ||
929         (mbRightUsed  && (mnRightLine != EXC_LINE_NONE)) ||
930         (mbTopUsed    && (mnTopLine != EXC_LINE_NONE)) ||
931         (mbBottomUsed && (mnBottomLine != EXC_LINE_NONE));
932 }
933 
934 namespace {
935 
936 /** Converts the passed line style to a ::editeng::SvxBorderLine, or returns false, if style is "no line". */
lclConvertBorderLine(::editeng::SvxBorderLine & rLine,const XclImpPalette & rPalette,sal_uInt8 nXclLine,sal_uInt16 nXclColor)937 bool lclConvertBorderLine( ::editeng::SvxBorderLine& rLine, const XclImpPalette& rPalette, sal_uInt8 nXclLine, sal_uInt16 nXclColor )
938 {
939     static const sal_uInt16 ppnLineParam[][ 4 ] =
940     {
941         //  outer width,        type
942         {   0,                  table::BorderLineStyle::SOLID        }, // 0 = none
943         {   EXC_BORDER_THIN,    table::BorderLineStyle::SOLID        }, // 1 = thin
944         {   EXC_BORDER_MEDIUM,  table::BorderLineStyle::SOLID        }, // 2 = medium
945         {   EXC_BORDER_THIN,    table::BorderLineStyle::FINE_DASHED  }, // 3 = dashed
946         {   EXC_BORDER_THIN,    table::BorderLineStyle::DOTTED       }, // 4 = dotted
947         {   EXC_BORDER_THICK,   table::BorderLineStyle::SOLID        }, // 5 = thick
948         {   EXC_BORDER_THICK,   table::BorderLineStyle::DOUBLE_THIN  }, // 6 = double
949         {   EXC_BORDER_HAIR,    table::BorderLineStyle::SOLID        }, // 7 = hair
950         {   EXC_BORDER_MEDIUM,  table::BorderLineStyle::DASHED       }, // 8 = med dash
951         {   EXC_BORDER_THIN,    table::BorderLineStyle::DASH_DOT     }, // 9 = thin dashdot
952         {   EXC_BORDER_MEDIUM,  table::BorderLineStyle::DASH_DOT     }, // A = med dashdot
953         {   EXC_BORDER_THIN,    table::BorderLineStyle::DASH_DOT_DOT }, // B = thin dashdotdot
954         {   EXC_BORDER_MEDIUM,  table::BorderLineStyle::DASH_DOT_DOT }, // C = med dashdotdot
955         {   EXC_BORDER_MEDIUM,  table::BorderLineStyle::DASH_DOT     }  // D = med slant dashdot
956     };
957 
958     if( nXclLine == EXC_LINE_NONE )
959         return false;
960     if( nXclLine >= SAL_N_ELEMENTS( ppnLineParam ) )
961         nXclLine = EXC_LINE_THIN;
962 
963     rLine.SetColor( rPalette.GetColor( nXclColor ) );
964     rLine.SetWidth( ppnLineParam[ nXclLine ][ 0 ] );
965     rLine.SetBorderLineStyle( static_cast< SvxBorderLineStyle>(
966                 ppnLineParam[ nXclLine ][ 1 ]) );
967     return true;
968 }
969 
970 } // namespace
971 
FillToItemSet(SfxItemSet & rItemSet,const XclImpPalette & rPalette,bool bSkipPoolDefs) const972 void XclImpCellBorder::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
973 {
974     if( mbLeftUsed || mbRightUsed || mbTopUsed || mbBottomUsed )
975     {
976         SvxBoxItem aBoxItem( ATTR_BORDER );
977         ::editeng::SvxBorderLine aLine;
978         if( mbLeftUsed && lclConvertBorderLine( aLine, rPalette, mnLeftLine, mnLeftColor ) )
979             aBoxItem.SetLine( &aLine, SvxBoxItemLine::LEFT );
980         if( mbRightUsed && lclConvertBorderLine( aLine, rPalette, mnRightLine, mnRightColor ) )
981             aBoxItem.SetLine( &aLine, SvxBoxItemLine::RIGHT );
982         if( mbTopUsed && lclConvertBorderLine( aLine, rPalette, mnTopLine, mnTopColor ) )
983             aBoxItem.SetLine( &aLine, SvxBoxItemLine::TOP );
984         if( mbBottomUsed && lclConvertBorderLine( aLine, rPalette, mnBottomLine, mnBottomColor ) )
985             aBoxItem.SetLine( &aLine, SvxBoxItemLine::BOTTOM );
986         ScfTools::PutItem( rItemSet, aBoxItem, bSkipPoolDefs );
987     }
988     if( mbDiagUsed )
989     {
990         SvxLineItem aTLBRItem( ATTR_BORDER_TLBR );
991         SvxLineItem aBLTRItem( ATTR_BORDER_BLTR );
992         ::editeng::SvxBorderLine aLine;
993         if( lclConvertBorderLine( aLine, rPalette, mnDiagLine, mnDiagColor ) )
994         {
995             if( mbDiagTLtoBR )
996                 aTLBRItem.SetLine( &aLine );
997             if( mbDiagBLtoTR )
998                 aBLTRItem.SetLine( &aLine );
999         }
1000         ScfTools::PutItem( rItemSet, aTLBRItem, bSkipPoolDefs );
1001         ScfTools::PutItem( rItemSet, aBLTRItem, bSkipPoolDefs );
1002     }
1003 }
1004 
XclImpCellArea()1005 XclImpCellArea::XclImpCellArea()
1006 {
1007     SetUsedFlags( false );
1008 }
1009 
SetUsedFlags(bool bUsed)1010 void XclImpCellArea::SetUsedFlags( bool bUsed )
1011 {
1012     mbForeUsed = mbBackUsed = mbPattUsed = bUsed;
1013 }
1014 
FillFromXF2(sal_uInt8 nFlags)1015 void XclImpCellArea::FillFromXF2( sal_uInt8 nFlags )
1016 {
1017     mnPattern = ::get_flagvalue( nFlags, EXC_XF2_BACKGROUND, EXC_PATT_12_5_PERC, EXC_PATT_NONE );
1018     mnForeColor = EXC_COLOR_BIFF2_BLACK;
1019     mnBackColor = EXC_COLOR_BIFF2_WHITE;
1020     SetUsedFlags( true );
1021 }
1022 
FillFromXF3(sal_uInt16 nArea)1023 void XclImpCellArea::FillFromXF3( sal_uInt16 nArea )
1024 {
1025     mnPattern   = ::extract_value< sal_uInt8  >( nArea,  0, 6 );
1026     mnForeColor = ::extract_value< sal_uInt16 >( nArea,  6, 5 );
1027     mnBackColor = ::extract_value< sal_uInt16 >( nArea, 11, 5 );
1028     SetUsedFlags( true );
1029 }
1030 
FillFromXF5(sal_uInt32 nArea)1031 void XclImpCellArea::FillFromXF5( sal_uInt32 nArea )
1032 {
1033     mnPattern   = ::extract_value< sal_uInt8  >( nArea, 16, 6 );
1034     mnForeColor = ::extract_value< sal_uInt16 >( nArea,  0, 7 );
1035     mnBackColor = ::extract_value< sal_uInt16 >( nArea,  7, 7 );
1036     SetUsedFlags( true );
1037 }
1038 
FillFromXF8(sal_uInt32 nBorder2,sal_uInt16 nArea)1039 void XclImpCellArea::FillFromXF8( sal_uInt32 nBorder2, sal_uInt16 nArea )
1040 {
1041     mnPattern   = ::extract_value< sal_uInt8  >( nBorder2, 26, 6 );
1042     mnForeColor = ::extract_value< sal_uInt16 >( nArea,     0, 7 );
1043     mnBackColor = ::extract_value< sal_uInt16 >( nArea,     7, 7 );
1044     SetUsedFlags( true );
1045 }
1046 
FillFromCF8(sal_uInt16 nPattern,sal_uInt16 nColor,sal_uInt32 nFlags)1047 void XclImpCellArea::FillFromCF8( sal_uInt16 nPattern, sal_uInt16 nColor, sal_uInt32 nFlags )
1048 {
1049     mnForeColor = ::extract_value< sal_uInt16 >( nColor,    0, 7 );
1050     mnBackColor = ::extract_value< sal_uInt16 >( nColor,    7, 7 );
1051     mnPattern   = ::extract_value< sal_uInt8  >( nPattern, 10, 6 );
1052     mbForeUsed  = !::get_flag( nFlags, EXC_CF_AREA_FGCOLOR );
1053     mbBackUsed  = !::get_flag( nFlags, EXC_CF_AREA_BGCOLOR );
1054     mbPattUsed  = !::get_flag( nFlags, EXC_CF_AREA_PATTERN );
1055 
1056     if( mbBackUsed && (!mbPattUsed || (mnPattern == EXC_PATT_SOLID)) )
1057     {
1058         mnForeColor = mnBackColor;
1059         mnPattern = EXC_PATT_SOLID;
1060         mbForeUsed = mbPattUsed = true;
1061     }
1062     else if( !mbBackUsed && mbPattUsed && (mnPattern == EXC_PATT_SOLID) )
1063     {
1064         mbPattUsed = false;
1065     }
1066 }
1067 
FillToItemSet(SfxItemSet & rItemSet,const XclImpPalette & rPalette,bool bSkipPoolDefs) const1068 void XclImpCellArea::FillToItemSet( SfxItemSet& rItemSet, const XclImpPalette& rPalette, bool bSkipPoolDefs ) const
1069 {
1070     if( mbPattUsed )    // colors may be both unused in cond. formats
1071     {
1072         SvxBrushItem aBrushItem( ATTR_BACKGROUND );
1073 
1074         // do not use IsTransparent() - old Calc filter writes tranparency with different color indexes
1075         if( mnPattern == EXC_PATT_NONE )
1076         {
1077             aBrushItem.SetColor( COL_TRANSPARENT );
1078         }
1079         else
1080         {
1081             Color aFore( rPalette.GetColor( mbForeUsed ? mnForeColor : EXC_COLOR_WINDOWTEXT ) );
1082             Color aBack( rPalette.GetColor( mbBackUsed ? mnBackColor : EXC_COLOR_WINDOWBACK ) );
1083             aBrushItem.SetColor( XclTools::GetPatternColor( aFore, aBack, mnPattern ) );
1084         }
1085 
1086         ScfTools::PutItem( rItemSet, aBrushItem, bSkipPoolDefs );
1087     }
1088 }
1089 
XclImpXF(const XclImpRoot & rRoot)1090 XclImpXF::XclImpXF( const XclImpRoot& rRoot ) :
1091     XclXFBase( true ),      // default is cell XF
1092     XclImpRoot( rRoot ),
1093     mpStyleSheet( nullptr ),
1094     mnXclNumFmt( 0 ),
1095     mnXclFont( 0 )
1096 {
1097 }
1098 
~XclImpXF()1099 XclImpXF::~XclImpXF()
1100 {
1101 }
1102 
ReadXF2(XclImpStream & rStrm)1103 void XclImpXF::ReadXF2( XclImpStream& rStrm )
1104 {
1105     sal_uInt8 nReadFont, nReadNumFmt, nFlags;
1106     nReadFont = rStrm.ReaduInt8();
1107     rStrm.Ignore( 1 );
1108     nReadNumFmt = rStrm.ReaduInt8();
1109     nFlags = rStrm.ReaduInt8();
1110 
1111     // XF type always cell, no parent, used flags always true
1112     SetAllUsedFlags( true );
1113 
1114     // attributes
1115     maProtection.FillFromXF2( nReadNumFmt );
1116     mnXclFont = nReadFont;
1117     mnXclNumFmt = nReadNumFmt & EXC_XF2_VALFMT_MASK;
1118     maAlignment.FillFromXF2( nFlags );
1119     maBorder.FillFromXF2( nFlags );
1120     maArea.FillFromXF2( nFlags );
1121 }
1122 
ReadXF3(XclImpStream & rStrm)1123 void XclImpXF::ReadXF3( XclImpStream& rStrm )
1124 {
1125     sal_uInt32 nBorder;
1126     sal_uInt16 nTypeProt, nAlign, nArea;
1127     sal_uInt8 nReadFont, nReadNumFmt;
1128     nReadFont = rStrm.ReaduInt8();
1129     nReadNumFmt = rStrm.ReaduInt8();
1130     nTypeProt = rStrm.ReaduInt16();
1131     nAlign = rStrm.ReaduInt16();
1132     nArea = rStrm.ReaduInt16();
1133     nBorder = rStrm.ReaduInt32();
1134 
1135     // XF type/parent, attribute used flags
1136     mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );          // new in BIFF3
1137     mnParent = ::extract_value< sal_uInt16 >( nAlign, 4, 12 );  // new in BIFF3
1138     SetUsedFlags( ::extract_value< sal_uInt8 >( nTypeProt, 10, 6 ) );
1139 
1140     // attributes
1141     maProtection.FillFromXF3( nTypeProt );
1142     mnXclFont = nReadFont;
1143     mnXclNumFmt = nReadNumFmt;
1144     maAlignment.FillFromXF3( nAlign );
1145     maBorder.FillFromXF3( nBorder );
1146     maArea.FillFromXF3( nArea );                        // new in BIFF3
1147 }
1148 
ReadXF4(XclImpStream & rStrm)1149 void XclImpXF::ReadXF4( XclImpStream& rStrm )
1150 {
1151     sal_uInt32 nBorder;
1152     sal_uInt16 nTypeProt, nAlign, nArea;
1153     sal_uInt8 nReadFont, nReadNumFmt;
1154     nReadFont = rStrm.ReaduInt8();
1155     nReadNumFmt = rStrm.ReaduInt8();
1156     nTypeProt = rStrm.ReaduInt16();
1157     nAlign = rStrm.ReaduInt16();
1158     nArea = rStrm.ReaduInt16();
1159     nBorder = rStrm.ReaduInt32();
1160 
1161     // XF type/parent, attribute used flags
1162     mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1163     mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1164     SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1165 
1166     // attributes
1167     maProtection.FillFromXF3( nTypeProt );
1168     mnXclFont = nReadFont;
1169     mnXclNumFmt = nReadNumFmt;
1170     maAlignment.FillFromXF4( nAlign );
1171     maBorder.FillFromXF3( nBorder );
1172     maArea.FillFromXF3( nArea );
1173 }
1174 
ReadXF5(XclImpStream & rStrm)1175 void XclImpXF::ReadXF5( XclImpStream& rStrm )
1176 {
1177     sal_uInt32 nArea, nBorder;
1178     sal_uInt16 nTypeProt, nAlign;
1179     mnXclFont = rStrm.ReaduInt16();
1180     mnXclNumFmt = rStrm.ReaduInt16();
1181     nTypeProt = rStrm.ReaduInt16();
1182     nAlign = rStrm.ReaduInt16();
1183     nArea = rStrm.ReaduInt32();
1184     nBorder = rStrm.ReaduInt32();
1185 
1186     // XF type/parent, attribute used flags
1187     mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1188     mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1189     SetUsedFlags( ::extract_value< sal_uInt8 >( nAlign, 10, 6 ) );
1190 
1191     // attributes
1192     maProtection.FillFromXF3( nTypeProt );
1193     maAlignment.FillFromXF5( nAlign );
1194     maBorder.FillFromXF5( nBorder, nArea );
1195     maArea.FillFromXF5( nArea );
1196 }
1197 
ReadXF8(XclImpStream & rStrm)1198 void XclImpXF::ReadXF8( XclImpStream& rStrm )
1199 {
1200     sal_uInt32 nBorder1, nBorder2;
1201     sal_uInt16 nTypeProt, nAlign, nMiscAttrib, nArea;
1202     mnXclFont = rStrm.ReaduInt16();
1203     mnXclNumFmt = rStrm.ReaduInt16();
1204     nTypeProt = rStrm.ReaduInt16();
1205     nAlign = rStrm.ReaduInt16();
1206     nMiscAttrib = rStrm.ReaduInt16();
1207     nBorder1 = rStrm.ReaduInt32();
1208     nBorder2 = rStrm.ReaduInt32(  );
1209     nArea = rStrm.ReaduInt16();
1210 
1211     // XF type/parent, attribute used flags
1212     mbCellXF = !::get_flag( nTypeProt, EXC_XF_STYLE );
1213     mnParent = ::extract_value< sal_uInt16 >( nTypeProt, 4, 12 );
1214     SetUsedFlags( ::extract_value< sal_uInt8 >( nMiscAttrib, 10, 6 ) );
1215 
1216     // attributes
1217     maProtection.FillFromXF3( nTypeProt );
1218     maAlignment.FillFromXF8( nAlign, nMiscAttrib );
1219     maBorder.FillFromXF8( nBorder1, nBorder2 );
1220     maArea.FillFromXF8( nBorder2, nArea );
1221 }
1222 
ReadXF(XclImpStream & rStrm)1223 void XclImpXF::ReadXF( XclImpStream& rStrm )
1224 {
1225     switch( GetBiff() )
1226     {
1227         case EXC_BIFF2: ReadXF2( rStrm );   break;
1228         case EXC_BIFF3: ReadXF3( rStrm );   break;
1229         case EXC_BIFF4: ReadXF4( rStrm );   break;
1230         case EXC_BIFF5: ReadXF5( rStrm );   break;
1231         case EXC_BIFF8: ReadXF8( rStrm );   break;
1232         default:        DBG_ERROR_BIFF();
1233     }
1234 }
1235 
CreatePattern(bool bSkipPoolDefs)1236 const ScPatternAttr& XclImpXF::CreatePattern( bool bSkipPoolDefs )
1237 {
1238     if( mpPattern.get() )
1239         return *mpPattern;
1240 
1241     // create new pattern attribute set
1242     mpPattern.reset( new ScPatternAttr( GetDoc().GetPool() ) );
1243     SfxItemSet& rItemSet = mpPattern->GetItemSet();
1244     XclImpXF* pParentXF = IsCellXF() ? GetXFBuffer().GetXF( mnParent ) : nullptr;
1245 
1246     // parent cell style
1247     if( IsCellXF() && !mpStyleSheet )
1248     {
1249         mpStyleSheet = GetXFBuffer().CreateStyleSheet( mnParent );
1250 
1251         /*  Enables mb***Used flags, if the formatting attributes differ from
1252             the passed XF record. In cell XFs Excel uses the cell attributes,
1253             if they differ from the parent style XF.
1254             ...or if the respective flag is not set in parent style XF. */
1255         if( pParentXF )
1256         {
1257             if( !mbProtUsed )
1258                 mbProtUsed = !pParentXF->mbProtUsed || !(maProtection == pParentXF->maProtection);
1259             if( !mbFontUsed )
1260                 mbFontUsed = !pParentXF->mbFontUsed || (mnXclFont != pParentXF->mnXclFont);
1261             if( !mbFmtUsed )
1262                 mbFmtUsed = !pParentXF->mbFmtUsed || (mnXclNumFmt != pParentXF->mnXclNumFmt);
1263             if( !mbAlignUsed )
1264                 mbAlignUsed = !pParentXF->mbAlignUsed || !(maAlignment == pParentXF->maAlignment);
1265             if( !mbBorderUsed )
1266                 mbBorderUsed = !pParentXF->mbBorderUsed || !(maBorder == pParentXF->maBorder);
1267             if( !mbAreaUsed )
1268                 mbAreaUsed = !pParentXF->mbAreaUsed || !(maArea == pParentXF->maArea);
1269         }
1270     }
1271 
1272     // cell protection
1273     if( mbProtUsed )
1274         maProtection.FillToItemSet( rItemSet, bSkipPoolDefs );
1275 
1276     // font
1277     if( mbFontUsed )
1278         GetFontBuffer().FillToItemSet( rItemSet, XclFontItemType::Cell, mnXclFont, bSkipPoolDefs );
1279 
1280     // value format
1281     if( mbFmtUsed )
1282     {
1283         GetNumFmtBuffer().FillToItemSet( rItemSet, mnXclNumFmt, bSkipPoolDefs );
1284         // Trace occurrences of Windows date formats
1285         GetTracer().TraceDates( mnXclNumFmt );
1286     }
1287 
1288     // alignment
1289     if( mbAlignUsed )
1290         maAlignment.FillToItemSet( rItemSet, GetFontBuffer().GetFont( mnXclFont ), bSkipPoolDefs );
1291 
1292     // border
1293     if( mbBorderUsed )
1294     {
1295         maBorder.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1296         GetTracer().TraceBorderLineStyle(maBorder.mnLeftLine > EXC_LINE_HAIR ||
1297             maBorder.mnRightLine > EXC_LINE_HAIR || maBorder.mnTopLine > EXC_LINE_HAIR ||
1298             maBorder.mnBottomLine > EXC_LINE_HAIR );
1299     }
1300 
1301     // area
1302     if( mbAreaUsed )
1303     {
1304         maArea.FillToItemSet( rItemSet, GetPalette(), bSkipPoolDefs );
1305         GetTracer().TraceFillPattern(maArea.mnPattern != EXC_PATT_NONE &&
1306             maArea.mnPattern != EXC_PATT_SOLID);
1307     }
1308 
1309     /*  #i38709# Decide which rotation reference mode to use. If any outer
1310         border line of the cell is set (either explicitly or via cell style),
1311         and the cell contents are rotated, set rotation reference to bottom of
1312         cell. This causes the borders to be painted rotated with the text. */
1313     if( mbAlignUsed || mbBorderUsed )
1314     {
1315         SvxRotateMode eRotateMode = SVX_ROTATE_MODE_STANDARD;
1316         const XclImpCellAlign* pAlign = mbAlignUsed ? &maAlignment : (pParentXF ? &pParentXF->maAlignment : nullptr);
1317         const XclImpCellBorder* pBorder = mbBorderUsed ? &maBorder : (pParentXF ? &pParentXF->maBorder : nullptr);
1318         if( pAlign && pBorder && (0 < pAlign->mnRotation) && (pAlign->mnRotation <= 180) && pBorder->HasAnyOuterBorder() )
1319             eRotateMode = SVX_ROTATE_MODE_BOTTOM;
1320         ScfTools::PutItem( rItemSet, SvxRotateModeItem( eRotateMode, ATTR_ROTATE_MODE ), bSkipPoolDefs );
1321     }
1322 
1323     // Excel's cell margins are different from Calc's default margins.
1324     SvxMarginItem aItem(40, 40, 40, 40, ATTR_MARGIN);
1325     ScfTools::PutItem(rItemSet, aItem, bSkipPoolDefs);
1326 
1327     return *mpPattern;
1328 }
1329 
ApplyPatternToAttrVector(std::vector<ScAttrEntry> & rAttrs,SCROW nRow1,SCROW nRow2,sal_uInt32 nForceScNumFmt)1330 void XclImpXF::ApplyPatternToAttrVector(
1331     std::vector<ScAttrEntry>& rAttrs, SCROW nRow1, SCROW nRow2, sal_uInt32 nForceScNumFmt)
1332 {
1333     // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1334     CreatePattern();
1335     ScPatternAttr& rPat = *mpPattern;
1336 
1337     // insert into document
1338     ScDocument& rDoc = GetDoc();
1339 
1340     if (IsCellXF())
1341     {
1342         if (mpStyleSheet)
1343         {
1344             // Apply style sheet.  Don't clear the direct formats.
1345             rPat.SetStyleSheet(mpStyleSheet, false);
1346         }
1347         else
1348         {
1349             // When the cell format is not associated with any style, use the
1350             // 'Default' style.  Some buggy XLS docs generated by apps other
1351             // than Excel (such as 1C) may not have any built-in styles at
1352             // all.
1353             ScStyleSheetPool* pStylePool = rDoc.GetStyleSheetPool();
1354             if (pStylePool)
1355             {
1356                 ScStyleSheet* pStyleSheet = static_cast<ScStyleSheet*>(
1357                     pStylePool->Find(
1358                         ScResId(STR_STYLENAME_STANDARD), SfxStyleFamily::Para));
1359 
1360                 if (pStyleSheet)
1361                     rPat.SetStyleSheet(pStyleSheet, false);
1362             }
1363 
1364         }
1365     }
1366 
1367     if (nForceScNumFmt != NUMBERFORMAT_ENTRY_NOT_FOUND)
1368     {
1369         ScPatternAttr aNumPat(rDoc.GetPool());
1370         GetNumFmtBuffer().FillScFmtToItemSet(aNumPat.GetItemSet(), nForceScNumFmt);
1371         rPat.GetItemSet().Put(aNumPat.GetItemSet());
1372     }
1373 
1374     // Make sure we skip unnamed styles.
1375     if (rPat.GetStyleName())
1376     {
1377         // Check for a gap between the last entry and this one.
1378         bool bHasGap = false;
1379         if (rAttrs.empty() && nRow1 > 0)
1380             // First attribute range doesn't start at row 0.
1381             bHasGap = true;
1382 
1383         if (!rAttrs.empty() && rAttrs.back().nEndRow + 1 < nRow1)
1384             bHasGap = true;
1385 
1386         if (bHasGap)
1387         {
1388             // Fill this gap with the default pattern.
1389             ScAttrEntry aEntry;
1390             aEntry.nEndRow = nRow1 - 1;
1391             aEntry.pPattern = rDoc.GetDefPattern();
1392             rAttrs.push_back(aEntry);
1393         }
1394 
1395         ScAttrEntry aEntry;
1396         aEntry.nEndRow = nRow2;
1397         aEntry.pPattern = &rDoc.GetPool()->Put(rPat);
1398         rAttrs.push_back(aEntry);
1399     }
1400 }
1401 
ApplyPattern(SCCOL nScCol1,SCROW nScRow1,SCCOL nScCol2,SCROW nScRow2,SCTAB nScTab)1402 void XclImpXF::ApplyPattern(
1403         SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2,
1404         SCTAB nScTab )
1405 {
1406     // force creation of cell style and hard formatting, do it here to have mpStyleSheet
1407     const ScPatternAttr& rPattern = CreatePattern();
1408 
1409     // insert into document
1410     ScDocument& rDoc = GetDoc();
1411     if( IsCellXF() && mpStyleSheet )
1412         rDoc.ApplyStyleAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, *mpStyleSheet );
1413     if( HasUsedFlags() )
1414         rDoc.ApplyPatternAreaTab( nScCol1, nScRow1, nScCol2, nScRow2, nScTab, rPattern );
1415 
1416 }
1417 
ApplyPatternForBiff2CellFormat(const XclImpRoot & rRoot,const ScAddress & rScPos,sal_uInt8 nFlags1,sal_uInt8 nFlags2,sal_uInt8 nFlags3)1418 /*static*/ void XclImpXF::ApplyPatternForBiff2CellFormat( const XclImpRoot& rRoot,
1419         const ScAddress& rScPos, sal_uInt8 nFlags1, sal_uInt8 nFlags2, sal_uInt8 nFlags3 )
1420 {
1421     /*  Create an XF object and let it do the work. We will have access to its
1422         private members here. */
1423     XclImpXF aXF( rRoot );
1424 
1425     // no used flags available in BIFF2 (always true)
1426     aXF.SetAllUsedFlags( true );
1427 
1428     // set the attributes
1429     aXF.maProtection.FillFromXF2( nFlags1 );
1430     aXF.maAlignment.FillFromXF2( nFlags3 );
1431     aXF.maBorder.FillFromXF2( nFlags3 );
1432     aXF.maArea.FillFromXF2( nFlags3 );
1433     aXF.mnXclNumFmt = ::extract_value< sal_uInt16 >( nFlags2, 0, 6 );
1434     aXF.mnXclFont = ::extract_value< sal_uInt16 >( nFlags2, 6, 2 );
1435 
1436     // write the attributes to the cell
1437     aXF.ApplyPattern( rScPos.Col(), rScPos.Row(), rScPos.Col(), rScPos.Row(), rScPos.Tab() );
1438 }
1439 
SetUsedFlags(sal_uInt8 nUsedFlags)1440 void XclImpXF::SetUsedFlags( sal_uInt8 nUsedFlags )
1441 {
1442     /*  Notes about finding the mb***Used flags:
1443         - In cell XFs a *set* bit means a used attribute.
1444         - In style XFs a *cleared* bit means a used attribute.
1445         The mb***Used members always store true, if the attribute is used.
1446         The "mbCellXF == ::get_flag(...)" construct evaluates to true in
1447         both mentioned cases: cell XF and set bit; or style XF and cleared bit.
1448      */
1449     mbProtUsed   = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_PROT ));
1450     mbFontUsed   = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_FONT ));
1451     mbFmtUsed    = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_VALFMT ));
1452     mbAlignUsed  = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_ALIGN ));
1453     mbBorderUsed = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_BORDER ));
1454     mbAreaUsed   = (mbCellXF == ::get_flag( nUsedFlags, EXC_XF_DIFF_AREA ));
1455 }
1456 
XclImpStyle(const XclImpRoot & rRoot)1457 XclImpStyle::XclImpStyle( const XclImpRoot& rRoot ) :
1458     XclImpRoot( rRoot ),
1459     mnXfId( EXC_XF_NOTFOUND ),
1460     mnBuiltinId( EXC_STYLE_USERDEF ),
1461     mnLevel( EXC_STYLE_NOLEVEL ),
1462     mbBuiltin( false ),
1463     mbCustom( false ),
1464     mbHidden( false ),
1465     mpStyleSheet( nullptr )
1466 {
1467 }
1468 
ReadStyle(XclImpStream & rStrm)1469 void XclImpStyle::ReadStyle( XclImpStream& rStrm )
1470 {
1471     OSL_ENSURE_BIFF( GetBiff() >= EXC_BIFF3 );
1472 
1473     sal_uInt16 nXFIndex;
1474     nXFIndex = rStrm.ReaduInt16();
1475     mnXfId = nXFIndex & EXC_STYLE_XFMASK;
1476     mbBuiltin = ::get_flag( nXFIndex, EXC_STYLE_BUILTIN );
1477 
1478     if( mbBuiltin )
1479     {
1480         mnBuiltinId = rStrm.ReaduInt8();
1481         mnLevel = rStrm.ReaduInt8();
1482     }
1483     else
1484     {
1485         maName = (GetBiff() <= EXC_BIFF5) ? rStrm.ReadByteString( false ) : rStrm.ReadUniString();
1486         // #i103281# check if this is a new built-in style introduced in XL2007
1487         if( (GetBiff() == EXC_BIFF8) && (rStrm.GetNextRecId() == EXC_ID_STYLEEXT) && rStrm.StartNextRecord() )
1488         {
1489             sal_uInt8 nExtFlags;
1490             rStrm.Ignore( 12 );
1491             nExtFlags = rStrm.ReaduInt8();
1492             mbBuiltin = ::get_flag( nExtFlags, EXC_STYLEEXT_BUILTIN );
1493             mbCustom = ::get_flag( nExtFlags, EXC_STYLEEXT_CUSTOM );
1494             mbHidden = ::get_flag( nExtFlags, EXC_STYLEEXT_HIDDEN );
1495             if( mbBuiltin )
1496             {
1497                 rStrm.Ignore( 1 );  // category
1498                 mnBuiltinId = rStrm.ReaduInt8();
1499                 mnLevel = rStrm.ReaduInt8();
1500             }
1501         }
1502     }
1503 }
1504 
CreateStyleSheet()1505 ScStyleSheet* XclImpStyle::CreateStyleSheet()
1506 {
1507     // #i1624# #i1768# ignore unnamed user styles
1508     if( !mpStyleSheet && (!maFinalName.isEmpty()) )
1509     {
1510         bool bCreatePattern = false;
1511         XclImpXF* pXF = GetXFBuffer().GetXF( mnXfId );
1512 
1513         bool bDefStyle = mbBuiltin && (mnBuiltinId == EXC_STYLE_NORMAL);
1514         if( bDefStyle )
1515         {
1516             // set all flags to true to get all items in XclImpXF::CreatePattern()
1517             if( pXF ) pXF->SetAllUsedFlags( true );
1518             // use existing "Default" style sheet
1519             mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find(
1520                 ScResId( STR_STYLENAME_STANDARD ), SfxStyleFamily::Para ) );
1521             OSL_ENSURE( mpStyleSheet, "XclImpStyle::CreateStyleSheet - Default style not found" );
1522             bCreatePattern = true;
1523         }
1524         else
1525         {
1526             /*  #i103281# do not create another style sheet of the same name,
1527                 if it exists already. This is needed to prevent that styles
1528                 pasted from clipboard get duplicated over and over. */
1529             mpStyleSheet = static_cast< ScStyleSheet* >( GetStyleSheetPool().Find( maFinalName, SfxStyleFamily::Para ) );
1530             if( !mpStyleSheet )
1531             {
1532                 mpStyleSheet = &static_cast< ScStyleSheet& >( GetStyleSheetPool().Make( maFinalName, SfxStyleFamily::Para, SfxStyleSearchBits::UserDefined ) );
1533                 bCreatePattern = true;
1534             }
1535         }
1536 
1537         // bDefStyle==true omits default pool items in CreatePattern()
1538         if( bCreatePattern && mpStyleSheet && pXF )
1539             mpStyleSheet->GetItemSet().Put( pXF->CreatePattern( bDefStyle ).GetItemSet() );
1540     }
1541     return mpStyleSheet;
1542 }
1543 
CreateUserStyle(const OUString & rFinalName)1544 void XclImpStyle::CreateUserStyle( const OUString& rFinalName )
1545 {
1546     maFinalName = rFinalName;
1547     if( !IsBuiltin() || mbCustom )
1548         CreateStyleSheet();
1549 }
1550 
XclImpXFBuffer(const XclImpRoot & rRoot)1551 XclImpXFBuffer::XclImpXFBuffer( const XclImpRoot& rRoot ) :
1552     XclImpRoot( rRoot )
1553 {
1554 }
1555 
Initialize()1556 void XclImpXFBuffer::Initialize()
1557 {
1558     maXFList.clear();
1559     maBuiltinStyles.clear();
1560     maUserStyles.clear();
1561     maStylesByXf.clear();
1562 }
1563 
ReadXF(XclImpStream & rStrm)1564 void XclImpXFBuffer::ReadXF( XclImpStream& rStrm )
1565 {
1566     XclImpXF* pXF = new XclImpXF( GetRoot() );
1567     pXF->ReadXF( rStrm );
1568     maXFList.push_back( std::unique_ptr<XclImpXF>(pXF) );
1569 }
1570 
ReadStyle(XclImpStream & rStrm)1571 void XclImpXFBuffer::ReadStyle( XclImpStream& rStrm )
1572 {
1573     XclImpStyle* pStyle = new XclImpStyle( GetRoot() );
1574     pStyle->ReadStyle( rStrm );
1575     (pStyle->IsBuiltin() ? maBuiltinStyles : maUserStyles).push_back( std::unique_ptr<XclImpStyle>(pStyle) );
1576     OSL_ENSURE( maStylesByXf.count( pStyle->GetXfId() ) == 0, "XclImpXFBuffer::ReadStyle - multiple styles with equal XF identifier" );
1577     maStylesByXf[ pStyle->GetXfId() ] = pStyle;
1578 }
1579 
GetFontIndex(sal_uInt16 nXFIndex) const1580 sal_uInt16 XclImpXFBuffer::GetFontIndex( sal_uInt16 nXFIndex ) const
1581 {
1582     const XclImpXF* pXF = GetXF( nXFIndex );
1583     return pXF ? pXF->GetFontIndex() : EXC_FONT_NOTFOUND;
1584 }
1585 
GetFont(sal_uInt16 nXFIndex) const1586 const XclImpFont* XclImpXFBuffer::GetFont( sal_uInt16 nXFIndex ) const
1587 {
1588     return GetFontBuffer().GetFont( GetFontIndex( nXFIndex ) );
1589 }
1590 
1591 namespace {
1592 
1593 /** Functor for case-insensitive string comparison, usable in maps etc. */
1594 struct IgnoreCaseCompare
1595 {
operator ()__anon18eef3b20211::IgnoreCaseCompare1596     bool operator()( const OUString& rName1, const OUString& rName2 ) const
1597         { return rName1.compareToIgnoreAsciiCase( rName2 ) < 0; }
1598 };
1599 
1600 } // namespace
1601 
CreateUserStyles()1602 void XclImpXFBuffer::CreateUserStyles()
1603 {
1604     // calculate final names of all styles
1605     typedef ::std::map< OUString, XclImpStyle*, IgnoreCaseCompare > CellStyleNameMap;
1606     typedef ::std::vector< XclImpStyle* > XclImpStyleVector;
1607 
1608     CellStyleNameMap aCellStyles;
1609     XclImpStyleVector aConflictNameStyles;
1610 
1611     /*  First, reserve style names that are built-in in Calc. This causes that
1612         imported cell styles get different unused names and thus do not try to
1613         overwrite these built-in styles. For BIFF4 workbooks (which contain a
1614         separate list of cell styles per sheet), reserve all existing styles if
1615         current sheet is not the first sheet (this styles buffer will be
1616         initialized again for every new sheet). This will create unique names
1617         for styles in different sheets with the same name. Assuming that the
1618         BIFF4W import filter is never used to import from clipboard... */
1619     bool bReserveAll = (GetBiff() == EXC_BIFF4) && (GetCurrScTab() > 0);
1620     SfxStyleSheetIterator aStyleIter( GetDoc().GetStyleSheetPool(), SfxStyleFamily::Para );
1621     OUString aStandardName = ScResId( STR_STYLENAME_STANDARD );
1622     for( SfxStyleSheetBase* pStyleSheet = aStyleIter.First(); pStyleSheet; pStyleSheet = aStyleIter.Next() )
1623         if( (pStyleSheet->GetName() != aStandardName) && (bReserveAll || !pStyleSheet->IsUserDefined()) )
1624             if( aCellStyles.count( pStyleSheet->GetName() ) == 0 )
1625                 aCellStyles[ pStyleSheet->GetName() ] = nullptr;
1626 
1627     /*  Calculate names of built-in styles. Store styles with reserved names
1628         in the aConflictNameStyles list. */
1629     for( const auto& rxStyle : maBuiltinStyles )
1630     {
1631         OUString aStyleName = XclTools::GetBuiltInStyleName( rxStyle->GetBuiltinId(), rxStyle->GetName(), rxStyle->GetLevel() );
1632         OSL_ENSURE( bReserveAll || (aCellStyles.count( aStyleName ) == 0),
1633             "XclImpXFBuffer::CreateUserStyles - multiple styles with equal built-in identifier" );
1634         if( aCellStyles.count( aStyleName ) > 0 )
1635             aConflictNameStyles.push_back( rxStyle.get() );
1636         else
1637             aCellStyles[ aStyleName ] = rxStyle.get();
1638     }
1639 
1640     /*  Calculate names of user defined styles. Store styles with reserved
1641         names in the aConflictNameStyles list. */
1642     for( const auto& rxStyle : maUserStyles )
1643     {
1644         // #i1624# #i1768# ignore unnamed user styles
1645         if( !rxStyle->GetName().isEmpty() )
1646         {
1647             if( aCellStyles.count( rxStyle->GetName() ) > 0 )
1648                 aConflictNameStyles.push_back( rxStyle.get() );
1649             else
1650                 aCellStyles[ rxStyle->GetName() ] = rxStyle.get();
1651         }
1652     }
1653 
1654     // find unused names for all styles with conflicting names
1655     for( XclImpStyle* pStyle : aConflictNameStyles )
1656     {
1657         OUString aUnusedName;
1658         sal_Int32 nIndex = 0;
1659         do
1660         {
1661             aUnusedName = pStyle->GetName() + " " + OUString::number( ++nIndex );
1662         }
1663         while( aCellStyles.count( aUnusedName ) > 0 );
1664         aCellStyles[ aUnusedName ] = pStyle;
1665     }
1666 
1667     // set final names and create user-defined and modified built-in cell styles
1668     for( auto& [rStyleName, rpStyle] : aCellStyles )
1669         if( rpStyle )
1670             rpStyle->CreateUserStyle( rStyleName );
1671 }
1672 
CreateStyleSheet(sal_uInt16 nXFIndex)1673 ScStyleSheet* XclImpXFBuffer::CreateStyleSheet( sal_uInt16 nXFIndex )
1674 {
1675     XclImpStyleMap::iterator aIt = maStylesByXf.find( nXFIndex );
1676     return (aIt == maStylesByXf.end()) ? nullptr : aIt->second->CreateStyleSheet();
1677 }
1678 
1679 // Buffer for XF indexes in cells =============================================
1680 
Expand(SCROW nScRow,const XclImpXFIndex & rXFIndex)1681 bool XclImpXFRange::Expand( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1682 {
1683     if( maXFIndex != rXFIndex )
1684         return false;
1685 
1686     if( mnScRow2 + 1 == nScRow )
1687     {
1688         ++mnScRow2;
1689         return true;
1690     }
1691     if( mnScRow1 > 0 && (mnScRow1 - 1 == nScRow) )
1692     {
1693         --mnScRow1;
1694         return true;
1695     }
1696 
1697     return false;
1698 }
1699 
Expand(const XclImpXFRange & rNextRange)1700 bool XclImpXFRange::Expand( const XclImpXFRange& rNextRange )
1701 {
1702     OSL_ENSURE( mnScRow2 < rNextRange.mnScRow1, "XclImpXFRange::Expand - rows out of order" );
1703     if( (maXFIndex == rNextRange.maXFIndex) && (mnScRow2 + 1 == rNextRange.mnScRow1) )
1704     {
1705         mnScRow2 = rNextRange.mnScRow2;
1706         return true;
1707     }
1708     return false;
1709 }
1710 
SetDefaultXF(const XclImpXFIndex & rXFIndex)1711 void XclImpXFRangeColumn::SetDefaultXF( const XclImpXFIndex& rXFIndex )
1712 {
1713     // List should be empty when inserting the default column format.
1714     // Later explicit SetXF() calls will break up this range.
1715     OSL_ENSURE( maIndexList.empty(), "XclImpXFRangeColumn::SetDefaultXF - Setting Default Column XF is not empty" );
1716 
1717     // insert a complete row range with one insert.
1718     maIndexList.push_back( std::make_unique<XclImpXFRange>( 0, MAXROW, rXFIndex ) );
1719 }
1720 
SetXF(SCROW nScRow,const XclImpXFIndex & rXFIndex)1721 void XclImpXFRangeColumn::SetXF( SCROW nScRow, const XclImpXFIndex& rXFIndex )
1722 {
1723     XclImpXFRange* pPrevRange;
1724     XclImpXFRange* pNextRange;
1725     sal_uLong nNextIndex;
1726 
1727     Find( pPrevRange, pNextRange, nNextIndex, nScRow );
1728 
1729     // previous range:
1730     // try to overwrite XF (if row is contained in) or try to expand range
1731     if( pPrevRange )
1732     {
1733         if( pPrevRange->Contains( nScRow ) )        // overwrite old XF
1734         {
1735             if( rXFIndex == pPrevRange->maXFIndex )
1736                 return;
1737 
1738             SCROW nFirstScRow = pPrevRange->mnScRow1;
1739             SCROW nLastScRow = pPrevRange->mnScRow2;
1740             sal_uLong nIndex = nNextIndex - 1;
1741             XclImpXFRange* pThisRange = pPrevRange;
1742             pPrevRange = (nIndex > 0 && nIndex <= maIndexList.size()) ? maIndexList[ nIndex - 1 ].get() : nullptr;
1743 
1744             if( nFirstScRow == nLastScRow )         // replace solely XF
1745             {
1746                 pThisRange->maXFIndex = rXFIndex;
1747                 TryConcatPrev( nNextIndex );        // try to concat. next with this
1748                 TryConcatPrev( nIndex );            // try to concat. this with previous
1749             }
1750             else if( nFirstScRow == nScRow )        // replace first XF
1751             {
1752                 ++(pThisRange->mnScRow1);
1753                 // try to concatenate with previous of this
1754                 if( !pPrevRange || !pPrevRange->Expand( nScRow, rXFIndex ) )
1755                     Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1756             }
1757             else if( nLastScRow == nScRow )         // replace last XF
1758             {
1759                 --(pThisRange->mnScRow2);
1760                 if( !pNextRange || !pNextRange->Expand( nScRow, rXFIndex ) )
1761                     Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1762             }
1763             else                                    // insert in the middle of the range
1764             {
1765                 pThisRange->mnScRow1 = nScRow + 1;
1766                 // List::Insert() moves entries towards end of list, so insert twice at nIndex
1767                 Insert( new XclImpXFRange( nScRow, rXFIndex ), nIndex );
1768                 Insert( new XclImpXFRange( nFirstScRow, nScRow - 1, pThisRange->maXFIndex ), nIndex );
1769             }
1770             return;
1771         }
1772         else if( pPrevRange->Expand( nScRow, rXFIndex ) )    // try to expand
1773         {
1774             TryConcatPrev( nNextIndex );    // try to concatenate next with expanded
1775             return;
1776         }
1777     }
1778 
1779     // try to expand next range
1780     if( pNextRange && pNextRange->Expand( nScRow, rXFIndex ) )
1781         return;
1782 
1783     // create new range
1784     Insert( new XclImpXFRange( nScRow, rXFIndex ), nNextIndex );
1785 }
1786 
Insert(XclImpXFRange * pXFRange,sal_uLong nIndex)1787 void XclImpXFRangeColumn::Insert(XclImpXFRange* pXFRange, sal_uLong nIndex)
1788 {
1789     maIndexList.insert( maIndexList.begin() + nIndex, std::unique_ptr<XclImpXFRange>(pXFRange) );
1790 }
1791 
Find(XclImpXFRange * & rpPrevRange,XclImpXFRange * & rpNextRange,sal_uLong & rnNextIndex,SCROW nScRow)1792 void XclImpXFRangeColumn::Find(
1793         XclImpXFRange*& rpPrevRange, XclImpXFRange*& rpNextRange,
1794         sal_uLong& rnNextIndex, SCROW nScRow )
1795 {
1796 
1797     // test whether list is empty
1798     if( maIndexList.empty() )
1799     {
1800         rpPrevRange = rpNextRange = nullptr;
1801         rnNextIndex = 0;
1802         return;
1803     }
1804 
1805     rpPrevRange = maIndexList.front().get();
1806     rpNextRange = maIndexList.back().get();
1807 
1808     // test whether row is at end of list (contained in or behind last range)
1809     // rpPrevRange will contain a possible existing row
1810     if( rpNextRange->mnScRow1 <= nScRow )
1811     {
1812         rpPrevRange = rpNextRange;
1813         rpNextRange = nullptr;
1814         rnNextIndex = maIndexList.size();
1815         return;
1816     }
1817 
1818     // test whether row is at beginning of list (really before first range)
1819     if( nScRow < rpPrevRange->mnScRow1 )
1820     {
1821         rpNextRange = rpPrevRange;
1822         rpPrevRange = nullptr;
1823         rnNextIndex = 0;
1824         return;
1825     }
1826 
1827     // loop: find range entries before and after new row
1828     // break the loop if there is no more range between first and last -or-
1829     // if rpPrevRange contains nScRow (rpNextRange will never contain nScRow)
1830     sal_uLong nPrevIndex = 0;
1831     sal_uLong nMidIndex;
1832     rnNextIndex = maIndexList.size() - 1;
1833     XclImpXFRange* pMidRange;
1834     while( ((rnNextIndex - nPrevIndex) > 1) && (rpPrevRange->mnScRow2 < nScRow) )
1835     {
1836         nMidIndex = (nPrevIndex + rnNextIndex) / 2;
1837         pMidRange = maIndexList[nMidIndex].get();
1838         OSL_ENSURE( pMidRange, "XclImpXFRangeColumn::Find - missing XF index range" );
1839         if( nScRow < pMidRange->mnScRow1 )      // row is really before pMidRange
1840         {
1841             rpNextRange = pMidRange;
1842             rnNextIndex = nMidIndex;
1843         }
1844         else                                    // row is in or after pMidRange
1845         {
1846             rpPrevRange = pMidRange;
1847             nPrevIndex = nMidIndex;
1848         }
1849     }
1850 
1851     // find next rpNextRange if rpPrevRange contains nScRow
1852     if( nScRow <= rpPrevRange->mnScRow2 )
1853     {
1854         rnNextIndex = nPrevIndex + 1;
1855         rpNextRange = maIndexList[rnNextIndex].get();
1856     }
1857 }
1858 
TryConcatPrev(sal_uLong nIndex)1859 void XclImpXFRangeColumn::TryConcatPrev( sal_uLong nIndex )
1860 {
1861     if( !nIndex || nIndex >= maIndexList.size() )
1862         return;
1863 
1864     XclImpXFRange& prevRange = *maIndexList[ nIndex - 1 ];
1865     XclImpXFRange& nextRange = *maIndexList[ nIndex ];
1866 
1867     if( prevRange.Expand( nextRange ) )
1868         maIndexList.erase( maIndexList.begin() + nIndex );
1869 }
1870 
XclImpXFRangeBuffer(const XclImpRoot & rRoot)1871 XclImpXFRangeBuffer::XclImpXFRangeBuffer( const XclImpRoot& rRoot ) :
1872     XclImpRoot( rRoot )
1873 {
1874 }
1875 
~XclImpXFRangeBuffer()1876 XclImpXFRangeBuffer::~XclImpXFRangeBuffer()
1877 {
1878 }
1879 
Initialize()1880 void XclImpXFRangeBuffer::Initialize()
1881 {
1882     maColumns.clear();
1883     maHyperlinks.clear();
1884     maMergeList.RemoveAll();
1885 }
1886 
SetXF(const ScAddress & rScPos,sal_uInt16 nXFIndex,XclImpXFInsertMode eMode)1887 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex, XclImpXFInsertMode eMode )
1888 {
1889     SCCOL nScCol = rScPos.Col();
1890     SCROW nScRow = rScPos.Row();
1891 
1892     // set cell XF's
1893     size_t nIndex = static_cast< size_t >( nScCol );
1894     if( maColumns.size() <= nIndex )
1895         maColumns.resize( nIndex + 1 );
1896     if( !maColumns[ nIndex ] )
1897         maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1898     // remember all Boolean cells, they will get 'Standard' number format
1899     maColumns[ nIndex ]->SetXF( nScRow, XclImpXFIndex( nXFIndex, eMode == xlXFModeBoolCell ) );
1900 
1901     // set "center across selection" and "fill" attribute for all following empty cells
1902     // ignore it on row default XFs
1903     if( eMode != xlXFModeRow )
1904     {
1905         const XclImpXF* pXF = GetXFBuffer().GetXF( nXFIndex );
1906         if( pXF && ((pXF->GetHorAlign() == EXC_XF_HOR_CENTER_AS) || (pXF->GetHorAlign() == EXC_XF_HOR_FILL)) )
1907         {
1908             // expand last merged range if this attribute is set repeatedly
1909             ScRange* pRange = maMergeList.empty() ? nullptr : &maMergeList.back();
1910             if (pRange && (pRange->aEnd.Row() == nScRow) && (pRange->aEnd.Col() + 1 == nScCol) && (eMode == xlXFModeBlank))
1911                 pRange->aEnd.IncCol();
1912             else if( eMode != xlXFModeBlank )   // do not merge empty cells
1913                 maMergeList.push_back( ScRange( nScCol, nScRow, 0 ) );
1914         }
1915     }
1916 }
1917 
SetXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1918 void XclImpXFRangeBuffer::SetXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1919 {
1920     SetXF( rScPos, nXFIndex, xlXFModeCell );
1921 }
1922 
SetBlankXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1923 void XclImpXFRangeBuffer::SetBlankXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1924 {
1925     SetXF( rScPos, nXFIndex, xlXFModeBlank );
1926 }
1927 
SetBoolXF(const ScAddress & rScPos,sal_uInt16 nXFIndex)1928 void XclImpXFRangeBuffer::SetBoolXF( const ScAddress& rScPos, sal_uInt16 nXFIndex )
1929 {
1930     SetXF( rScPos, nXFIndex, xlXFModeBoolCell );
1931 }
1932 
SetRowDefXF(SCROW nScRow,sal_uInt16 nXFIndex)1933 void XclImpXFRangeBuffer::SetRowDefXF( SCROW nScRow, sal_uInt16 nXFIndex )
1934 {
1935     for( SCCOL nScCol = 0; nScCol <= MAXCOL; ++nScCol )
1936         SetXF( ScAddress( nScCol, nScRow, 0 ), nXFIndex, xlXFModeRow );
1937 }
1938 
SetColumnDefXF(SCCOL nScCol,sal_uInt16 nXFIndex)1939 void XclImpXFRangeBuffer::SetColumnDefXF( SCCOL nScCol, sal_uInt16 nXFIndex )
1940 {
1941     // our array should not have values when creating the default column format.
1942     size_t nIndex = static_cast< size_t >( nScCol );
1943     if( maColumns.size() <= nIndex )
1944         maColumns.resize( nIndex + 1 );
1945     OSL_ENSURE( !maColumns[ nIndex ], "XclImpXFRangeBuffer::SetColumnDefXF - default column of XFs already has values" );
1946     maColumns[ nIndex ].reset( new XclImpXFRangeColumn );
1947     maColumns[ nIndex ]->SetDefaultXF( XclImpXFIndex( nXFIndex ) );
1948 }
1949 
SetBorderLine(const ScRange & rRange,SCTAB nScTab,SvxBoxItemLine nLine)1950 void XclImpXFRangeBuffer::SetBorderLine( const ScRange& rRange, SCTAB nScTab, SvxBoxItemLine nLine )
1951 {
1952     SCCOL nFromScCol = (nLine == SvxBoxItemLine::RIGHT) ? rRange.aEnd.Col() : rRange.aStart.Col();
1953     SCROW nFromScRow = (nLine == SvxBoxItemLine::BOTTOM) ? rRange.aEnd.Row() : rRange.aStart.Row();
1954     ScDocument& rDoc = GetDoc();
1955 
1956     const SvxBoxItem* pFromItem =
1957         rDoc.GetAttr( nFromScCol, nFromScRow, nScTab, ATTR_BORDER );
1958     const SvxBoxItem* pToItem =
1959         rDoc.GetAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, ATTR_BORDER );
1960 
1961     SvxBoxItem aNewItem( *pToItem );
1962     aNewItem.SetLine( pFromItem->GetLine( nLine ), nLine );
1963     rDoc.ApplyAttr( rRange.aStart.Col(), rRange.aStart.Row(), nScTab, aNewItem );
1964 }
1965 
SetHyperlink(const XclRange & rXclRange,const OUString & rUrl)1966 void XclImpXFRangeBuffer::SetHyperlink( const XclRange& rXclRange, const OUString& rUrl )
1967 {
1968     maHyperlinks.emplace_back( rXclRange, rUrl );
1969 }
1970 
SetMerge(SCCOL nScCol1,SCROW nScRow1,SCCOL nScCol2,SCROW nScRow2)1971 void XclImpXFRangeBuffer::SetMerge( SCCOL nScCol1, SCROW nScRow1, SCCOL nScCol2, SCROW nScRow2 )
1972 {
1973     if( (nScCol1 < nScCol2) || (nScRow1 < nScRow2) )
1974         maMergeList.push_back( ScRange( nScCol1, nScRow1, 0, nScCol2, nScRow2, 0 ) );
1975 }
1976 
Finalize()1977 void XclImpXFRangeBuffer::Finalize()
1978 {
1979     ScDocumentImport& rDocImport = GetDocImport();
1980     ScDocument& rDoc = rDocImport.getDoc();
1981     SCTAB nScTab = GetCurrScTab();
1982 
1983     // apply patterns
1984     XclImpXFBuffer& rXFBuffer = GetXFBuffer();
1985     SCCOL nScCol = 0;
1986     for( const auto& rxColumn : maColumns )
1987     {
1988         // apply all cell styles of an existing column
1989         if( rxColumn.get() )
1990         {
1991             XclImpXFRangeColumn& rColumn = *rxColumn;
1992             std::vector<ScAttrEntry> aAttrs;
1993             aAttrs.reserve(rColumn.end() - rColumn.begin());
1994 
1995             for (const auto& rxStyle : rColumn)
1996             {
1997                 XclImpXFRange& rStyle = *rxStyle;
1998                 const XclImpXFIndex& rXFIndex = rStyle.maXFIndex;
1999                 XclImpXF* pXF = rXFBuffer.GetXF( rXFIndex.GetXFIndex() );
2000                 if (!pXF)
2001                     continue;
2002 
2003                 sal_uInt32 nForceScNumFmt = rXFIndex.IsBoolCell() ?
2004                     GetNumFmtBuffer().GetStdScNumFmt() : NUMBERFORMAT_ENTRY_NOT_FOUND;
2005 
2006                 pXF->ApplyPatternToAttrVector(aAttrs, rStyle.mnScRow1, rStyle.mnScRow2, nForceScNumFmt);
2007             }
2008 
2009             if (aAttrs.empty() || aAttrs.back().nEndRow != rDoc.MaxRow())
2010             {
2011                 ScAttrEntry aEntry;
2012                 aEntry.nEndRow = rDoc.MaxRow();
2013                 aEntry.pPattern = rDoc.GetDefPattern();
2014                 aAttrs.push_back(aEntry);
2015             }
2016 
2017             aAttrs.shrink_to_fit();
2018             assert(aAttrs.size() > 0);
2019             ScDocumentImport::Attrs aAttrParam;
2020             aAttrParam.mvData.swap(aAttrs);
2021             aAttrParam.mbLatinNumFmtOnly = false; // when unsure, set it to false.
2022             rDocImport.setAttrEntries(nScTab, nScCol, std::move(aAttrParam));
2023         }
2024         ++nScCol;
2025     }
2026 
2027     // insert hyperlink cells
2028     for( const auto& [rXclRange, rUrl] : maHyperlinks )
2029         XclImpHyperlink::InsertUrl( GetRoot(), rXclRange, rUrl );
2030 
2031     // apply cell merging
2032     for ( size_t i = 0, nRange = maMergeList.size(); i < nRange; ++i )
2033     {
2034         const ScRange & rRange = maMergeList[ i ];
2035         const ScAddress& rStart = rRange.aStart;
2036         const ScAddress& rEnd = rRange.aEnd;
2037         bool bMultiCol = rStart.Col() != rEnd.Col();
2038         bool bMultiRow = rStart.Row() != rEnd.Row();
2039         // set correct right border
2040         if( bMultiCol )
2041             SetBorderLine( rRange, nScTab, SvxBoxItemLine::RIGHT );
2042         // set correct lower border
2043         if( bMultiRow )
2044             SetBorderLine( rRange, nScTab, SvxBoxItemLine::BOTTOM );
2045         // do merge
2046         if( bMultiCol || bMultiRow )
2047             rDoc.DoMerge( nScTab, rStart.Col(), rStart.Row(), rEnd.Col(), rEnd.Row() );
2048         // #i93609# merged range in a single row: test if manual row height is needed
2049         if( !bMultiRow )
2050         {
2051             bool bTextWrap = rDoc.GetAttr( rStart, ATTR_LINEBREAK )->GetValue();
2052             if( !bTextWrap && (rDoc.GetCellType( rStart ) == CELLTYPE_EDIT) )
2053                 if (const EditTextObject* pEditObj = rDoc.GetEditText(rStart))
2054                     bTextWrap = pEditObj->GetParagraphCount() > 1;
2055             if( bTextWrap )
2056                 GetOldRoot().pColRowBuff->SetManualRowHeight( rStart.Row() );
2057         }
2058     }
2059 }
2060 
2061 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2062