diff options
Diffstat (limited to 'sc/source/filter/excel/xltools.cxx')
-rw-r--r-- | sc/source/filter/excel/xltools.cxx | 744 |
1 files changed, 744 insertions, 0 deletions
diff --git a/sc/source/filter/excel/xltools.cxx b/sc/source/filter/excel/xltools.cxx new file mode 100644 index 000000000..3a69e7da0 --- /dev/null +++ b/sc/source/filter/excel/xltools.cxx @@ -0,0 +1,744 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <algorithm> +#include <math.h> +#include <string_view> + +#include <o3tl/unit_conversion.hxx> +#include <sal/mathconf.h> +#include <sal/macros.h> +#include <sal/log.hxx> +#include <tools/solar.h> +#include <o3tl/string_view.hxx> +#include <unotools/fontdefs.hxx> +#include <filter/msfilter/msvbahelper.hxx> +#include <xestream.hxx> +#include <formula/errorcodes.hxx> +#include <globstr.hrc> +#include <scresid.hxx> +#include <xlstyle.hxx> +#include <xlname.hxx> +#include <xistream.hxx> +#include <xltools.hxx> + +// GUID import/export + +XclGuid::XclGuid() + : mpnData{} +{ +} + +XclGuid::XclGuid( + sal_uInt32 nData1, sal_uInt16 nData2, sal_uInt16 nData3, + sal_uInt8 nData41, sal_uInt8 nData42, sal_uInt8 nData43, sal_uInt8 nData44, + sal_uInt8 nData45, sal_uInt8 nData46, sal_uInt8 nData47, sal_uInt8 nData48 ) +{ + // convert to little endian -> makes streaming easy + UInt32ToSVBT32( nData1, mpnData ); + ShortToSVBT16( nData2, mpnData + 4 ); + ShortToSVBT16( nData3, mpnData + 6 ); + mpnData[ 8 ] = nData41; + mpnData[ 9 ] = nData42; + mpnData[ 10 ] = nData43; + mpnData[ 11 ] = nData44; + mpnData[ 12 ] = nData45; + mpnData[ 13 ] = nData46; + mpnData[ 14 ] = nData47; + mpnData[ 15 ] = nData48; +} + +bool operator==( const XclGuid& rCmp1, const XclGuid& rCmp2 ) +{ + return ::std::equal( rCmp1.mpnData, std::end( rCmp1.mpnData ), rCmp2.mpnData ); +} + +XclImpStream& operator>>( XclImpStream& rStrm, XclGuid& rGuid ) +{ + rStrm.Read( rGuid.mpnData, 16 ); // mpnData always in little endian + return rStrm; +} + +XclExpStream& operator<<( XclExpStream& rStrm, const XclGuid& rGuid ) +{ + rStrm.Write( rGuid.mpnData, 16 ); // mpnData already in little endian + return rStrm; +} + +// Excel Tools + +// GUID's +const XclGuid XclTools::maGuidStdLink( + 0x79EAC9D0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B ); + +const XclGuid XclTools::maGuidUrlMoniker( + 0x79EAC9E0, 0xBAF9, 0x11CE, 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B ); + +const XclGuid XclTools::maGuidFileMoniker( + 0x00000303, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 ); + +// numeric conversion + +double XclTools::GetDoubleFromRK( sal_Int32 nRKValue ) +{ + union + { + double fVal; + sal_math_Double smD; + }; + fVal = 0.0; + + if( ::get_flag( nRKValue, EXC_RK_INTFLAG ) ) + { + sal_Int32 nTemp = nRKValue >> 2; + ::set_flag< sal_Int32 >( nTemp, 0xE0000000, nRKValue < 0 ); + fVal = nTemp; + } + else + { + smD.w32_parts.msw = nRKValue & EXC_RK_VALUEMASK; + } + + if( ::get_flag( nRKValue, EXC_RK_100FLAG ) ) + fVal /= 100.0; + + return fVal; +} + +bool XclTools::GetRKFromDouble( sal_Int32& rnRKValue, double fValue ) +{ + double fFrac, fInt; + + // integer + fFrac = modf( fValue, &fInt ); + if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) ) // 2^29 + { + rnRKValue + = static_cast<sal_Int32>( + static_cast<sal_uInt32>(static_cast<sal_Int32>(fInt)) << 2) + | EXC_RK_INT; + return true; + } + + // integer/100 + fFrac = modf( fValue * 100.0, &fInt ); + if( (fFrac == 0.0) && (fInt >= -536870912.0) && (fInt <= 536870911.0) ) + { + rnRKValue + = static_cast<sal_Int32>( + static_cast<sal_uInt32>(static_cast<sal_Int32>(fInt)) << 2) + | EXC_RK_INT100; + return true; + } + + // double + return false; +} + +Degree100 XclTools::GetScRotation( sal_uInt16 nXclRot, Degree100 nRotForStacked ) +{ + if( nXclRot == EXC_ROT_STACKED ) + return nRotForStacked; + OSL_ENSURE( nXclRot <= 180, "XclTools::GetScRotation - illegal rotation angle" ); + return Degree100(static_cast< sal_Int32 >( (nXclRot <= 180) ? (100 * ((nXclRot > 90) ? (450 - nXclRot) : nXclRot)) : 0 )); +} + +sal_uInt8 XclTools::GetXclRotation( Degree100 nScRot ) +{ + sal_Int32 nXclRot = nScRot.get() / 100; + if( (0 <= nXclRot) && (nXclRot <= 90) ) + return static_cast< sal_uInt8 >( nXclRot ); + if( nXclRot < 180 ) + return static_cast< sal_uInt8 >( 270 - nXclRot ); + if( nXclRot < 270 ) + return static_cast< sal_uInt8 >( nXclRot - 180 ); + if( nXclRot < 360 ) + return static_cast< sal_uInt8 >( 450 - nXclRot ); + return 0; +} + +sal_uInt8 XclTools::GetXclRotFromOrient( sal_uInt8 nXclOrient ) +{ + switch( nXclOrient ) + { + case EXC_ORIENT_NONE: return EXC_ROT_NONE; + case EXC_ORIENT_STACKED: return EXC_ROT_STACKED; + case EXC_ORIENT_90CCW: return EXC_ROT_90CCW; + case EXC_ORIENT_90CW: return EXC_ROT_90CW; + default: OSL_FAIL( "XclTools::GetXclRotFromOrient - unknown text orientation" ); + } + return EXC_ROT_NONE; +} + +sal_uInt8 XclTools::GetXclOrientFromRot( sal_uInt16 nXclRot ) +{ + if( nXclRot == EXC_ROT_STACKED ) + return EXC_ORIENT_STACKED; + OSL_ENSURE( nXclRot <= 180, "XclTools::GetXclOrientFromRot - unknown text rotation" ); + if( (45 < nXclRot) && (nXclRot <= 90) ) + return EXC_ORIENT_90CCW; + if( (135 < nXclRot) && (nXclRot <= 180) ) + return EXC_ORIENT_90CW; + return EXC_ORIENT_NONE; +} + +sal_uInt8 XclTools::GetXclErrorCode( FormulaError nScError ) +{ + switch( nScError ) + { + case FormulaError::IllegalArgument: return EXC_ERR_VALUE; + case FormulaError::IllegalFPOperation: return EXC_ERR_NUM; // maybe DIV/0 or NUM... + case FormulaError::DivisionByZero: return EXC_ERR_DIV0; + case FormulaError::IllegalParameter: return EXC_ERR_VALUE; + case FormulaError::PairExpected: return EXC_ERR_VALUE; + case FormulaError::OperatorExpected: return EXC_ERR_VALUE; + case FormulaError::VariableExpected: return EXC_ERR_VALUE; + case FormulaError::ParameterExpected: return EXC_ERR_VALUE; + case FormulaError::NoValue: return EXC_ERR_VALUE; + case FormulaError::CircularReference: return EXC_ERR_VALUE; + case FormulaError::NoCode: return EXC_ERR_NULL; + case FormulaError::NoRef: return EXC_ERR_REF; + case FormulaError::NoName: return EXC_ERR_NAME; + case FormulaError::NoAddin: return EXC_ERR_NAME; + case FormulaError::NoMacro: return EXC_ERR_NAME; + case FormulaError::NotAvailable: return EXC_ERR_NA; + default: break; + } + return EXC_ERR_NA; +} + +FormulaError XclTools::GetScErrorCode( sal_uInt8 nXclError ) +{ + switch( nXclError ) + { + case EXC_ERR_NULL: return FormulaError::NoCode; + case EXC_ERR_DIV0: return FormulaError::DivisionByZero; + case EXC_ERR_VALUE: return FormulaError::NoValue; + case EXC_ERR_REF: return FormulaError::NoRef; + case EXC_ERR_NAME: return FormulaError::NoName; + case EXC_ERR_NUM: return FormulaError::IllegalFPOperation; + case EXC_ERR_NA: return FormulaError::NotAvailable; + default: OSL_FAIL( "XclTools::GetScErrorCode - unknown error code" ); + } + return FormulaError::NotAvailable; +} + +double XclTools::ErrorToDouble( sal_uInt8 nXclError ) +{ + return CreateDoubleError(GetScErrorCode( nXclError )); +} + +XclBoolError XclTools::ErrorToEnum( double& rfDblValue, bool bErrOrBool, sal_uInt8 nValue ) +{ + XclBoolError eType; + if( bErrOrBool ) + { + // error value + switch( nValue ) + { + case EXC_ERR_NULL: eType = xlErrNull; break; + case EXC_ERR_DIV0: eType = xlErrDiv0; break; + case EXC_ERR_VALUE: eType = xlErrValue; break; + case EXC_ERR_REF: eType = xlErrRef; break; + case EXC_ERR_NAME: eType = xlErrName; break; + case EXC_ERR_NUM: eType = xlErrNum; break; + case EXC_ERR_NA: eType = xlErrNA; break; + default: eType = xlErrUnknown; + } + rfDblValue = 0.0; + } + else + { + // Boolean value + eType = nValue ? xlErrTrue : xlErrFalse; + rfDblValue = nValue ? 1.0 : 0.0; + } + return eType; +} + +template <typename N> static N to(double f) { return limit_cast<N>(f + 0.5); } + +sal_uInt16 XclTools::GetTwipsFromInch( double fInches ) +{ + return to<sal_uInt16>(o3tl::convert(fInches, o3tl::Length::in, o3tl::Length::twip)); +} + +sal_uInt16 XclTools::GetTwipsFromHmm( sal_Int32 nHmm ) +{ + return limit_cast<sal_uInt16>(o3tl::convert(nHmm, o3tl::Length::mm100, o3tl::Length::twip)); +} + +double XclTools::GetInchFromTwips( sal_Int32 nTwips ) +{ + return o3tl::convert<double>(nTwips, o3tl::Length::twip, o3tl::Length::in); +} + +double XclTools::GetInchFromHmm( sal_Int32 nHmm ) +{ + return o3tl::convert<double>(nHmm, o3tl::Length::mm100, o3tl::Length::in); +} + +sal_Int32 XclTools::GetHmmFromInch( double fInches ) +{ + return to<sal_Int32>(o3tl::convert(fInches, o3tl::Length::in, o3tl::Length::mm100)); +} + +sal_Int32 XclTools::GetHmmFromTwips( sal_Int32 nTwips ) +{ + return limit_cast<sal_Int32>(o3tl::convert(nTwips, o3tl::Length::twip, o3tl::Length::mm100)); +} + +sal_uInt16 XclTools::GetScColumnWidth( sal_uInt16 nXclWidth, tools::Long nScCharWidth ) +{ + double fScWidth = static_cast< double >( nXclWidth ) / 256.0 * nScCharWidth - 0.5; + return limit_cast< sal_uInt16 >( fScWidth ); +} + +sal_uInt16 XclTools::GetXclColumnWidth( sal_uInt16 nScWidth, tools::Long nScCharWidth ) +{ + double fXclWidth = ( static_cast< double >( nScWidth ) + 0.5 ) * 256.0 / nScCharWidth; + return limit_cast< sal_uInt16 >( fXclWidth ); +} + +// takes font height in twips (1/20 pt = 1/1440 in) +// returns correction value in 1/256th of *digit width* of default font +double XclTools::GetXclDefColWidthCorrection( tools::Long nXclDefFontHeight ) +{ + // Excel uses *max digit width of default font* (W) as cell width unit. Also it has 5-pixel + // "correction" to cell widths (ECMA-376-1:2016 18.3.1.81): each cell has 1-pixel padding, then + // 3 pixels for the border (which may be 1-pixel - hairline - then it will have 2 additional + // 1-pixel spacings from each side; or e.g. 2 hairlines with 1-pixel spacing in the middle; or + // thick 3-pixel). Obviously, correction size entirely depends on pixel size (and it is actually + // different in Excel on monitors with different resolution). Thus actual (displayed/printed) + // cell widths consist of X*W+5px; stored in file is the X (or X*256 if 1/256th of digit width + // units are used) value. + // This formula apparently converts this 5-pixel correction to 1/256th of digit width units. + // Looks like it is created from + // + // 5 * 256 * 1440 * 2.1333 / (96 * max(N-15, 60)) + 50.0 + // + // where 5 - pixel correction; 256 - used to produce 1/256th of digit width; 1440 - used to + // convert font height N (in twips) to inches; 2.1333 - an (empirical?) quotient to convert + // font *height* into digit *width*; 96 - "standard" monitor resolution (DPI). + // Additionally the formula uses 15 (of unknown origin), 60 (minimal font height 3 pt), and + // 50.0 (also of unknown origin). + // + // TODO: convert this to take font digit width directly (and possibly DPI?), to avoid guessing + // the digit width and pixel size. Or DPI might stay 96, to not follow Excel dependency on DPI + // in addition to used font, and have absolute size of the correction fixed 5/96 in. + return 40960.0 / ::std::max( nXclDefFontHeight - 15, tools::Long(60) ) + 50.0; +} + +// formatting + +Color XclTools::GetPatternColor( const Color& rPattColor, const Color& rBackColor, sal_uInt16 nXclPattern ) +{ + // 0x00 == 0% transparence (full rPattColor) + // 0x80 == 100% transparence (full rBackColor) + static const sal_uInt8 pnRatioTable[] = + { + 0x80, 0x00, 0x40, 0x20, 0x60, 0x40, 0x40, 0x40, // 00 - 07 + 0x40, 0x40, 0x20, 0x60, 0x60, 0x60, 0x60, 0x48, // 08 - 15 + 0x50, 0x70, 0x78 // 16 - 18 + }; + return (nXclPattern < SAL_N_ELEMENTS( pnRatioTable )) ? + ScfTools::GetMixedColor( rPattColor, rBackColor, pnRatioTable[ nXclPattern ] ) : rPattColor; +} + +// text encoding + +namespace { + +const struct XclCodePageEntry +{ + sal_uInt16 mnCodePage; + rtl_TextEncoding meTextEnc; +} +pCodePageTable[] = +{ + { 437, RTL_TEXTENCODING_IBM_437 }, // OEM US +// { 720, RTL_TEXTENCODING_IBM_720 }, // OEM Arabic + { 737, RTL_TEXTENCODING_IBM_737 }, // OEM Greek + { 775, RTL_TEXTENCODING_IBM_775 }, // OEM Baltic + { 850, RTL_TEXTENCODING_IBM_850 }, // OEM Latin I + { 852, RTL_TEXTENCODING_IBM_852 }, // OEM Latin II (Central European) + { 855, RTL_TEXTENCODING_IBM_855 }, // OEM Cyrillic + { 857, RTL_TEXTENCODING_IBM_857 }, // OEM Turkish +// { 858, RTL_TEXTENCODING_IBM_858 }, // OEM Multilingual Latin I with Euro + { 860, RTL_TEXTENCODING_IBM_860 }, // OEM Portuguese + { 861, RTL_TEXTENCODING_IBM_861 }, // OEM Icelandic + { 862, RTL_TEXTENCODING_IBM_862 }, // OEM Hebrew + { 863, RTL_TEXTENCODING_IBM_863 }, // OEM Canadian (French) + { 864, RTL_TEXTENCODING_IBM_864 }, // OEM Arabic + { 865, RTL_TEXTENCODING_IBM_865 }, // OEM Nordic + { 866, RTL_TEXTENCODING_IBM_866 }, // OEM Cyrillic (Russian) + { 869, RTL_TEXTENCODING_IBM_869 }, // OEM Greek (Modern) + { 874, RTL_TEXTENCODING_MS_874 }, // MS Windows Thai + { 932, RTL_TEXTENCODING_MS_932 }, // MS Windows Japanese Shift-JIS + { 936, RTL_TEXTENCODING_MS_936 }, // MS Windows Chinese Simplified GBK + { 949, RTL_TEXTENCODING_MS_949 }, // MS Windows Korean (Wansung) + { 950, RTL_TEXTENCODING_MS_950 }, // MS Windows Chinese Traditional BIG5 + { 1200, RTL_TEXTENCODING_DONTKNOW }, // Unicode (BIFF8) - return *_DONTKNOW to preserve old code page + { 1250, RTL_TEXTENCODING_MS_1250 }, // MS Windows Latin II (Central European) + { 1251, RTL_TEXTENCODING_MS_1251 }, // MS Windows Cyrillic + { 1252, RTL_TEXTENCODING_MS_1252 }, // MS Windows Latin I (BIFF4-BIFF8) + { 1253, RTL_TEXTENCODING_MS_1253 }, // MS Windows Greek + { 1254, RTL_TEXTENCODING_MS_1254 }, // MS Windows Turkish + { 1255, RTL_TEXTENCODING_MS_1255 }, // MS Windows Hebrew + { 1256, RTL_TEXTENCODING_MS_1256 }, // MS Windows Arabic + { 1257, RTL_TEXTENCODING_MS_1257 }, // MS Windows Baltic + { 1258, RTL_TEXTENCODING_MS_1258 }, // MS Windows Vietnamese + { 1361, RTL_TEXTENCODING_MS_1361 }, // MS Windows Korean (Johab) + { 10000, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman + { 32768, RTL_TEXTENCODING_APPLE_ROMAN }, // Apple Roman + { 32769, RTL_TEXTENCODING_MS_1252 } // MS Windows Latin I (BIFF2-BIFF3) +}; +const XclCodePageEntry* const pCodePageTableEnd = std::end(pCodePageTable); + +struct XclCodePageEntry_CPPred +{ + explicit XclCodePageEntry_CPPred( sal_uInt16 nCodePage ) : mnCodePage( nCodePage ) {} + bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.mnCodePage == mnCodePage; } + sal_uInt16 mnCodePage; +}; + +struct XclCodePageEntry_TEPred +{ + explicit XclCodePageEntry_TEPred( rtl_TextEncoding eTextEnc ) : meTextEnc( eTextEnc ) {} + bool operator()( const XclCodePageEntry& rEntry ) const { return rEntry.meTextEnc == meTextEnc; } + rtl_TextEncoding meTextEnc; +}; + +} // namespace + +rtl_TextEncoding XclTools::GetTextEncoding( sal_uInt16 nCodePage ) +{ + const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_CPPred( nCodePage ) ); + if( pEntry == pCodePageTableEnd ) + { + SAL_WARN("sc", "XclTools::GetTextEncoding - unknown code page: 0x" << std::hex << nCodePage ); + return RTL_TEXTENCODING_DONTKNOW; + } + return pEntry->meTextEnc; +} + +sal_uInt16 XclTools::GetXclCodePage( rtl_TextEncoding eTextEnc ) +{ + if( eTextEnc == RTL_TEXTENCODING_UNICODE ) + return 1200; // for BIFF8 + + const XclCodePageEntry* pEntry = ::std::find_if( pCodePageTable, pCodePageTableEnd, XclCodePageEntry_TEPred( eTextEnc ) ); + if( pEntry == pCodePageTableEnd ) + { + SAL_WARN("sc", "XclTools::GetXclCodePage - unsupported text encoding: 0x" << std::hex << eTextEnc ); + return 1252; + } + return pEntry->mnCodePage; +} + +OUString XclTools::GetXclFontName( const OUString& rFontName ) +{ + // substitute with MS fonts + OUString aNewName = GetSubsFontName(rFontName, SubsFontFlags::ONLYONE | SubsFontFlags::MS); + return aNewName.isEmpty() ? rFontName : aNewName; +} + +// built-in defined names +const char maDefNamePrefix[] = "Excel_BuiltIn_"; /// Prefix for built-in defined names. +const char maDefNamePrefixXml[] = "_xlnm."; /// Prefix for built-in defined names for OOX + +const char* const ppcDefNames[] = +{ + "Consolidate_Area", + "Auto_Open", + "Auto_Close", + "Extract", + "Database", + "Criteria", + "Print_Area", + "Print_Titles", + "Recorder", + "Data_Form", + "Auto_Activate", + "Auto_Deactivate", + "Sheet_Title", + "_FilterDatabase" +}; + +OUString XclTools::GetXclBuiltInDefName( sal_Unicode cBuiltIn ) +{ + OSL_ENSURE( SAL_N_ELEMENTS( ppcDefNames ) == EXC_BUILTIN_UNKNOWN, + "XclTools::GetXclBuiltInDefName - built-in defined name list modified" ); + + if( cBuiltIn < SAL_N_ELEMENTS( ppcDefNames ) ) + return OUString::createFromAscii(ppcDefNames[cBuiltIn]); + else + return OUString::number(cBuiltIn); +} + +OUString XclTools::GetBuiltInDefName( sal_Unicode cBuiltIn ) +{ + return maDefNamePrefix + GetXclBuiltInDefName(cBuiltIn); +} + +OUString XclTools::GetBuiltInDefNameXml( sal_Unicode cBuiltIn ) +{ + return maDefNamePrefixXml + GetXclBuiltInDefName(cBuiltIn); +} + +sal_Unicode XclTools::GetBuiltInDefNameIndex( const OUString& rDefName ) +{ + sal_Int32 nPrefixLen = 0; + if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefix ) ) + nPrefixLen = strlen(maDefNamePrefix); + else if( rDefName.startsWithIgnoreAsciiCase( maDefNamePrefixXml ) ) + nPrefixLen = strlen(maDefNamePrefixXml); + if( nPrefixLen > 0 ) + { + for( sal_Unicode cBuiltIn = 0; cBuiltIn < EXC_BUILTIN_UNKNOWN; ++cBuiltIn ) + { + OUString aBuiltInName(GetXclBuiltInDefName(cBuiltIn)); + sal_Int32 nBuiltInLen = aBuiltInName.getLength(); + if( rDefName.matchIgnoreAsciiCase( aBuiltInName, nPrefixLen ) ) + { + // name can be followed by underline or space character + sal_Int32 nNextCharPos = nPrefixLen + nBuiltInLen; + sal_Unicode cNextChar = (rDefName.getLength() > nNextCharPos) ? rDefName[nNextCharPos] : '\0'; + if( (cNextChar == '\0') || (cNextChar == ' ') || (cNextChar == '_') ) + return cBuiltIn; + } + } + } + return EXC_BUILTIN_UNKNOWN; +} + +// built-in style names + +const char maStyleNamePrefix1[] = "Excel_BuiltIn_"; /// Prefix for built-in cell style names. +const char maStyleNamePrefix2[] = "Excel Built-in "; /// Prefix for built-in cell style names from OOX filter. + +const char* const ppcStyleNames[] = +{ + "", // "Normal" not used directly, but localized "Default" + "RowLevel_", // outline level will be appended + "ColumnLevel_", // outline level will be appended + "Comma", + "Currency", + "Percent", + "Comma_0", + "Currency_0", + "Hyperlink", + "Followed_Hyperlink" +}; + +OUString XclTools::GetBuiltInStyleName( sal_uInt8 nStyleId, std::u16string_view rName, sal_uInt8 nLevel ) +{ + OUString aStyleName; + + if( nStyleId == EXC_STYLE_NORMAL ) // "Normal" becomes "Default" style + { + aStyleName = ScResId( STR_STYLENAME_STANDARD ); + } + else + { + OUStringBuffer aBuf(maStyleNamePrefix1); + if( nStyleId < SAL_N_ELEMENTS( ppcStyleNames ) ) + aBuf.appendAscii(ppcStyleNames[nStyleId]); + else if (!rName.empty()) + aBuf.append(rName); + else + aBuf.append(static_cast<sal_Int32>(nStyleId)); + + if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) ) + aBuf.append(static_cast<sal_Int32>(nLevel+1)); + + aStyleName = aBuf.makeStringAndClear(); + } + + return aStyleName; +} + +bool XclTools::IsBuiltInStyleName( const OUString& rStyleName, sal_uInt8* pnStyleId, sal_Int32* pnNextChar ) +{ + // "Default" becomes "Normal" + if (rStyleName == ScResId(STR_STYLENAME_STANDARD)) + { + if( pnStyleId ) *pnStyleId = EXC_STYLE_NORMAL; + if( pnNextChar ) *pnNextChar = rStyleName.getLength(); + return true; + } + + // try the other built-in styles + sal_uInt8 nFoundId = 0; + sal_Int32 nNextChar = 0; + + sal_Int32 nPrefixLen = 0; + if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix1 ) ) + nPrefixLen = strlen(maStyleNamePrefix1); + else if( rStyleName.startsWithIgnoreAsciiCase( maStyleNamePrefix2 ) ) + nPrefixLen = strlen(maStyleNamePrefix2); + if( nPrefixLen > 0 ) + { + for( sal_uInt8 nId = 0; nId < SAL_N_ELEMENTS( ppcStyleNames ); ++nId ) + { + if( nId != EXC_STYLE_NORMAL ) + { + OUString aShortName = OUString::createFromAscii(ppcStyleNames[nId]); + if( rStyleName.matchIgnoreAsciiCase( aShortName, nPrefixLen ) && + (nNextChar < nPrefixLen + aShortName.getLength())) + { + nFoundId = nId; + nNextChar = nPrefixLen + aShortName.getLength(); + } + } + } + } + + if( nNextChar > 0 ) + { + if( pnStyleId ) *pnStyleId = nFoundId; + if( pnNextChar ) *pnNextChar = nNextChar; + return true; + } + + if( pnStyleId ) *pnStyleId = EXC_STYLE_USERDEF; + if( pnNextChar ) *pnNextChar = 0; + return nPrefixLen > 0; // also return true for unknown built-in styles +} + +bool XclTools::GetBuiltInStyleId( sal_uInt8& rnStyleId, sal_uInt8& rnLevel, const OUString& rStyleName ) +{ + sal_uInt8 nStyleId; + sal_Int32 nNextChar; + if( IsBuiltInStyleName( rStyleName, &nStyleId, &nNextChar ) && (nStyleId != EXC_STYLE_USERDEF) ) + { + if( (nStyleId == EXC_STYLE_ROWLEVEL) || (nStyleId == EXC_STYLE_COLLEVEL) ) + { + std::u16string_view aLevel = rStyleName.subView(nNextChar); + sal_Int32 nLevel = o3tl::toInt32(aLevel); + if (std::u16string_view(OUString::number(nLevel)) == aLevel + && nLevel > 0 && nLevel <= EXC_STYLE_LEVELCOUNT) + { + rnStyleId = nStyleId; + rnLevel = static_cast< sal_uInt8 >( nLevel - 1 ); + return true; + } + } + else if( rStyleName.getLength() == nNextChar ) + { + rnStyleId = nStyleId; + rnLevel = EXC_STYLE_NOLEVEL; + return true; + } + } + + rnStyleId = EXC_STYLE_USERDEF; + rnLevel = EXC_STYLE_NOLEVEL; + return false; +} + +// conditional formatting style names + +const char maCFStyleNamePrefix1[] = "Excel_CondFormat_"; /// Prefix for cond. formatting style names. +const char maCFStyleNamePrefix2[] = "ConditionalStyle_"; /// Prefix for cond. formatting style names from OOX filter. +const char maCFStyleNamePrefix3[] = "ExtConditionalStyle_"; + +OUString XclTools::GetCondFormatStyleName( SCTAB nScTab, sal_Int32 nFormat, sal_uInt16 nCondition ) +{ + return maCFStyleNamePrefix1 + + OUString::number(static_cast<sal_Int32>(nScTab+1)) + + "_" + + OUString::number(static_cast<sal_Int32>(nFormat+1)) + + "_" + + OUString::number(static_cast<sal_Int32>(nCondition+1)); +} + +bool XclTools::IsCondFormatStyleName( const OUString& rStyleName ) +{ + if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix1 ) ) + return true; + + if( rStyleName.startsWithIgnoreAsciiCase( maCFStyleNamePrefix2 ) ) + return true; + + if (rStyleName.startsWithIgnoreAsciiCase(maCFStyleNamePrefix3)) + return true; + + return false; +} + +// stream handling + +void XclTools::SkipSubStream( XclImpStream& rStrm ) +{ + bool bLoop = true; + while( bLoop && rStrm.StartNextRecord() ) + { + sal_uInt16 nRecId = rStrm.GetRecId(); + bLoop = nRecId != EXC_ID_EOF; + if( (nRecId == EXC_ID2_BOF) || (nRecId == EXC_ID3_BOF) || (nRecId == EXC_ID4_BOF) || (nRecId == EXC_ID5_BOF) ) + SkipSubStream( rStrm ); + } +} + +// Basic macro names + +const char maSbMacroPrefix[] = "vnd.sun.star.script:"; /// Prefix for StarBasic macros. +const char maSbMacroSuffix[] = "?language=Basic&location=document"; /// Suffix for StarBasic macros. + +OUString XclTools::GetSbMacroUrl( const OUString& rMacroName, SfxObjectShell* pDocShell ) +{ + OSL_ENSURE( !rMacroName.isEmpty(), "XclTools::GetSbMacroUrl - macro name is empty" ); + ::ooo::vba::MacroResolvedInfo aMacroInfo = ::ooo::vba::resolveVBAMacro( pDocShell, rMacroName ); + if( aMacroInfo.mbFound ) + return ::ooo::vba::makeMacroURL( aMacroInfo.msResolvedMacro ); + return OUString(); +} + +OUString XclTools::GetXclMacroName( const OUString& rSbMacroUrl ) +{ + sal_Int32 nSbMacroUrlLen = rSbMacroUrl.getLength(); + sal_Int32 nMacroNameLen = nSbMacroUrlLen - strlen(maSbMacroPrefix) - strlen(maSbMacroSuffix); + if( (nMacroNameLen > 0) && rSbMacroUrl.startsWithIgnoreAsciiCase( maSbMacroPrefix ) && + rSbMacroUrl.endsWithIgnoreAsciiCase( maSbMacroSuffix ) ) + { + sal_Int32 nPrjDot = rSbMacroUrl.indexOf( '.', strlen(maSbMacroPrefix) ) + 1; + return rSbMacroUrl.copy( nPrjDot, nSbMacroUrlLen - nPrjDot - strlen(maSbMacroSuffix) ); + } + return OUString(); +} + +// read/write colors + +XclImpStream& operator>>( XclImpStream& rStrm, Color& rColor ) +{ + sal_uInt8 nR = rStrm.ReaduInt8(); + sal_uInt8 nG = rStrm.ReaduInt8(); + sal_uInt8 nB = rStrm.ReaduInt8(); + rStrm.Ignore( 1 );//nD + rColor = Color( nR, nG, nB ); + return rStrm; +} + +XclExpStream& operator<<( XclExpStream& rStrm, const Color& rColor ) +{ + return rStrm << rColor.GetRed() << rColor.GetGreen() << rColor.GetBlue() << sal_uInt8( 0 ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |