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