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  return maDefNamePrefix + GetXclBuiltInDefName(cBuiltIn);
498 }
499 
501 {
502  return maDefNamePrefixXml + GetXclBuiltInDefName(cBuiltIn);
503 }
504 
506 {
507  sal_Int32 nPrefixLen = 0;
508  if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefix ) )
509  nPrefixLen = strlen(maDefNamePrefix);
510  else if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefixXml ) )
511  nPrefixLen = strlen(maDefNamePrefixXml);
512  if( nPrefixLen > 0 )
513  {
514  for( sal_Unicode cBuiltIn = 0; cBuiltIn < EXC_BUILTIN_UNKNOWN; ++cBuiltIn )
515  {
516  OUString aBuiltInName(GetXclBuiltInDefName(cBuiltIn));
517  sal_Int32 nBuiltInLen = aBuiltInName.getLength();
518  if( rDefName.matchIgnoreAsciiCase( aBuiltInName, nPrefixLen ) )
519  {
520  // name can be followed by underline or space character
521  sal_Int32 nNextCharPos = nPrefixLen + nBuiltInLen;
522  sal_Unicode cNextChar = (rDefName.getLength() > nNextCharPos) ? rDefName[nNextCharPos] : '\0';
523  if( (cNextChar == '\0') || (cNextChar == ' ') || (cNextChar == '_') )
524  return cBuiltIn;
525  }
526  }
527  }
528  return EXC_BUILTIN_UNKNOWN;
529 }
530 
531 // built-in style names
532 
533 const char maStyleNamePrefix1[] = "Excel_BuiltIn_";
534 const char maStyleNamePrefix2[] = "Excel Built-in ";
535 
536 const char* const ppcStyleNames[] =
537 {
538  "", // "Normal" not used directly, but localized "Default"
539  "RowLevel_", // outline level will be appended
540  "ColumnLevel_", // outline level will be appended
541  "Comma",
542  "Currency",
543  "Percent",
544  "Comma_0",
545  "Currency_0",
546  "Hyperlink",
547  "Followed_Hyperlink"
548 };
549 
550 OUString XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, std::u16string_view rName, sal_uInt8 nLevel )
551 {
552  OUString aStyleName;
553 
554  if( nStyleId == EXC_STYLE_NORMAL ) // "Normal" becomes "Default" style
555  {
556  aStyleName = ScResId( STR_STYLENAME_STANDARD );
557  }
558  else
559  {
560  OUStringBuffer aBuf(maStyleNamePrefix1);
561  if( nStyleId < SAL_N_ELEMENTS( ppcStyleNames ) )
562  aBuf.appendAscii(ppcStyleNames[nStyleId]);
563  else if (!rName.empty())
564  aBuf.append(rName);
565  else
566  aBuf.append(static_cast<sal_Int32>(nStyleId));
567 
568  if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
569  aBuf.append(static_cast<sal_Int32>(nLevel+1));
570 
571  aStyleName = aBuf.makeStringAndClear();
572  }
573 
574  return aStyleName;
575 }
576 
577 bool XclTools::IsBuiltInStyleName( const OUString& rStyleName, sal_uInt8* pnStyleId, sal_Int32* pnNextChar )
578 {
579  // "Default" becomes "Normal"
580  if (rStyleName == ScResId(STR_STYLENAME_STANDARD))
581  {
582  if( pnStyleId ) *pnStyleId = EXC_STYLE_NORMAL;
583  if( pnNextChar ) *pnNextChar = rStyleName.getLength();
584  return true;
585  }
586 
587  // try the other built-in styles
588  sal_uInt8 nFoundId = 0;
589  sal_Int32 nNextChar = 0;
590 
591  sal_Int32 nPrefixLen = 0;
592  if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix1 ) )
593  nPrefixLen = strlen(maStyleNamePrefix1);
594  else if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix2 ) )
595  nPrefixLen = strlen(maStyleNamePrefix2);
596  if( nPrefixLen > 0 )
597  {
598  for( sal_uInt8 nId = 0; nId < SAL_N_ELEMENTS( ppcStyleNames ); ++nId )
599  {
600  if( nId != EXC_STYLE_NORMAL )
601  {
602  OUString aShortName = OUString::createFromAscii(ppcStyleNames[nId]);
603  if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) &&
604  (nNextChar < nPrefixLen + aShortName.getLength()))
605  {
606  nFoundId = nId;
607  nNextChar = nPrefixLen + aShortName.getLength();
608  }
609  }
610  }
611  }
612 
613  if( nNextChar > 0 )
614  {
615  if( pnStyleId ) *pnStyleId = nFoundId;
616  if( pnNextChar ) *pnNextChar = nNextChar;
617  return true;
618  }
619 
620  if( pnStyleId ) *pnStyleId = EXC_STYLE_USERDEF;
621  if( pnNextChar ) *pnNextChar = 0;
622  return nPrefixLen > 0; // also return true for unknown built-in styles
623 }
624 
625 bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, const OUString& rStyleName )
626 {
627  sal_uInt8 nStyleId;
628  sal_Int32 nNextChar;
629  if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) && (nStyleId != EXC_STYLE_USERDEF) )
630  {
631  if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) )
632  {
633  OUString aLevel = rStyleName.copy(nNextChar);
634  sal_Int32 nLevel = aLevel.toInt32();
635  if (std::u16string_view(OUString::number(nLevel)) == aLevel
636  && nLevel > 0 && nLevel <= EXC_STYLE_LEVELCOUNT)
637  {
638  rnStyleId = nStyleId;
639  rnLevel = static_cast< sal_uInt8 >( nLevel - 1 );
640  return true;
641  }
642  }
643  else if( rStyleName.getLength() == nNextChar )
644  {
645  rnStyleId = nStyleId;
646  rnLevel = EXC_STYLE_NOLEVEL;
647  return true;
648  }
649  }
650 
651  rnStyleId = EXC_STYLE_USERDEF;
652  rnLevel = EXC_STYLE_NOLEVEL;
653  return false;
654 }
655 
656 // conditional formatting style names
657 
658 const char maCFStyleNamePrefix1[] = "Excel_CondFormat_";
659 const char maCFStyleNamePrefix2[] = "ConditionalStyle_";
660 const char maCFStyleNamePrefix3[] = "ExtConditionalStyle_";
661 
662 OUString XclTools::GetCondFormatStyleName( SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition )
663 {
664  return maCFStyleNamePrefix1 +
665  OUString::number(static_cast<sal_Int32>(nScTab+1)) +
666  "_" +
667  OUString::number(static_cast<sal_Int32>(nFormat+1)) +
668  "_" +
669  OUString::number(static_cast<sal_Int32>(nCondition+1));
670 }
671 
672 bool XclTools::IsCondFormatStyleName( const OUString& rStyleName )
673 {
674  if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix1 ) )
675  return true;
676 
677  if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix2 ) )
678  return true;
679 
680  if (rStyleName.startsWithIgnoreAsciiCase(maCFStyleNamePrefix3))
681  return true;
682 
683  return false;
684 }
685 
686 // stream handling
687 
689 {
690  bool bLoop = true;
691  while( bLoop && rStrm.StartNextRecord() )
692  {
693  sal_uInt16 nRecId = rStrm.GetRecId();
694  bLoop = nRecId != EXC_ID_EOF;
695  if( (nRecId == EXC_ID2_BOF) || (nRecId == EXC_ID3_BOF) || (nRecId == EXC_ID4_BOF) || (nRecId == EXC_ID5_BOF) )
696  SkipSubStream( rStrm );
697  }
698 }
699 
700 // Basic macro names
701 
702 const char maSbMacroPrefix[] = "vnd.sun.star.script:";
703 const char maSbMacroSuffix[] = "?language=Basic&location=document";
704 
705 OUString XclTools::GetSbMacroUrl( const OUString& rMacroName, SfxObjectShell* pDocShell )
706 {
707  OSL_ENSURE( !rMacroName.isEmpty(), "XclTools::GetSbMacroUrl - macro name is empty" );
708  ::ooo::vba::MacroResolvedInfo aMacroInfo = ::ooo::vba::resolveVBAMacro( pDocShell, rMacroName );
709  if( aMacroInfo.mbFound )
710  return ::ooo::vba::makeMacroURL( aMacroInfo.msResolvedMacro );
711  return OUString();
712 }
713 
714 OUString XclTools::GetXclMacroName( const OUString& rSbMacroUrl )
715 {
716  sal_Int32 nSbMacroUrlLen = rSbMacroUrl.getLength();
717  sal_Int32 nMacroNameLen = nSbMacroUrlLen - strlen(maSbMacroPrefix) - strlen(maSbMacroSuffix);
718  if( (nMacroNameLen > 0) && rSbMacroUrl.startsWithIgnoreAsciiCase( maSbMacroPrefix ) &&
719  rSbMacroUrl.endsWithIgnoreAsciiCase( maSbMacroSuffix ) )
720  {
721  sal_Int32 nPrjDot = rSbMacroUrl.indexOf( '.', strlen(maSbMacroPrefix) ) + 1;
722  return rSbMacroUrl.copy( nPrjDot, nSbMacroUrlLen - nPrjDot - strlen(maSbMacroSuffix) );
723  }
724  return OUString();
725 }
726 
727 // read/write colors
728 
730 {
731  sal_uInt8 nR = rStrm.ReaduInt8();
732  sal_uInt8 nG = rStrm.ReaduInt8();
733  sal_uInt8 nB = rStrm.ReaduInt8();
734  rStrm.Ignore( 1 );//nD
735  rColor = Color( nR, nG, nB );
736  return rStrm;
737 }
738 
739 XclExpStream& operator<<( XclExpStream& rStrm, const Color& rColor )
740 {
741  return rStrm << rColor.GetRed() << rColor.GetGreen() << rColor.GetBlue() << sal_uInt8( 0 );
742 }
743 
744 /* 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:217
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:702
OUString ScResId(TranslateId aId)
Definition: scdll.cxx:89
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:703
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
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
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:625
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:500
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:714
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:658
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:660
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
#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:136
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:505
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:672
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
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:577
static OUString GetBuiltInStyleName(sal_uInt8 nStyleId, std::u16string_view rName, sal_uInt8 nLevel)
Returns the specified built-in cell style name.
Definition: xltools.cxx:550
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:688
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:705
const char maCFStyleNamePrefix2[]
Prefix for cond. formatting style names.
Definition: xltools.cxx:659
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:533
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:662
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:534
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:536
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