fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sax / source / tools / converter.cxx
blob5c969741113165b8364fea0979c19de2d57ad8a1
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
34 #include <osl/time.h>
35 #include <osl/diagnose.h>
37 #include <algorithm>
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;
45 namespace sax {
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 */ )
62 bool bNeg = false;
63 double nVal = 0;
65 sal_Int32 nPos = 0;
66 sal_Int32 const nLen = rString.getLength();
68 // skip white space
69 while( (nPos < nLen) && (rString[nPos] <= ' ') )
70 nPos++;
72 if( nPos < nLen && '-' == rString[nPos] )
74 bNeg = true;
75 nPos++;
78 // get number
79 while( nPos < nLen &&
80 '0' <= rString[nPos] &&
81 '9' >= rString[nPos] )
83 // TODO: check overflow!
84 nVal *= 10;
85 nVal += (rString[nPos] - '0');
86 nPos++;
88 if( nPos < nLen && '.' == rString[nPos] )
90 nPos++;
91 double nDiv = 1.;
93 while( nPos < nLen &&
94 '0' <= rString[nPos] &&
95 '9' >= rString[nPos] )
97 // TODO: check overflow!
98 nDiv *= 10;
99 nVal += ( ((double)(rString[nPos] - '0')) / nDiv );
100 nPos++;
104 // skip white space
105 while( (nPos < nLen) && (rString[nPos] <= ' ') )
106 nPos++;
108 if( nPos < nLen )
111 if( MeasureUnit::PERCENT == nTargetUnit )
113 if( '%' != rString[nPos] )
114 return false;
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]) )
123 return false;
125 else
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'):
139 aCmpsL[0] = "cm";
140 aCmpsU[0] = "CM";
141 aScales[0] = (72.*20.)/2.54; // twip
142 break;
143 case sal_Unicode('i'):
144 case sal_Unicode('I'):
145 aCmpsL[0] = "in";
146 aCmpsU[0] = "IN";
147 aScales[0] = 72.*20.; // twip
148 break;
149 case sal_Unicode('m'):
150 case sal_Unicode('M'):
151 aCmpsL[0] = "mm";
152 aCmpsU[0] = "MM";
153 aScales[0] = (72.*20.)/25.4; // twip
154 break;
155 case sal_Unicode('p'):
156 case sal_Unicode('P'):
157 aCmpsL[0] = "pt";
158 aCmpsU[0] = "PT";
159 aScales[0] = 20.; // twip
161 aCmpsL[1] = "pc";
162 aCmpsU[1] = "PC";
163 aScales[1] = 12.*20.; // twip
164 break;
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'):
174 aCmpsL[0] = "cm";
175 aCmpsU[0] = "CM";
176 aScales[0] = 10.0 * nScaleFactor; // mm/100
177 break;
178 case sal_Unicode('i'):
179 case sal_Unicode('I'):
180 aCmpsL[0] = "in";
181 aCmpsU[0] = "IN";
182 aScales[0] = 1000.*2.54; // mm/100
183 break;
184 case sal_Unicode('m'):
185 case sal_Unicode('M'):
186 aCmpsL[0] = "mm";
187 aCmpsU[0] = "MM";
188 aScales[0] = 1.0 * nScaleFactor; // mm/100
189 break;
190 case sal_Unicode('p'):
191 case sal_Unicode('P'):
192 aCmpsL[0] = "pt";
193 aCmpsU[0] = "PT";
194 aScales[0] = (10.0 * nScaleFactor*2.54)/72.; // mm/100
196 aCmpsL[1] = "pc";
197 aCmpsU[1] = "PC";
198 aScales[1] = (10.0 * nScaleFactor*2.54)/12.; // mm/100
199 break;
202 else if( MeasureUnit::POINT == nTargetUnit )
204 if( rString[nPos] == 'p' || rString[nPos] == 'P' )
206 aCmpsL[0] = "pt";
207 aCmpsU[0] = "PT";
208 aScales[0] = 1;
212 if( aCmpsL[0] == NULL )
213 return false;
215 double nScale = 0.;
216 for( sal_uInt16 i= 0; i < 2; i++ )
218 const sal_Char *pL = aCmpsL[i];
219 if( pL )
221 const sal_Char *pU = aCmpsU[i];
222 while( nPos < nLen && *pL )
224 sal_Unicode c = rString[nPos];
225 if( c != *pL && c != *pU )
226 break;
227 pL++;
228 pU++;
229 nPos++;
231 if( !*pL && (nPos == nLen || ' ' == rString[nPos]) )
233 nScale = aScales[i];
234 break;
239 if( 0. == nScale )
240 return false;
242 // TODO: check overflow
243 if( nScale != 1. )
244 nVal *= nScale;
248 nVal += .5;
249 if( bNeg )
250 nVal = -nVal;
252 if( nVal <= (double)nMin )
253 rValue = nMin;
254 else if( nVal >= (double)nMax )
255 rValue = nMax;
256 else
257 rValue = (sal_Int32)nVal;
259 return true;
262 /** convert measure in given unit to string with given unit */
263 void Converter::convertMeasure( OUStringBuffer& rBuffer,
264 sal_Int32 nMeasure,
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( '%' );
276 return;
278 // the sign is processed separately
279 if( nMeasure < 0 )
281 nMeasure = -nMeasure;
282 rBuffer.append( '-' );
285 // The new length is (nVal * nMul)/(nDiv*nFac*10)
286 long nMul = 1000;
287 long nDiv = 1;
288 long nFac = 100;
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" );
298 //fall-through
299 case MeasureUnit::MM:
300 // 0.01mm = 0.57twip (exactly)
301 nMul = 25400; // 25.4 * 1000
302 nDiv = 1440; // 72 * 20;
303 nFac = 100;
304 psUnit = gpsMM;
305 break;
307 case MeasureUnit::CM:
308 // 0.001cm = 0.57twip (exactly)
309 nMul = 25400; // 2.54 * 10000
310 nDiv = 1440; // 72 * 20;
311 nFac = 1000;
312 psUnit = gpsCM;
313 break;
315 case MeasureUnit::POINT:
316 // 0.01pt = 0.2twip (exactly)
317 nMul = 1000;
318 nDiv = 20;
319 nFac = 100;
320 psUnit = gpsPT;
321 break;
323 case MeasureUnit::INCH:
324 default:
325 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
326 "output unit not supported for twip values" );
327 // 0.0001in = 0.144twip (exactly)
328 nMul = 100000;
329 nDiv = 1440; // 72 * 20;
330 nFac = 10000;
331 psUnit = gpsINCH;
332 break;
334 break;
336 case MeasureUnit::POINT:
337 // 1pt = 1pt (exactly)
338 OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
339 "output unit not supported for pt values" );
340 nMul = 10;
341 nDiv = 1;
342 nFac = 1;
343 psUnit = gpsPT;
344 break;
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" );
355 //fall-through
356 case MeasureUnit::MM:
357 // 0.01mm = 1 mm/100 (exactly)
358 nMul = 10;
359 nDiv = 1;
360 nFac = nFac2;
361 psUnit = gpsMM;
362 break;
364 case MeasureUnit::CM:
365 // 0.001mm = 1 mm/100 (exactly)
366 nMul = 10;
367 nDiv = 1; // 72 * 20;
368 nFac = 10*nFac2;
369 psUnit = gpsCM;
370 break;
372 case MeasureUnit::POINT:
373 // 0.01pt = 0.35 mm/100 (exactly)
374 nMul = 72000;
375 nDiv = 2540;
376 nFac = nFac2;
377 psUnit = gpsPT;
378 break;
380 case MeasureUnit::INCH:
381 default:
382 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
383 "output unit not supported for 1/100mm values" );
384 // 0.0001in = 0.254 mm/100 (exactly)
385 nMul = 100000;
386 nDiv = 2540;
387 nFac = 100*nFac2;
388 psUnit = gpsINCH;
389 break;
391 break;
393 default:
394 OSL_ENSURE(false, "sax::Converter::convertMeasure(): "
395 "source unit not supported");
396 break;
399 sal_Int64 nValue = nMeasure;
400 OSL_ENSURE(nValue <= SAL_MAX_INT64 / nMul, "convertMeasure: overflow");
401 nValue *= nMul;
402 nValue /= nDiv;
403 nValue += 5;
404 nValue /= 10;
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)
412 nFac /= 10;
413 rBuffer.append( static_cast<sal_Int32>((nValue / nFac) % 10) );
417 if( psUnit )
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' )
475 return nChar - '0';
476 else if( nChar >= 'a' && nChar <= 'f' )
477 return nChar - 'a' + 10;
478 else if( nChar >= 'A' && nChar <= 'F' )
479 return nChar - 'A' + 10;
480 else
481 return 0;
484 /** convert string to rgb color */
485 bool Converter::convertColor( sal_Int32& rColor, const OUString& rValue )
487 if( rValue.getLength() != 7 || rValue[0] != '#' )
488 return false;
490 rColor = lcl_gethex( rValue[1] ) * 16 + lcl_gethex( rValue[2] );
491 rColor <<= 8;
493 rColor |= ( lcl_gethex( rValue[3] ) * 16 + lcl_gethex( rValue[4] ) );
494 rColor <<= 8;
496 rColor |= ( lcl_gethex( rValue[5] ) * 16 + lcl_gethex( rValue[6] ) );
498 return true;
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 )
532 rValue = 0;
533 sal_Int64 nNumber = 0;
534 bool bRet = convertNumber64(nNumber,rString,nMin,nMax);
535 if ( bRet )
536 rValue = static_cast<sal_Int32>(nNumber);
537 return bRet;
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 )
545 bool bNeg = false;
546 rValue = 0;
548 sal_Int32 nPos = 0;
549 sal_Int32 const nLen = rString.getLength();
551 // skip white space
552 while( (nPos < nLen) && (rString[nPos] <= ' ') )
553 nPos++;
555 if( nPos < nLen && '-' == rString[nPos] )
557 bNeg = true;
558 nPos++;
561 // get number
562 while( nPos < nLen &&
563 '0' <= rString[nPos] &&
564 '9' >= rString[nPos] )
566 // TODO: check overflow!
567 rValue *= 10;
568 rValue += (rString[nPos] - sal_Unicode('0'));
569 nPos++;
572 if( bNeg )
573 rValue *= -1;
575 if( rValue < nMin )
576 rValue = nMin;
577 else if( rValue > nMax )
578 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,
585 double fNumber,
586 bool bWriteUnits,
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);
594 if(bWriteUnits)
595 rBuffer.append('%');
597 else
599 OUStringBuffer sUnit;
600 double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
601 if(fFactor != 1.0)
602 fNumber *= fFactor;
603 ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
604 if(bWriteUnits)
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)
629 rValue /= fFactor;
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)
646 #if 1
647 // wrong, but backward compatible with OOo/LO < 4.4
648 ::sax::Converter::convertNumber(rBuffer, nAngle);
649 #else
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");
654 #endif
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.
666 sal_Int32 nValue(0);
667 double fValue(0.0);
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;
687 if (nValue < 0)
689 nValue += 3600;
691 assert(0 <= nValue && nValue <= 3600);
692 if (bRet)
694 rAngle = sal::static_int_cast<sal_Int16>(nValue);
696 return bRet;
699 /** convert double to ISO "duration" string; negative durations allowed */
700 void Converter::convertDuration(OUStringBuffer& rBuffer,
701 const double fTime)
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
707 if (fValue < 0.0)
709 rBuffer.append('-');
710 fValue = - fValue;
713 rBuffer.append( "PT" );
714 fValue *= 24;
715 double fHoursValue = ::rtl::math::approxFloor (fValue);
716 fValue -= fHoursValue;
717 fValue *= 60;
718 double fMinsValue = ::rtl::math::approxFloor (fValue);
719 fValue -= fMinsValue;
720 fValue *= 60;
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);
726 else
727 fNanoSecsValue = 0.0;
729 if (fNanoSecsValue == 1.0)
731 fNanoSecsValue = 0.0;
732 fSecsValue += 1.0;
734 if (fSecsValue >= 60.0)
736 fSecsValue -= 60.0;
737 fMinsValue += 1.0;
739 if (fMinsValue >= 60.0)
741 fMinsValue -= 60.0;
742 fHoursValue += 1.0;
745 if (fHoursValue < 10)
746 rBuffer.append( '0');
747 rBuffer.append( sal_Int32( fHoursValue));
748 rBuffer.append( 'H');
749 if (fMinsValue < 10)
750 rBuffer.append( '0');
751 rBuffer.append( sal_Int32( fMinsValue));
752 rBuffer.append( 'M');
753 if (fSecsValue < 10)
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, '.',
760 true));
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;
782 pStr++;
785 if ( *(pStr++) != 'P' ) // duration must start with "P"
786 return false;
788 OUString sDoubleStr;
789 bool bSuccess = true;
790 bool bDone = false;
791 bool bTimePart = false;
792 bool bIsFraction = false;
793 sal_Int32 nDays = 0;
794 sal_Int32 nHours = 0;
795 sal_Int32 nMins = 0;
796 sal_Int32 nSecs = 0;
797 sal_Int32 nTemp = 0;
799 while ( bSuccess && !bDone )
801 sal_Unicode c = *(pStr++);
802 if ( !c ) // end
803 bDone = true;
804 else if ( '0' <= c && '9' >= c )
806 if ( nTemp >= SAL_MAX_INT32 / 10 )
807 bSuccess = false;
808 else
810 if ( !bIsFraction )
812 nTemp *= 10;
813 nTemp += (c - sal_Unicode('0'));
815 else
817 sDoubleStr += OUString(c);
821 else if ( bTimePart )
823 if ( c == 'H' )
825 nHours = nTemp;
826 nTemp = 0;
828 else if ( c == 'M' )
830 nMins = nTemp;
831 nTemp = 0;
833 else if ( (c == ',') || (c == '.') )
835 nSecs = nTemp;
836 nTemp = 0;
837 bIsFraction = true;
838 sDoubleStr = "0.";
840 else if ( c == 'S' )
842 if ( !bIsFraction )
844 nSecs = nTemp;
845 nTemp = 0;
846 sDoubleStr = "0.0";
849 else
850 bSuccess = false; // invalid character
852 else
854 if ( c == 'T' ) // "T" starts time part
855 bTimePart = true;
856 else if ( c == 'D' )
858 nDays = nTemp;
859 nTemp = 0;
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");
866 bSuccess = false;
868 else
869 bSuccess = false; // invalid character
873 if ( bSuccess )
875 if ( nDays )
876 nHours += nDays * 24; // add the days to the hours part
877 double fTempTime = 0.0;
878 double fHour = nHours;
879 double fMin = nMins;
880 double fSec = nSecs;
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;
893 rfTime = fTempTime;
895 return bSuccess;
898 /** convert util::Duration to ISO8601 "duration" string */
899 void Converter::convertDuration(OUStringBuffer& rBuffer,
900 const ::util::Duration& rDuration)
902 if (rDuration.Negative)
904 rBuffer.append('-');
906 rBuffer.append('P');
907 const bool bHaveDate(rDuration.Years != 0 ||
908 rDuration.Months != 0 ||
909 rDuration.Days != 0);
910 if (rDuration.Years)
912 rBuffer.append(static_cast<sal_Int32>(rDuration.Years));
913 rBuffer.append('Y');
915 if (rDuration.Months)
917 rBuffer.append(static_cast<sal_Int32>(rDuration.Months));
918 rBuffer.append('M');
920 if (rDuration.Days)
922 rBuffer.append(static_cast<sal_Int32>(rDuration.Days));
923 rBuffer.append('D');
925 if ( rDuration.Hours != 0
926 || rDuration.Minutes != 0
927 || rDuration.Seconds != 0
928 || rDuration.NanoSeconds != 0 )
930 rBuffer.append('T'); // time separator
931 if (rDuration.Hours)
933 rBuffer.append(static_cast<sal_Int32>(rDuration.Hours));
934 rBuffer.append('H');
936 if (rDuration.Minutes)
938 rBuffer.append(static_cast<sal_Int32>(rDuration.Minutes));
939 rBuffer.append('M');
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");
948 rBuffer.append('.');
949 std::ostringstream ostr;
950 ostr.fill('0');
951 ostr.width(9);
952 ostr << rDuration.NanoSeconds;
953 rBuffer.append(OUString::createFromAscii(ostr.str().c_str()));
955 rBuffer.append('S');
958 else if (!bHaveDate)
960 // zero duration: XMLSchema-2 says there must be at least one component
961 rBuffer.append('0');
962 rBuffer.append('D');
966 enum Result { R_NOTHING, R_OVERFLOW, R_SUCCESS };
968 static Result
969 readUnsignedNumber(const OUString & rString,
970 sal_Int32 & io_rnPos, sal_Int32 & o_rNumber)
972 bool bOverflow(false);
973 sal_Int64 nTemp(0);
974 sal_Int32 nPos(io_rnPos);
976 while (nPos < rString.getLength())
978 const sal_Unicode c = rString[nPos];
979 if (('0' <= c) && (c <= '9'))
981 nTemp *= 10;
982 nTemp += (c - sal_Unicode('0'));
983 if (nTemp >= SAL_MAX_INT32)
985 bOverflow = true;
988 else
990 break;
992 ++nPos;
995 if (io_rnPos == nPos) // read something?
997 o_rNumber = -1;
998 return R_NOTHING;
1001 io_rnPos = nPos;
1002 o_rNumber = nTemp;
1003 return (bOverflow) ? R_OVERFLOW : R_SUCCESS;
1006 static Result
1007 readUnsignedNumberMaxDigits(int maxDigits,
1008 const ::rtl::OUString & rString, sal_Int32 & io_rnPos,
1009 sal_Int32 & o_rNumber)
1011 bool bOverflow(false);
1012 sal_Int64 nTemp(0);
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'))
1021 if (maxDigits > 0)
1023 nTemp *= 10;
1024 nTemp += (c - sal_Unicode('0'));
1025 if (nTemp >= SAL_MAX_INT32)
1027 bOverflow = true;
1029 --maxDigits;
1032 else
1034 break;
1036 ++nPos;
1039 if (io_rnPos == nPos) // read something?
1041 o_rNumber = -1;
1042 return R_NOTHING;
1045 io_rnPos = nPos;
1046 o_rNumber = nTemp;
1047 return (bOverflow) ? R_OVERFLOW : R_SUCCESS;
1050 static bool
1051 readDurationT(const OUString & rString, sal_Int32 & io_rnPos)
1053 if ((io_rnPos < rString.getLength()) &&
1054 (rString[io_rnPos] == 'T'))
1056 ++io_rnPos;
1057 return true;
1059 return false;
1062 static bool
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])
1071 ++io_rnPos;
1072 if (-1 != io_rnTemp)
1074 o_rnTarget = io_rnTemp;
1075 io_rnTemp = -1;
1076 if (!io_rbTimePart)
1078 io_rbTimePart = readDurationT(rString, io_rnPos);
1080 return (R_OVERFLOW !=
1081 readUnsignedNumber(rString, io_rnPos, io_rnTemp));
1083 else
1085 return false;
1089 return true;
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();
1097 sal_Int32 nPos(0);
1099 bool bIsNegativeDuration(false);
1100 if (!string.isEmpty() && ('-' == string[0]))
1102 bIsNegativeDuration = true;
1103 ++nPos;
1106 if ((nPos < string.getLength())
1107 && (string[nPos] != 'P')) // duration must start with "P"
1109 return false;
1112 ++nPos;
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);
1120 sal_Int32 nDays(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,
1132 nYears, 'Y');
1135 if (!bTimePart && bSuccess)
1137 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1138 nMonths, 'M');
1141 if (!bTimePart && bSuccess)
1143 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1144 nDays, 'D');
1147 if (bTimePart)
1149 if (-1 == nTemp) // a 'T' must be followed by a component
1151 bSuccess = false;
1154 if (bSuccess)
1156 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1157 nHours, 'H');
1160 if (bSuccess)
1162 bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1163 nMinutes, 'M');
1166 // eeek! seconds are icky.
1167 if ((nPos < string.getLength()) && bSuccess)
1169 if (string[nPos] == '.' ||
1170 string[nPos] == ',')
1172 ++nPos;
1173 if (-1 != nTemp)
1175 nSeconds = nTemp;
1176 nTemp = -1;
1177 const sal_Int32 nStart(nPos);
1178 bSuccess = readUnsignedNumberMaxDigits(9, string, nPos, nTemp) == R_SUCCESS;
1179 if ((nPos < string.getLength()) && bSuccess)
1181 if (-1 != nTemp)
1183 nNanoSeconds = nTemp;
1184 sal_Int32 nDigits = nPos - nStart;
1185 assert(nDigits >= 0);
1186 for (; nDigits < 9; ++nDigits)
1188 nNanoSeconds *= 10;
1190 nTemp=-1;
1191 if ('S' == string[nPos])
1193 ++nPos;
1195 else
1197 bSuccess = false;
1200 else
1202 bSuccess = false;
1206 else
1208 bSuccess = false;
1211 else if ('S' == string[nPos])
1213 ++nPos;
1214 if (-1 != nTemp)
1216 nSeconds = nTemp;
1217 nTemp = -1;
1219 else
1221 bSuccess = false;
1227 if (nPos != string.getLength()) // string not processed completely?
1229 bSuccess = false;
1232 if (nTemp != -1) // unprocessed number?
1234 bSuccess = false;
1237 if (bSuccess)
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);
1249 return bSuccess;
1253 static void
1254 lcl_AppendTimezone(OUStringBuffer & i_rBuffer, sal_Int16 const nOffset)
1256 if (0 == nOffset)
1258 i_rBuffer.append('Z');
1260 else
1262 if (0 < nOffset)
1264 i_rBuffer.append('+');
1266 else
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");
1274 if (nHours < 10)
1276 i_rBuffer.append('0');
1278 i_rBuffer.append(nHours);
1279 i_rBuffer.append(':');
1280 if (nMinutes < 10)
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) )
1307 .append(':');
1308 if (i_rDateTime.Minutes < 10) {
1309 i_rBuffer.append('0');
1311 i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Minutes) )
1312 .append(':');
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;
1321 ostr.fill('0');
1322 ostr.width(9);
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);
1356 else
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
1376 if (nYear < 1000) {
1377 i_rBuffer.append(zero);
1379 if (nYear < 100) {
1380 i_rBuffer.append(zero);
1382 if (nYear < 10) {
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 ||
1398 i_bAddTimeIf0AM )
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 )
1412 bool isDateTime;
1413 return parseDateOrDateTime(0, rDateTime, isDateTime, pTimeZoneOffset,
1414 rString);
1417 static bool lcl_isLeapYear(const sal_uInt32 nYear)
1419 return ((nYear % 4) == 0)
1420 && (((nYear % 100) != 0) || ((nYear % 400) == 0));
1423 static sal_uInt16
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))
1431 return 29;
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)
1449 o_rMinutes -= 60;
1450 ++nOffsetHours;
1452 o_rHours += nOffsetHours;
1453 if (o_rHours < 24)
1455 return;
1457 sal_Int16 nDayAdd(0);
1458 while (24 <= o_rHours)
1460 o_rHours -= 24;
1461 ++nDayAdd;
1463 if (o_rDay == 0)
1465 return; // handle time without date - don't adjust what isn't there
1467 o_rDay += nDayAdd;
1468 sal_Int16 const nDaysInMonth(lcl_MaxDaysPerMonth(o_rMonth, o_rYear));
1469 if (o_rDay <= nDaysInMonth)
1471 return;
1473 o_rDay -= nDaysInMonth;
1474 ++o_rMonth;
1475 if (o_rMonth <= 12)
1477 return;
1479 o_rMonth = 1;
1480 ++o_rYear; // works for negative year too
1482 else if (0 < nSourceOffset)
1484 // argh everything is unsigned
1485 if (o_rMinutes < nOffsetMinutes)
1487 o_rMinutes += 60;
1488 ++nOffsetHours;
1490 o_rMinutes -= nOffsetMinutes;
1491 sal_Int16 nDaySubtract(0);
1492 while (o_rHours < nOffsetHours)
1494 o_rHours += 24;
1495 ++nDaySubtract;
1497 o_rHours -= nOffsetHours;
1498 if (o_rDay == 0)
1500 return; // handle time without date - don't adjust what isn't there
1502 if (nDaySubtract < o_rDay)
1504 o_rDay -= nDaySubtract;
1505 return;
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;
1510 --o_rMonth;
1511 if (0 == o_rMonth)
1513 o_rMonth = 12;
1514 --o_rYear; // works for negative year too
1516 o_rDay -= nDaySubtract;
1520 static bool
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);
1526 sal_Int32 nTemp(0);
1527 if (R_SUCCESS != readUnsignedNumber(rString, io_rnPos, nTemp))
1529 return false;
1531 const sal_Int32 nTokenLength(io_rnPos - nOldPos);
1532 if ((nTokenLength < nMinLength) ||
1533 (bExactLength && (nTokenLength > nMinLength)))
1535 return false; // bad length
1537 o_rnTarget = nTemp;
1538 return true;
1541 /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
1542 static bool lcl_parseDate(
1543 bool & isNegative,
1544 sal_Int32 & nYear, sal_Int32 & nMonth, sal_Int32 & nDay,
1545 bool & bHaveTime,
1546 sal_Int32 & nPos,
1547 const OUString & string,
1548 bool const bIgnoreInvalidOrMissingDate)
1550 bool bSuccess = true;
1552 if (string.getLength() > nPos)
1554 if ('-' == string[nPos])
1556 isNegative = true;
1557 ++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
1574 bSuccess = false;
1576 if (bSuccess)
1578 ++nPos;
1581 if (bSuccess)
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
1593 bSuccess = false;
1595 if (bSuccess)
1597 ++nPos;
1600 if (bSuccess)
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
1618 bHaveTime = true;
1619 ++nPos;
1623 return bSuccess;
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,
1629 bool & rbDateTime,
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);
1639 sal_Int32 nYear(0);
1640 sal_Int32 nMonth(0);
1641 sal_Int32 nDay(0);
1642 sal_Int32 nPos(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);
1653 else
1655 bHaveTime = true;
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
1671 bSuccess = false;
1673 if (bSuccess)
1675 ++nPos;
1678 if (bSuccess)
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
1686 bSuccess = false;
1688 if (bSuccess)
1690 ++nPos;
1693 if (bSuccess)
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
1701 ++nPos;
1702 const sal_Int32 nStart(nPos);
1703 sal_Int32 nTemp(0);
1704 if (R_NOTHING == readUnsignedNumberMaxDigits(9, string, nPos, nTemp))
1706 bSuccess = false;
1708 if (bSuccess)
1710 sal_Int32 nDigits = std::min<sal_Int32>(nPos - nStart, 9);
1711 assert(nDigits > 0);
1712 for (; nDigits < 9; ++nDigits)
1714 nTemp *= 10;
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]);
1735 if ('+' == c)
1737 bHaveTimezone = true;
1738 bHaveTimezonePlus = true;
1739 ++nPos;
1741 else if ('-' == c)
1743 bHaveTimezone = true;
1744 bHaveTimezoneMinus = true;
1745 ++nPos;
1747 else if ('Z' == c)
1749 bHaveTimezone = true;
1750 ++nPos;
1752 else
1754 bSuccess = false;
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
1767 bSuccess = false;
1769 if (bSuccess)
1771 ++nPos;
1773 if (bSuccess)
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?
1790 if (bSuccess)
1792 sal_Int16 const nTimezoneOffset = ((bHaveTimezoneMinus) ? (-1) : (+1))
1793 * ((nTimezoneHours * 60) + nTimezoneMinutes);
1794 if (!pDate || bHaveTime) // time is optional
1796 rDateTime.Year =
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);
1804 if (bHaveTimezone)
1806 if (pTimeZoneOffset)
1808 *pTimeZoneOffset = nTimezoneOffset;
1809 rDateTime.IsUTC = (0 == nTimezoneOffset);
1811 else
1813 lcl_ConvertToUTC(rDateTime.Year, rDateTime.Month,
1814 rDateTime.Day, rDateTime.Hours, rDateTime.Minutes,
1815 nTimezoneOffset);
1816 rDateTime.IsUTC = true;
1819 else
1821 if (pTimeZoneOffset)
1823 pTimeZoneOffset->reset();
1825 rDateTime.IsUTC = false;
1827 rbDateTime = bHaveTime;
1829 else
1831 pDate->Year =
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);
1835 if (bHaveTimezone)
1837 if (pTimeZoneOffset)
1839 *pTimeZoneOffset = nTimezoneOffset;
1841 else
1843 // a Date cannot be adjusted
1844 SAL_INFO("sax", "dropping timezone");
1847 else
1849 if (pTimeZoneOffset)
1851 pTimeZoneOffset->reset();
1854 rbDateTime = false;
1857 return bSuccess;
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)
1866 bool dummy;
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,
1874 bool & rbDateTime,
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,
1886 sal_Int32 nPos )
1888 sal_Unicode cQuote = 0;
1889 sal_Int32 nLen = rStr.getLength();
1890 for( ; nPos < nLen; nPos++ )
1892 sal_Unicode c = rStr[nPos];
1893 switch( c )
1895 case sal_Unicode('\''):
1896 if( 0 == cQuote )
1897 cQuote = c;
1898 else if( '\'' == cQuote )
1899 cQuote = 0;
1900 break;
1902 case sal_Unicode('"'):
1903 if( 0 == cQuote )
1904 cQuote = c;
1905 else if( '\"' == cQuote )
1906 cQuote = 0;
1907 break;
1909 case sal_Unicode(','):
1910 if( 0 == cQuote )
1911 return nPos;
1912 break;
1916 return -1;
1919 const
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', '+', '/' };
1927 const
1928 sal_uInt8 aBase64DecodeTable[] =
1929 { 62,255,255,255, 63, // 43-47
1930 // + /
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);
1952 if (nLen > 3)
1953 nLen = 3;
1954 if (nLen == 0)
1956 return;
1959 sal_Int32 nBinaer;
1960 switch (nLen)
1962 case 1:
1964 nBinaer = ((sal_uInt8)pBuffer[nStart + 0]) << 16;
1966 break;
1967 case 2:
1969 nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
1970 (((sal_uInt8)pBuffer[nStart + 1]) << 8);
1972 break;
1973 default:
1975 nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
1976 (((sal_uInt8)pBuffer[nStart + 1]) << 8) +
1977 ((sal_uInt8)pBuffer[nStart + 2]);
1979 break;
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];
1989 if (nLen > 1)
1991 nIndex = static_cast<sal_uInt8>((nBinaer & 0xFC0) >> 6);
1992 buf[2] = aBase64EncodeTable [nIndex];
1993 if (nLen > 2)
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)
2004 sal_Int32 i(0);
2005 sal_Int32 nBufferLength(aPass.getLength());
2006 const sal_Int8* pBuffer = aPass.getConstArray();
2007 while (i < nBufferLength)
2009 ThreeByteToFourByte (pBuffer, i, nBufferLength, aStrBuffer);
2010 i += 3;
2014 void Converter::decodeBase64(uno::Sequence<sal_Int8>& aBuffer, const OUString& sBuffer)
2016 #if OSL_DEBUG_LEVEL > 0
2017 sal_Int32 nCharsDecoded =
2018 #endif
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-'+'];
2047 if( nByte != 255 )
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) +
2062 aDecodeBuffer[3];
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;
2070 nBytesToDecode = 0;
2071 nBytesGotFromDecoding = 3;
2074 else
2076 nCharsDecoded++;
2079 else
2081 nCharsDecoded++;
2084 nInBufferPos++;
2085 pInBuffer++;
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)
2102 switch(nSourceUnit)
2104 case MeasureUnit::TWIP:
2106 switch(nTargetUnit)
2108 case MeasureUnit::MM_100TH:
2110 // 0.01mm = 0.57twip (exactly)
2111 fRetval = ((25400.0 / 1440.0) / 10.0);
2112 break;
2114 case MeasureUnit::MM_10TH:
2116 // 0.01mm = 0.57twip (exactly)
2117 fRetval = ((25400.0 / 1440.0) / 100.0);
2118 break;
2120 case MeasureUnit::MM:
2122 // 0.01mm = 0.57twip (exactly)
2123 fRetval = ((25400.0 / 1440.0) / 1000.0);
2124 psUnit = gpsMM;
2125 break;
2127 case MeasureUnit::CM:
2129 // 0.001cm = 0.57twip (exactly)
2130 fRetval = ((25400.0 / 1440.0) / 10000.0);
2131 psUnit = gpsCM;
2132 break;
2134 case MeasureUnit::POINT:
2136 // 0.01pt = 0.2twip (exactly)
2137 fRetval = ((1000.0 / 20.0) / 1000.0);
2138 psUnit = gpsPT;
2139 break;
2141 case MeasureUnit::INCH:
2142 default:
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);
2147 psUnit = gpsINCH;
2148 break;
2151 break;
2153 case MeasureUnit::POINT:
2155 switch(nTargetUnit)
2157 case MeasureUnit::MM_100TH:
2159 // 1mm = 72 / 25.4 pt (exactly)
2160 fRetval = ( 2540.0 / 72.0 );
2161 break;
2163 case MeasureUnit::MM_10TH:
2165 // 1mm = 72 / 25.4 pt (exactly)
2166 fRetval = ( 254.0 / 72.0 );
2167 break;
2169 case MeasureUnit::MM:
2171 // 1mm = 72 / 25.4 pt (exactly)
2172 fRetval = ( 25.4 / 72.0 );
2173 psUnit = gpsMM;
2174 break;
2177 case MeasureUnit::CM:
2179 // 1cm = 72 / 2.54 pt (exactly)
2180 fRetval = ( 2.54 / 72.0 );
2181 psUnit = gpsCM;
2182 break;
2184 case MeasureUnit::TWIP:
2186 // 1twip = 72 / 1440 pt (exactly)
2187 fRetval = 20.0; // 1440.0 / 72.0
2188 psUnit = gpsPC;
2189 break;
2191 case MeasureUnit::INCH:
2192 default:
2194 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for pt values");
2195 // 1in = 72 pt (exactly)
2196 fRetval = ( 1.0 / 72.0 );
2197 psUnit = gpsINCH;
2198 break;
2201 break;
2203 case MeasureUnit::MM_10TH:
2205 switch(nTargetUnit)
2207 case MeasureUnit::MM_100TH:
2209 fRetval = 10.0;
2210 break;
2212 case MeasureUnit::MM:
2214 // 0.01mm = 1 mm/100 (exactly)
2215 fRetval = ((10.0 / 1.0) / 100.0);
2216 psUnit = gpsMM;
2217 break;
2219 case MeasureUnit::CM:
2221 fRetval = ((10.0 / 1.0) / 1000.0);
2222 psUnit = gpsCM;
2223 break;
2225 case MeasureUnit::POINT:
2227 // 0.01pt = 0.35 mm/100 (exactly)
2228 fRetval = ((72000.0 / 2540.0) / 100.0);
2229 psUnit = gpsPT;
2230 break;
2232 case MeasureUnit::TWIP:
2234 fRetval = ((20.0 * 72000.0 / 2540.0) / 100.0);
2235 psUnit = gpsPC;
2236 break;
2238 case MeasureUnit::INCH:
2239 default:
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);
2244 psUnit = gpsINCH;
2245 break;
2248 break;
2250 case MeasureUnit::MM_100TH:
2252 switch(nTargetUnit)
2254 case MeasureUnit::MM_10TH:
2256 fRetval = ((10.0 / 1.0) / 100.0);
2257 break;
2259 case MeasureUnit::MM:
2261 // 0.01mm = 1 mm/100 (exactly)
2262 fRetval = ((10.0 / 1.0) / 1000.0);
2263 psUnit = gpsMM;
2264 break;
2266 case MeasureUnit::CM:
2268 fRetval = ((10.0 / 1.0) / 10000.0);
2269 psUnit = gpsCM;
2270 break;
2272 case MeasureUnit::POINT:
2274 // 0.01pt = 0.35 mm/100 (exactly)
2275 fRetval = ((72000.0 / 2540.0) / 1000.0);
2276 psUnit = gpsPT;
2277 break;
2279 case MeasureUnit::TWIP:
2281 fRetval = ((20.0 * 72000.0 / 2540.0) / 1000.0);
2282 psUnit = gpsPC;
2283 break;
2285 case MeasureUnit::INCH:
2286 default:
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);
2291 psUnit = gpsINCH;
2292 break;
2295 break;
2297 case MeasureUnit::MM:
2299 switch(nTargetUnit)
2301 case MeasureUnit::MM_100TH:
2303 fRetval = 100.0;
2304 break;
2306 case MeasureUnit::MM_10TH:
2308 fRetval = 10.0;
2309 break;
2311 case MeasureUnit::CM:
2313 fRetval = 0.1;
2314 psUnit = gpsCM;
2315 break;
2317 case MeasureUnit::POINT:
2319 fRetval = 72.0 / (2.54 * 10);
2320 psUnit = gpsPT;
2321 break;
2323 case MeasureUnit::TWIP:
2325 fRetval = (20.0 * 72.0) / (2.54 * 10);
2326 psUnit = gpsPC;
2327 break;
2329 case MeasureUnit::INCH:
2330 default:
2332 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
2333 fRetval = 1 / (2.54 * 10);
2334 psUnit = gpsINCH;
2335 break;
2338 break;
2340 case MeasureUnit::CM:
2342 switch(nTargetUnit)
2344 case MeasureUnit::MM_100TH:
2346 fRetval = 1000.0;
2347 break;
2349 case MeasureUnit::MM_10TH:
2351 fRetval = 100.0;
2352 break;
2354 case MeasureUnit::MM:
2356 fRetval = 10.0;
2357 psUnit = gpsMM;
2358 break;
2360 case MeasureUnit::CM:
2362 break;
2364 case MeasureUnit::POINT:
2366 fRetval = 72.0 / 2.54;
2367 psUnit = gpsPT;
2368 break;
2370 case MeasureUnit::TWIP:
2372 fRetval = (20.0 * 72.0) / 2.54;
2373 psUnit = gpsPC;
2374 break;
2376 case MeasureUnit::INCH:
2377 default:
2379 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for cm values");
2380 fRetval = 1 / 2.54;
2381 psUnit = gpsINCH;
2382 break;
2385 break;
2387 case MeasureUnit::INCH:
2389 switch (nTargetUnit)
2391 case MeasureUnit::MM_100TH:
2393 fRetval = 2540;
2394 break;
2396 case MeasureUnit::MM_10TH:
2398 fRetval = 254;
2399 break;
2401 case MeasureUnit::MM:
2403 fRetval = 25.4;
2404 psUnit = gpsMM;
2405 break;
2407 case MeasureUnit::CM:
2409 fRetval = 2.54;
2410 psUnit = gpsCM;
2411 break;
2413 case MeasureUnit::POINT:
2415 fRetval = 72.0;
2416 psUnit = gpsPT;
2417 break;
2419 case MeasureUnit::TWIP:
2421 fRetval = 72.0 * 20.0;
2422 psUnit = gpsPC;
2423 break;
2425 default:
2427 OSL_FAIL("output unit not supported for in values");
2428 fRetval = 1;
2429 psUnit = gpsINCH;
2430 break;
2433 break;
2435 default:
2436 OSL_ENSURE(false, "sax::Converter::GetConversionFactor(): "
2437 "source unit not supported");
2438 break;
2441 if( psUnit )
2442 rUnit.appendAscii( psUnit );
2445 return fRetval;
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;
2454 // skip white space
2455 while( nPos < nLen && ' ' == rString[nPos] )
2456 nPos++;
2458 // skip negative
2459 if( nPos < nLen && '-' == rString[nPos] )
2460 nPos++;
2462 // skip number
2463 while( nPos < nLen && '0' <= rString[nPos] && '9' >= rString[nPos] )
2464 nPos++;
2466 if( nPos < nLen && '.' == rString[nPos] )
2468 nPos++;
2469 while( nPos < nLen && '0' <= rString[nPos] && '9' >= rString[nPos] )
2470 nPos++;
2473 // skip white space
2474 while( nPos < nLen && ' ' == rString[nPos] )
2475 nPos++;
2477 if( nPos < nLen )
2479 switch(rString[nPos])
2481 case sal_Unicode('%') :
2483 nRetUnit = MeasureUnit::PERCENT;
2484 break;
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;
2492 break;
2494 case sal_Unicode('e'):
2495 case sal_Unicode('E'):
2497 // CSS1_EMS or CSS1_EMX later
2498 break;
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;
2506 break;
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;
2514 break;
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;
2525 break;
2530 return nRetUnit;
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");
2555 bConverted = true;
2556 ::sax::Converter::convertNumber(rsValue, nTempValue);
2559 break;
2561 case com::sun::star::uno::TypeClass_BOOLEAN :
2563 bool bTempValue = false;
2564 if (rValue >>= bTempValue)
2566 rsType.appendAscii("boolean");
2567 bConverted = true;
2568 ::sax::Converter::convertBool(rsValue, bTempValue);
2571 break;
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");
2580 bConverted = true;
2581 ::sax::Converter::convertDouble(rsValue, fTempValue);
2584 break;
2586 case com::sun::star::uno::TypeClass_STRING :
2588 OUString sTempValue;
2589 if (rValue >>= sTempValue)
2591 rsType.appendAscii("string");
2592 bConverted = true;
2593 rsValue.append(sTempValue);
2596 break;
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");
2607 bConverted = true;
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);
2618 else
2619 if (rValue >>= aTime)
2621 rsType.appendAscii("time");
2622 bConverted = true;
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);
2633 else
2634 if (rValue >>= aDateTime)
2636 rsType.appendAscii("date");
2637 bConverted = true;
2638 ::sax::Converter::convertDateTime(rsValue, aDateTime, 0);
2641 break;
2642 default:
2643 break;
2646 return bConverted;
2651 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */