1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sax/tools/converter.hxx>
22 #include <com/sun/star/i18n/UnicodeType.hpp>
23 #include <com/sun/star/util/DateTime.hpp>
24 #include <com/sun/star/util/Date.hpp>
25 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
26 #include <com/sun/star/util/DateWithTimezone.hpp>
27 #include <com/sun/star/util/Duration.hpp>
28 #include <com/sun/star/util/Time.hpp>
29 #include <com/sun/star/uno/Sequence.hxx>
31 #include <rtl/ustrbuf.hxx>
32 #include <rtl/math.hxx>
33 #include <sal/log.hxx>
35 #include <osl/diagnose.h>
39 using namespace com::sun::star
;
40 using namespace com::sun::star::uno
;
41 using namespace com::sun::star::util
;
42 using namespace ::com::sun::star::i18n
;
47 static const sal_Char
* gpsMM
= "mm";
48 static const sal_Char
* gpsCM
= "cm";
49 static const sal_Char
* gpsPT
= "pt";
50 static const sal_Char
* gpsINCH
= "in";
51 static const sal_Char
* gpsPC
= "pc";
53 const sal_Int8 XML_MAXDIGITSCOUNT_TIME
= 14;
55 /** convert string to measure using optional min and max values*/
56 bool Converter::convertMeasure( sal_Int32
& rValue
,
57 const OUString
& rString
,
58 sal_Int16 nTargetUnit
/* = MeasureUnit::MM_100TH */,
59 sal_Int32 nMin
/* = SAL_MIN_INT32 */,
60 sal_Int32 nMax
/* = SAL_MAX_INT32 */ )
66 sal_Int32
const nLen
= rString
.getLength();
69 while( (nPos
< nLen
) && (rString
[nPos
] <= ' ') )
72 if( nPos
< nLen
&& '-' == rString
[nPos
] )
80 '0' <= rString
[nPos
] &&
81 '9' >= rString
[nPos
] )
83 // TODO: check overflow!
85 nVal
+= (rString
[nPos
] - '0');
88 if( nPos
< nLen
&& '.' == rString
[nPos
] )
94 '0' <= rString
[nPos
] &&
95 '9' >= rString
[nPos
] )
97 // TODO: check overflow!
99 nVal
+= ( ((double)(rString
[nPos
] - '0')) / nDiv
);
105 while( (nPos
< nLen
) && (rString
[nPos
] <= ' ') )
111 if( MeasureUnit::PERCENT
== nTargetUnit
)
113 if( '%' != rString
[nPos
] )
116 else if( MeasureUnit::PIXEL
== nTargetUnit
)
118 if( nPos
+ 1 >= nLen
||
119 ('p' != rString
[nPos
] &&
120 'P' != rString
[nPos
])||
121 ('x' != rString
[nPos
+1] &&
122 'X' != rString
[nPos
+1]) )
127 OSL_ENSURE( MeasureUnit::TWIP
== nTargetUnit
|| MeasureUnit::POINT
== nTargetUnit
||
128 MeasureUnit::MM_100TH
== nTargetUnit
|| MeasureUnit::MM_10TH
== nTargetUnit
, "unit is not supported");
129 const sal_Char
*aCmpsL
[2] = { 0, 0 };
130 const sal_Char
*aCmpsU
[2] = { 0, 0 };
131 double aScales
[2] = { 1., 1. };
133 if( MeasureUnit::TWIP
== nTargetUnit
)
135 switch( rString
[nPos
] )
137 case sal_Unicode('c'):
138 case sal_Unicode('C'):
141 aScales
[0] = (72.*20.)/2.54; // twip
143 case sal_Unicode('i'):
144 case sal_Unicode('I'):
147 aScales
[0] = 72.*20.; // twip
149 case sal_Unicode('m'):
150 case sal_Unicode('M'):
153 aScales
[0] = (72.*20.)/25.4; // twip
155 case sal_Unicode('p'):
156 case sal_Unicode('P'):
159 aScales
[0] = 20.; // twip
163 aScales
[1] = 12.*20.; // twip
167 else if( MeasureUnit::MM_100TH
== nTargetUnit
|| MeasureUnit::MM_10TH
== nTargetUnit
)
169 double nScaleFactor
= (MeasureUnit::MM_100TH
== nTargetUnit
) ? 100.0 : 10.0;
170 switch( rString
[nPos
] )
172 case sal_Unicode('c'):
173 case sal_Unicode('C'):
176 aScales
[0] = 10.0 * nScaleFactor
; // mm/100
178 case sal_Unicode('i'):
179 case sal_Unicode('I'):
182 aScales
[0] = 1000.*2.54; // mm/100
184 case sal_Unicode('m'):
185 case sal_Unicode('M'):
188 aScales
[0] = 1.0 * nScaleFactor
; // mm/100
190 case sal_Unicode('p'):
191 case sal_Unicode('P'):
194 aScales
[0] = (10.0 * nScaleFactor
*2.54)/72.; // mm/100
198 aScales
[1] = (10.0 * nScaleFactor
*2.54)/12.; // mm/100
202 else if( MeasureUnit::POINT
== nTargetUnit
)
204 if( rString
[nPos
] == 'p' || rString
[nPos
] == 'P' )
212 if( aCmpsL
[0] == NULL
)
216 for( sal_uInt16 i
= 0; i
< 2; i
++ )
218 const sal_Char
*pL
= aCmpsL
[i
];
221 const sal_Char
*pU
= aCmpsU
[i
];
222 while( nPos
< nLen
&& *pL
)
224 sal_Unicode c
= rString
[nPos
];
225 if( c
!= *pL
&& c
!= *pU
)
231 if( !*pL
&& (nPos
== nLen
|| ' ' == rString
[nPos
]) )
242 // TODO: check overflow
252 if( nVal
<= (double)nMin
)
254 else if( nVal
>= (double)nMax
)
257 rValue
= (sal_Int32
)nVal
;
262 /** convert measure in given unit to string with given unit */
263 void Converter::convertMeasure( OUStringBuffer
& rBuffer
,
265 sal_Int16 nSourceUnit
/* = MeasureUnit::MM_100TH */,
266 sal_Int16 nTargetUnit
/* = MeasureUnit::INCH */ )
268 if( nSourceUnit
== MeasureUnit::PERCENT
)
270 OSL_ENSURE( nTargetUnit
== MeasureUnit::PERCENT
,
271 "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
273 rBuffer
.append( nMeasure
);
274 rBuffer
.append( '%' );
278 // the sign is processed separately
281 nMeasure
= -nMeasure
;
282 rBuffer
.append( '-' );
285 // The new length is (nVal * nMul)/(nDiv*nFac*10)
289 const sal_Char
* psUnit
= 0;
290 switch( nSourceUnit
)
292 case MeasureUnit::TWIP
:
293 switch( nTargetUnit
)
295 case MeasureUnit::MM_100TH
:
296 case MeasureUnit::MM_10TH
:
297 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
,"output unit not supported for twip values" );
299 case MeasureUnit::MM
:
300 // 0.01mm = 0.57twip (exactly)
301 nMul
= 25400; // 25.4 * 1000
302 nDiv
= 1440; // 72 * 20;
307 case MeasureUnit::CM
:
308 // 0.001cm = 0.57twip (exactly)
309 nMul
= 25400; // 2.54 * 10000
310 nDiv
= 1440; // 72 * 20;
315 case MeasureUnit::POINT
:
316 // 0.01pt = 0.2twip (exactly)
323 case MeasureUnit::INCH
:
325 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
,
326 "output unit not supported for twip values" );
327 // 0.0001in = 0.144twip (exactly)
329 nDiv
= 1440; // 72 * 20;
336 case MeasureUnit::POINT
:
337 // 1pt = 1pt (exactly)
338 OSL_ENSURE( MeasureUnit::POINT
== nTargetUnit
,
339 "output unit not supported for pt values" );
345 case MeasureUnit::MM_10TH
:
346 case MeasureUnit::MM_100TH
:
348 long nFac2
= (MeasureUnit::MM_100TH
== nSourceUnit
) ? 100 : 10;
349 switch( nTargetUnit
)
351 case MeasureUnit::MM_100TH
:
352 case MeasureUnit::MM_10TH
:
353 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
,
354 "output unit not supported for 1/100mm values" );
356 case MeasureUnit::MM
:
357 // 0.01mm = 1 mm/100 (exactly)
364 case MeasureUnit::CM
:
365 // 0.001mm = 1 mm/100 (exactly)
367 nDiv
= 1; // 72 * 20;
372 case MeasureUnit::POINT
:
373 // 0.01pt = 0.35 mm/100 (exactly)
380 case MeasureUnit::INCH
:
382 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
,
383 "output unit not supported for 1/100mm values" );
384 // 0.0001in = 0.254 mm/100 (exactly)
394 OSL_ENSURE(false, "sax::Converter::convertMeasure(): "
395 "source unit not supported");
399 sal_Int64 nValue
= nMeasure
;
400 OSL_ENSURE(nValue
<= SAL_MAX_INT64
/ nMul
, "convertMeasure: overflow");
406 rBuffer
.append( static_cast<sal_Int64
>(nValue
/ nFac
) );
407 if (nFac
> 1 && (nValue
% nFac
) != 0)
409 rBuffer
.append( '.' );
410 while (nFac
> 1 && (nValue
% nFac
) != 0)
413 rBuffer
.append( static_cast<sal_Int32
>((nValue
/ nFac
) % 10) );
418 rBuffer
.appendAscii( psUnit
);
421 static OUString
getTrueString()
423 return OUString( "true" );
426 static OUString
getFalseString()
428 return OUString( "false" );
431 /** convert string to boolean */
432 bool Converter::convertBool( bool& rBool
, const OUString
& rString
)
434 rBool
= rString
== getTrueString();
436 return rBool
|| (rString
== getFalseString());
439 /** convert boolean to string */
440 void Converter::convertBool( OUStringBuffer
& rBuffer
, bool bValue
)
442 rBuffer
.append( bValue
? getTrueString() : getFalseString() );
445 /** convert string to percent */
446 bool Converter::convertPercent( sal_Int32
& rPercent
, const OUString
& rString
)
448 return convertMeasure( rPercent
, rString
, MeasureUnit::PERCENT
);
451 /** convert percent to string */
452 void Converter::convertPercent( OUStringBuffer
& rBuffer
, sal_Int32 nValue
)
454 rBuffer
.append( nValue
);
455 rBuffer
.append( '%' );
458 /** convert string to pixel measure */
459 bool Converter::convertMeasurePx( sal_Int32
& rPixel
, const OUString
& rString
)
461 return convertMeasure( rPixel
, rString
, MeasureUnit::PIXEL
);
464 /** convert pixel measure to string */
465 void Converter::convertMeasurePx( OUStringBuffer
& rBuffer
, sal_Int32 nValue
)
467 rBuffer
.append( nValue
);
468 rBuffer
.append( 'p' );
469 rBuffer
.append( 'x' );
472 int lcl_gethex( int nChar
)
474 if( nChar
>= '0' && nChar
<= '9' )
476 else if( nChar
>= 'a' && nChar
<= 'f' )
477 return nChar
- 'a' + 10;
478 else if( nChar
>= 'A' && nChar
<= 'F' )
479 return nChar
- 'A' + 10;
484 /** convert string to rgb color */
485 bool Converter::convertColor( sal_Int32
& rColor
, const OUString
& rValue
)
487 if( rValue
.getLength() != 7 || rValue
[0] != '#' )
490 rColor
= lcl_gethex( rValue
[1] ) * 16 + lcl_gethex( rValue
[2] );
493 rColor
|= ( lcl_gethex( rValue
[3] ) * 16 + lcl_gethex( rValue
[4] ) );
496 rColor
|= ( lcl_gethex( rValue
[5] ) * 16 + lcl_gethex( rValue
[6] ) );
501 static const sal_Char aHexTab
[] = "0123456789abcdef";
503 /** convert color to string */
504 void Converter::convertColor( OUStringBuffer
& rBuffer
, sal_Int32 nColor
)
506 rBuffer
.append( '#' );
508 sal_uInt8 nCol
= (sal_uInt8
)(nColor
>> 16);
509 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
>> 4 ] ) );
510 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
& 0xf ] ) );
512 nCol
= (sal_uInt8
)(nColor
>> 8);
513 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
>> 4 ] ) );
514 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
& 0xf ] ) );
516 nCol
= (sal_uInt8
)nColor
;
517 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
>> 4 ] ) );
518 rBuffer
.append( sal_Unicode( aHexTab
[ nCol
& 0xf ] ) );
521 /** convert number to string */
522 void Converter::convertNumber( OUStringBuffer
& rBuffer
, sal_Int32 nNumber
)
524 rBuffer
.append( nNumber
);
527 /** convert string to number with optional min and max values */
528 bool Converter::convertNumber( sal_Int32
& rValue
,
529 const OUString
& rString
,
530 sal_Int32 nMin
, sal_Int32 nMax
)
533 sal_Int64 nNumber
= 0;
534 bool bRet
= convertNumber64(nNumber
,rString
,nMin
,nMax
);
536 rValue
= static_cast<sal_Int32
>(nNumber
);
540 /** convert string to 64-bit number with optional min and max values */
541 bool Converter::convertNumber64( sal_Int64
& rValue
,
542 const OUString
& rString
,
543 sal_Int64 nMin
, sal_Int64 nMax
)
549 sal_Int32
const nLen
= rString
.getLength();
552 while( (nPos
< nLen
) && (rString
[nPos
] <= ' ') )
555 if( nPos
< nLen
&& '-' == rString
[nPos
] )
562 while( nPos
< nLen
&&
563 '0' <= rString
[nPos
] &&
564 '9' >= rString
[nPos
] )
566 // TODO: check overflow!
568 rValue
+= (rString
[nPos
] - sal_Unicode('0'));
577 else if( rValue
> nMax
)
580 return ( nPos
== nLen
&& rValue
>= nMin
&& rValue
<= nMax
);
583 /** convert double number to string (using ::rtl::math) */
584 void Converter::convertDouble( OUStringBuffer
& rBuffer
,
587 sal_Int16 nSourceUnit
,
588 sal_Int16 nTargetUnit
)
590 if(MeasureUnit::PERCENT
== nSourceUnit
)
592 OSL_ENSURE( nTargetUnit
== MeasureUnit::PERCENT
, "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
593 ::rtl::math::doubleToUStringBuffer( rBuffer
, fNumber
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
, '.', true);
599 OUStringBuffer sUnit
;
600 double fFactor
= GetConversionFactor(sUnit
, nSourceUnit
, nTargetUnit
);
603 ::rtl::math::doubleToUStringBuffer( rBuffer
, fNumber
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
, '.', true);
605 rBuffer
.append(sUnit
.makeStringAndClear());
609 /** convert double number to string (using ::rtl::math) */
610 void Converter::convertDouble( OUStringBuffer
& rBuffer
, double fNumber
)
612 ::rtl::math::doubleToUStringBuffer( rBuffer
, fNumber
, rtl_math_StringFormat_Automatic
, rtl_math_DecimalPlaces_Max
, '.', true);
615 /** convert string to double number (using ::rtl::math) */
616 bool Converter::convertDouble(double& rValue
,
617 const OUString
& rString
, sal_Int16 nSourceUnit
, sal_Int16 nTargetUnit
)
619 rtl_math_ConversionStatus eStatus
;
620 rValue
= ::rtl::math::stringToDouble( rString
, '.', ',', &eStatus
, NULL
);
622 if(eStatus
== rtl_math_ConversionStatus_Ok
)
624 OUStringBuffer sUnit
;
625 // fdo#48969: switch source and target because factor is used to divide!
626 double const fFactor
=
627 GetConversionFactor(sUnit
, nTargetUnit
, nSourceUnit
);
628 if(fFactor
!= 1.0 && fFactor
!= 0.0)
632 return ( eStatus
== rtl_math_ConversionStatus_Ok
);
635 /** convert string to double number (using ::rtl::math) */
636 bool Converter::convertDouble(double& rValue
, const OUString
& rString
)
638 rtl_math_ConversionStatus eStatus
;
639 rValue
= ::rtl::math::stringToDouble( rString
, '.', ',', &eStatus
, NULL
);
640 return ( eStatus
== rtl_math_ConversionStatus_Ok
);
643 /** convert number, 10th of degrees with range [0..3600] to SVG angle */
644 void Converter::convertAngle(OUStringBuffer
& rBuffer
, sal_Int16
const nAngle
)
647 // wrong, but backward compatible with OOo/LO < 4.4
648 ::sax::Converter::convertNumber(rBuffer
, nAngle
);
650 // maybe in the future... (see other convertAngle)
651 double fAngle(double(nAngle
) / 10.0);
652 ::sax::Converter::convertDouble(rBuffer
, fAngle
);
653 rBuffer
.append("deg");
657 /** convert SVG angle to number, 10th of degrees with range [0..3600] */
658 bool Converter::convertAngle(sal_Int16
& rAngle
, OUString
const& rString
)
660 // ODF 1.1 leaves it undefined what the number means, but ODF 1.2 says it's
661 // degrees, while OOo has historically used 10th of degrees :(
662 // So import degrees when we see the "deg" suffix but continue with 10th of
663 // degrees for now for the sake of existing OOo/LO documents, until the
664 // new versions that can read "deg" suffix are widely deployed and we can
665 // start to write the "deg" suffix.
668 bool bRet
= ::sax::Converter::convertDouble(fValue
, rString
);
669 if (-1 != rString
.indexOf("deg"))
671 nValue
= fValue
* 10.0;
673 else if (-1 != rString
.indexOf("grad"))
675 nValue
= (fValue
* 9.0 / 10.0) * 10.0;
677 else if (-1 != rString
.indexOf("rad"))
679 nValue
= (fValue
* 180.0 / M_PI
) * 10.0;
681 else // no explicit unit
683 nValue
= fValue
; // wrong, but backward compatible with OOo/LO < 4.4
685 // limit to valid range [0..3600]
686 nValue
= nValue
% 3600;
691 assert(0 <= nValue
&& nValue
<= 3600);
694 rAngle
= sal::static_int_cast
<sal_Int16
>(nValue
);
699 /** convert double to ISO "duration" string; negative durations allowed */
700 void Converter::convertDuration(OUStringBuffer
& rBuffer
,
703 double fValue
= fTime
;
705 // take care of negative durations as specified in:
706 // XML Schema, W3C Working Draft 07 April 2000, section 3.2.6.1
713 rBuffer
.append( "PT" );
715 double fHoursValue
= ::rtl::math::approxFloor (fValue
);
716 fValue
-= fHoursValue
;
718 double fMinsValue
= ::rtl::math::approxFloor (fValue
);
719 fValue
-= fMinsValue
;
721 double fSecsValue
= ::rtl::math::approxFloor (fValue
);
722 fValue
-= fSecsValue
;
723 double fNanoSecsValue
;
724 if (fValue
> 0.00000000001)
725 fNanoSecsValue
= ::rtl::math::round( fValue
, XML_MAXDIGITSCOUNT_TIME
- 5);
727 fNanoSecsValue
= 0.0;
729 if (fNanoSecsValue
== 1.0)
731 fNanoSecsValue
= 0.0;
734 if (fSecsValue
>= 60.0)
739 if (fMinsValue
>= 60.0)
745 if (fHoursValue
< 10)
746 rBuffer
.append( '0');
747 rBuffer
.append( sal_Int32( fHoursValue
));
748 rBuffer
.append( 'H');
750 rBuffer
.append( '0');
751 rBuffer
.append( sal_Int32( fMinsValue
));
752 rBuffer
.append( 'M');
754 rBuffer
.append( '0');
755 rBuffer
.append( sal_Int32( fSecsValue
));
756 if (fNanoSecsValue
> 0.0)
758 OUString
aNS( ::rtl::math::doubleToUString( fValue
,
759 rtl_math_StringFormat_F
, XML_MAXDIGITSCOUNT_TIME
- 5, '.',
761 if ( aNS
.getLength() > 2 )
763 rBuffer
.append( '.');
764 rBuffer
.append( aNS
.copy( 2 ) ); // strip "0."
767 rBuffer
.append( 'S');
770 /** convert ISO "duration" string to double; negative durations allowed */
771 bool Converter::convertDuration(double& rfTime
,
772 const OUString
& rString
)
774 OUString aTrimmed
= rString
.trim().toAsciiUpperCase();
775 const sal_Unicode
* pStr
= aTrimmed
.getStr();
777 // negative time duration?
778 bool bIsNegativeDuration
= false;
779 if ( '-' == (*pStr
) )
781 bIsNegativeDuration
= true;
785 if ( *(pStr
++) != 'P' ) // duration must start with "P"
789 bool bSuccess
= true;
791 bool bTimePart
= false;
792 bool bIsFraction
= false;
794 sal_Int32 nHours
= 0;
799 while ( bSuccess
&& !bDone
)
801 sal_Unicode c
= *(pStr
++);
804 else if ( '0' <= c
&& '9' >= c
)
806 if ( nTemp
>= SAL_MAX_INT32
/ 10 )
813 nTemp
+= (c
- sal_Unicode('0'));
817 sDoubleStr
+= OUString(c
);
821 else if ( bTimePart
)
833 else if ( (c
== ',') || (c
== '.') )
850 bSuccess
= false; // invalid character
854 if ( c
== 'T' ) // "T" starts time part
861 else if ( c
== 'Y' || c
== 'M' )
863 //! how many days is a year or month?
865 OSL_FAIL( "years or months in duration: not implemented");
869 bSuccess
= false; // invalid character
876 nHours
+= nDays
* 24; // add the days to the hours part
877 double fTempTime
= 0.0;
878 double fHour
= nHours
;
881 double fFraction
= sDoubleStr
.toDouble();
882 fTempTime
= fHour
/ 24;
883 fTempTime
+= fMin
/ (24 * 60);
884 fTempTime
+= fSec
/ (24 * 60 * 60);
885 fTempTime
+= fFraction
/ (24 * 60 * 60);
887 // negative duration?
888 if ( bIsNegativeDuration
)
890 fTempTime
= -fTempTime
;
898 /** convert util::Duration to ISO8601 "duration" string */
899 void Converter::convertDuration(OUStringBuffer
& rBuffer
,
900 const ::util::Duration
& rDuration
)
902 if (rDuration
.Negative
)
907 const bool bHaveDate(rDuration
.Years
!= 0 ||
908 rDuration
.Months
!= 0 ||
909 rDuration
.Days
!= 0);
912 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Years
));
915 if (rDuration
.Months
)
917 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Months
));
922 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Days
));
925 if ( rDuration
.Hours
!= 0
926 || rDuration
.Minutes
!= 0
927 || rDuration
.Seconds
!= 0
928 || rDuration
.NanoSeconds
!= 0 )
930 rBuffer
.append('T'); // time separator
933 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Hours
));
936 if (rDuration
.Minutes
)
938 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Minutes
));
941 if (rDuration
.Seconds
!= 0 || rDuration
.NanoSeconds
!= 0)
943 // seconds must not be omitted (i.e. ".42S" is not valid)
944 rBuffer
.append(static_cast<sal_Int32
>(rDuration
.Seconds
));
945 if (rDuration
.NanoSeconds
)
947 OSL_ENSURE(rDuration
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
949 std::ostringstream ostr
;
952 ostr
<< rDuration
.NanoSeconds
;
953 rBuffer
.append(OUString::createFromAscii(ostr
.str().c_str()));
960 // zero duration: XMLSchema-2 says there must be at least one component
966 enum Result
{ R_NOTHING
, R_OVERFLOW
, R_SUCCESS
};
969 readUnsignedNumber(const OUString
& rString
,
970 sal_Int32
& io_rnPos
, sal_Int32
& o_rNumber
)
972 bool bOverflow(false);
974 sal_Int32
nPos(io_rnPos
);
976 while (nPos
< rString
.getLength())
978 const sal_Unicode c
= rString
[nPos
];
979 if (('0' <= c
) && (c
<= '9'))
982 nTemp
+= (c
- sal_Unicode('0'));
983 if (nTemp
>= SAL_MAX_INT32
)
995 if (io_rnPos
== nPos
) // read something?
1003 return (bOverflow
) ? R_OVERFLOW
: R_SUCCESS
;
1007 readUnsignedNumberMaxDigits(int maxDigits
,
1008 const ::rtl::OUString
& rString
, sal_Int32
& io_rnPos
,
1009 sal_Int32
& o_rNumber
)
1011 bool bOverflow(false);
1013 sal_Int32
nPos(io_rnPos
);
1014 OSL_ENSURE(maxDigits
>= 0, "negative amount of digits makes no sense");
1016 while (nPos
< rString
.getLength())
1018 const sal_Unicode c
= rString
[nPos
];
1019 if (('0' <= c
) && (c
<= '9'))
1024 nTemp
+= (c
- sal_Unicode('0'));
1025 if (nTemp
>= SAL_MAX_INT32
)
1039 if (io_rnPos
== nPos
) // read something?
1047 return (bOverflow
) ? R_OVERFLOW
: R_SUCCESS
;
1051 readDurationT(const OUString
& rString
, sal_Int32
& io_rnPos
)
1053 if ((io_rnPos
< rString
.getLength()) &&
1054 (rString
[io_rnPos
] == 'T'))
1063 readDurationComponent(const OUString
& rString
,
1064 sal_Int32
& io_rnPos
, sal_Int32
& io_rnTemp
, bool & io_rbTimePart
,
1065 sal_Int32
& o_rnTarget
, const sal_Unicode c
)
1067 if ((io_rnPos
< rString
.getLength()))
1069 if (c
== rString
[io_rnPos
])
1072 if (-1 != io_rnTemp
)
1074 o_rnTarget
= io_rnTemp
;
1078 io_rbTimePart
= readDurationT(rString
, io_rnPos
);
1080 return (R_OVERFLOW
!=
1081 readUnsignedNumber(rString
, io_rnPos
, io_rnTemp
));
1092 /** convert ISO8601 "duration" string to util::Duration */
1093 bool Converter::convertDuration(util::Duration
& rDuration
,
1094 const OUString
& rString
)
1096 const OUString string
= rString
.trim().toAsciiUpperCase();
1099 bool bIsNegativeDuration(false);
1100 if (!string
.isEmpty() && ('-' == string
[0]))
1102 bIsNegativeDuration
= true;
1106 if ((nPos
< string
.getLength())
1107 && (string
[nPos
] != 'P')) // duration must start with "P"
1114 /// last read number; -1 == no valid number! always reset after using!
1115 sal_Int32
nTemp(-1);
1116 bool bTimePart(false); // have we read 'T'?
1117 bool bSuccess(false);
1118 sal_Int32
nYears(0);
1119 sal_Int32
nMonths(0);
1121 sal_Int32
nHours(0);
1122 sal_Int32
nMinutes(0);
1123 sal_Int32
nSeconds(0);
1124 sal_Int32
nNanoSeconds(0);
1126 bTimePart
= readDurationT(string
, nPos
);
1127 bSuccess
= (R_SUCCESS
== readUnsignedNumber(string
, nPos
, nTemp
));
1129 if (!bTimePart
&& bSuccess
)
1131 bSuccess
= readDurationComponent(string
, nPos
, nTemp
, bTimePart
,
1135 if (!bTimePart
&& bSuccess
)
1137 bSuccess
= readDurationComponent(string
, nPos
, nTemp
, bTimePart
,
1141 if (!bTimePart
&& bSuccess
)
1143 bSuccess
= readDurationComponent(string
, nPos
, nTemp
, bTimePart
,
1149 if (-1 == nTemp
) // a 'T' must be followed by a component
1156 bSuccess
= readDurationComponent(string
, nPos
, nTemp
, bTimePart
,
1162 bSuccess
= readDurationComponent(string
, nPos
, nTemp
, bTimePart
,
1166 // eeek! seconds are icky.
1167 if ((nPos
< string
.getLength()) && bSuccess
)
1169 if (string
[nPos
] == '.' ||
1170 string
[nPos
] == ',')
1177 const sal_Int32
nStart(nPos
);
1178 bSuccess
= readUnsignedNumberMaxDigits(9, string
, nPos
, nTemp
) == R_SUCCESS
;
1179 if ((nPos
< string
.getLength()) && bSuccess
)
1183 nNanoSeconds
= nTemp
;
1184 sal_Int32 nDigits
= nPos
- nStart
;
1185 assert(nDigits
>= 0);
1186 for (; nDigits
< 9; ++nDigits
)
1191 if ('S' == string
[nPos
])
1211 else if ('S' == string
[nPos
])
1227 if (nPos
!= string
.getLength()) // string not processed completely?
1232 if (nTemp
!= -1) // unprocessed number?
1239 rDuration
.Negative
= bIsNegativeDuration
;
1240 rDuration
.Years
= static_cast<sal_Int16
>(nYears
);
1241 rDuration
.Months
= static_cast<sal_Int16
>(nMonths
);
1242 rDuration
.Days
= static_cast<sal_Int16
>(nDays
);
1243 rDuration
.Hours
= static_cast<sal_Int16
>(nHours
);
1244 rDuration
.Minutes
= static_cast<sal_Int16
>(nMinutes
);
1245 rDuration
.Seconds
= static_cast<sal_Int16
>(nSeconds
);
1246 rDuration
.NanoSeconds
= static_cast<sal_Int32
>(nNanoSeconds
);
1254 lcl_AppendTimezone(OUStringBuffer
& i_rBuffer
, sal_Int16
const nOffset
)
1258 i_rBuffer
.append('Z');
1264 i_rBuffer
.append('+');
1268 i_rBuffer
.append('-');
1270 const sal_Int32
nHours (abs(nOffset
) / 60);
1271 const sal_Int32
nMinutes(abs(nOffset
) % 60);
1272 SAL_WARN_IF(nHours
> 14 || (nHours
== 14 && nMinutes
> 0),
1273 "sax", "convertDateTime: timezone overflow");
1276 i_rBuffer
.append('0');
1278 i_rBuffer
.append(nHours
);
1279 i_rBuffer
.append(':');
1282 i_rBuffer
.append('0');
1284 i_rBuffer
.append(nMinutes
);
1288 /** convert util::Date to ISO "date" string */
1289 void Converter::convertDate(
1290 OUStringBuffer
& i_rBuffer
,
1291 const util::Date
& i_rDate
,
1292 sal_Int16
const*const pTimeZoneOffset
)
1294 const util::DateTime
dt(0, 0, 0, 0,
1295 i_rDate
.Day
, i_rDate
.Month
, i_rDate
.Year
, false);
1296 convertDateTime(i_rBuffer
, dt
, pTimeZoneOffset
, false);
1299 static void convertTime(
1300 OUStringBuffer
& i_rBuffer
,
1301 const com::sun::star::util::DateTime
& i_rDateTime
)
1303 if (i_rDateTime
.Hours
< 10) {
1304 i_rBuffer
.append('0');
1306 i_rBuffer
.append( static_cast<sal_Int32
>(i_rDateTime
.Hours
) )
1308 if (i_rDateTime
.Minutes
< 10) {
1309 i_rBuffer
.append('0');
1311 i_rBuffer
.append( static_cast<sal_Int32
>(i_rDateTime
.Minutes
) )
1313 if (i_rDateTime
.Seconds
< 10) {
1314 i_rBuffer
.append('0');
1316 i_rBuffer
.append( static_cast<sal_Int32
>(i_rDateTime
.Seconds
) );
1317 if (i_rDateTime
.NanoSeconds
> 0) {
1318 OSL_ENSURE(i_rDateTime
.NanoSeconds
< 1000000000,"NanoSeconds cannot be more than 999 999 999");
1319 i_rBuffer
.append('.');
1320 std::ostringstream ostr
;
1323 ostr
<< i_rDateTime
.NanoSeconds
;
1324 i_rBuffer
.append(OUString::createFromAscii(ostr
.str().c_str()));
1328 static void convertTimeZone(
1329 OUStringBuffer
& i_rBuffer
,
1330 const com::sun::star::util::DateTime
& i_rDateTime
,
1331 sal_Int16
const* pTimeZoneOffset
)
1333 if (pTimeZoneOffset
)
1335 lcl_AppendTimezone(i_rBuffer
, *pTimeZoneOffset
);
1337 else if (i_rDateTime
.IsUTC
)
1339 lcl_AppendTimezone(i_rBuffer
, 0);
1343 /** convert util::DateTime to ISO "time" or "dateTime" string */
1344 void Converter::convertTimeOrDateTime(
1345 OUStringBuffer
& i_rBuffer
,
1346 const com::sun::star::util::DateTime
& i_rDateTime
,
1347 sal_Int16
const* pTimeZoneOffset
)
1349 if (i_rDateTime
.Year
== 0 ||
1350 i_rDateTime
.Month
< 1 || i_rDateTime
.Month
> 12 ||
1351 i_rDateTime
.Day
< 1 || i_rDateTime
.Day
> 31)
1353 convertTime(i_rBuffer
, i_rDateTime
);
1354 convertTimeZone(i_rBuffer
, i_rDateTime
, pTimeZoneOffset
);
1358 convertDateTime(i_rBuffer
, i_rDateTime
, pTimeZoneOffset
, true);
1362 /** convert util::DateTime to ISO "date" or "dateTime" string */
1363 void Converter::convertDateTime(
1364 OUStringBuffer
& i_rBuffer
,
1365 const com::sun::star::util::DateTime
& i_rDateTime
,
1366 sal_Int16
const*const pTimeZoneOffset
,
1367 bool i_bAddTimeIf0AM
)
1369 const sal_Unicode
dash('-');
1370 const sal_Unicode
zero('0');
1372 sal_Int32
const nYear(abs(i_rDateTime
.Year
));
1373 if (i_rDateTime
.Year
< 0) {
1374 i_rBuffer
.append(dash
); // negative
1377 i_rBuffer
.append(zero
);
1380 i_rBuffer
.append(zero
);
1383 i_rBuffer
.append(zero
);
1385 i_rBuffer
.append(nYear
).append(dash
);
1386 if( i_rDateTime
.Month
< 10 ) {
1387 i_rBuffer
.append(zero
);
1389 i_rBuffer
.append( static_cast<sal_Int32
>(i_rDateTime
.Month
) ).append(dash
);
1390 if( i_rDateTime
.Day
< 10 ) {
1391 i_rBuffer
.append(zero
);
1393 i_rBuffer
.append( static_cast<sal_Int32
>(i_rDateTime
.Day
) );
1395 if( i_rDateTime
.Seconds
!= 0 ||
1396 i_rDateTime
.Minutes
!= 0 ||
1397 i_rDateTime
.Hours
!= 0 ||
1400 i_rBuffer
.append('T');
1401 convertTime(i_rBuffer
, i_rDateTime
);
1404 convertTimeZone(i_rBuffer
, i_rDateTime
, pTimeZoneOffset
);
1407 /** convert ISO "date" or "dateTime" string to util::DateTime */
1408 bool Converter::parseDateTime( util::DateTime
& rDateTime
,
1409 boost::optional
<sal_Int16
> *const pTimeZoneOffset
,
1410 const OUString
& rString
)
1413 return parseDateOrDateTime(0, rDateTime
, isDateTime
, pTimeZoneOffset
,
1417 static bool lcl_isLeapYear(const sal_uInt32 nYear
)
1419 return ((nYear
% 4) == 0)
1420 && (((nYear
% 100) != 0) || ((nYear
% 400) == 0));
1424 lcl_MaxDaysPerMonth(const sal_Int32 nMonth
, const sal_Int32 nYear
)
1426 static const sal_uInt16 s_MaxDaysPerMonth
[12] =
1427 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1428 assert(0 < nMonth
&& nMonth
<= 12);
1429 if ((2 == nMonth
) && lcl_isLeapYear(nYear
))
1433 return s_MaxDaysPerMonth
[nMonth
- 1];
1436 static void lcl_ConvertToUTC(
1437 sal_Int16
& o_rYear
, sal_uInt16
& o_rMonth
, sal_uInt16
& o_rDay
,
1438 sal_uInt16
& o_rHours
, sal_uInt16
& o_rMinutes
,
1439 sal_Int16
const nSourceOffset
)
1441 sal_Int16
nOffsetHours(abs(nSourceOffset
) / 60);
1442 sal_Int16
const nOffsetMinutes(abs(nSourceOffset
) % 60);
1443 o_rMinutes
+= nOffsetMinutes
;
1444 if (nSourceOffset
< 0)
1446 o_rMinutes
+= nOffsetMinutes
;
1447 if (60 <= o_rMinutes
)
1452 o_rHours
+= nOffsetHours
;
1457 sal_Int16
nDayAdd(0);
1458 while (24 <= o_rHours
)
1465 return; // handle time without date - don't adjust what isn't there
1468 sal_Int16
const nDaysInMonth(lcl_MaxDaysPerMonth(o_rMonth
, o_rYear
));
1469 if (o_rDay
<= nDaysInMonth
)
1473 o_rDay
-= nDaysInMonth
;
1480 ++o_rYear
; // works for negative year too
1482 else if (0 < nSourceOffset
)
1484 // argh everything is unsigned
1485 if (o_rMinutes
< nOffsetMinutes
)
1490 o_rMinutes
-= nOffsetMinutes
;
1491 sal_Int16
nDaySubtract(0);
1492 while (o_rHours
< nOffsetHours
)
1497 o_rHours
-= nOffsetHours
;
1500 return; // handle time without date - don't adjust what isn't there
1502 if (nDaySubtract
< o_rDay
)
1504 o_rDay
-= nDaySubtract
;
1507 sal_Int16
const nPrevMonth((o_rMonth
== 1) ? 12 : o_rMonth
- 1);
1508 sal_Int16
const nDaysInMonth(lcl_MaxDaysPerMonth(nPrevMonth
, o_rYear
));
1509 o_rDay
+= nDaysInMonth
;
1514 --o_rYear
; // works for negative year too
1516 o_rDay
-= nDaySubtract
;
1521 readDateTimeComponent(const OUString
& rString
,
1522 sal_Int32
& io_rnPos
, sal_Int32
& o_rnTarget
,
1523 const sal_Int32 nMinLength
, const bool bExactLength
)
1525 const sal_Int32
nOldPos(io_rnPos
);
1527 if (R_SUCCESS
!= readUnsignedNumber(rString
, io_rnPos
, nTemp
))
1531 const sal_Int32
nTokenLength(io_rnPos
- nOldPos
);
1532 if ((nTokenLength
< nMinLength
) ||
1533 (bExactLength
&& (nTokenLength
> nMinLength
)))
1535 return false; // bad length
1541 /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
1542 static bool lcl_parseDate(
1544 sal_Int32
& nYear
, sal_Int32
& nMonth
, sal_Int32
& nDay
,
1547 const OUString
& string
,
1548 bool const bIgnoreInvalidOrMissingDate
)
1550 bool bSuccess
= true;
1552 if (string
.getLength() > nPos
)
1554 if ('-' == string
[nPos
])
1562 // While W3C XMLSchema specifies years with a minimum of 4 digits, be
1563 // leninent in what we accept for years < 1000. One digit is acceptable
1564 // if the remainders match.
1565 bSuccess
= readDateTimeComponent(string
, nPos
, nYear
, 1, false);
1566 if (!bIgnoreInvalidOrMissingDate
)
1568 bSuccess
&= (0 < nYear
);
1570 bSuccess
&= (nPos
< string
.getLength()); // not last token
1572 if (bSuccess
&& ('-' != string
[nPos
])) // separator
1583 bSuccess
= readDateTimeComponent(string
, nPos
, nMonth
, 2, true);
1584 if (!bIgnoreInvalidOrMissingDate
)
1586 bSuccess
&= (0 < nMonth
);
1588 bSuccess
&= (nMonth
<= 12);
1589 bSuccess
&= (nPos
< string
.getLength()); // not last token
1591 if (bSuccess
&& ('-' != string
[nPos
])) // separator
1602 bSuccess
= readDateTimeComponent(string
, nPos
, nDay
, 2, true);
1603 if (!bIgnoreInvalidOrMissingDate
)
1605 bSuccess
&= (0 < nDay
);
1607 if (nMonth
> 0) // not possible to check if month was missing
1609 bSuccess
&= (nDay
<= lcl_MaxDaysPerMonth(nMonth
, nYear
));
1611 else assert(bIgnoreInvalidOrMissingDate
);
1614 if (bSuccess
&& (nPos
< string
.getLength()))
1616 if ('T' == string
[nPos
]) // time separator
1626 /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
1627 static bool lcl_parseDateTime(
1628 util::Date
*const pDate
, util::DateTime
& rDateTime
,
1630 boost::optional
<sal_Int16
> *const pTimeZoneOffset
,
1631 const OUString
& rString
,
1632 bool const bIgnoreInvalidOrMissingDate
)
1634 bool bSuccess
= true;
1636 const OUString string
= rString
.trim().toAsciiUpperCase();
1638 bool isNegative(false);
1640 sal_Int32
nMonth(0);
1643 bool bHaveTime(false);
1645 if ( !bIgnoreInvalidOrMissingDate
1646 || string
.indexOf(':') == -1 // no time?
1647 || (string
.indexOf('-') != -1
1648 && string
.indexOf('-') < string
.indexOf(':')))
1650 bSuccess
&= lcl_parseDate(isNegative
, nYear
, nMonth
, nDay
,
1651 bHaveTime
, nPos
, string
, bIgnoreInvalidOrMissingDate
);
1658 sal_Int32
nHours(0);
1659 sal_Int32
nMinutes(0);
1660 sal_Int32
nSeconds(0);
1661 sal_Int32
nNanoSeconds(0);
1662 if (bSuccess
&& bHaveTime
)
1665 bSuccess
= readDateTimeComponent(string
, nPos
, nHours
, 2, true);
1666 bSuccess
&= (0 <= nHours
) && (nHours
<= 24);
1667 bSuccess
&= (nPos
< string
.getLength()); // not last token
1669 if (bSuccess
&& (':' != string
[nPos
])) // separator
1680 bSuccess
= readDateTimeComponent(string
, nPos
, nMinutes
, 2, true);
1681 bSuccess
&= (0 <= nMinutes
) && (nMinutes
< 60);
1682 bSuccess
&= (nPos
< string
.getLength()); // not last token
1684 if (bSuccess
&& (':' != string
[nPos
])) // separator
1695 bSuccess
= readDateTimeComponent(string
, nPos
, nSeconds
, 2, true);
1696 bSuccess
&= (0 <= nSeconds
) && (nSeconds
< 60);
1698 if (bSuccess
&& (nPos
< string
.getLength()) &&
1699 ('.' == string
[nPos
] || ',' == string
[nPos
])) // fraction separator
1702 const sal_Int32
nStart(nPos
);
1704 if (R_NOTHING
== readUnsignedNumberMaxDigits(9, string
, nPos
, nTemp
))
1710 sal_Int32 nDigits
= std::min
<sal_Int32
>(nPos
- nStart
, 9);
1711 assert(nDigits
> 0);
1712 for (; nDigits
< 9; ++nDigits
)
1716 nNanoSeconds
= nTemp
;
1720 if (bSuccess
&& (nHours
== 24))
1722 if (!((0 == nMinutes
) && (0 == nSeconds
) && (0 == nNanoSeconds
)))
1724 bSuccess
= false; // only 24:00:00 is valid
1729 bool bHaveTimezone(false);
1730 bool bHaveTimezonePlus(false);
1731 bool bHaveTimezoneMinus(false);
1732 if (bSuccess
&& (nPos
< string
.getLength()))
1734 const sal_Unicode
c(string
[nPos
]);
1737 bHaveTimezone
= true;
1738 bHaveTimezonePlus
= true;
1743 bHaveTimezone
= true;
1744 bHaveTimezoneMinus
= true;
1749 bHaveTimezone
= true;
1757 sal_Int32
nTimezoneHours(0);
1758 sal_Int32
nTimezoneMinutes(0);
1759 if (bSuccess
&& (bHaveTimezonePlus
|| bHaveTimezoneMinus
))
1761 bSuccess
= readDateTimeComponent(
1762 string
, nPos
, nTimezoneHours
, 2, true);
1763 bSuccess
&= (0 <= nTimezoneHours
) && (nTimezoneHours
<= 14);
1764 bSuccess
&= (nPos
< string
.getLength()); // not last token
1765 if (bSuccess
&& (':' != string
[nPos
])) // separator
1775 bSuccess
= readDateTimeComponent(
1776 string
, nPos
, nTimezoneMinutes
, 2, true);
1777 bSuccess
&= (0 <= nTimezoneMinutes
) && (nTimezoneMinutes
< 60);
1779 if (bSuccess
&& (nTimezoneHours
== 14))
1781 if (0 != nTimezoneMinutes
)
1783 bSuccess
= false; // only +-14:00 is valid
1788 bSuccess
&= (nPos
== string
.getLength()); // trailing junk?
1792 sal_Int16
const nTimezoneOffset
= ((bHaveTimezoneMinus
) ? (-1) : (+1))
1793 * ((nTimezoneHours
* 60) + nTimezoneMinutes
);
1794 if (!pDate
|| bHaveTime
) // time is optional
1797 ((isNegative
) ? (-1) : (+1)) * static_cast<sal_Int16
>(nYear
);
1798 rDateTime
.Month
= static_cast<sal_uInt16
>(nMonth
);
1799 rDateTime
.Day
= static_cast<sal_uInt16
>(nDay
);
1800 rDateTime
.Hours
= static_cast<sal_uInt16
>(nHours
);
1801 rDateTime
.Minutes
= static_cast<sal_uInt16
>(nMinutes
);
1802 rDateTime
.Seconds
= static_cast<sal_uInt16
>(nSeconds
);
1803 rDateTime
.NanoSeconds
= static_cast<sal_uInt32
>(nNanoSeconds
);
1806 if (pTimeZoneOffset
)
1808 *pTimeZoneOffset
= nTimezoneOffset
;
1809 rDateTime
.IsUTC
= (0 == nTimezoneOffset
);
1813 lcl_ConvertToUTC(rDateTime
.Year
, rDateTime
.Month
,
1814 rDateTime
.Day
, rDateTime
.Hours
, rDateTime
.Minutes
,
1816 rDateTime
.IsUTC
= true;
1821 if (pTimeZoneOffset
)
1823 pTimeZoneOffset
->reset();
1825 rDateTime
.IsUTC
= false;
1827 rbDateTime
= bHaveTime
;
1832 ((isNegative
) ? (-1) : (+1)) * static_cast<sal_Int16
>(nYear
);
1833 pDate
->Month
= static_cast<sal_uInt16
>(nMonth
);
1834 pDate
->Day
= static_cast<sal_uInt16
>(nDay
);
1837 if (pTimeZoneOffset
)
1839 *pTimeZoneOffset
= nTimezoneOffset
;
1843 // a Date cannot be adjusted
1844 SAL_INFO("sax", "dropping timezone");
1849 if (pTimeZoneOffset
)
1851 pTimeZoneOffset
->reset();
1860 /** convert ISO "time" or "dateTime" string to util::DateTime */
1861 bool Converter::parseTimeOrDateTime(
1862 util::DateTime
& rDateTime
,
1863 boost::optional
<sal_Int16
> * pTimeZoneOffset
,
1864 const OUString
& rString
)
1867 return lcl_parseDateTime(
1868 0, rDateTime
, dummy
, pTimeZoneOffset
, rString
, true);
1871 /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
1872 bool Converter::parseDateOrDateTime(
1873 util::Date
*const pDate
, util::DateTime
& rDateTime
,
1875 boost::optional
<sal_Int16
> *const pTimeZoneOffset
,
1876 const OUString
& rString
)
1878 return lcl_parseDateTime(
1879 pDate
, rDateTime
, rbDateTime
, pTimeZoneOffset
, rString
, false);
1883 /** gets the position of the first comma after npos in the string
1884 rStr. Commas inside '"' pairs are not matched */
1885 sal_Int32
Converter::indexOfComma( const OUString
& rStr
,
1888 sal_Unicode cQuote
= 0;
1889 sal_Int32 nLen
= rStr
.getLength();
1890 for( ; nPos
< nLen
; nPos
++ )
1892 sal_Unicode c
= rStr
[nPos
];
1895 case sal_Unicode('\''):
1898 else if( '\'' == cQuote
)
1902 case sal_Unicode('"'):
1905 else if( '\"' == cQuote
)
1909 case sal_Unicode(','):
1920 sal_Char aBase64EncodeTable
[] =
1921 { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
1922 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
1923 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
1924 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
1925 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
1928 sal_uInt8 aBase64DecodeTable
[] =
1929 { 62,255,255,255, 63, // 43-47
1932 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255, // 48-63
1933 // 0 1 2 3 4 5 6 7 8 9 =
1935 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64-79
1936 // A B C D E F G H I J K L M N O
1938 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 80-95
1939 // P Q R S T U V W X Y Z
1941 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
1942 // a b c d e f g h i j k l m n o
1944 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; // 112-123
1945 // p q r s t u v w x y z
1949 void ThreeByteToFourByte (const sal_Int8
* pBuffer
, const sal_Int32 nStart
, const sal_Int32 nFullLen
, OUStringBuffer
& sBuffer
)
1951 sal_Int32
nLen(nFullLen
- nStart
);
1964 nBinaer
= ((sal_uInt8
)pBuffer
[nStart
+ 0]) << 16;
1969 nBinaer
= (((sal_uInt8
)pBuffer
[nStart
+ 0]) << 16) +
1970 (((sal_uInt8
)pBuffer
[nStart
+ 1]) << 8);
1975 nBinaer
= (((sal_uInt8
)pBuffer
[nStart
+ 0]) << 16) +
1976 (((sal_uInt8
)pBuffer
[nStart
+ 1]) << 8) +
1977 ((sal_uInt8
)pBuffer
[nStart
+ 2]);
1982 sal_Unicode buf
[] = { '=', '=', '=', '=' };
1984 sal_uInt8
nIndex (static_cast<sal_uInt8
>((nBinaer
& 0xFC0000) >> 18));
1985 buf
[0] = aBase64EncodeTable
[nIndex
];
1987 nIndex
= static_cast<sal_uInt8
>((nBinaer
& 0x3F000) >> 12);
1988 buf
[1] = aBase64EncodeTable
[nIndex
];
1991 nIndex
= static_cast<sal_uInt8
>((nBinaer
& 0xFC0) >> 6);
1992 buf
[2] = aBase64EncodeTable
[nIndex
];
1995 nIndex
= static_cast<sal_uInt8
>((nBinaer
& 0x3F));
1996 buf
[3] = aBase64EncodeTable
[nIndex
];
1999 sBuffer
.append(buf
, SAL_N_ELEMENTS(buf
));
2002 void Converter::encodeBase64(OUStringBuffer
& aStrBuffer
, const uno::Sequence
<sal_Int8
>& aPass
)
2005 sal_Int32
nBufferLength(aPass
.getLength());
2006 const sal_Int8
* pBuffer
= aPass
.getConstArray();
2007 while (i
< nBufferLength
)
2009 ThreeByteToFourByte (pBuffer
, i
, nBufferLength
, aStrBuffer
);
2014 void Converter::decodeBase64(uno::Sequence
<sal_Int8
>& aBuffer
, const OUString
& sBuffer
)
2016 #if OSL_DEBUG_LEVEL > 0
2017 sal_Int32 nCharsDecoded
=
2019 decodeBase64SomeChars( aBuffer
, sBuffer
);
2020 OSL_ENSURE( nCharsDecoded
== sBuffer
.getLength(), "some bytes left in base64 decoding!" );
2023 sal_Int32
Converter::decodeBase64SomeChars(
2024 uno::Sequence
<sal_Int8
>& rOutBuffer
,
2025 const OUString
& rInBuffer
)
2027 sal_Int32 nInBufferLen
= rInBuffer
.getLength();
2028 sal_Int32 nMinOutBufferLen
= (nInBufferLen
/ 4) * 3;
2029 if( rOutBuffer
.getLength() < nMinOutBufferLen
)
2030 rOutBuffer
.realloc( nMinOutBufferLen
);
2032 const sal_Unicode
*pInBuffer
= rInBuffer
.getStr();
2033 sal_Int8
*pOutBuffer
= rOutBuffer
.getArray();
2034 sal_Int8
*pOutBufferStart
= pOutBuffer
;
2035 sal_Int32 nCharsDecoded
= 0;
2037 sal_uInt8 aDecodeBuffer
[4];
2038 sal_Int32 nBytesToDecode
= 0;
2039 sal_Int32 nBytesGotFromDecoding
= 3;
2040 sal_Int32 nInBufferPos
= 0;
2041 while( nInBufferPos
< nInBufferLen
)
2043 sal_Unicode cChar
= *pInBuffer
;
2044 if( cChar
>= '+' && cChar
<= 'z' )
2046 sal_uInt8 nByte
= aBase64DecodeTable
[cChar
-'+'];
2049 // We have found a valid character!
2050 aDecodeBuffer
[nBytesToDecode
++] = nByte
;
2052 // One '=' character at the end means 2 out bytes
2053 // Two '=' characters at the end mean 1 out bytes
2054 if( '=' == cChar
&& nBytesToDecode
> 2 )
2055 nBytesGotFromDecoding
--;
2056 if( 4 == nBytesToDecode
)
2058 // Four characters found, so we may convert now!
2059 sal_uInt32 nOut
= (aDecodeBuffer
[0] << 18) +
2060 (aDecodeBuffer
[1] << 12) +
2061 (aDecodeBuffer
[2] << 6) +
2064 *pOutBuffer
++ = (sal_Int8
)((nOut
& 0xff0000) >> 16);
2065 if( nBytesGotFromDecoding
> 1 )
2066 *pOutBuffer
++ = (sal_Int8
)((nOut
& 0xff00) >> 8);
2067 if( nBytesGotFromDecoding
> 2 )
2068 *pOutBuffer
++ = (sal_Int8
)(nOut
& 0xff);
2069 nCharsDecoded
= nInBufferPos
+ 1;
2071 nBytesGotFromDecoding
= 3;
2087 if( (pOutBuffer
- pOutBufferStart
) != rOutBuffer
.getLength() )
2088 rOutBuffer
.realloc( pOutBuffer
- pOutBufferStart
);
2090 return nCharsDecoded
;
2093 double Converter::GetConversionFactor(OUStringBuffer
& rUnit
, sal_Int16 nSourceUnit
, sal_Int16 nTargetUnit
)
2095 double fRetval(1.0);
2096 rUnit
.setLength(0L);
2098 const sal_Char
* psUnit
= 0;
2100 if(nSourceUnit
!= nTargetUnit
)
2104 case MeasureUnit::TWIP
:
2108 case MeasureUnit::MM_100TH
:
2110 // 0.01mm = 0.57twip (exactly)
2111 fRetval
= ((25400.0 / 1440.0) / 10.0);
2114 case MeasureUnit::MM_10TH
:
2116 // 0.01mm = 0.57twip (exactly)
2117 fRetval
= ((25400.0 / 1440.0) / 100.0);
2120 case MeasureUnit::MM
:
2122 // 0.01mm = 0.57twip (exactly)
2123 fRetval
= ((25400.0 / 1440.0) / 1000.0);
2127 case MeasureUnit::CM
:
2129 // 0.001cm = 0.57twip (exactly)
2130 fRetval
= ((25400.0 / 1440.0) / 10000.0);
2134 case MeasureUnit::POINT
:
2136 // 0.01pt = 0.2twip (exactly)
2137 fRetval
= ((1000.0 / 20.0) / 1000.0);
2141 case MeasureUnit::INCH
:
2144 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for twip values");
2145 // 0.0001in = 0.144twip (exactly)
2146 fRetval
= ((100000.0 / 1440.0) / 100000.0);
2153 case MeasureUnit::POINT
:
2157 case MeasureUnit::MM_100TH
:
2159 // 1mm = 72 / 25.4 pt (exactly)
2160 fRetval
= ( 2540.0 / 72.0 );
2163 case MeasureUnit::MM_10TH
:
2165 // 1mm = 72 / 25.4 pt (exactly)
2166 fRetval
= ( 254.0 / 72.0 );
2169 case MeasureUnit::MM
:
2171 // 1mm = 72 / 25.4 pt (exactly)
2172 fRetval
= ( 25.4 / 72.0 );
2177 case MeasureUnit::CM
:
2179 // 1cm = 72 / 2.54 pt (exactly)
2180 fRetval
= ( 2.54 / 72.0 );
2184 case MeasureUnit::TWIP
:
2186 // 1twip = 72 / 1440 pt (exactly)
2187 fRetval
= 20.0; // 1440.0 / 72.0
2191 case MeasureUnit::INCH
:
2194 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for pt values");
2195 // 1in = 72 pt (exactly)
2196 fRetval
= ( 1.0 / 72.0 );
2203 case MeasureUnit::MM_10TH
:
2207 case MeasureUnit::MM_100TH
:
2212 case MeasureUnit::MM
:
2214 // 0.01mm = 1 mm/100 (exactly)
2215 fRetval
= ((10.0 / 1.0) / 100.0);
2219 case MeasureUnit::CM
:
2221 fRetval
= ((10.0 / 1.0) / 1000.0);
2225 case MeasureUnit::POINT
:
2227 // 0.01pt = 0.35 mm/100 (exactly)
2228 fRetval
= ((72000.0 / 2540.0) / 100.0);
2232 case MeasureUnit::TWIP
:
2234 fRetval
= ((20.0 * 72000.0 / 2540.0) / 100.0);
2238 case MeasureUnit::INCH
:
2241 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for 1/10mm values");
2242 // 0.0001in = 0.254 mm/100 (exactly)
2243 fRetval
= ((100000.0 / 2540.0) / 10000.0);
2250 case MeasureUnit::MM_100TH
:
2254 case MeasureUnit::MM_10TH
:
2256 fRetval
= ((10.0 / 1.0) / 100.0);
2259 case MeasureUnit::MM
:
2261 // 0.01mm = 1 mm/100 (exactly)
2262 fRetval
= ((10.0 / 1.0) / 1000.0);
2266 case MeasureUnit::CM
:
2268 fRetval
= ((10.0 / 1.0) / 10000.0);
2272 case MeasureUnit::POINT
:
2274 // 0.01pt = 0.35 mm/100 (exactly)
2275 fRetval
= ((72000.0 / 2540.0) / 1000.0);
2279 case MeasureUnit::TWIP
:
2281 fRetval
= ((20.0 * 72000.0 / 2540.0) / 1000.0);
2285 case MeasureUnit::INCH
:
2288 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for 1/100mm values");
2289 // 0.0001in = 0.254 mm/100 (exactly)
2290 fRetval
= ((100000.0 / 2540.0) / 100000.0);
2297 case MeasureUnit::MM
:
2301 case MeasureUnit::MM_100TH
:
2306 case MeasureUnit::MM_10TH
:
2311 case MeasureUnit::CM
:
2317 case MeasureUnit::POINT
:
2319 fRetval
= 72.0 / (2.54 * 10);
2323 case MeasureUnit::TWIP
:
2325 fRetval
= (20.0 * 72.0) / (2.54 * 10);
2329 case MeasureUnit::INCH
:
2332 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for cm values");
2333 fRetval
= 1 / (2.54 * 10);
2340 case MeasureUnit::CM
:
2344 case MeasureUnit::MM_100TH
:
2349 case MeasureUnit::MM_10TH
:
2354 case MeasureUnit::MM
:
2360 case MeasureUnit::CM
:
2364 case MeasureUnit::POINT
:
2366 fRetval
= 72.0 / 2.54;
2370 case MeasureUnit::TWIP
:
2372 fRetval
= (20.0 * 72.0) / 2.54;
2376 case MeasureUnit::INCH
:
2379 OSL_ENSURE( MeasureUnit::INCH
== nTargetUnit
, "output unit not supported for cm values");
2387 case MeasureUnit::INCH
:
2389 switch (nTargetUnit
)
2391 case MeasureUnit::MM_100TH
:
2396 case MeasureUnit::MM_10TH
:
2401 case MeasureUnit::MM
:
2407 case MeasureUnit::CM
:
2413 case MeasureUnit::POINT
:
2419 case MeasureUnit::TWIP
:
2421 fRetval
= 72.0 * 20.0;
2427 OSL_FAIL("output unit not supported for in values");
2436 OSL_ENSURE(false, "sax::Converter::GetConversionFactor(): "
2437 "source unit not supported");
2442 rUnit
.appendAscii( psUnit
);
2448 sal_Int16
Converter::GetUnitFromString(const OUString
& rString
, sal_Int16 nDefaultUnit
)
2450 sal_Int32 nPos
= 0L;
2451 sal_Int32 nLen
= rString
.getLength();
2452 sal_Int16 nRetUnit
= nDefaultUnit
;
2455 while( nPos
< nLen
&& ' ' == rString
[nPos
] )
2459 if( nPos
< nLen
&& '-' == rString
[nPos
] )
2463 while( nPos
< nLen
&& '0' <= rString
[nPos
] && '9' >= rString
[nPos
] )
2466 if( nPos
< nLen
&& '.' == rString
[nPos
] )
2469 while( nPos
< nLen
&& '0' <= rString
[nPos
] && '9' >= rString
[nPos
] )
2474 while( nPos
< nLen
&& ' ' == rString
[nPos
] )
2479 switch(rString
[nPos
])
2481 case sal_Unicode('%') :
2483 nRetUnit
= MeasureUnit::PERCENT
;
2486 case sal_Unicode('c'):
2487 case sal_Unicode('C'):
2489 if(nPos
+1 < nLen
&& (rString
[nPos
+1] == 'm'
2490 || rString
[nPos
+1] == 'M'))
2491 nRetUnit
= MeasureUnit::CM
;
2494 case sal_Unicode('e'):
2495 case sal_Unicode('E'):
2497 // CSS1_EMS or CSS1_EMX later
2500 case sal_Unicode('i'):
2501 case sal_Unicode('I'):
2503 if(nPos
+1 < nLen
&& (rString
[nPos
+1] == 'n'
2504 || rString
[nPos
+1] == 'N'))
2505 nRetUnit
= MeasureUnit::INCH
;
2508 case sal_Unicode('m'):
2509 case sal_Unicode('M'):
2511 if(nPos
+1 < nLen
&& (rString
[nPos
+1] == 'm'
2512 || rString
[nPos
+1] == 'M'))
2513 nRetUnit
= MeasureUnit::MM
;
2516 case sal_Unicode('p'):
2517 case sal_Unicode('P'):
2519 if(nPos
+1 < nLen
&& (rString
[nPos
+1] == 't'
2520 || rString
[nPos
+1] == 'T'))
2521 nRetUnit
= MeasureUnit::POINT
;
2522 if(nPos
+1 < nLen
&& (rString
[nPos
+1] == 'c'
2523 || rString
[nPos
+1] == 'C'))
2524 nRetUnit
= MeasureUnit::TWIP
;
2534 bool Converter::convertAny(OUStringBuffer
& rsValue
,
2535 OUStringBuffer
& rsType
,
2536 const com::sun::star::uno::Any
& rValue
)
2538 bool bConverted
= false;
2540 rsValue
.setLength(0);
2541 rsType
.setLength (0);
2543 switch (rValue
.getValueTypeClass())
2545 case com::sun::star::uno::TypeClass_BYTE
:
2546 case com::sun::star::uno::TypeClass_SHORT
:
2547 case com::sun::star::uno::TypeClass_UNSIGNED_SHORT
:
2548 case com::sun::star::uno::TypeClass_LONG
:
2549 case com::sun::star::uno::TypeClass_UNSIGNED_LONG
:
2551 sal_Int32 nTempValue
= 0;
2552 if (rValue
>>= nTempValue
)
2554 rsType
.appendAscii("integer");
2556 ::sax::Converter::convertNumber(rsValue
, nTempValue
);
2561 case com::sun::star::uno::TypeClass_BOOLEAN
:
2563 bool bTempValue
= false;
2564 if (rValue
>>= bTempValue
)
2566 rsType
.appendAscii("boolean");
2568 ::sax::Converter::convertBool(rsValue
, bTempValue
);
2573 case com::sun::star::uno::TypeClass_FLOAT
:
2574 case com::sun::star::uno::TypeClass_DOUBLE
:
2576 double fTempValue
= 0.0;
2577 if (rValue
>>= fTempValue
)
2579 rsType
.appendAscii("float");
2581 ::sax::Converter::convertDouble(rsValue
, fTempValue
);
2586 case com::sun::star::uno::TypeClass_STRING
:
2588 OUString sTempValue
;
2589 if (rValue
>>= sTempValue
)
2591 rsType
.appendAscii("string");
2593 rsValue
.append(sTempValue
);
2598 case com::sun::star::uno::TypeClass_STRUCT
:
2600 com::sun::star::util::Date aDate
;
2601 com::sun::star::util::Time aTime
;
2602 com::sun::star::util::DateTime aDateTime
;
2604 if (rValue
>>= aDate
)
2606 rsType
.appendAscii("date");
2608 com::sun::star::util::DateTime aTempValue
;
2609 aTempValue
.Day
= aDate
.Day
;
2610 aTempValue
.Month
= aDate
.Month
;
2611 aTempValue
.Year
= aDate
.Year
;
2612 aTempValue
.NanoSeconds
= 0;
2613 aTempValue
.Seconds
= 0;
2614 aTempValue
.Minutes
= 0;
2615 aTempValue
.Hours
= 0;
2616 ::sax::Converter::convertDateTime(rsValue
, aTempValue
, 0);
2619 if (rValue
>>= aTime
)
2621 rsType
.appendAscii("time");
2623 com::sun::star::util::Duration aTempValue
;
2624 aTempValue
.Days
= 0;
2625 aTempValue
.Months
= 0;
2626 aTempValue
.Years
= 0;
2627 aTempValue
.NanoSeconds
= aTime
.NanoSeconds
;
2628 aTempValue
.Seconds
= aTime
.Seconds
;
2629 aTempValue
.Minutes
= aTime
.Minutes
;
2630 aTempValue
.Hours
= aTime
.Hours
;
2631 ::sax::Converter::convertDuration(rsValue
, aTempValue
);
2634 if (rValue
>>= aDateTime
)
2636 rsType
.appendAscii("date");
2638 ::sax::Converter::convertDateTime(rsValue
, aDateTime
, 0);
2651 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */