summaryrefslogtreecommitdiff
path: root/sax
diff options
context:
space:
mode:
Diffstat (limited to 'sax')
-rw-r--r--sax/source/tools/converter.cxx585
1 files changed, 113 insertions, 472 deletions
diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx
index 4f7c686a1aba..18731b45ac77 100644
--- a/sax/source/tools/converter.cxx
+++ b/sax/source/tools/converter.cxx
@@ -28,7 +28,9 @@
#include <rtl/ustrbuf.hxx>
#include <rtl/math.hxx>
+#include <rtl/character.hxx>
#include <sal/log.hxx>
+#include <o3tl/unit_conversion.hxx>
#include <osl/diagnose.h>
#include <tools/long.hxx>
@@ -43,11 +45,11 @@ using namespace ::com::sun::star::i18n;
namespace sax {
-const char* const gpsMM = "mm";
-const char* const gpsCM = "cm";
-const char* const gpsPT = "pt";
-const char* const gpsINCH = "in";
-const char* const gpsPC = "pc";
+const std::string_view gpsMM = "mm";
+const std::string_view gpsCM = "cm";
+const std::string_view gpsPT = "pt";
+const std::string_view gpsINCH = "in";
+const std::string_view gpsPC = "pc";
const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 14;
@@ -60,6 +62,62 @@ static sal_Int64 toInt64_WithLength(const char * str, sal_Int16 radix, sal_Int32
return rtl_str_toInt64_WithLength(str, radix, nStrLength);
}
+namespace
+{
+o3tl::Length Measure2O3tlUnit(sal_Int16 nUnit)
+{
+ switch (nUnit)
+ {
+ case MeasureUnit::TWIP:
+ return o3tl::Length::twip;
+ case MeasureUnit::POINT:
+ return o3tl::Length::pt;
+ case MeasureUnit::MM_10TH:
+ return o3tl::Length::mm10;
+ case MeasureUnit::MM_100TH:
+ return o3tl::Length::mm100;
+ case MeasureUnit::MM:
+ return o3tl::Length::mm;
+ case MeasureUnit::CM:
+ return o3tl::Length::cm;
+ default:
+ SAL_WARN("sax", "unit not supported for length");
+ [[fallthrough]];
+ case MeasureUnit::INCH:
+ return o3tl::Length::in;
+ }
+}
+
+std::string_view Measure2UnitString(sal_Int16 nUnit)
+{
+ switch (nUnit)
+ {
+ case MeasureUnit::TWIP:
+ return gpsPC; // ??
+ case MeasureUnit::POINT:
+ return gpsPT;
+ case MeasureUnit::MM_10TH:
+ case MeasureUnit::MM_100TH:
+ return {};
+ case MeasureUnit::MM:
+ return gpsMM;
+ case MeasureUnit::CM:
+ return gpsCM;
+ case MeasureUnit::INCH:
+ default:
+ return gpsINCH;
+ }
+}
+
+template <typename V> bool wordEndsWith(V string, std::string_view expected)
+{
+ V substr = string.substr(0, expected.size());
+ return std::equal(substr.begin(), substr.end(), expected.begin(), expected.end(),
+ [](sal_uInt32 c1, sal_uInt32 c2) { return rtl::toAsciiLowerCase(c1) == c2; })
+ && (string.size() == expected.size() || string[expected.size()] == ' ');
+}
+
+}
/** convert string to measure using optional min and max values*/
template<typename V>
@@ -137,127 +195,70 @@ static bool lcl_convertMeasure( sal_Int32& rValue,
OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit ||
MeasureUnit::PIXEL == nTargetUnit, "unit is not supported");
- const char *aCmpsL[3] = { nullptr, nullptr, nullptr };
- const char *aCmpsU[3] = { nullptr, nullptr, nullptr };
- double aScales[3] = { 1., 1., 1. };
+
+ o3tl::Length eFrom = o3tl::Length::invalid;
if( MeasureUnit::TWIP == nTargetUnit )
{
- switch( rString[nPos] )
+ switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
{
case u'c':
- case u'C':
- aCmpsL[0] = "cm";
- aCmpsU[0] = "CM";
- aScales[0] = (72.*20.)/2.54; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::cm;
break;
case u'i':
- case u'I':
- aCmpsL[0] = "in";
- aCmpsU[0] = "IN";
- aScales[0] = 72.*20.; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "n"))
+ eFrom = o3tl::Length::in;
break;
case u'm':
- case u'M':
- aCmpsL[0] = "mm";
- aCmpsU[0] = "MM";
- aScales[0] = (72.*20.)/25.4; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::mm;
break;
case u'p':
- case u'P':
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = 20.; // twip
-
- aCmpsL[1] = "pc";
- aCmpsU[1] = "PC";
- aScales[1] = 12.*20.; // twip
+ if (wordEndsWith(rString.substr(nPos + 1), "t"))
+ eFrom = o3tl::Length::pt;
+ else if (wordEndsWith(rString.substr(nPos + 1), "c"))
+ eFrom = o3tl::Length::pc;
break;
}
}
else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
{
- double nScaleFactor = (MeasureUnit::MM_100TH == nTargetUnit) ? 100.0 : 10.0;
- switch( rString[nPos] )
+ switch (rtl::toAsciiLowerCase<sal_uInt32>(rString[nPos]))
{
case u'c':
- case u'C':
- aCmpsL[0] = "cm";
- aCmpsU[0] = "CM";
- aScales[0] = 10.0 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::cm;
break;
case u'i':
- case u'I':
- aCmpsL[0] = "in";
- aCmpsU[0] = "IN";
- aScales[0] = 1000.*2.54; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "n"))
+ eFrom = o3tl::Length::in;
break;
case u'm':
- case u'M':
- aCmpsL[0] = "mm";
- aCmpsU[0] = "MM";
- aScales[0] = 1.0 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "m"))
+ eFrom = o3tl::Length::mm;
break;
case u'p':
- case u'P':
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = (10.0 * nScaleFactor*2.54)/72.; // mm/100
-
- aCmpsL[1] = "pc";
- aCmpsU[1] = "PC";
- aScales[1] = (10.0 * nScaleFactor*2.54)/12.; // mm/100
-
- aCmpsL[2] = "px";
- aCmpsU[2] = "PX";
- aScales[2] = 0.28 * nScaleFactor; // mm/100
+ if (wordEndsWith(rString.substr(nPos + 1), "t"))
+ eFrom = o3tl::Length::pt;
+ else if (wordEndsWith(rString.substr(nPos + 1), "c"))
+ eFrom = o3tl::Length::pc;
+ else if (wordEndsWith(rString.substr(nPos + 1), "x"))
+ eFrom = o3tl::Length::px;
break;
}
}
else if( MeasureUnit::POINT == nTargetUnit )
{
- if( rString[nPos] == 'p' || rString[nPos] == 'P' )
- {
- aCmpsL[0] = "pt";
- aCmpsU[0] = "PT";
- aScales[0] = 1;
- }
- }
-
- if( aCmpsL[0] == nullptr )
- return false;
-
- double nScale = 0.;
- for( sal_uInt16 i= 0; i < 3; i++ )
- {
- sal_Int32 nTmp = nPos; // come back to the initial position before each iteration
- const char *pL = aCmpsL[i];
- if( pL )
- {
- const char *pU = aCmpsU[i];
- while( nTmp < nLen && *pL )
- {
- sal_Unicode c = rString[nTmp];
- if( c != *pL && c != *pU )
- break;
- pL++;
- pU++;
- nTmp++;
- }
- if( !*pL && (nTmp == nLen || ' ' == rString[nTmp]) )
- {
- nScale = aScales[i];
- break;
- }
- }
+ if (wordEndsWith(rString.substr(nPos), "pt"))
+ eFrom = o3tl::Length::pt;
}
- if( 0. == nScale )
+ if (eFrom == o3tl::Length::invalid)
return false;
// TODO: check overflow
- if( nScale != 1. )
- nVal *= nScale;
+ nVal = o3tl::convert(nVal, eFrom, Measure2O3tlUnit(nTargetUnit));
}
}
@@ -320,14 +321,13 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
rBuffer.append( '-' );
}
- // The new length is (nVal * nMul)/(nDiv*nFac*10)
- tools::Long nMul = 1000;
- tools::Long nDiv = 1;
- tools::Long nFac = 100;
- const char* psUnit = nullptr;
+ o3tl::Length eFrom = o3tl::Length::in, eTo = o3tl::Length::in;
+ int nFac = 100; // used to get specific number of decimals (2 by default)
+ std::string_view psUnit;
switch( nSourceUnit )
{
case MeasureUnit::TWIP:
+ eFrom = o3tl::Length::twip;
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
@@ -335,25 +335,19 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,"output unit not supported for twip values" );
[[fallthrough]];
case MeasureUnit::MM:
- // 0.01mm = 0.57twip (exactly)
- nMul = 25400; // 25.4 * 1000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::mm;
nFac = 100;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
- // 0.001cm = 0.57twip (exactly)
- nMul = 25400; // 2.54 * 10000
- nDiv = 1440; // 72 * 20;
+ eTo = o3tl::Length::cm;
nFac = 1000;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
- // 0.01pt = 0.2twip (exactly)
- nMul = 1000;
- nDiv = 20;
+ eTo = o3tl::Length::pt;
nFac = 100;
psUnit = gpsPT;
break;
@@ -362,9 +356,6 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
default:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
"output unit not supported for twip values" );
- // 0.0001in = 0.144twip (exactly)
- nMul = 100000;
- nDiv = 1440; // 72 * 20;
nFac = 10000;
psUnit = gpsINCH;
break;
@@ -375,8 +366,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
// 1pt = 1pt (exactly)
OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
"output unit not supported for pt values" );
- nMul = 10;
- nDiv = 1;
+ eFrom = eTo = o3tl::Length::pt;
nFac = 1;
psUnit = gpsPT;
break;
@@ -384,6 +374,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
case MeasureUnit::MM_100TH:
{
int nFac2 = (MeasureUnit::MM_100TH == nSourceUnit) ? 100 : 10;
+ eFrom = Measure2O3tlUnit(nSourceUnit);
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
@@ -392,25 +383,19 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
"output unit not supported for 1/100mm values" );
[[fallthrough]];
case MeasureUnit::MM:
- // 0.01mm = 1 mm/100 (exactly)
- nMul = 10;
- nDiv = 1;
+ eTo = o3tl::Length::mm;
nFac = nFac2;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
- // 0.001mm = 1 mm/100 (exactly)
- nMul = 10;
- nDiv = 1; // 72 * 20;
+ eTo = o3tl::Length::cm;
nFac = 10*nFac2;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
- // 0.01pt = 0.35 mm/100 (exactly)
- nMul = 72000;
- nDiv = 2540;
+ eTo = o3tl::Length::pt;
nFac = nFac2;
psUnit = gpsPT;
break;
@@ -419,9 +404,6 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
default:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
"output unit not supported for 1/100mm values" );
- // 0.0001in = 0.254 mm/100 (exactly)
- nMul = 100000;
- nDiv = 2540;
nFac = 100*nFac2;
psUnit = gpsINCH;
break;
@@ -434,11 +416,7 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
break;
}
- OSL_ENSURE(nValue <= SAL_MAX_INT64 / nMul, "convertMeasure: overflow");
- nValue *= nMul;
- nValue /= nDiv;
- nValue += 5;
- nValue /= 10;
+ nValue = o3tl::convert(nValue * nFac, eFrom, eTo);
rBuffer.append( static_cast<sal_Int64>(nValue / nFac) );
if (nFac > 1 && (nValue % nFac) != 0)
@@ -451,8 +429,8 @@ void Converter::convertMeasure( OUStringBuffer& rBuffer,
}
}
- if( psUnit )
- rBuffer.appendAscii( psUnit );
+ if (psUnit.length() > 0)
+ rBuffer.appendAscii(psUnit.data(), psUnit.length());
}
/** convert string to boolean */
@@ -2240,349 +2218,12 @@ double Converter::GetConversionFactor(OUStringBuffer& rUnit, sal_Int16 nSourceUn
if(nSourceUnit != nTargetUnit)
{
- const char* psUnit = nullptr;
-
- switch(nSourceUnit)
- {
- case MeasureUnit::TWIP:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 10.0);
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 100.0);
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 1000.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- // 0.001cm = 0.57twip (exactly)
- fRetval = ((25400.0 / 1440.0) / 10000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.2twip (exactly)
- fRetval = ((1000.0 / 20.0) / 1000.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
- // 0.0001in = 0.144twip (exactly)
- fRetval = ((100000.0 / 1440.0) / 100000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::POINT:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 2540.0 / 72.0 );
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 254.0 / 72.0 );
- break;
- }
- case MeasureUnit::MM:
- {
- // 1mm = 72 / 25.4 pt (exactly)
- fRetval = ( 25.4 / 72.0 );
- psUnit = gpsMM;
- break;
-
- }
- case MeasureUnit::CM:
- {
- // 1cm = 72 / 2.54 pt (exactly)
- fRetval = ( 2.54 / 72.0 );
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::TWIP:
- {
- // 1twip = 72 / 1440 pt (exactly)
- fRetval = 20.0; // 1440.0 / 72.0
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for pt values");
- // 1in = 72 pt (exactly)
- fRetval = ( 1.0 / 72.0 );
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 10.0;
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 1 mm/100 (exactly)
- fRetval = ((10.0 / 1.0) / 100.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = ((10.0 / 1.0) / 1000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.35 mm/100 (exactly)
- fRetval = ((72000.0 / 2540.0) / 100.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = ((20.0 * 72000.0 / 2540.0) / 100.0);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/10mm values");
- // 0.0001in = 0.254 mm/100 (exactly)
- fRetval = ((100000.0 / 2540.0) / 10000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM_100TH:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_10TH:
- {
- fRetval = ((10.0 / 1.0) / 100.0);
- break;
- }
- case MeasureUnit::MM:
- {
- // 0.01mm = 1 mm/100 (exactly)
- fRetval = ((10.0 / 1.0) / 1000.0);
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = ((10.0 / 1.0) / 10000.0);
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- // 0.01pt = 0.35 mm/100 (exactly)
- fRetval = ((72000.0 / 2540.0) / 1000.0);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = ((20.0 * 72000.0 / 2540.0) / 1000.0);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
- // 0.0001in = 0.254 mm/100 (exactly)
- fRetval = ((100000.0 / 2540.0) / 100000.0);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::MM:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 100.0;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 10.0;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = 0.1;
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0 / (2.54 * 10);
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = (20.0 * 72.0) / (2.54 * 10);
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
- fRetval = 1 / (2.54 * 10);
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::CM:
- {
- switch(nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 1000.0;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 100.0;
- break;
- }
- case MeasureUnit::MM:
- {
- fRetval = 10.0;
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0 / 2.54;
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = (20.0 * 72.0) / 2.54;
- psUnit = gpsPC;
- break;
- }
- case MeasureUnit::INCH:
- default:
- {
- OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
- fRetval = 1 / 2.54;
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- case MeasureUnit::INCH:
- {
- switch (nTargetUnit)
- {
- case MeasureUnit::MM_100TH:
- {
- fRetval = 2540;
- break;
- }
- case MeasureUnit::MM_10TH:
- {
- fRetval = 254;
- break;
- }
- case MeasureUnit::MM:
- {
- fRetval = 25.4;
- psUnit = gpsMM;
- break;
- }
- case MeasureUnit::CM:
- {
- fRetval = 2.54;
- psUnit = gpsCM;
- break;
- }
- case MeasureUnit::POINT:
- {
- fRetval = 72.0;
- psUnit = gpsPT;
- break;
- }
- case MeasureUnit::TWIP:
- {
- fRetval = 72.0 * 20.0;
- psUnit = gpsPC;
- break;
- }
- default:
- {
- OSL_FAIL("output unit not supported for in values");
- fRetval = 1;
- psUnit = gpsINCH;
- break;
- }
- }
- break;
- }
- default:
- OSL_ENSURE(false, "sax::Converter::GetConversionFactor(): "
- "source unit not supported");
- break;
- }
+ const o3tl::Length eFrom = Measure2O3tlUnit(nSourceUnit);
+ const o3tl::Length eTo = Measure2O3tlUnit(nTargetUnit);
+ fRetval = o3tl::convert(1.0, eFrom, eTo);
- if( psUnit )
- rUnit.appendAscii( psUnit );
+ if (const auto sUnit = Measure2UnitString(nTargetUnit); sUnit.size() > 0)
+ rUnit.appendAscii(sUnit.data(), sUnit.size());
}
return fRetval;