LibreOffice Module sc (master)  1
xltools.cxx
Go to the documentation of this file.
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 <algorithm>
21 #include <math.h>
22 #include <string_view>
23 
24 #include <o3tl/unit_conversion.hxx>
25 #include <sal/mathconf.h>
26 #include <sal/macros.h>
27 #include <sal/log.hxx>
28 #include <tools/solar.h>
29 #include <unotools/fontdefs.hxx>
31 #include <xestream.hxx>
32 #include <global.hxx>
33 #include <formula/errorcodes.hxx>
34 #include <globstr.hrc>
35 #include <scresid.hxx>
36 #include <xlstyle.hxx>
37 #include <xlname.hxx>
38 #include <xistream.hxx>
39 #include <xltools.hxx>
40 
41 // GUID import/export
42 
44  : mpnData{}
45 {
46 }
47 
49  sal_uInt32 nData1, sal_uInt16 nData2, sal_uInt16 nData3,
50  sal_uInt8 nData41, sal_uInt8 nData42, sal_uInt8 nData43, sal_uInt8 nData44,
51  sal_uInt8 nData45, sal_uInt8 nData46, sal_uInt8 nData47, sal_uInt8 nData48 )
52 {
53  // convert to little endian -> makes streaming easy
54  UInt32ToSVBT32( nData1, mpnData );
55  ShortToSVBT16( nData2, mpnData + 4 );
56  ShortToSVBT16( nData3, mpnData + 6 );
57  mpnData[ 8 ] = nData41;
58  mpnData[ 9 ] = nData42;
59  mpnData[ 10 ] = nData43;
60  mpnData[ 11 ] = nData44;
61  mpnData[ 12 ] = nData45;
62  mpnData[ 13 ] = nData46;
63  mpnData[ 14 ] = nData47;
64  mpnData[ 15 ] = nData48;
65 }
66 
67 bool operator==( const XclGuid& rCmp1, const XclGuid& rCmp2 )
68 {
69  return ::std::equal( rCmp1.mpnData, std::end( rCmp1.mpnData ), rCmp2.mpnData );
70 }
71 
73 {
74  rStrm.Read( rGuid.mpnData, 16 ); // mpnData always in little endian
75  return rStrm;
76 }
77 
78 XclExpStream& operator<<( XclExpStream& rStrm, const XclGuid& rGuid )
79 {
80  rStrm.Write( rGuid.mpnData, 16 ); // mpnData already in little endian
81  return rStrm;
82 }
83 
84 // Excel Tools
85 
86 // GUID's
88  0x79EAC9D0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
89 
91  0x79EAC9E0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B );
92 
94  0x00000303, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 );
95 
96 // numeric conversion
97 
98 double XclTools::GetDoubleFromRK( sal_Int32 nRKValue )
99 {
100  union
101  {
102  double fVal;
103  sal_math_Double smD;
104  };
105  fVal = 0.0;
106 
107  if( ::get_flag( nRKValue, EXC_RK_INTFLAG ) )
108  {
109  sal_Int32 nTemp = nRKValue >> 2;
110  ::set_flag< sal_Int32 >( nTemp, 0xE0000000, nRKValue < 0 );
111  fVal = nTemp;
112  }
113  else
114  {
115  smD.w32_parts.msw = nRKValue & EXC_RK_VALUEMASK;
116  }
117 
118  if( ::get_flag( nRKValue, EXC_RK_100FLAG ) )
119  fVal /= 100.0;
120 
121  return fVal;
122 }
123 
124 bool XclTools::GetRKFromDouble( sal_Int32& rnRKValue, double fValue )
125 {
126  double fFrac, fInt;
127 
128  // integer
129  fFrac = modf( fValue, &fInt );
130  if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) ) // 2^29
131  {
132  rnRKValue
133  = static_cast<sal_Int32>(
134  static_cast<sal_uInt32>(static_cast<sal_Int32>(fInt)) << 2)
135  | EXC_RK_INT;
136  return true;
137  }
138 
139  // integer/100
140  fFrac = modf( fValue * 100.0, &fInt );
141  if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) )
142  {
143  rnRKValue
144  = static_cast<sal_Int32>(
145  static_cast<sal_uInt32>(static_cast<sal_Int32>(fInt)) << 2)
146  | EXC_RK_INT100;
147  return true;
148  }
149 
150  // double
151  return false;
152 }
153 
154 Degree100 XclTools::GetScRotation( sal_uInt16 nXclRot, Degree100 nRotForStacked )
155 {
156  if( nXclRot == EXC_ROT_STACKED )
157  return nRotForStacked;
158  OSL_ENSURE( nXclRot <= 180, "XclTools::GetScRotation - illegal rotation angle" );
159  return Degree100(static_cast< sal_Int32 >( (nXclRot <= 180) ? (100 * ((nXclRot > 90) ? (450 - nXclRot) : nXclRot)) : 0 ));
160 }
161 
163 {
164  sal_Int32 nXclRot = nScRot.get() / 100;
165  if( (0 <= nXclRot) && (nXclRot <= 90) )
166  return static_cast< sal_uInt8 >( nXclRot );
167  if( nXclRot < 180 )
168  return static_cast< sal_uInt8 >( 270 - nXclRot );
169  if( nXclRot < 270 )
170  return static_cast< sal_uInt8 >( nXclRot - 180 );
171  if( nXclRot < 360 )
172  return static_cast< sal_uInt8 >( 450 - nXclRot );
173  return 0;
174 }
175 
177 {
178  switch( nXclOrient )
179  {
180  case EXC_ORIENT_NONE: return EXC_ROT_NONE;
181  case EXC_ORIENT_STACKED: return EXC_ROT_STACKED;
182  case EXC_ORIENT_90CCW: return EXC_ROT_90CCW;
183  case EXC_ORIENT_90CW: return EXC_ROT_90CW;
184  default: OSL_FAIL( "XclTools::GetXclRotFromOrient - unknown text orientation" );
185  }
186  return EXC_ROT_NONE;
187 }
188 
190 {
191  if( nXclRot == EXC_ROT_STACKED )
192  return EXC_ORIENT_STACKED;
193  OSL_ENSURE( nXclRot <= 180, "XclTools::GetXclOrientFromRot - unknown text rotation" );
194  if( (45 < nXclRot) && (nXclRot <= 90) )
195  return EXC_ORIENT_90CCW;
196  if( (135 < nXclRot) && (nXclRot <= 180) )
197  return EXC_ORIENT_90CW;
198  return EXC_ORIENT_NONE;
199 }
200 
202 {
203  switch( nScError )
204  {
205  case FormulaError::IllegalArgument: return EXC_ERR_VALUE;
206  case FormulaError::IllegalFPOperation: return EXC_ERR_NUM; // maybe DIV/0 or NUM...
207  case FormulaError::DivisionByZero: return EXC_ERR_DIV0;
208  case FormulaError::IllegalParameter: return EXC_ERR_VALUE;
209  case FormulaError::PairExpected: return EXC_ERR_VALUE;
210  case FormulaError::OperatorExpected: return EXC_ERR_VALUE;
211  case FormulaError::VariableExpected: return EXC_ERR_VALUE;
212  case FormulaError::ParameterExpected: return EXC_ERR_VALUE;
213  case FormulaError::NoValue: return EXC_ERR_VALUE;
214  case FormulaError::CircularReference: return EXC_ERR_VALUE;
215  case FormulaError::NoCode: return EXC_ERR_NULL;
216  case FormulaError::NoRef: return EXC_ERR_REF;
217  case FormulaError::NoName: return EXC_ERR_NAME;
218  case FormulaError::NoAddin: return EXC_ERR_NAME;
219  case FormulaError::NoMacro: return EXC_ERR_NAME;
220  case FormulaError::NotAvailable: return EXC_ERR_NA;
221  default: break;
222  }
223  return EXC_ERR_NA;
224 }
225 
227 {
228  switch( nXclError )
229  {
230  case EXC_ERR_NULL: return FormulaError::NoCode;
231  case EXC_ERR_DIV0: return FormulaError::DivisionByZero;
232  case EXC_ERR_VALUE: return FormulaError::NoValue;
233  case EXC_ERR_REF: return FormulaError::NoRef;
234  case EXC_ERR_NAME: return FormulaError::NoName;
235  case EXC_ERR_NUM: return FormulaError::IllegalFPOperation;
236  case EXC_ERR_NA: return FormulaError::NotAvailable;
237  default: OSL_FAIL( "XclTools::GetScErrorCode - unknown error code" );
238  }
239  return FormulaError::NotAvailable;
240 }
241 
243 {
244  return CreateDoubleError(GetScErrorCode( nXclError ));
245 }
246 
247 XclBoolError XclTools::ErrorToEnum( double& rfDblValue, bool bErrOrBool, sal_uInt8 nValue )
248 {
250  if( bErrOrBool )
251  {
252  // error value
253  switch( nValue )
254  {
255  case EXC_ERR_NULL: eType = xlErrNull; break;
256  case EXC_ERR_DIV0: eType = xlErrDiv0; break;
257  case EXC_ERR_VALUE: eType = xlErrValue; break;
258  case EXC_ERR_REF: eType = xlErrRef; break;
259  case EXC_ERR_NAME: eType = xlErrName; break;
260  case EXC_ERR_NUM: eType = xlErrNum; break;
261  case EXC_ERR_NA: eType = xlErrNA; break;
262  default: eType = xlErrUnknown;
263  }
264  rfDblValue = 0.0;
265  }
266  else
267  {
268  // Boolean value
269  eType = nValue ? xlErrTrue : xlErrFalse;
270  rfDblValue = nValue ? 1.0 : 0.0;
271  }
272  return eType;
273 }
274 
275 template <typename N> static N to(double f) { return limit_cast<N>(f + 0.5); }
276 
277 sal_uInt16 XclTools::GetTwipsFromInch( double fInches )
278 {
279  return to<sal_uInt16>(o3tl::convert(fInches, o3tl::Length::in, o3tl::Length::twip));
280 }
281 
282 sal_uInt16 XclTools::GetTwipsFromHmm( sal_Int32 nHmm )
283 {
285 }
286 
287 double XclTools::GetInchFromTwips( sal_Int32 nTwips )
288 {
289  return o3tl::convert<double>(nTwips, o3tl::Length::twip, o3tl::Length::in);
290 }
291 
292 double XclTools::GetInchFromHmm( sal_Int32 nHmm )
293 {
294  return o3tl::convert<double>(nHmm, o3tl::Length::mm100, o3tl::Length::in);
295 }
296 
297 sal_Int32 XclTools::GetHmmFromInch( double fInches )
298 {
299  return to<sal_Int32>(o3tl::convert(fInches, o3tl::Length::in, o3tl::Length::mm100));
300 }
301 
302 sal_Int32 XclTools::GetHmmFromTwips( sal_Int32 nTwips )
303 {
304  return limit_cast<sal_Int32>(o3tl::convert(nTwips, o3tl::Length::twip, o3tl::Length::mm100));
305 }
306 
307 sal_uInt16 XclTools::GetScColumnWidth( sal_uInt16 nXclWidth, tools::Long nScCharWidth )
308 {
309  double fScWidth = static_cast< double >( nXclWidth ) / 256.0 * nScCharWidth - 0.5;
310  return limit_cast< sal_uInt16 >( fScWidth );
311 }
312 
313 sal_uInt16 XclTools::GetXclColumnWidth( sal_uInt16 nScWidth, tools::Long nScCharWidth )
314 {
315  double fXclWidth = ( static_cast< double >( nScWidth ) + 0.5 ) * 256.0 / nScCharWidth;
316  return limit_cast< sal_uInt16 >( fXclWidth );
317 }
318 
319 // takes font height in twips (1/20 pt = 1/1440 in)
320 // returns correction value in 1/256th of *digit width* of default font
322 {
323  // Excel uses *max digit width of default font* (W) as cell width unit. Also it has 5-pixel
324  // "correction" to cell widths (ECMA-376-1:2016 18.3.1.81): each cell has 1-pixel padding, then
325  // 3 pixels for the border (which may be 1-pixel - hairline - then it will have 2 additional
326  // 1-pixel spacings from each side; or e.g. 2 hairlines with 1-pixel spacing in the middle; or
327  // thick 3-pixel). Obviously, correction size entirely depends on pixel size (and it is actually
328  // different in Excel on monitors with different resolution). Thus actual (displayed/printed)
329  // cell widths consist of X*W+5px; stored in file is the X (or X*256 if 1/256th of digit width
330  // units are used) value.
331  // This formula apparently converts this 5-pixel correction to 1/256th of digit width units.
332  // Looks like it is created from
333  //
334  // 5 * 256 * 1440 * 2.1333 / (96 * max(N-15, 60)) + 50.0
335  //
336  // where 5 - pixel correction; 256 - used to produce 1/256th of digit width; 1440 - used to
337  // convert font height N (in twips) to inches; 2.1333 - an (empirical?) quotient to convert
338  // font *height* into digit *width*; 96 - "standard" monitor resolution (DPI).
339  // Additionally the formula uses 15 (of unknown origin), 60 (minimal font height 3 pt), and
340  // 50.0 (also of unknown origin).
341  //
342  // TODO: convert this to take font digit width directly (and possibly DPI?), to avoid guessing
343  // the digit width and pixel size. Or DPI might stay 96, to not follow Excel dependency on DPI
344  // in addition to used font, and have absolute size of the correction fixed 5/96 in.
345  return 40960.0 / ::std::max( nXclDefFontHeight - 15, tools::Long(60) ) + 50.0;
346 }
347 
348 // formatting
349 
350 Color XclTools::GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt16 nXclPattern )
351 {
352  // 0x00 == 0% transparence (full rPattColor)
353  // 0x80 == 100% transparence (full rBackColor)
354  static const sal_uInt8 pnRatioTable[] =
355  {
356  0x80, 0x00, 0x40, 0x20, 0x60, 0x40, 0x40, 0x40, // 00 - 07
357  0x40, 0x40, 0x20, 0x60, 0x60, 0x60, 0x60, 0x48, // 08 - 15
358  0x50, 0x70, 0x78 // 16 - 18
359  };
360  return (nXclPattern < SAL_N_ELEMENTS( pnRatioTable )) ?
361  ScfTools::GetMixedColor( rPattColor, rBackColor, pnRatioTable[ nXclPattern ] ) : rPattColor;
362 }
363 
364 // text encoding
365 
366 namespace {
367 
368 const struct XclCodePageEntry
369 {
370  sal_uInt16 mnCodePage;
371  rtl_TextEncoding meTextEnc;
372 }
373 pCodePageTable[] =
374 {
375  { 437, RTL_TEXTENCODING_IBM_437 }, // OEM US
376 // { 720, RTL_TEXTENCODING_IBM_720 }, // OEM Arabic
377  { 737, RTL_TEXTENCODING_IBM_737 }, // OEM Greek
378  { 775, RTL_TEXTENCODING_IBM_775 }, // OEM Baltic
379  { 850, RTL_TEXTENCODING_IBM_850 }, // OEM Latin I
380  { 852, RTL_TEXTENCODING_IBM_852 }, // OEM Latin II (Central European)
381  { 855, RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic
382  { 857, RTL_TEXTENCODING_IBM_857 }, // OEM Turkish
383 // { 858, RTL_TEXTENCODING_IBM_858 }, // OEM Multilingual Latin I with Euro
384  { 860, RTL_TEXTENCODING_IBM_860 }, // OEM Portuguese
385  { 861, RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic
386  { 862, RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew
387  { 863, RTL_TEXTENCODING_IBM_863 }, // OEM Canadian (French)
388  { 864, RTL_TEXTENCODING_IBM_864 }, // OEM Arabic
389  { 865, RTL_TEXTENCODING_IBM_865 }, // OEM Nordic
390  { 866, RTL_TEXTENCODING_IBM_866 }, // OEM Cyrillic (Russian)
391  { 869, RTL_TEXTENCODING_IBM_869 }, // OEM Greek (Modern)
392  { 874, RTL_TEXTENCODING_MS_874 }, // MS Windows Thai
393  { 932, RTL_TEXTENCODING_MS_932 }, // MS Windows Japanese Shift-JIS
394  { 936, RTL_TEXTENCODING_MS_936 }, // MS Windows Chinese Simplified GBK
395  { 949, RTL_TEXTENCODING_MS_949 }, // MS Windows Korean (Wansung)
396  { 950, RTL_TEXTENCODING_MS_950 }, // MS Windows Chinese Traditional BIG5
397  { 1200, RTL_TEXTENCODING_DONTKNOW }, // Unicode (BIFF8) - return *_DONTKNOW to preserve old code page
398  { 1250, RTL_TEXTENCODING_MS_1250 }, // MS Windows Latin II (Central European)
399  { 1251, RTL_TEXTENCODING_MS_1251 }, // MS Windows Cyrillic
400  { 1252, RTL_TEXTENCODING_MS_1252 }, // MS Windows Latin I (BIFF4-BIFF8)
401  { 1253, RTL_TEXTENCODING_MS_1253 }, // MS Windows Greek
402  { 1254, RTL_TEXTENCODING_MS_1254 }, // MS Windows Turkish
403  { 1255, RTL_TEXTENCODING_MS_1255 }, // MS Windows Hebrew
404  { 1256, RTL_TEXTENCODING_MS_1256 }, // MS Windows Arabic
405  { 1257, RTL_TEXTENCODING_MS_1257 }, // MS Windows Baltic
406  { 1258, RTL_TEXTENCODING_MS_1258 }, // MS Windows Vietnamese
407  { 1361, RTL_TEXTENCODING_MS_1361 }, // MS Windows Korean (Johab)
408  { 10000, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
409  { 32768, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman
410  { 32769, RTL_TEXTENCODING_MS_1252 } // MS Windows Latin I (BIFF2-BIFF3)
411 };
412 const XclCodePageEntry* const pCodePageTableEnd = std::end(pCodePageTable);
413 
414 struct XclCodePageEntry_CPPred
415 {
416  explicit XclCodePageEntry_CPPred( sal_uInt16 nCodePage ) : mnCodePage( nCodePage ) {}
417  bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.mnCodePage == mnCodePage; }
418  sal_uInt16 mnCodePage;
419 };
420 
421 struct XclCodePageEntry_TEPred
422 {
423  explicit XclCodePageEntry_TEPred( rtl_TextEncoding eTextEnc ) : meTextEnc( eTextEnc ) {}
424  bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.meTextEnc == meTextEnc; }
425  rtl_TextEncoding meTextEnc;
426 };
427 
428 } // namespace
429 
430 rtl_TextEncoding XclTools::GetTextEncoding( sal_uInt16 nCodePage )
431 {
432  const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_CPPred( nCodePage ) );
433  if( pEntry == pCodePageTableEnd )
434  {
435  SAL_WARN("sc", "XclTools::GetTextEncoding - unknown code page: 0x" << std::hex << nCodePage );
436  return RTL_TEXTENCODING_DONTKNOW;
437  }
438  return pEntry->meTextEnc;
439 }
440 
441 sal_uInt16 XclTools::GetXclCodePage( rtl_TextEncoding eTextEnc )
442 {
443  if( eTextEnc == RTL_TEXTENCODING_UNICODE )
444  return 1200; // for BIFF8
445 
446  const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_TEPred( eTextEnc ) );
447  if( pEntry == pCodePageTableEnd )
448  {
449  SAL_WARN("sc", "XclTools::GetXclCodePage - unsupported text encoding: 0x" << std::hex << eTextEnc );
450  return 1252;
451  }
452  return pEntry->mnCodePage;
453 }
454 
455 OUString XclTools::GetXclFontName( const OUString& rFontName )
456 {
457  // substitute with MS fonts
458  OUString aNewName = GetSubsFontName(rFontName, SubsFontFlags::ONLYONE | SubsFontFlags::MS);
459  return aNewName.isEmpty() ? rFontName : aNewName;
460 }
461 
462 // built-in defined names
463 const char maDefNamePrefix[] = "Excel_BuiltIn_";
464 const char maDefNamePrefixXml[] = "_xlnm.";
465 
466 const char* const ppcDefNames[] =
467 {
468  "Consolidate_Area",
469  "Auto_Open",
470  "Auto_Close",
471  "Extract",
472  "Database",
473  "Criteria",
474  "Print_Area",
475  "Print_Titles",
476  "Recorder",
477  "Data_Form",
478  "Auto_Activate",
479  "Auto_Deactivate",
480  "Sheet_Title",
481  "_FilterDatabase"
482 };
483 
485 {
487  "XclTools::GetXclBuiltInDefName - built-in defined name list modified" );
488 
489  if( cBuiltIn < SAL_N_ELEMENTS( ppcDefNames ) )
490  return OUString::createFromAscii(ppcDefNames[cBuiltIn]);
491  else
492  return OUString::number(cBuiltIn);
493 }
494 
496 {
497  OUStringBuffer aBuf(maDefNamePrefix);
498  aBuf.append(GetXclBuiltInDefName(cBuiltIn));
499  return aBuf.makeStringAndClear();
500 }
501 
503 {
504  OUStringBuffer aBuf(maDefNamePrefixXml);
505  aBuf.append(GetXclBuiltInDefName(cBuiltIn));
506  return aBuf.makeStringAndClear();
507 }
508 
510 {
511  sal_Int32 nPrefixLen = 0;
512  if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefix ) )
513  nPrefixLen = strlen(maDefNamePrefix);
514  else if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefixXml ) )
515  nPrefixLen = strlen(maDefNamePrefixXml);
516  if( nPrefixLen > 0 )
517  {
518  for( sal_Unicode cBuiltIn = 0; cBuiltIn < EXC_BUILTIN_UNKNOWN; ++cBuiltIn )
519  {
520  OUString aBuiltInName(GetXclBuiltInDefName(cBuiltIn));
521  sal_Int32 nBuiltInLen = aBuiltInName.getLength();
522  if( rDefName.matchIgnoreAsciiCase( aBuiltInName, nPrefixLen ) )
523  {
524  // name can be followed by underline or space character
525  sal_Int32 nNextCharPos = nPrefixLen + nBuiltInLen;
526  sal_Unicode cNextChar = (rDefName.getLength() > nNextCharPos) ? rDefName[nNextCharPos] : '\0';
527  if( (cNextChar == '\0') || (cNextChar == ' ') || (cNextChar == '_') )
528  return cBuiltIn;
529  }
530  }
531  }
532  return EXC_BUILTIN_UNKNOWN;
533 }
534 
535 // built-in style names
536 
537 const char maStyleNamePrefix1[] = "Excel_BuiltIn_";
538 const char maStyleNamePrefix2[] = "Excel Built-in ";
539 
540 const char* const ppcStyleNames[] =
541 {
542  "", // "Normal" not used directly, but localized "Default"
543  "RowLevel_", // outline level will be appended
544  "ColumnLevel_", // outline level will be appended
545  "Comma",
546  "Currency",
547  "Percent",
548  "Comma_0",
549  "Currency_0",
550  "Hyperlink",
551  "Followed_Hyperlink"
552 };
553 
554 OUString XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, std::u16string_view rName, sal_uInt8 nLevel )
555 {
556  OUString aStyleName;
557 
558  if( nStyleId == EXC_STYLE_NORMAL ) // "Normal" becomes "Default" style
559  {
560  aStyleName = ScResId( STR_STYLENAME_STANDARD );
561  }
562  else
563  {
564  OUStringBuffer aBuf(maStyleNamePrefix1);
565  if( nStyleId < SAL_N_ELEMENTS( ppcStyleNames ) )
566  aBuf.appendAscii(ppcStyleNames[nStyleId]);
567  else if (!rName.empty())
568  aBuf.append(rName);
569  else
570  aBuf.append(static_cast<sal_Int32>(nStyleId));
571 
572  if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
573  aBuf.append(static_cast<sal_Int32>(nLevel+1));
574 
575  aStyleName = aBuf.makeStringAndClear();
576  }
577 
578  return aStyleName;
579 }
580 
581 bool XclTools::IsBuiltInStyleName( const OUString& rStyleName, sal_uInt8* pnStyleId, sal_Int32* pnNextChar )
582 {
583  // "Default" becomes "Normal"
584  if (rStyleName == ScResId(STR_STYLENAME_STANDARD))
585  {
586  if( pnStyleId ) *pnStyleId = EXC_STYLE_NORMAL;
587  if( pnNextChar ) *pnNextChar = rStyleName.getLength();
588  return true;
589  }
590 
591  // try the other built-in styles
592  sal_uInt8 nFoundId = 0;
593  sal_Int32 nNextChar = 0;
594 
595  sal_Int32 nPrefixLen = 0;
596  if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix1 ) )
597  nPrefixLen = strlen(maStyleNamePrefix1);
598  else if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix2 ) )
599  nPrefixLen = strlen(maStyleNamePrefix2);
600  if( nPrefixLen > 0 )
601  {
602  for( sal_uInt8 nId = 0; nId < SAL_N_ELEMENTS( ppcStyleNames ); ++nId )
603  {
604  if( nId != EXC_STYLE_NORMAL )
605  {
606  OUString aShortName = OUString::createFromAscii(ppcStyleNames[nId]);
607  if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) &&
608  (nNextChar < nPrefixLen + aShortName.getLength()))
609  {
610  nFoundId = nId;
611  nNextChar = nPrefixLen + aShortName.getLength();
612  }
613  }
614  }
615  }
616 
617  if( nNextChar > 0 )
618  {
619  if( pnStyleId ) *pnStyleId = nFoundId;
620  if( pnNextChar ) *pnNextChar = nNextChar;
621  return true;
622  }
623 
624  if( pnStyleId ) *pnStyleId = EXC_STYLE_USERDEF;
625  if( pnNextChar ) *pnNextChar = 0;
626  return nPrefixLen > 0; // also return true for unknown built-in styles
627 }
628 
629 bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, const OUString& rStyleName )
630 {
631  sal_uInt8 nStyleId;
632  sal_Int32 nNextChar;
633  if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) && (nStyleId != EXC_STYLE_USERDEF) )
634  {
635  if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
636  {
637  OUString aLevel = rStyleName.copy(nNextChar);
638  sal_Int32 nLevel = aLevel.toInt32();
639  if (std::u16string_view(OUString::number(nLevel)) == aLevel
640  && nLevel > 0 && nLevel <= EXC_STYLE_LEVELCOUNT)
641  {
642  rnStyleId = nStyleId;
643  rnLevel = static_cast< sal_uInt8 >( nLevel - 1 );
644  return true;
645  }
646  }
647  else if( rStyleName.getLength() == nNextChar )
648  {
649  rnStyleId = nStyleId;
650  rnLevel = EXC_STYLE_NOLEVEL;
651  return true;
652  }
653  }
654 
655  rnStyleId = EXC_STYLE_USERDEF;
656  rnLevel = EXC_STYLE_NOLEVEL;
657  return false;
658 }
659 
660 // conditional formatting style names
661 
662 const char maCFStyleNamePrefix1[] = "Excel_CondFormat_";
663 const char maCFStyleNamePrefix2[] = "ConditionalStyle_";
664 const char maCFStyleNamePrefix3[] = "ExtConditionalStyle_";
665 
666 OUString XclTools::GetCondFormatStyleName( SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition )
667 {
668  return maCFStyleNamePrefix1 +
669  OUString::number(static_cast<sal_Int32>(nScTab+1)) +
670  "_" +
671  OUString::number(static_cast<sal_Int32>(nFormat+1)) +
672  "_" +
673  OUString::number(static_cast<sal_Int32>(nCondition+1));
674 }
675 
676 bool XclTools::IsCondFormatStyleName( const OUString& rStyleName )
677 {
678  if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix1 ) )
679  return true;
680 
681  if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix2 ) )
682  return true;
683 
684  if (rStyleName.startsWithIgnoreAsciiCase(maCFStyleNamePrefix3))
685  return true;
686 
687  return false;
688 }
689 
690 // stream handling
691 
693 {
694  bool bLoop = true;
695  while( bLoop && rStrm.StartNextRecord() )
696  {
697  sal_uInt16 nRecId = rStrm.GetRecId();
698  bLoop = nRecId != EXC_ID_EOF;
699  if( (nRecId == EXC_ID2_BOF) || (nRecId == EXC_ID3_BOF) || (nRecId == EXC_ID4_BOF) || (nRecId == EXC_ID5_BOF) )
700  SkipSubStream( rStrm );
701  }
702 }
703 
704 // Basic macro names
705 
706 const char maSbMacroPrefix[] = "vnd.sun.star.script:";
707 const char maSbMacroSuffix[] = "?language=Basic&location=document";
708 
709 OUString XclTools::GetSbMacroUrl( const OUString& rMacroName, SfxObjectShell* pDocShell )
710 {
711  OSL_ENSURE( !rMacroName.isEmpty(), "XclTools::GetSbMacroUrl - macro name is empty" );
712  ::ooo::vba::MacroResolvedInfo aMacroInfo = ::ooo::vba::resolveVBAMacro( pDocShell, rMacroName );
713  if( aMacroInfo.mbFound )
714  return ::ooo::vba::makeMacroURL( aMacroInfo.msResolvedMacro );
715  return OUString();
716 }
717 
718 OUString XclTools::GetXclMacroName( const OUString& rSbMacroUrl )
719 {
720  sal_Int32 nSbMacroUrlLen = rSbMacroUrl.getLength();
721  sal_Int32 nMacroNameLen = nSbMacroUrlLen - strlen(maSbMacroPrefix) - strlen(maSbMacroSuffix);
722  if( (nMacroNameLen > 0) && rSbMacroUrl.startsWithIgnoreAsciiCase( maSbMacroPrefix ) &&
723  rSbMacroUrl.endsWithIgnoreAsciiCase( maSbMacroSuffix ) )
724  {
725  sal_Int32 nPrjDot = rSbMacroUrl.indexOf( '.', strlen(maSbMacroPrefix) ) + 1;
726  return rSbMacroUrl.copy( nPrjDot, nSbMacroUrlLen - nPrjDot - strlen(maSbMacroSuffix) );
727  }
728  return OUString();
729 }
730 
731 // read/write colors
732 
734 {
735  sal_uInt8 nR = rStrm.ReaduInt8();
736  sal_uInt8 nG = rStrm.ReaduInt8();
737  sal_uInt8 nB = rStrm.ReaduInt8();
738  rStrm.Ignore( 1 );//nD
739  rColor = Color( nR, nG, nB );
740  return rStrm;
741 }
742 
743 XclExpStream& operator<<( XclExpStream& rStrm, const Color& rColor )
744 {
745  return rStrm << rColor.GetRed() << rColor.GetGreen() << rColor.GetBlue() << sal_uInt8( 0 );
746 }
747 
748 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static const XclGuid maGuidUrlMoniker
GUID of StdLink (HLINK record).
Definition: xltools.hxx:96
const sal_uInt8 EXC_ORIENT_NONE
Definition: xlconst.hxx:133
const sal_uInt8 EXC_ERR_NULL
DDE application-topic delimiter.
Definition: xlconst.hxx:104
static N to(double f)
Definition: xltools.cxx:275
std::size_t Write(const void *pData, std::size_t nBytes)
Writes nBytes bytes from memory.
Definition: xestream.cxx:216
const sal_uInt8 EXC_ERR_NA
Definition: xlconst.hxx:110
sal_uInt8 GetRed() const
static XclBoolError ErrorToEnum(double &rfDblValue, bool bErrOrBool, sal_uInt8 nValue)
Gets a translated error code or Boolean value from Excel error codes.
Definition: xltools.cxx:247
const char maSbMacroPrefix[]
Definition: xltools.cxx:706
static sal_Int32 GetHmmFromInch(double fInches)
Returns the length in 1/100 mm calculated from a length in inches.
Definition: xltools.cxx:297
static double GetXclDefColWidthCorrection(tools::Long nXclDefFontHeight)
Returns a correction value to convert column widths from/to default column widths.
Definition: xltools.cxx:321
sal_uInt16 GetRecId() const
Returns the current record ID.
Definition: xistream.hxx:353
This class is used to export Excel record streams.
Definition: xestream.hxx:72
static const XclGuid maGuidFileMoniker
GUID of URL moniker (HLINK record).
Definition: xltools.hxx:97
XclGuid()
Stores GUID always in little endian.
Definition: xltools.cxx:43
const char maSbMacroSuffix[]
Prefix for StarBasic macros.
Definition: xltools.cxx:707
static sal_uInt8 GetXclRotation(Degree100 nScRot)
Calculates the Excel angle value from an angle in 1/100 of degrees.
Definition: xltools.cxx:162
static sal_uInt8 GetXclOrientFromRot(sal_uInt16 nXclRot)
Calculates BIFF2-BIFF5 text orientation from BIFF8 rotation angle.
Definition: xltools.cxx:189
const sal_uInt8 EXC_ROT_STACKED
Text rotation: 90 deg clockwise.
Definition: xlconst.hxx:141
XclBoolError
An enumeration for all Excel error codes and the values true and false.
Definition: xltools.hxx:39
const char *const ppcDefNames[]
Prefix for built-in defined names for OOX.
Definition: xltools.cxx:466
long Long
static bool GetBuiltInStyleId(sal_uInt8 &rnStyleId, sal_uInt8 &rnLevel, const OUString &rStyleName)
Returns the Excel built-in style identifier of a passed style name.
Definition: xltools.cxx:629
std::size_t Read(void *pData, std::size_t nBytes)
Reads nBytes bytes to the existing(!) buffer pData.
Definition: xistream.cxx:721
static sal_uInt16 GetTwipsFromInch(double fInches)
Returns the length in twips calculated from a length in inches.
Definition: xltools.cxx:277
#define N
aBuf
sal_Int16 nId
const sal_Int32 EXC_RK_INTFLAG
Definition: xlconst.hxx:123
OUString GetSubsFontName(const OUString &rName, SubsFontFlags nFlags)
static sal_uInt8 GetXclRotFromOrient(sal_uInt8 nXclOrient)
Calculates BIFF8 rotation angle from BIFF2-BIFF5 text orientation.
Definition: xltools.cxx:176
ReturnType limit_cast(Type nValue, ReturnType nMin, ReturnType nMax)
Returns the value, if it is not less than nMin and not greater than nMax, otherwise one of the limits...
Definition: ftools.hxx:63
const sal_uInt16 EXC_ID5_BOF
Definition: xlconst.hxx:150
const sal_uInt8 EXC_STYLE_USERDEF
"Followed_Hyperlink" style.
Definition: xlstyle.hxx:234
The Boolean value false.
Definition: xltools.hxx:50
static double ErrorToDouble(sal_uInt8 nXclError)
Converts the passed BIFF error to a double containing the respective Calc error code.
Definition: xltools.cxx:242
static bool GetRKFromDouble(sal_Int32 &rnRKValue, double fValue)
Calculates an RK value (encoded integer or double) from a double value.
Definition: xltools.cxx:124
The error code #REF!
Definition: xltools.hxx:45
The Boolean value true.
Definition: xltools.hxx:49
const sal_uInt8 EXC_ORIENT_STACKED
Text orientation: not rotated.
Definition: xlconst.hxx:134
static OUString GetBuiltInDefNameXml(sal_Unicode cBuiltIn)
Returns the Excel built-in name with OOXML prefix Adds the "_xlnm." prefix to the representation ret...
Definition: xltools.cxx:502
XclImpStream & operator>>(XclImpStream &rStrm, XclGuid &rGuid)
Definition: xltools.cxx:72
sal_uInt16 sal_Unicode
The error code NULL!
Definition: xltools.hxx:42
static OUString GetXclFontName(const OUString &rFontName)
Returns the matching Excel font name for a passed Calc font name.
Definition: xltools.cxx:455
static Degree100 GetScRotation(sal_uInt16 nXclRot, Degree100 nRotForStacked)
Calculates an angle (in 1/100 of degrees) from an Excel angle value.
Definition: xltools.cxx:154
const sal_uInt8 EXC_ERR_NUM
Definition: xlconst.hxx:109
static const XclGuid maGuidStdLink
Definition: xltools.hxx:95
static OUString GetXclMacroName(const OUString &rSbMacroUrl)
Returns the Excel macro name from a full StarBasic macro URL.
Definition: xltools.cxx:718
static FormulaError GetScErrorCode(sal_uInt8 nXclError)
Converts an Excel error code to a Calc error code.
Definition: xltools.cxx:226
static OUString GetBuiltInDefName(sal_Unicode cBuiltIn)
Returns the Calc UI representation of a built-in defined name used in NAME records.
Definition: xltools.cxx:495
bool StartNextRecord()
Sets stream pointer to the start of the next record content.
Definition: xistream.cxx:456
const char maCFStyleNamePrefix1[]
Definition: xltools.cxx:662
XclExpStream & operator<<(XclExpStream &rStrm, const XclGuid &rGuid)
Definition: xltools.cxx:78
const char maCFStyleNamePrefix3[]
Prefix for cond. formatting style names from OOX filter.
Definition: xltools.cxx:664
The error code #NUM!
Definition: xltools.hxx:47
const sal_Unicode EXC_BUILTIN_UNKNOWN
Definition: xlname.hxx:61
sal_uInt8 GetBlue() const
const sal_uInt8 EXC_STYLE_ROWLEVEL
"Normal" style.
Definition: xlstyle.hxx:225
const sal_uInt8 EXC_ERR_REF
Definition: xlconst.hxx:107
constexpr auto convert(N n, sal_Int64 mul, sal_Int64 div)
#define SAL_N_ELEMENTS(arr)
DocumentType eType
static sal_Int32 GetHmmFromTwips(sal_Int32 nTwips)
Returns the length in 1/100 mm calculated from a length in twips.
Definition: xltools.cxx:302
static Color GetMixedColor(const Color &rFore, const Color &rBack, sal_uInt8 nTrans)
Mixes colors with given transparence.
Definition: ftools.cxx:132
const char maDefNamePrefixXml[]
Prefix for built-in defined names.
Definition: xltools.cxx:464
static sal_uInt16 GetScColumnWidth(sal_uInt16 nXclWidth, tools::Long nScCharWidth)
Returns the Calc column width (twips) for the passed Excel width.
Definition: xltools.cxx:307
UNDERLYING_TYPE get() const
const sal_Int32 EXC_RK_VALUEMASK
Definition: xlconst.hxx:124
static sal_uInt16 GetTwipsFromHmm(sal_Int32 nHmm)
Returns the length in twips calculated from a length in 1/100 mm.
Definition: xltools.cxx:282
static sal_Unicode GetBuiltInDefNameIndex(const OUString &rDefName)
Returns the Excel built-in name index of the passed defined name from Calc.
Definition: xltools.cxx:509
const sal_Int32 EXC_RK_100FLAG
Definition: xlconst.hxx:122
const sal_uInt16 EXC_ID4_BOF
Definition: xlconst.hxx:149
static double GetDoubleFromRK(sal_Int32 nRKValue)
GUID of file moniker (HLINK record).
Definition: xltools.cxx:98
const sal_uInt8 EXC_ERR_VALUE
Definition: xlconst.hxx:106
static sal_uInt8 GetXclErrorCode(FormulaError nScError)
Converts a Calc error code to an Excel error code.
Definition: xltools.cxx:201
const sal_uInt8 EXC_STYLE_LEVELCOUNT
No built-in style.
Definition: xlstyle.hxx:236
static bool IsCondFormatStyleName(const OUString &rStyleName)
Returns true, if the passed string is a name of a conditional format style created by Excel import...
Definition: xltools.cxx:676
static rtl_TextEncoding GetTextEncoding(sal_uInt16 nCodePage)
Returns a text encoding from an Excel code page.
Definition: xltools.cxx:430
static Color GetPatternColor(const Color &rPattColor, const Color &rBackColor, sal_uInt16 nXclPattern)
Returns the best fitting color for an Excel pattern area format.
Definition: xltools.cxx:350
sal_uInt8 mpnData[16]
Definition: xltools.hxx:61
OUString ScResId(const char *pId)
Definition: scdll.cxx:89
static bool IsBuiltInStyleName(const OUString &rStyleName, sal_uInt8 *pnStyleId=nullptr, sal_Int32 *pnNextChar=nullptr)
Returns true, if the passed string is a name of an Excel built-in style.
Definition: xltools.cxx:581
static OUString GetBuiltInStyleName(sal_uInt8 nStyleId, std::u16string_view rName, sal_uInt8 nLevel)
Returns the specified built-in cell style name.
Definition: xltools.cxx:554
bool get_flag(Type nBitField, Type nMask)
Returns true, if at least one of the bits set in nMask is set in nBitField.
Definition: ftools.hxx:75
static double GetInchFromTwips(sal_Int32 nTwips)
Returns the length in inches calculated from a length in twips.
Definition: xltools.cxx:287
const char maDefNamePrefix[]
Definition: xltools.cxx:463
const sal_uInt8 EXC_STYLE_NOLEVEL
Number of outline level styles.
Definition: xlstyle.hxx:237
static void SkipSubStream(XclImpStream &rStrm)
Skips a substream (BOF/EOF record block).
Definition: xltools.cxx:692
const sal_Int32 EXC_RK_INT100
Definition: xlconst.hxx:129
static sal_uInt16 GetXclCodePage(rtl_TextEncoding eTextEnc)
Returns an Excel code page from a text encoding.
Definition: xltools.cxx:441
FormulaError
const sal_uInt8 EXC_STYLE_COLLEVEL
"RowLevel_*" styles.
Definition: xlstyle.hxx:226
The error code #VALUE!
Definition: xltools.hxx:44
const sal_uInt8 EXC_STYLE_NORMAL
Definition: xlstyle.hxx:224
bool operator==(const XclGuid &rCmp1, const XclGuid &rCmp2)
Definition: xltools.cxx:67
sal_uInt8 GetGreen() const
The error code #DIV/0!
Definition: xltools.hxx:43
static double GetInchFromHmm(sal_Int32 nHmm)
Returns the length in inches calculated from a length in 1/100 mm.
Definition: xltools.cxx:292
This struct stores a GUID (class ID) and supports reading, writing and comparison.
Definition: xltools.hxx:59
double CreateDoubleError(FormulaError nErr)
static OUString GetSbMacroUrl(const OUString &rMacroName, SfxObjectShell *pDocShell)
Returns the full StarBasic macro URL from an Excel macro name.
Definition: xltools.cxx:709
const char maCFStyleNamePrefix2[]
Prefix for cond. formatting style names.
Definition: xltools.cxx:663
The error code N/A!
Definition: xltools.hxx:48
void Ignore(std::size_t nBytes)
Seeks forward inside the current record.
Definition: xistream.cxx:798
unsigned char sal_uInt8
const sal_uInt8 EXC_ERR_NAME
Definition: xlconst.hxx:108
sal_uInt8 ReaduInt8()
Definition: xistream.cxx:617
const sal_Int32 EXC_RK_INT
Definition: xlconst.hxx:128
const sal_uInt8 EXC_ERR_DIV0
Definition: xlconst.hxx:105
const sal_uInt8 EXC_ROT_90CW
Text rotation: 90 deg counterclockwise.
Definition: xlconst.hxx:140
const sal_uInt8 EXC_ROT_90CCW
Text rotation: not rotated.
Definition: xlconst.hxx:139
const sal_uInt8 EXC_ROT_NONE
Text orientation: 90 deg clockwise.
Definition: xlconst.hxx:138
#define SAL_WARN(area, stream)
static sal_uInt16 GetXclColumnWidth(sal_uInt16 nScWidth, tools::Long nScCharWidth)
Returns the Excel column width for the passed Calc width (twips).
Definition: xltools.cxx:313
const sal_uInt16 EXC_ID3_BOF
Definition: xlconst.hxx:148
const sal_uInt8 EXC_ORIENT_90CCW
Text orientation: vertically stacked.
Definition: xlconst.hxx:135
const char maStyleNamePrefix1[]
Definition: xltools.cxx:537
This class is used to import record oriented streams.
Definition: xistream.hxx:277
static OUString GetCondFormatStyleName(SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition)
Returns the style name for a single condition of a conditional formatting.
Definition: xltools.cxx:666
const sal_uInt16 EXC_ID2_BOF
Text rotation: vertically stacked.
Definition: xlconst.hxx:147
const char maStyleNamePrefix2[]
Prefix for built-in cell style names.
Definition: xltools.cxx:538
sal_Int16 SCTAB
Definition: types.hxx:22
static OUString GetXclBuiltInDefName(sal_Unicode cBuiltIn)
Returns the raw English UI representation of a built-in defined name used in NAME records...
Definition: xltools.cxx:484
const char *const ppcStyleNames[]
Prefix for built-in cell style names from OOX filter.
Definition: xltools.cxx:540
const sal_uInt8 EXC_ORIENT_90CW
Text orientation: 90 deg counterclockwise.
Definition: xlconst.hxx:136
The error code #NAME?
Definition: xltools.hxx:46
const sal_uInt16 EXC_ID_EOF
Internal use only.
Definition: xlconst.hxx:167