blob: 3e1d0fd0c2cce5dea17a5db4be958327f4c0afde [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
#include <com/sun/star/i18n/UnicodeType.hpp>
#include <com/sun/star/util/DateTime.hpp>
#include <com/sun/star/util/Date.hpp>
#include <com/sun/star/util/Duration.hpp>
#include <com/sun/star/uno/Sequence.hxx>
#include <rtl/ustrbuf.hxx>
#include <rtl/math.hxx>
#include "sax/tools/converter.hxx"
using namespace rtl;
using namespace com::sun::star;
using namespace com::sun::star::uno;
using namespace com::sun::star::util;
//using namespace com::sun::star::text;
//using namespace com::sun::star::style;
using namespace ::com::sun::star::i18n;
namespace sax {
static const sal_Char* gpsMM = "mm";
static const sal_Char* gpsCM = "cm";
static const sal_Char* gpsPT = "pt";
static const sal_Char* gpsINCH = "in";
static const sal_Char* gpsPC = "pc";
const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11;
const sal_Int8 XML_MAXDIGITSCOUNT_DATETIME = 6;
#define XML_NULLDATE "NullDate"
/** convert string to measure using optional min and max values*/
bool Converter::convertMeasure( sal_Int32& rValue,
const OUString& rString,
sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
sal_Int32 nMin /* = SAL_MIN_INT32 */,
sal_Int32 nMax /* = SAL_MAX_INT32 */ )
{
bool bNeg = false;
double nVal = 0;
sal_Int32 nPos = 0;
sal_Int32 nLen = rString.getLength();
// skip white space
while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
nPos++;
if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
{
bNeg = true;
nPos++;
}
// get number
while( nPos < nLen &&
sal_Unicode('0') <= rString[nPos] &&
sal_Unicode('9') >= rString[nPos] )
{
// TODO: check overflow!
nVal *= 10;
nVal += (rString[nPos] - sal_Unicode('0'));
nPos++;
}
double nDiv = 1.;
if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
{
nPos++;
while( nPos < nLen &&
sal_Unicode('0') <= rString[nPos] &&
sal_Unicode('9') >= rString[nPos] )
{
// TODO: check overflow!
nDiv *= 10;
nVal += ( ((double)(rString[nPos] - sal_Unicode('0'))) / nDiv );
nPos++;
}
}
// skip white space
while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
nPos++;
if( nPos < nLen )
{
if( MeasureUnit::PERCENT == nTargetUnit )
{
if( sal_Unicode('%') != rString[nPos] )
return false;
}
else if( MeasureUnit::PIXEL == nTargetUnit )
{
if( nPos + 1 >= nLen ||
(sal_Unicode('p') != rString[nPos] &&
sal_Unicode('P') != rString[nPos])||
(sal_Unicode('x') != rString[nPos+1] &&
sal_Unicode('X') != rString[nPos+1]) )
return false;
}
else
{
OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit, "unit is not supported");
const sal_Char *aCmpsL[2] = { 0, 0 };
const sal_Char *aCmpsU[2] = { 0, 0 };
double aScales[2] = { 1., 1. };
if( MeasureUnit::TWIP == nTargetUnit )
{
switch( rString[nPos] )
{
case sal_Unicode('c'):
case sal_Unicode('C'):
aCmpsL[0] = "cm";
aCmpsU[0] = "CM";
aScales[0] = (72.*20.)/2.54; // twip
break;
case sal_Unicode('i'):
case sal_Unicode('I'):
aCmpsL[0] = "in";
aCmpsU[0] = "IN";
aScales[0] = 72.*20.; // twip
break;
case sal_Unicode('m'):
case sal_Unicode('M'):
aCmpsL[0] = "mm";
aCmpsU[0] = "MM";
aScales[0] = (72.*20.)/25.4; // twip
break;
case sal_Unicode('p'):
case sal_Unicode('P'):
aCmpsL[0] = "pt";
aCmpsU[0] = "PT";
aScales[0] = 20.; // twip
aCmpsL[1] = "pc";
aCmpsU[1] = "PC";
aScales[1] = 12.*20.; // twip
break;
}
}
else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
{
double nScaleFactor = (MeasureUnit::MM_100TH == nTargetUnit) ? 100.0 : 10.0;
switch( rString[nPos] )
{
case sal_Unicode('c'):
case sal_Unicode('C'):
aCmpsL[0] = "cm";
aCmpsU[0] = "CM";
aScales[0] = 10.0 * nScaleFactor; // mm/100
break;
case sal_Unicode('i'):
case sal_Unicode('I'):
aCmpsL[0] = "in";
aCmpsU[0] = "IN";
aScales[0] = 1000.*2.54; // mm/100
break;
case sal_Unicode('m'):
case sal_Unicode('M'):
aCmpsL[0] = "mm";
aCmpsU[0] = "MM";
aScales[0] = 1.0 * nScaleFactor; // mm/100
break;
case sal_Unicode('p'):
case sal_Unicode('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
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] == NULL )
return false;
double nScale = 0.;
for( sal_uInt16 i= 0; i < 2; i++ )
{
const sal_Char *pL = aCmpsL[i];
if( pL )
{
const sal_Char *pU = aCmpsU[i];
while( nPos < nLen && *pL )
{
sal_Unicode c = rString[nPos];
if( c != *pL && c != *pU )
break;
pL++;
pU++;
nPos++;
}
if( !*pL && (nPos == nLen || ' ' == rString[nPos]) )
{
nScale = aScales[i];
break;
}
}
}
if( 0. == nScale )
return false;
// TODO: check overflow
if( nScale != 1. )
nVal *= nScale;
}
}
nVal += .5;
if( bNeg )
nVal = -nVal;
if( nVal <= (double)nMin )
rValue = nMin;
else if( nVal >= (double)nMax )
rValue = nMax;
else
rValue = (sal_Int32)nVal;
return true;
}
/** convert measure in given unit to string with given unit */
void Converter::convertMeasure( OUStringBuffer& rBuffer,
sal_Int32 nMeasure,
sal_Int16 nSourceUnit /* = MeasureUnit::MM_100TH */,
sal_Int16 nTargetUnit /* = MeasureUnit::INCH */ )
{
OSL_ENSURE( false, "Converter::convertMeasure - not implemented, tools/BigInt needs replacement" );
(void)rBuffer;
(void)nMeasure;
(void)nSourceUnit;
(void)nTargetUnit;
#if 0
if( nSourceUnit == MeasureUnit::PERCENT )
{
OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT,
"MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
rBuffer.append( nMeasure );
rBuffer.append( sal_Unicode('%' ) );
}
else
{
// the sign is processed seperatly
if( nMeasure < 0 )
{
nMeasure = -nMeasure;
rBuffer.append( sal_Unicode('-') );
}
// The new length is (nVal * nMul)/(nDiv*nFac*10)
long nMul = 1000;
long nDiv = 1;
long nFac = 100;
const sal_Char* psUnit = 0;
switch( nSourceUnit )
{
case MeasureUnit::TWIP:
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
case MeasureUnit::MM_10TH:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,"output unit not supported for twip values" );
case MeasureUnit::MM:
// 0.01mm = 0.57twip (exactly)
nMul = 25400; // 25.4 * 1000
nDiv = 1440; // 72 * 20;
nFac = 100;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
// 0.001cm = 0.57twip (exactly)
nMul = 25400; // 2.54 * 10000
nDiv = 1440; // 72 * 20;
nFac = 1000;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
// 0.01pt = 0.2twip (exactly)
nMul = 1000;
nDiv = 20;
nFac = 100;
psUnit = gpsPT;
break;
case MeasureUnit::INCH:
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;
}
break;
case MeasureUnit::POINT:
// 1pt = 1pt (exactly)
OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
"output unit not supported for pt values" );
nMul = 10;
nDiv = 1;
nFac = 1;
psUnit = gpsPT;
break;
case MeasureUnit::MM_10TH:
case MeasureUnit::MM_100TH:
{
long nFac2 = (MeasureUnit::MM_100TH == nSourceUnit) ? 100 : 10;
switch( nTargetUnit )
{
case MeasureUnit::MM_100TH:
case MeasureUnit::MM_10TH:
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
"output unit not supported for 1/100mm values" );
case MeasureUnit::MM:
// 0.01mm = 1 mm/100 (exactly)
nMul = 10;
nDiv = 1;
nFac = nFac2;
psUnit = gpsMM;
break;
case MeasureUnit::CM:
// 0.001mm = 1 mm/100 (exactly)
nMul = 10;
nDiv = 1; // 72 * 20;
nFac = 10*nFac2;
psUnit = gpsCM;
break;
case MeasureUnit::POINT:
// 0.01pt = 0.35 mm/100 (exactly)
nMul = 72000;
nDiv = 2540;
nFac = nFac2;
psUnit = gpsPT;
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)
nMul = 100000;
nDiv = 2540;
nFac = 100*nFac2;
psUnit = gpsINCH;
break;
}
break;
}
}
long nLongVal = 0;
bool bOutLongVal = true;
if( nMeasure > SAL_INT32_MAX / nMul )
{
// A big int is required for calculation
BigInt nBigVal( nMeasure );
BigInt nBigFac( nFac );
nBigVal *= nMul;
nBigVal /= nDiv;
nBigVal += 5;
nBigVal /= 10;
if( nBigVal.IsLong() )
{
// To convert the value into a string a long is sufficient
nLongVal = (long)nBigVal;
}
else
{
BigInt nBigFac2( nFac );
BigInt nBig10( 10 );
rBuffer.append( (sal_Int32)(nBigVal / nBigFac2) );
if( !(nBigVal % nBigFac2).IsZero() )
{
rBuffer.append( sal_Unicode('.') );
while( nFac > 1 && !(nBigVal % nBigFac2).IsZero() )
{
nFac /= 10;
nBigFac2 = nFac;
rBuffer.append( (sal_Int32)((nBigVal / nBigFac2) % nBig10 ) );
}
}
bOutLongVal = false;
}
}
else
{
nLongVal = nMeasure * nMul;
nLongVal /= nDiv;
nLongVal += 5;
nLongVal /= 10;
}
if( bOutLongVal )
{
rBuffer.append( (sal_Int32)(nLongVal / nFac) );
if( nFac > 1 && (nLongVal % nFac) != 0 )
{
rBuffer.append( sal_Unicode('.') );
while( nFac > 1 && (nLongVal % nFac) != 0 )
{
nFac /= 10;
rBuffer.append( (sal_Int32)((nLongVal / nFac) % 10) );
}
}
}
if( psUnit )
rBuffer.appendAscii( psUnit );
}
#endif
}
static const OUString& getTrueString()
{
static const OUString sTrue( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
return sTrue;
}
static const OUString& getFalseString()
{
static const OUString sFalse( RTL_CONSTASCII_USTRINGPARAM( "false" ) );
return sFalse;
}
/** convert string to boolean */
bool Converter::convertBool( bool& rBool, const OUString& rString )
{
rBool = rString == getTrueString();
return rBool || (rString == getFalseString());
}
/** convert boolean to string */
void Converter::convertBool( OUStringBuffer& rBuffer, bool bValue )
{
rBuffer.append( bValue ? getTrueString() : getFalseString() );
}
/** convert string to percent */
bool Converter::convertPercent( sal_Int32& rPercent, const OUString& rString )
{
return convertMeasure( rPercent, rString, MeasureUnit::PERCENT );
}
/** convert percent to string */
void Converter::convertPercent( OUStringBuffer& rBuffer, sal_Int32 nValue )
{
rBuffer.append( nValue );
rBuffer.append( sal_Unicode('%' ) );
}
/** convert string to pixel measure */
bool Converter::convertMeasurePx( sal_Int32& rPixel, const OUString& rString )
{
return convertMeasure( rPixel, rString, MeasureUnit::PIXEL );
}
/** convert pixel measure to string */
void Converter::convertMeasurePx( OUStringBuffer& rBuffer, sal_Int32 nValue )
{
rBuffer.append( nValue );
rBuffer.append( sal_Unicode('p' ) );
rBuffer.append( sal_Unicode('x' ) );
}
int lcl_gethex( int nChar )
{
if( nChar >= '0' && nChar <= '9' )
return nChar - '0';
else if( nChar >= 'a' && nChar <= 'f' )
return nChar - 'a' + 10;
else if( nChar >= 'A' && nChar <= 'F' )
return nChar - 'A' + 10;
else
return 0;
}
/** convert string to color */
bool Converter::convertColor( sal_Int32& rColor, const OUString& rValue )
{
if( rValue.getLength() != 7 || rValue[0] != '#' )
return false;
rColor = lcl_gethex( rValue[1] ) * 16 + lcl_gethex( rValue[2] );
rColor <<= 8;
rColor |= ( lcl_gethex( rValue[3] ) * 16 + lcl_gethex( rValue[4] ) );
rColor <<= 8;
rColor |= ( lcl_gethex( rValue[5] ) * 16 + lcl_gethex( rValue[6] ) );
return true;
}
static sal_Char aHexTab[] = "0123456789abcdef";
/** convert color to string */
void Converter::convertColor( OUStringBuffer& rBuffer, sal_Int32 nColor )
{
rBuffer.append( sal_Unicode( '#' ) );
sal_uInt8 nCol = (sal_uInt8)(nColor >> 16);
rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
nCol = (sal_uInt8)(nColor >> 8);
rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
nCol = (sal_uInt8)nColor;
rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
}
/** convert number to string */
void Converter::convertNumber( OUStringBuffer& rBuffer, sal_Int32 nNumber )
{
rBuffer.append( nNumber );
}
/** convert string to number with optional min and max values */
bool Converter::convertNumber( sal_Int32& rValue,
const OUString& rString,
sal_Int32 nMin, sal_Int32 nMax )
{
bool bNeg = false;
rValue = 0;
sal_Int32 nPos = 0;
sal_Int32 nLen = rString.getLength();
// skip white space
while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
nPos++;
if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
{
bNeg = true;
nPos++;
}
// get number
while( nPos < nLen &&
sal_Unicode('0') <= rString[nPos] &&
sal_Unicode('9') >= rString[nPos] )
{
// TODO: check overflow!
rValue *= 10;
rValue += (rString[nPos] - sal_Unicode('0'));
nPos++;
}
if( bNeg )
rValue *= -1;
if( rValue < nMin )
rValue = nMin;
else if( rValue > nMax )
rValue = nMax;
return nPos == nLen;
}
/** convert double number to string (using ::rtl::math) */
void Converter::convertDouble( OUStringBuffer& rBuffer,
double fNumber,
bool bWriteUnits,
sal_Int16 nSourceUnit,
sal_Int16 nTargetUnit)
{
if(MeasureUnit::PERCENT == nSourceUnit)
{
OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT, "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
if(bWriteUnits)
rBuffer.append(sal_Unicode('%'));
}
else
{
OUStringBuffer sUnit;
double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
if(fFactor != 1.0)
fNumber *= fFactor;
::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
if(bWriteUnits)
rBuffer.append(sUnit);
}
}
/** convert double number to string (using ::rtl::math) */
void Converter::convertDouble( ::rtl::OUStringBuffer& rBuffer, double fNumber)
{
::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
}
/** convert string to double number (using ::rtl::math) */
bool Converter::convertDouble(double& rValue,
const ::rtl::OUString& rString, sal_Int16 nTargetUnit)
{
sal_Int16 nSourceUnit = GetUnitFromString(rString, nTargetUnit);
return convertDouble(rValue, rString, nSourceUnit, nTargetUnit );
}
/** convert string to double number (using ::rtl::math) */
bool Converter::convertDouble(double& rValue,
const ::rtl::OUString& rString, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
{
rtl_math_ConversionStatus eStatus;
rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
if(eStatus == rtl_math_ConversionStatus_Ok)
{
OUStringBuffer sUnit;
double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
if(fFactor != 1.0 && fFactor != 0.0)
rValue /= fFactor;
}
return ( eStatus == rtl_math_ConversionStatus_Ok );
}
/** convert string to double number (using ::rtl::math) */
bool Converter::convertDouble(double& rValue, const ::rtl::OUString& rString)
{
rtl_math_ConversionStatus eStatus;
rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
return ( eStatus == rtl_math_ConversionStatus_Ok );
}
/** convert double to ISO "duration" string; negative durations allowed */
void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
const double fTime)
{
double fValue = fTime;
// take care of negative durations as specified in:
// XML Schema, W3C Working Draft 07 April 2000, section 3.2.6.1
if (fValue < 0.0)
{
rBuffer.append(sal_Unicode('-'));
fValue = - fValue;
}
rBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM( "PT" ));
fValue *= 24;
double fHoursValue = ::rtl::math::approxFloor (fValue);
fValue -= fHoursValue;
fValue *= 60;
double fMinsValue = ::rtl::math::approxFloor (fValue);
fValue -= fMinsValue;
fValue *= 60;
double fSecsValue = ::rtl::math::approxFloor (fValue);
fValue -= fSecsValue;
double f100SecsValue;
if (fValue > 0.00001)
f100SecsValue = ::rtl::math::round( fValue, XML_MAXDIGITSCOUNT_TIME - 5);
else
f100SecsValue = 0.0;
if (f100SecsValue == 1.0)
{
f100SecsValue = 0.0;
fSecsValue += 1.0;
}
if (fSecsValue >= 60.0)
{
fSecsValue -= 60.0;
fMinsValue += 1.0;
}
if (fMinsValue >= 60.0)
{
fMinsValue -= 60.0;
fHoursValue += 1.0;
}
if (fHoursValue < 10)
rBuffer.append( sal_Unicode('0'));
rBuffer.append( sal_Int32( fHoursValue));
rBuffer.append( sal_Unicode('H'));
if (fMinsValue < 10)
rBuffer.append( sal_Unicode('0'));
rBuffer.append( sal_Int32( fMinsValue));
rBuffer.append( sal_Unicode('M'));
if (fSecsValue < 10)
rBuffer.append( sal_Unicode('0'));
rBuffer.append( sal_Int32( fSecsValue));
if (f100SecsValue > 0.0)
{
::rtl::OUString a100th( ::rtl::math::doubleToUString( fValue,
rtl_math_StringFormat_F, XML_MAXDIGITSCOUNT_TIME - 5, '.',
true));
if ( a100th.getLength() > 2 )
{
rBuffer.append( sal_Unicode('.'));
rBuffer.append( a100th.copy( 2 ) ); // strip 0.
}
}
rBuffer.append( sal_Unicode('S'));
}
/** convert ISO "duration" string to double; negative durations allowed */
bool Converter::convertDuration(double& rfTime,
const ::rtl::OUString& rString)
{
rtl::OUString aTrimmed = rString.trim().toAsciiUpperCase();
const sal_Unicode* pStr = aTrimmed.getStr();
// negative time duration?
bool bIsNegativeDuration = false;
if ( sal_Unicode('-') == (*pStr) )
{
bIsNegativeDuration = true;
pStr++;
}
if ( *(pStr++) != sal_Unicode('P') ) // duration must start with "P"
return false;
rtl::OUString sDoubleStr;
bool bSuccess = true;
bool bDone = false;
bool bTimePart = false;
bool bIsFraction = false;
sal_Int32 nDays = 0;
sal_Int32 nHours = 0;
sal_Int32 nMins = 0;
sal_Int32 nSecs = 0;
sal_Int32 nTemp = 0;
while ( bSuccess && !bDone )
{
sal_Unicode c = *(pStr++);
if ( !c ) // end
bDone = true;
else if ( sal_Unicode('0') <= c && sal_Unicode('9') >= c )
{
if ( nTemp >= SAL_MAX_INT32 / 10 )
bSuccess = false;
else
{
if ( !bIsFraction )
{
nTemp *= 10;
nTemp += (c - sal_Unicode('0'));
}
else
{
sDoubleStr += OUString::valueOf(c);
}
}
}
else if ( bTimePart )
{
if ( c == sal_Unicode('H') )
{
nHours = nTemp;
nTemp = 0;
}
else if ( c == sal_Unicode('M') )
{
nMins = nTemp;
nTemp = 0;
}
else if ( (c == sal_Unicode(',')) || (c == sal_Unicode('.')) )
{
nSecs = nTemp;
nTemp = 0;
bIsFraction = true;
sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0."));
}
else if ( c == sal_Unicode('S') )
{
if ( !bIsFraction )
{
nSecs = nTemp;
nTemp = 0;
sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0.0"));
}
}
else
bSuccess = false; // invalid character
}
else
{
if ( c == sal_Unicode('T') ) // "T" starts time part
bTimePart = true;
else if ( c == sal_Unicode('D') )
{
nDays = nTemp;
nTemp = 0;
}
else if ( c == sal_Unicode('Y') || c == sal_Unicode('M') )
{
//! how many days is a year or month?
OSL_ENSURE( false, "years or months in duration: not implemented");
bSuccess = false;
}
else
bSuccess = false; // invalid character
}
}
if ( bSuccess )
{
if ( nDays )
nHours += nDays * 24; // add the days to the hours part
double fTempTime = 0.0;
double fHour = nHours;
double fMin = nMins;
double fSec = nSecs;
double fSec100 = 0.0;
double fFraction = sDoubleStr.toDouble();
fTempTime = fHour / 24;
fTempTime += fMin / (24 * 60);
fTempTime += fSec / (24 * 60 * 60);
fTempTime += fSec100 / (24 * 60 * 60 * 60);
fTempTime += fFraction / (24 * 60 * 60);
// negative duration?
if ( bIsNegativeDuration )
{
fTempTime = -fTempTime;
}
rfTime = fTempTime;
}
return bSuccess;
}
/** convert util::Duration to ISO "duration" string */
void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
const ::util::Duration& rDuration)
{
if (rDuration.Negative)
{
rBuffer.append(sal_Unicode('-'));
}
rBuffer.append(sal_Unicode('P'));
const bool bHaveDate(static_cast<sal_Int32>(rDuration.Years)
+static_cast<sal_Int32>(rDuration.Months)
+static_cast<sal_Int32>(rDuration.Days));
if (rDuration.Years)
{
rBuffer.append(static_cast<sal_Int32>(rDuration.Years));
rBuffer.append(sal_Unicode('Y'));
}
if (rDuration.Months)
{
rBuffer.append(static_cast<sal_Int32>(rDuration.Months));
rBuffer.append(sal_Unicode('M'));
}
if (rDuration.Days)
{
rBuffer.append(static_cast<sal_Int32>(rDuration.Days));
rBuffer.append(sal_Unicode('D'));
}
const sal_Int32 nMSecs(static_cast<sal_Int32>(rDuration.Seconds)
+ static_cast<sal_Int32>(rDuration.MilliSeconds));
if (static_cast<sal_Int32>(rDuration.Hours) +
static_cast<sal_Int32>(rDuration.Minutes) + nMSecs)
{
rBuffer.append(sal_Unicode('T')); // time separator
if (rDuration.Hours)
{
rBuffer.append(static_cast<sal_Int32>(rDuration.Hours));
rBuffer.append(sal_Unicode('H'));
}
if (rDuration.Minutes)
{
rBuffer.append(static_cast<sal_Int32>(rDuration.Minutes));
rBuffer.append(sal_Unicode('M'));
}
if (nMSecs)
{
// seconds must not be omitted (i.e. ".42S" is not valid)
rBuffer.append(static_cast<sal_Int32>(rDuration.Seconds));
if (rDuration.MilliSeconds)
{
rBuffer.append(sal_Unicode('.'));
const sal_Int32 nMilliSeconds(rDuration.MilliSeconds % 1000);
if (nMilliSeconds < 100)
{
rBuffer.append(sal_Unicode('0'));
}
if (nMilliSeconds < 10)
{
rBuffer.append(sal_Unicode('0'));
}
if (0 == (nMilliSeconds % 10))
{
if (0 == (nMilliSeconds % 100))
{
rBuffer.append(nMilliSeconds / 100);
}
else
{
rBuffer.append(nMilliSeconds / 10);
}
}
else
{
rBuffer.append(nMilliSeconds);
}
}
rBuffer.append(sal_Unicode('S'));
}
}
else if (!bHaveDate)
{
// zero duration: XMLSchema-2 says there must be at least one component
rBuffer.append(sal_Unicode('0'));
rBuffer.append(sal_Unicode('D'));
}
}
enum Result { R_NOTHING, R_OVERFLOW, R_SUCCESS };
static Result
readUnsignedNumber(const ::rtl::OUString & rString,
sal_Int32 & io_rnPos, sal_Int32 & o_rNumber)
{
bool bOverflow(false);
sal_Int32 nTemp(0);
sal_Int32 nPos(io_rnPos);
while (nPos < rString.getLength())
{
const sal_Unicode c = rString[nPos];
if ((sal_Unicode('0') <= c) && (c <= sal_Unicode('9')))
{
nTemp *= 10;
nTemp += (c - sal_Unicode('0'));
if (nTemp >= SAL_MAX_INT16)
{
bOverflow = true;
}
}
else
{
break;
}
++nPos;
}
if (io_rnPos == nPos) // read something?
{
o_rNumber = -1;
return R_NOTHING;
}
io_rnPos = nPos;
o_rNumber = nTemp;
return (bOverflow) ? R_OVERFLOW : R_SUCCESS;
}
static bool
readDurationT(const ::rtl::OUString & rString, sal_Int32 & io_rnPos)
{
if ((io_rnPos < rString.getLength()) &&
(rString[io_rnPos] == sal_Unicode('T')))
{
++io_rnPos;
return true;
}
return false;
}
static bool
readDurationComponent(const ::rtl::OUString & rString,
sal_Int32 & io_rnPos, sal_Int32 & io_rnTemp, bool & io_rbTimePart,
sal_Int32 & o_rnTarget, const sal_Unicode c)
{
if ((io_rnPos < rString.getLength()))
{
if (c == rString[io_rnPos])
{
++io_rnPos;
if (-1 != io_rnTemp)
{
o_rnTarget = io_rnTemp;
io_rnTemp = -1;
if (!io_rbTimePart)
{
io_rbTimePart = readDurationT(rString, io_rnPos);
}
return (R_OVERFLOW !=
readUnsignedNumber(rString, io_rnPos, io_rnTemp));
}
else
{
return false;
}
}
}
return true;
}
/** convert ISO "duration" string to util::Duration */
bool Converter::convertDuration(util::Duration& rDuration,
const ::rtl::OUString& rString)
{
const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
sal_Int32 nPos(0);
bool bIsNegativeDuration(false);
if (string.getLength() && (sal_Unicode('-') == string[0]))
{
bIsNegativeDuration = true;
++nPos;
}
if ((nPos < string.getLength())
&& (string[nPos] != sal_Unicode('P'))) // duration must start with "P"
{
return false;
}
++nPos;
/// last read number; -1 == no valid number! always reset after using!
sal_Int32 nTemp(-1);
bool bTimePart(false); // have we read 'T'?
bool bSuccess(false);
sal_Int32 nYears(0);
sal_Int32 nMonths(0);
sal_Int32 nDays(0);
sal_Int32 nHours(0);
sal_Int32 nMinutes(0);
sal_Int32 nSeconds(0);
sal_Int32 nMilliSeconds(0);
bTimePart = readDurationT(string, nPos);
bSuccess = (R_SUCCESS == readUnsignedNumber(string, nPos, nTemp));
if (!bTimePart && bSuccess)
{
bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
nYears, sal_Unicode('Y'));
}
if (!bTimePart && bSuccess)
{
bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
nMonths, sal_Unicode('M'));
}
if (!bTimePart && bSuccess)
{
bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
nDays, sal_Unicode('D'));
}
if (bTimePart)
{
if (-1 == nTemp) // a 'T' must be followed by a component
{
bSuccess = false;
}
if (bSuccess)
{
bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
nHours, sal_Unicode('H'));
}
if (bSuccess)
{
bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
nMinutes, sal_Unicode('M'));
}
// eeek! seconds are icky.
if ((nPos < string.getLength()) && bSuccess)
{
if (sal_Unicode('.') == string[nPos])
{
++nPos;
if (-1 != nTemp)
{
nSeconds = nTemp;
nTemp = -1;
const sal_Int32 nStart(nPos);
bSuccess =
(R_NOTHING != readUnsignedNumber(string, nPos, nTemp));
if ((nPos < string.getLength()) && bSuccess)
{
if (-1 != nTemp)
{
nTemp = -1;
const sal_Int32 nDigits = nPos - nStart;
OSL_ENSURE(nDigits > 0, "bad code monkey");
const sal_Unicode cZero('0');
nMilliSeconds = 100 * (string[nStart] - cZero);
if (nDigits >= 2)
{
nMilliSeconds += 10 *
(string[nStart+1] - cZero);
if (nDigits >= 3)
{
nMilliSeconds += (string[nStart+2] - cZero);
}
}
if (sal_Unicode('S') == string[nPos])
{
++nPos;
}
else
{
bSuccess = false;
}
}
else
{
bSuccess = false;
}
}
}
else
{
bSuccess = false;
}
}
else if (sal_Unicode('S') == string[nPos])
{
++nPos;
if (-1 != nTemp)
{
nSeconds = nTemp;
nTemp = -1;
}
else
{
bSuccess = false;
}
}
}
}
if (nPos != string.getLength()) // string not processed completely?
{
bSuccess = false;
}
if (nTemp != -1) // unprocessed number?
{
bSuccess = false;
}
if (bSuccess)
{
rDuration.Negative = bIsNegativeDuration;
rDuration.Years = static_cast<sal_Int16>(nYears);
rDuration.Months = static_cast<sal_Int16>(nMonths);
rDuration.Days = static_cast<sal_Int16>(nDays);
rDuration.Hours = static_cast<sal_Int16>(nHours);
rDuration.Minutes = static_cast<sal_Int16>(nMinutes);
rDuration.Seconds = static_cast<sal_Int16>(nSeconds);
rDuration.MilliSeconds = static_cast<sal_Int16>(nMilliSeconds);
}
return bSuccess;
}
/** convert util::Date to ISO "date" string */
void Converter::convertDate(
::rtl::OUStringBuffer& i_rBuffer,
const util::Date& i_rDate)
{
const util::DateTime dt(
0, 0, 0, 0, i_rDate.Day, i_rDate.Month, i_rDate.Year);
convertDateTime(i_rBuffer, dt, false);
}
/** convert util::DateTime to ISO "date" or "dateTime" string */
void Converter::convertDateTime(
::rtl::OUStringBuffer& i_rBuffer,
const com::sun::star::util::DateTime& i_rDateTime,
bool i_bAddTimeIf0AM )
{
const sal_Unicode dash('-');
const sal_Unicode col (':');
const sal_Unicode dot ('.');
const sal_Unicode zero('0');
const sal_Unicode tee ('T');
if (i_rDateTime.Year < 1000) {
i_rBuffer.append(zero);
}
if (i_rDateTime.Year < 100) {
i_rBuffer.append(zero);
}
if (i_rDateTime.Year < 10) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Year) ).append(dash);
if( i_rDateTime.Month < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Month) ).append(dash);
if( i_rDateTime.Day < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Day) );
if( i_rDateTime.Seconds != 0 ||
i_rDateTime.Minutes != 0 ||
i_rDateTime.Hours != 0 ||
i_bAddTimeIf0AM )
{
i_rBuffer.append(tee);
if( i_rDateTime.Hours < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Hours) )
.append(col);
if( i_rDateTime.Minutes < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Minutes) )
.append(col);
if( i_rDateTime.Seconds < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Seconds) );
if( i_rDateTime.HundredthSeconds > 0 ) {
i_rBuffer.append(dot);
if( i_rDateTime.HundredthSeconds < 10 ) {
i_rBuffer.append(zero);
}
i_rBuffer.append(
static_cast<sal_Int32>(i_rDateTime.HundredthSeconds) );
}
}
}
/** convert ISO "date" or "dateTime" string to util::DateTime */
bool Converter::convertDateTime( util::DateTime& rDateTime,
const ::rtl::OUString& rString )
{
bool isDateTime;
util::Date date;
if (convertDateOrDateTime(date, rDateTime, isDateTime, rString))
{
if (!isDateTime)
{
rDateTime.Year = date.Year;
rDateTime.Month = date.Month;
rDateTime.Day = date.Day;
rDateTime.Hours = 0;
rDateTime.Minutes = 0;
rDateTime.Seconds = 0;
rDateTime.HundredthSeconds = 0;
}
return true;
}
else
{
return false;
}
}
static bool
readDateTimeComponent(const ::rtl::OUString & rString,
sal_Int32 & io_rnPos, sal_Int32 & o_rnTarget,
const sal_Int32 nMinLength, const bool bExactLength)
{
const sal_Int32 nOldPos(io_rnPos);
sal_Int32 nTemp(0);
if (R_SUCCESS != readUnsignedNumber(rString, io_rnPos, nTemp))
{
return false;
}
const sal_Int32 nTokenLength(io_rnPos - nOldPos);
if ((nTokenLength < nMinLength) ||
(bExactLength && (nTokenLength > nMinLength)))
{
return false; // bad length
}
o_rnTarget = nTemp;
return true;
}
static bool lcl_isLeapYear(const sal_uInt32 nYear)
{
return (((nYear % 4 == 0) && (nYear % 100 != 0)) ||
(nYear % 400 == 0));
}
static sal_uInt16
lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear)
{
static sal_uInt16 s_MaxDaysPerMonth[12] =
{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
OSL_ASSERT(0 < nMonth && nMonth <= 12);
if ((2 == nMonth) && lcl_isLeapYear(nYear))
{
return 29;
}
return s_MaxDaysPerMonth[nMonth - 1];
}
/** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
bool Converter::convertDateOrDateTime(
util::Date & rDate, util::DateTime & rDateTime,
bool & rbDateTime, const ::rtl::OUString & rString )
{
bool bSuccess = true;
const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
sal_Int32 nPos(0);
bool bNegative(false);
if ((string.getLength() > nPos) && (sal_Unicode('-') == string[nPos]))
{
++nPos;
bNegative = true;
}
sal_Int32 nYear(0);
{
bSuccess = readDateTimeComponent(string, nPos, nYear, 4, false);
bSuccess &= (0 < nYear);
bSuccess &= (nPos < string.getLength()); // not last token
}
if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
{
bSuccess = false;
}
if (bSuccess)
{
++nPos;
}
sal_Int32 nMonth(0);
if (bSuccess)
{
bSuccess = readDateTimeComponent(string, nPos, nMonth, 2, true);
bSuccess &= (0 < nMonth) && (nMonth <= 12);
bSuccess &= (nPos < string.getLength()); // not last token
}
if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
{
bSuccess = false;
}
if (bSuccess)
{
++nPos;
}
sal_Int32 nDay(0);
if (bSuccess)
{
bSuccess = readDateTimeComponent(string, nPos, nDay, 2, true);
bSuccess &= (0 < nDay) && (nDay <= lcl_MaxDaysPerMonth(nMonth, nYear));
}
bool bHaveTime(false);
if (bSuccess && (nPos < string.getLength()))
{
if (sal_Unicode('T') == string[nPos]) // time separator
{
bHaveTime = true;
++nPos;
}
}
sal_Int32 nHours(0);
sal_Int32 nMinutes(0);
sal_Int32 nSeconds(0);
sal_Int32 nMilliSeconds(0);
if (bSuccess && bHaveTime)
{
{
bSuccess = readDateTimeComponent(string, nPos, nHours, 2, true);
bSuccess &= (0 <= nHours) && (nHours <= 24);
bSuccess &= (nPos < string.getLength()); // not last token
}
if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
{
bSuccess = false;
}
if (bSuccess)
{
++nPos;
}
if (bSuccess)
{
bSuccess = readDateTimeComponent(string, nPos, nMinutes, 2, true);
bSuccess &= (0 <= nMinutes) && (nMinutes < 60);
bSuccess &= (nPos < string.getLength()); // not last token
}
if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
{
bSuccess = false;
}
if (bSuccess)
{
++nPos;
}
if (bSuccess)
{
bSuccess = readDateTimeComponent(string, nPos, nSeconds, 2, true);
bSuccess &= (0 <= nSeconds) && (nSeconds < 60);
}
if (bSuccess && (nPos < string.getLength()) &&
(sal_Unicode('.') == string[nPos])) // fraction separator
{
++nPos;
const sal_Int32 nStart(nPos);
sal_Int32 nTemp(0);
if (R_NOTHING == readUnsignedNumber(string, nPos, nTemp))
{
bSuccess = false;
}
if (bSuccess)
{
// cannot use nTemp because of possible leading zeros
// and possible overflow => read digits directly
const sal_Int32 nDigits(nPos - nStart);
OSL_ENSURE(nDigits > 0, "bad code monkey");
const sal_Unicode cZero('0');
nMilliSeconds = 100 * (string[nStart] - cZero);
if (nDigits >= 2)
{
nMilliSeconds += 10 * (string[nStart+1] - cZero);
if (nDigits >= 3)
{
nMilliSeconds += (string[nStart+2] - cZero);
}
}
}
}
if (bSuccess && (nHours == 24))
{
if (!((0 == nMinutes) && (0 == nSeconds) && (0 == nMilliSeconds)))
{
bSuccess = false; // only 24:00:00 is valid
}
#if 0
else
{
nHours = 0; // normalize 24:00:00 to 00:00:00 of next day
lcl_addDay(bNegative, nYear, nMonth, nDay, 1);
}
#endif
}
}
bool bHaveTimezone(false);
bool bHaveTimezonePlus(false);
bool bHaveTimezoneMinus(false);
if (bSuccess && (nPos < string.getLength()))
{
const sal_Unicode c(string[nPos]);
if (sal_Unicode('+') == c)
{
bHaveTimezone = true;
bHaveTimezonePlus = true;
++nPos;
}
else if (sal_Unicode('-') == c)
{
bHaveTimezone = true;
bHaveTimezoneMinus = true;
++nPos;
}
else if (sal_Unicode('Z') == c)
{
bHaveTimezone = true;
++nPos;
}
else
{
bSuccess = false;
}
}
sal_Int32 nTimezoneHours(0);
sal_Int32 nTimezoneMinutes(0);
if (bSuccess && (bHaveTimezonePlus || bHaveTimezoneMinus))
{
bSuccess = readDateTimeComponent(
string, nPos, nTimezoneHours, 2, true);
bSuccess &= (0 <= nTimezoneHours) && (nTimezoneHours <= 14);
bSuccess &= (nPos < string.getLength()); // not last token
if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
{
bSuccess = false;
}
if (bSuccess)
{
++nPos;
}
if (bSuccess)
{
bSuccess = readDateTimeComponent(
string, nPos, nTimezoneMinutes, 2, true);
bSuccess &= (0 <= nTimezoneMinutes) && (nTimezoneMinutes < 60);
}
if (bSuccess && (nTimezoneHours == 14))
{
if (0 != nTimezoneMinutes)
{
bSuccess = false; // only +-14:00 is valid
}
}
}
bSuccess &= (nPos == string.getLength()); // trailing junk?
if (bSuccess && bHaveTimezone)
{
// util::DateTime does not support timezones!
#if 0
// do not add timezone, just strip it (as suggested by er)
lcl_addTimezone(bNegative, nYear, nMonth, nDay, nHours, nMinutes,
!bHaveTimezoneMinus, nTimezoneHours, nTimezoneMinutes);
#endif
}
if (bSuccess)
{
if (bHaveTime) // time is optional
{
// util::DateTime does not support negative years!
rDateTime.Year = static_cast<sal_uInt16>(nYear);
rDateTime.Month = static_cast<sal_uInt16>(nMonth);
rDateTime.Day = static_cast<sal_uInt16>(nDay);
rDateTime.Hours = static_cast<sal_uInt16>(nHours);
rDateTime.Minutes = static_cast<sal_uInt16>(nMinutes);
rDateTime.Seconds = static_cast<sal_uInt16>(nSeconds);
// util::DateTime does not support 3 decimal digits of precision!
rDateTime.HundredthSeconds =
static_cast<sal_uInt16>(nMilliSeconds / 10);
rbDateTime = true;
}
else
{
rDate.Year = static_cast<sal_uInt16>(nYear);
rDate.Month = static_cast<sal_uInt16>(nMonth);
rDate.Day = static_cast<sal_uInt16>(nDay);
rbDateTime = false;
}
}
return bSuccess;
}
/** gets the position of the first comma after npos in the string
rStr. Commas inside '"' pairs are not matched */
sal_Int32 Converter::indexOfComma( const OUString& rStr,
sal_Int32 nPos )
{
sal_Unicode cQuote = 0;
sal_Int32 nLen = rStr.getLength();
for( ; nPos < nLen; nPos++ )
{
sal_Unicode c = rStr[nPos];
switch( c )
{
case sal_Unicode('\''):
if( 0 == cQuote )
cQuote = c;
else if( '\'' == cQuote )
cQuote = 0;
break;
case sal_Unicode('"'):
if( 0 == cQuote )
cQuote = c;
else if( '\"' == cQuote )
cQuote = 0;
break;
case sal_Unicode(','):
if( 0 == cQuote )
return nPos;
break;
}
}
return -1;
}
const
sal_Char aBase64EncodeTable[] =
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
const
sal_uInt8 aBase64DecodeTable[] =
{ 62,255,255,255, 63, // 43-47
// + /
52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, // 48-63
// 0 1 2 3 4 5 6 7 8 9 =
255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
// A B C D E F G H I J K L M N O
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 80-95
// P Q R S T U V W X Y Z
0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
// a b c d e f g h i j k l m n o
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; // 112-123
// p q r s t u v w x y z
void ThreeByteToFourByte (const sal_Int8* pBuffer, const sal_Int32 nStart, const sal_Int32 nFullLen, rtl::OUStringBuffer& sBuffer)
{
sal_Int32 nLen(nFullLen - nStart);
if (nLen > 3)
nLen = 3;
if (nLen == 0)
{
sBuffer.setLength(0);
return;
}
sal_Int32 nBinaer;
switch (nLen)
{
case 1:
{
nBinaer = ((sal_uInt8)pBuffer[nStart + 0]) << 16;
}
break;
case 2:
{
nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
(((sal_uInt8)pBuffer[nStart + 1]) << 8);
}
break;
default:
{
nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
(((sal_uInt8)pBuffer[nStart + 1]) << 8) +
((sal_uInt8)pBuffer[nStart + 2]);
}
break;
}
sBuffer.appendAscii("====");
sal_uInt8 nIndex (static_cast<sal_uInt8>((nBinaer & 0xFC0000) >> 18));
sBuffer.setCharAt(0, aBase64EncodeTable [nIndex]);
nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F000) >> 12);
sBuffer.setCharAt(1, aBase64EncodeTable [nIndex]);
if (nLen == 1)
return;
nIndex = static_cast<sal_uInt8>((nBinaer & 0xFC0) >> 6);
sBuffer.setCharAt(2, aBase64EncodeTable [nIndex]);
if (nLen == 2)
return;
nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F));
sBuffer.setCharAt(3, aBase64EncodeTable [nIndex]);
}
void Converter::encodeBase64(rtl::OUStringBuffer& aStrBuffer, const uno::Sequence<sal_Int8>& aPass)
{
sal_Int32 i(0);
sal_Int32 nBufferLength(aPass.getLength());
const sal_Int8* pBuffer = aPass.getConstArray();
while (i < nBufferLength)
{
rtl::OUStringBuffer sBuffer;
ThreeByteToFourByte (pBuffer, i, nBufferLength, sBuffer);
aStrBuffer.append(sBuffer);
i += 3;
}
}
void Converter::decodeBase64(uno::Sequence<sal_Int8>& aBuffer, const rtl::OUString& sBuffer)
{
#if OSL_DEBUG_LEVEL > 0
sal_Int32 nCharsDecoded =
#endif
decodeBase64SomeChars( aBuffer, sBuffer );
OSL_ENSURE( nCharsDecoded == sBuffer.getLength(), "some bytes left in base64 decoding!" );
}
sal_Int32 Converter::decodeBase64SomeChars(
uno::Sequence<sal_Int8>& rOutBuffer,
const rtl::OUString& rInBuffer)
{
sal_Int32 nInBufferLen = rInBuffer.getLength();
sal_Int32 nMinOutBufferLen = (nInBufferLen / 4) * 3;
if( rOutBuffer.getLength() < nMinOutBufferLen )
rOutBuffer.realloc( nMinOutBufferLen );
const sal_Unicode *pInBuffer = rInBuffer.getStr();
sal_Int8 *pOutBuffer = rOutBuffer.getArray();
sal_Int8 *pOutBufferStart = pOutBuffer;
sal_Int32 nCharsDecoded = 0;
sal_uInt8 aDecodeBuffer[4];
sal_Int32 nBytesToDecode = 0;
sal_Int32 nBytesGotFromDecoding = 3;
sal_Int32 nInBufferPos= 0;
while( nInBufferPos < nInBufferLen )
{
sal_Unicode cChar = *pInBuffer;
if( cChar >= '+' && cChar <= 'z' )
{
sal_uInt8 nByte = aBase64DecodeTable[cChar-'+'];
if( nByte != 255 )
{
// We have found a valid character!
aDecodeBuffer[nBytesToDecode++] = nByte;
// One '=' character at the end means 2 out bytes
// Two '=' characters at the end mean 1 out bytes
if( '=' == cChar && nBytesToDecode > 2 )
nBytesGotFromDecoding--;
if( 4 == nBytesToDecode )
{
// Four characters found, so we may convert now!
sal_uInt32 nOut = (aDecodeBuffer[0] << 18) +
(aDecodeBuffer[1] << 12) +
(aDecodeBuffer[2] << 6) +
aDecodeBuffer[3];
*pOutBuffer++ = (sal_Int8)((nOut & 0xff0000) >> 16);
if( nBytesGotFromDecoding > 1 )
*pOutBuffer++ = (sal_Int8)((nOut & 0xff00) >> 8);
if( nBytesGotFromDecoding > 2 )
*pOutBuffer++ = (sal_Int8)(nOut & 0xff);
nCharsDecoded = nInBufferPos + 1;
nBytesToDecode = 0;
nBytesGotFromDecoding = 3;
}
}
else
{
nCharsDecoded++;
}
}
else
{
nCharsDecoded++;
}
nInBufferPos++;
pInBuffer++;
}
if( (pOutBuffer - pOutBufferStart) != rOutBuffer.getLength() )
rOutBuffer.realloc( pOutBuffer - pOutBufferStart );
return nCharsDecoded;
}
void Converter::clearUndefinedChars(rtl::OUString& rTarget, const rtl::OUString& rSource)
{
sal_uInt32 nLength(rSource.getLength());
rtl::OUStringBuffer sBuffer(nLength);
for (sal_uInt32 i = 0; i < nLength; i++)
{
sal_Unicode cChar = rSource[i];
if (!(cChar < 0x0020) ||
(cChar == 0x0009) || // TAB
(cChar == 0x000A) || // LF
(cChar == 0x000D)) // legal character
sBuffer.append(cChar);
}
rTarget = sBuffer.makeStringAndClear();
}
double Converter::GetConversionFactor(::rtl::OUStringBuffer& rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
{
double fRetval(1.0);
rUnit.setLength(0L);
const sal_Char* psUnit = 0;
if(nSourceUnit != nTargetUnit)
{
switch(nSourceUnit)
{
case MeasureUnit::TWIP:
{
switch(nTargetUnit)
{
case MeasureUnit::MM_100TH:
case MeasureUnit::MM_10TH:
{
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
}
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:
// 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:
case MeasureUnit::MM_10TH:
{
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
}
case MeasureUnit::MM:
{
// 0.01mm = 1 mm/100 (exactly)
fRetval = ((10.0 / 1.0) / 100.0);
psUnit = gpsMM;
break;
}
case MeasureUnit::CM:
{
// 0.001mm = 1 mm/100 (exactly)
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::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) / 10000.0);
psUnit = gpsINCH;
break;
}
}
break;
}
case MeasureUnit::MM_100TH:
{
switch(nTargetUnit)
{
case MeasureUnit::MM_100TH:
case MeasureUnit::MM_10TH:
{
OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
}
case MeasureUnit::MM:
{
// 0.01mm = 1 mm/100 (exactly)
fRetval = ((10.0 / 1.0) / 1000.0);
psUnit = gpsMM;
break;
}
case MeasureUnit::CM:
{
// 0.001mm = 1 mm/100 (exactly)
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::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;
}
}
if( psUnit )
rUnit.appendAscii( psUnit );
}
return fRetval;
}
sal_Int16 Converter::GetUnitFromString(const ::rtl::OUString& rString, sal_Int16 nDefaultUnit)
{
sal_Int32 nPos = 0L;
sal_Int32 nLen = rString.getLength();
sal_Int16 nRetUnit = nDefaultUnit;
// skip white space
while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
nPos++;
// skip negative
if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
nPos++;
// skip number
while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
nPos++;
if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
{
nPos++;
while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
nPos++;
}
// skip white space
while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
nPos++;
if( nPos < nLen )
{
switch(rString[nPos])
{
case sal_Unicode('%') :
{
nRetUnit = MeasureUnit::PERCENT;
break;
}
case sal_Unicode('c'):
case sal_Unicode('C'):
{
if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
|| rString[nPos+1] == sal_Unicode('M')))
nRetUnit = MeasureUnit::CM;
break;
}
case sal_Unicode('e'):
case sal_Unicode('E'):
{
// CSS1_EMS or CSS1_EMX later
break;
}
case sal_Unicode('i'):
case sal_Unicode('I'):
{
if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('n')
|| rString[nPos+1] == sal_Unicode('n')))
nRetUnit = MeasureUnit::INCH;
break;
}
case sal_Unicode('m'):
case sal_Unicode('M'):
{
if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
|| rString[nPos+1] == sal_Unicode('M')))
nRetUnit = MeasureUnit::MM;
break;
}
case sal_Unicode('p'):
case sal_Unicode('P'):
{
if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('t')
|| rString[nPos+1] == sal_Unicode('T')))
nRetUnit = MeasureUnit::POINT;
if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('c')
|| rString[nPos+1] == sal_Unicode('C')))
nRetUnit = MeasureUnit::TWIP;
break;
}
}
}
return nRetUnit;
}
}