xref: /aoo41x/main/sax/source/tools/converter.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 
29 #include <com/sun/star/i18n/UnicodeType.hpp>
30 #include <com/sun/star/util/DateTime.hpp>
31 #include <com/sun/star/util/Date.hpp>
32 #include <com/sun/star/util/Duration.hpp>
33 #include <com/sun/star/uno/Sequence.hxx>
34 
35 #include <rtl/ustrbuf.hxx>
36 #include <rtl/math.hxx>
37 #include "sax/tools/converter.hxx"
38 
39 using namespace rtl;
40 using namespace com::sun::star;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::util;
43 //using namespace com::sun::star::text;
44 //using namespace com::sun::star::style;
45 using namespace ::com::sun::star::i18n;
46 
47 namespace sax {
48 
49 static const sal_Char* gpsMM = "mm";
50 static const sal_Char* gpsCM = "cm";
51 static const sal_Char* gpsPT = "pt";
52 static const sal_Char* gpsINCH = "in";
53 static const sal_Char* gpsPC = "pc";
54 
55 const sal_Int8 XML_MAXDIGITSCOUNT_TIME = 11;
56 const sal_Int8 XML_MAXDIGITSCOUNT_DATETIME = 6;
57 #define XML_NULLDATE "NullDate"
58 
59 /** convert string to measure using optional min and max values*/
60 bool Converter::convertMeasure(	sal_Int32& rValue,
61 								const OUString& rString,
62 								sal_Int16 nTargetUnit /* = MeasureUnit::MM_100TH */,
63 								sal_Int32 nMin /* = SAL_MIN_INT32 */,
64 								sal_Int32 nMax /* = SAL_MAX_INT32 */ )
65 {
66     bool bNeg = false;
67     double nVal = 0;
68 
69     sal_Int32 nPos = 0;
70     sal_Int32 nLen = rString.getLength();
71 
72     // skip white space
73     while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
74         nPos++;
75 
76     if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
77     {
78         bNeg = true;
79         nPos++;
80     }
81 
82     // get number
83     while( nPos < nLen &&
84            sal_Unicode('0') <= rString[nPos] &&
85            sal_Unicode('9') >= rString[nPos] )
86     {
87         // TODO: check overflow!
88         nVal *= 10;
89         nVal += (rString[nPos] - sal_Unicode('0'));
90         nPos++;
91     }
92     double nDiv = 1.;
93     if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
94     {
95         nPos++;
96 
97         while( nPos < nLen &&
98                sal_Unicode('0') <= rString[nPos] &&
99                sal_Unicode('9') >= rString[nPos] )
100         {
101             // TODO: check overflow!
102             nDiv *= 10;
103             nVal += ( ((double)(rString[nPos] - sal_Unicode('0'))) / nDiv );
104             nPos++;
105         }
106     }
107 
108     // skip white space
109     while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
110         nPos++;
111 
112     if( nPos < nLen )
113     {
114 
115 		if( MeasureUnit::PERCENT == nTargetUnit )
116         {
117             if( sal_Unicode('%') != rString[nPos] )
118                 return false;
119         }
120 		else if( MeasureUnit::PIXEL == nTargetUnit )
121         {
122             if( nPos + 1 >= nLen ||
123                 (sal_Unicode('p') != rString[nPos] &&
124                  sal_Unicode('P') != rString[nPos])||
125                 (sal_Unicode('x') != rString[nPos+1] &&
126                  sal_Unicode('X') != rString[nPos+1]) )
127                 return false;
128         }
129         else
130         {
131             OSL_ENSURE( MeasureUnit::TWIP == nTargetUnit || MeasureUnit::POINT == nTargetUnit ||
132                         MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit, "unit is not supported");
133             const sal_Char *aCmpsL[2] = { 0, 0 };
134             const sal_Char *aCmpsU[2] = { 0, 0 };
135             double aScales[2] = { 1., 1. };
136 
137             if( MeasureUnit::TWIP == nTargetUnit )
138             {
139                 switch( rString[nPos] )
140                 {
141                 case sal_Unicode('c'):
142                 case sal_Unicode('C'):
143                     aCmpsL[0] = "cm";
144                     aCmpsU[0] = "CM";
145                     aScales[0] = (72.*20.)/2.54; // twip
146                     break;
147                 case sal_Unicode('i'):
148                 case sal_Unicode('I'):
149                     aCmpsL[0] = "in";
150                     aCmpsU[0] = "IN";
151                     aScales[0] = 72.*20.; // twip
152                     break;
153                 case sal_Unicode('m'):
154                 case sal_Unicode('M'):
155                     aCmpsL[0] = "mm";
156                     aCmpsU[0] = "MM";
157                     aScales[0] = (72.*20.)/25.4; // twip
158                     break;
159                 case sal_Unicode('p'):
160                 case sal_Unicode('P'):
161                     aCmpsL[0] = "pt";
162                     aCmpsU[0] = "PT";
163                     aScales[0] = 20.; // twip
164 
165                     aCmpsL[1] = "pc";
166                     aCmpsU[1] = "PC";
167                     aScales[1] = 12.*20.; // twip
168                     break;
169                 }
170             }
171             else if( MeasureUnit::MM_100TH == nTargetUnit || MeasureUnit::MM_10TH == nTargetUnit )
172             {
173 				double nScaleFactor = (MeasureUnit::MM_100TH == nTargetUnit) ? 100.0 : 10.0;
174                 switch( rString[nPos] )
175                 {
176                 case sal_Unicode('c'):
177                 case sal_Unicode('C'):
178                     aCmpsL[0] = "cm";
179                     aCmpsU[0] = "CM";
180                     aScales[0] = 10.0 * nScaleFactor; // mm/100
181                     break;
182                 case sal_Unicode('i'):
183                 case sal_Unicode('I'):
184                     aCmpsL[0] = "in";
185                     aCmpsU[0] = "IN";
186                     aScales[0] = 1000.*2.54; // mm/100
187                     break;
188                 case sal_Unicode('m'):
189                 case sal_Unicode('M'):
190                     aCmpsL[0] = "mm";
191                     aCmpsU[0] = "MM";
192                     aScales[0] = 1.0 * nScaleFactor; // mm/100
193                     break;
194                 case sal_Unicode('p'):
195                 case sal_Unicode('P'):
196                     aCmpsL[0] = "pt";
197                     aCmpsU[0] = "PT";
198                     aScales[0] = (10.0 * nScaleFactor*2.54)/72.; // mm/100
199 
200                     aCmpsL[1] = "pc";
201                     aCmpsU[1] = "PC";
202                     aScales[1] = (10.0 * nScaleFactor*2.54)/12.; // mm/100
203                     break;
204                 }
205             }
206             else if( MeasureUnit::POINT == nTargetUnit )
207             {
208                 if( rString[nPos] == 'p' || rString[nPos] == 'P' )
209                 {
210                     aCmpsL[0] = "pt";
211                     aCmpsU[0] = "PT";
212                     aScales[0] = 1;
213                 }
214             }
215 
216             if( aCmpsL[0] == NULL )
217                 return false;
218 
219             double nScale = 0.;
220             for( sal_uInt16 i= 0; i < 2; i++ )
221             {
222                 const sal_Char *pL = aCmpsL[i];
223                 if( pL )
224                 {
225                     const sal_Char *pU = aCmpsU[i];
226                     while( nPos < nLen && *pL )
227                     {
228                         sal_Unicode c = rString[nPos];
229                         if( c != *pL && c != *pU )
230                             break;
231                         pL++;
232                         pU++;
233                         nPos++;
234                     }
235                     if( !*pL && (nPos == nLen || ' ' == rString[nPos]) )
236                     {
237                         nScale = aScales[i];
238                         break;
239                     }
240                 }
241             }
242 
243             if( 0. == nScale )
244                 return false;
245 
246             // TODO: check overflow
247             if( nScale != 1. )
248                 nVal *= nScale;
249         }
250     }
251 
252     nVal += .5;
253     if( bNeg )
254         nVal = -nVal;
255 
256     if( nVal <= (double)nMin )
257         rValue = nMin;
258     else if( nVal >= (double)nMax )
259         rValue = nMax;
260     else
261         rValue = (sal_Int32)nVal;
262 
263     return true;
264 }
265 
266 /** convert measure in given unit to string with given unit */
267 void Converter::convertMeasure( OUStringBuffer& rBuffer,
268 								sal_Int32 nMeasure,
269 								sal_Int16 nSourceUnit /* = MeasureUnit::MM_100TH */,
270 								sal_Int16 nTargetUnit /* = MeasureUnit::INCH */  )
271 {
272     OSL_ENSURE( false, "Converter::convertMeasure - not implemented, tools/BigInt needs replacement" );
273     (void)rBuffer;
274     (void)nMeasure;
275     (void)nSourceUnit;
276     (void)nTargetUnit;
277 #if 0
278     if( nSourceUnit == MeasureUnit::PERCENT )
279     {
280         OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT,
281                     "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
282 
283         rBuffer.append( nMeasure );
284         rBuffer.append( sal_Unicode('%' ) );
285     }
286     else
287     {
288 	// the sign is processed seperatly
289 	if( nMeasure < 0 )
290 	{
291 		nMeasure = -nMeasure;
292 		rBuffer.append( sal_Unicode('-') );
293 	}
294 
295 	// The new length is (nVal * nMul)/(nDiv*nFac*10)
296 	long nMul = 1000;
297 	long nDiv = 1;
298 	long nFac = 100;
299 	const sal_Char* psUnit = 0;
300 	switch( nSourceUnit )
301 	{
302 	case MeasureUnit::TWIP:
303 		switch( nTargetUnit )
304 		{
305 		case MeasureUnit::MM_100TH:
306 		case MeasureUnit::MM_10TH:
307             OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,"output unit not supported for twip values" );
308 		case MeasureUnit::MM:
309 			// 0.01mm = 0.57twip (exactly)
310 			nMul = 25400;	// 25.4 * 1000
311 			nDiv = 1440;	// 72 * 20;
312 			nFac = 100;
313 			psUnit = gpsMM;
314 			break;
315 
316 		case MeasureUnit::CM:
317 			// 0.001cm = 0.57twip (exactly)
318 			nMul = 25400;	// 2.54 * 10000
319 			nDiv = 1440;	// 72 * 20;
320 			nFac = 1000;
321 			psUnit = gpsCM;
322 			break;
323 
324 		case MeasureUnit::POINT:
325 			// 0.01pt = 0.2twip (exactly)
326 			nMul = 1000;
327 			nDiv = 20;
328 			nFac = 100;
329 			psUnit = gpsPT;
330 			break;
331 
332 		case MeasureUnit::INCH:
333 		default:
334             OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
335 						"output unit not supported for twip values" );
336 			// 0.0001in = 0.144twip (exactly)
337 			nMul = 100000;
338 			nDiv = 1440;	// 72 * 20;
339 			nFac = 10000;
340 			psUnit = gpsINCH;
341 			break;
342 		}
343 		break;
344 
345 	case MeasureUnit::POINT:
346 		// 1pt = 1pt (exactly)
347         OSL_ENSURE( MeasureUnit::POINT == nTargetUnit,
348 					"output unit not supported for pt values" );
349 		nMul = 10;
350 		nDiv = 1;
351 		nFac = 1;
352 		psUnit = gpsPT;
353 		break;
354     case MeasureUnit::MM_10TH:
355 	case MeasureUnit::MM_100TH:
356         {
357             long nFac2 = (MeasureUnit::MM_100TH == nSourceUnit) ? 100 : 10;
358 		    switch( nTargetUnit )
359 		    {
360 		    case MeasureUnit::MM_100TH:
361 		    case MeasureUnit::MM_10TH:
362                 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
363 						    "output unit not supported for 1/100mm values" );
364 		    case MeasureUnit::MM:
365 			    // 0.01mm = 1 mm/100 (exactly)
366 			    nMul = 10;
367 			    nDiv = 1;
368 			    nFac = nFac2;
369 			    psUnit = gpsMM;
370 			    break;
371 
372 		    case MeasureUnit::CM:
373 			    // 0.001mm = 1 mm/100 (exactly)
374 			    nMul = 10;
375 			    nDiv = 1;	// 72 * 20;
376 			    nFac = 10*nFac2;
377 			    psUnit = gpsCM;
378 			    break;
379 
380 		    case MeasureUnit::POINT:
381 			    // 0.01pt = 0.35 mm/100 (exactly)
382 			    nMul = 72000;
383 			    nDiv = 2540;
384 			    nFac = nFac2;
385 			    psUnit = gpsPT;
386 			    break;
387 
388 		    case MeasureUnit::INCH:
389 		    default:
390                 OSL_ENSURE( MeasureUnit::INCH == nTargetUnit,
391 						    "output unit not supported for 1/100mm values" );
392 			    // 0.0001in = 0.254 mm/100 (exactly)
393 			    nMul = 100000;
394 			    nDiv = 2540;
395 			    nFac = 100*nFac2;
396 			    psUnit = gpsINCH;
397 			    break;
398 		    }
399 		    break;
400         }
401 	}
402 
403 	long nLongVal = 0;
404 	bool bOutLongVal = true;
405 	if( nMeasure > SAL_INT32_MAX / nMul )
406 	{
407 		// A big int is required for calculation
408 		BigInt nBigVal( nMeasure );
409 		BigInt nBigFac( nFac );
410 		nBigVal *= nMul;
411 		nBigVal /= nDiv;
412 		nBigVal += 5;
413 		nBigVal /= 10;
414 
415 		if( nBigVal.IsLong() )
416 		{
417 			// To convert the value into a string a long is sufficient
418 			nLongVal = (long)nBigVal;
419 		}
420 		else
421 		{
422 			BigInt nBigFac2( nFac );
423 			BigInt nBig10( 10 );
424 			rBuffer.append( (sal_Int32)(nBigVal / nBigFac2) );
425 			if( !(nBigVal % nBigFac2).IsZero() )
426 			{
427 				rBuffer.append( sal_Unicode('.') );
428 				while( nFac > 1 && !(nBigVal % nBigFac2).IsZero() )
429 				{
430 					nFac /= 10;
431 					nBigFac2 = nFac;
432 					rBuffer.append( (sal_Int32)((nBigVal / nBigFac2) % nBig10 ) );
433 				}
434 			}
435 			bOutLongVal = false;
436 		}
437 	}
438 	else
439 	{
440 		nLongVal = nMeasure * nMul;
441 		nLongVal /= nDiv;
442 		nLongVal += 5;
443 		nLongVal /= 10;
444 	}
445 
446 	if( bOutLongVal )
447 	{
448 		rBuffer.append( (sal_Int32)(nLongVal / nFac) );
449 		if( nFac > 1 && (nLongVal % nFac) != 0 )
450 		{
451 			rBuffer.append( sal_Unicode('.') );
452 			while( nFac > 1 && (nLongVal % nFac) != 0 )
453 			{
454 				nFac /= 10;
455 				rBuffer.append( (sal_Int32)((nLongVal / nFac) % 10) );
456 			}
457 		}
458 	}
459 
460 	if( psUnit )
461 		rBuffer.appendAscii( psUnit );
462     }
463 #endif
464 }
465 
466 static const OUString& getTrueString()
467 {
468 	static const OUString sTrue( RTL_CONSTASCII_USTRINGPARAM( "true" ) );
469 	return sTrue;
470 }
471 
472 static const OUString& getFalseString()
473 {
474 	static const OUString sFalse( RTL_CONSTASCII_USTRINGPARAM( "false" ) );
475 	return sFalse;
476 }
477 
478 /** convert string to boolean */
479 bool Converter::convertBool( bool& rBool, const OUString& rString )
480 {
481     rBool = rString == getTrueString();
482 
483     return rBool || (rString == getFalseString());
484 }
485 
486 /** convert boolean to string */
487 void Converter::convertBool( OUStringBuffer& rBuffer, bool bValue )
488 {
489     rBuffer.append( bValue ? getTrueString() : getFalseString() );
490 }
491 
492 /** convert string to percent */
493 bool Converter::convertPercent( sal_Int32& rPercent, const OUString& rString )
494 {
495     return convertMeasure( rPercent, rString, MeasureUnit::PERCENT );
496 }
497 
498 /** convert percent to string */
499 void Converter::convertPercent( OUStringBuffer& rBuffer, sal_Int32 nValue )
500 {
501     rBuffer.append( nValue );
502     rBuffer.append( sal_Unicode('%' ) );
503 }
504 
505 /** convert string to pixel measure */
506 bool Converter::convertMeasurePx( sal_Int32& rPixel, const OUString& rString )
507 {
508     return convertMeasure( rPixel, rString, MeasureUnit::PIXEL );
509 }
510 
511 /** convert pixel measure to string */
512 void Converter::convertMeasurePx( OUStringBuffer& rBuffer, sal_Int32 nValue )
513 {
514     rBuffer.append( nValue );
515     rBuffer.append( sal_Unicode('p' ) );
516     rBuffer.append( sal_Unicode('x' ) );
517 }
518 
519 int lcl_gethex( int nChar )
520 {
521     if( nChar >= '0' && nChar <= '9' )
522         return nChar - '0';
523     else if( nChar >= 'a' && nChar <= 'f' )
524         return nChar - 'a' + 10;
525     else if( nChar >= 'A' && nChar <= 'F' )
526         return nChar - 'A' + 10;
527     else
528         return 0;
529 }
530 
531 /** convert string to color */
532 bool Converter::convertColor( sal_Int32& rColor, const OUString& rValue )
533 {
534     if( rValue.getLength() != 7 || rValue[0] != '#' )
535         return false;
536 
537 	rColor = lcl_gethex( rValue[1] ) * 16 + lcl_gethex( rValue[2] );
538 	rColor <<= 8;
539 
540 	rColor |= ( lcl_gethex( rValue[3] ) * 16 + lcl_gethex( rValue[4] ) );
541 	rColor <<= 8;
542 
543 	rColor |= ( lcl_gethex( rValue[5] ) * 16 + lcl_gethex( rValue[6] ) );
544 
545     return true;
546 }
547 
548 static sal_Char aHexTab[] = "0123456789abcdef";
549 
550 /** convert color to string */
551 void Converter::convertColor( OUStringBuffer& rBuffer, sal_Int32 nColor )
552 {
553     rBuffer.append( sal_Unicode( '#' ) );
554 
555     sal_uInt8 nCol = (sal_uInt8)(nColor >> 16);
556     rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
557     rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
558 
559     nCol = (sal_uInt8)(nColor >> 8);
560     rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
561     rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
562 
563     nCol = (sal_uInt8)nColor;
564     rBuffer.append( sal_Unicode( aHexTab[ nCol >> 4 ] ) );
565     rBuffer.append( sal_Unicode( aHexTab[ nCol & 0xf ] ) );
566 }
567 
568 /** convert number to string */
569 void Converter::convertNumber( OUStringBuffer& rBuffer, sal_Int32 nNumber )
570 {
571     rBuffer.append( nNumber );
572 }
573 
574 /** convert string to number with optional min and max values */
575 bool Converter::convertNumber(	sal_Int32& rValue,
576 								const OUString& rString,
577 								sal_Int32 nMin, sal_Int32 nMax )
578 {
579     bool bNeg = false;
580     rValue = 0;
581 
582     sal_Int32 nPos = 0;
583     sal_Int32 nLen = rString.getLength();
584 
585     // skip white space
586     while( (nPos < nLen) && (rString[nPos] <= sal_Unicode(' ')) )
587         nPos++;
588 
589     if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
590     {
591         bNeg = true;
592         nPos++;
593     }
594 
595     // get number
596     while( nPos < nLen &&
597            sal_Unicode('0') <= rString[nPos] &&
598            sal_Unicode('9') >= rString[nPos] )
599     {
600         // TODO: check overflow!
601         rValue *= 10;
602         rValue += (rString[nPos] - sal_Unicode('0'));
603         nPos++;
604     }
605 
606     if( bNeg )
607         rValue *= -1;
608 
609 	if( rValue < nMin )
610 		rValue = nMin;
611 	else if( rValue > nMax )
612 		rValue = nMax;
613 
614     return nPos == nLen;
615 }
616 
617 /** convert double number to string (using ::rtl::math) */
618 void Converter::convertDouble(  OUStringBuffer& rBuffer,
619 								double fNumber,
620 								bool bWriteUnits,
621 								sal_Int16 nSourceUnit,
622 								sal_Int16 nTargetUnit)
623 {
624     if(MeasureUnit::PERCENT == nSourceUnit)
625     {
626         OSL_ENSURE( nTargetUnit == MeasureUnit::PERCENT, "MeasureUnit::PERCENT only maps to MeasureUnit::PERCENT!" );
627         ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
628         if(bWriteUnits)
629             rBuffer.append(sal_Unicode('%'));
630     }
631     else
632     {
633         OUStringBuffer sUnit;
634         double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
635         if(fFactor != 1.0)
636             fNumber *= fFactor;
637         ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
638         if(bWriteUnits)
639             rBuffer.append(sUnit);
640     }
641 }
642 
643 /** convert double number to string (using ::rtl::math) */
644 void Converter::convertDouble( ::rtl::OUStringBuffer& rBuffer, double fNumber)
645 {
646     ::rtl::math::doubleToUStringBuffer( rBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true);
647 }
648 
649 /** convert string to double number (using ::rtl::math) */
650 bool Converter::convertDouble(double& rValue,
651     const ::rtl::OUString& rString, sal_Int16 nTargetUnit)
652 {
653 	sal_Int16 nSourceUnit = GetUnitFromString(rString, nTargetUnit);
654 
655 	return convertDouble(rValue, rString, nSourceUnit, nTargetUnit );
656 }
657 
658 /** convert string to double number (using ::rtl::math) */
659 bool Converter::convertDouble(double& rValue,
660     const ::rtl::OUString& rString, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
661 {
662     rtl_math_ConversionStatus eStatus;
663     rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
664 
665     if(eStatus == rtl_math_ConversionStatus_Ok)
666     {
667 		OUStringBuffer sUnit;
668         double fFactor = GetConversionFactor(sUnit, nSourceUnit, nTargetUnit);
669         if(fFactor != 1.0 && fFactor != 0.0)
670             rValue /= fFactor;
671     }
672 
673     return ( eStatus == rtl_math_ConversionStatus_Ok );
674 }
675 
676 /** convert string to double number (using ::rtl::math) */
677 bool Converter::convertDouble(double& rValue, const ::rtl::OUString& rString)
678 {
679     rtl_math_ConversionStatus eStatus;
680     rValue = ::rtl::math::stringToDouble( rString, (sal_Unicode)('.'), (sal_Unicode)(','), &eStatus, NULL );
681     return ( eStatus == rtl_math_ConversionStatus_Ok );
682 }
683 
684 /** convert double to ISO "duration" string; negative durations allowed */
685 void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
686                                 const double fTime)
687 {
688     double fValue = fTime;
689 
690     // take care of negative durations as specified in:
691     // XML Schema, W3C Working Draft 07 April 2000, section 3.2.6.1
692     if (fValue < 0.0)
693     {
694         rBuffer.append(sal_Unicode('-'));
695         fValue = - fValue;
696     }
697 
698     rBuffer.appendAscii(RTL_CONSTASCII_STRINGPARAM( "PT" ));
699     fValue *= 24;
700     double fHoursValue = ::rtl::math::approxFloor (fValue);
701     fValue -= fHoursValue;
702     fValue *= 60;
703     double fMinsValue = ::rtl::math::approxFloor (fValue);
704     fValue -= fMinsValue;
705     fValue *= 60;
706     double fSecsValue = ::rtl::math::approxFloor (fValue);
707     fValue -= fSecsValue;
708     double f100SecsValue;
709     if (fValue > 0.00001)
710         f100SecsValue = ::rtl::math::round( fValue, XML_MAXDIGITSCOUNT_TIME - 5);
711     else
712         f100SecsValue = 0.0;
713 
714     if (f100SecsValue == 1.0)
715     {
716         f100SecsValue = 0.0;
717         fSecsValue += 1.0;
718     }
719     if (fSecsValue >= 60.0)
720     {
721         fSecsValue -= 60.0;
722         fMinsValue += 1.0;
723     }
724     if (fMinsValue >= 60.0)
725     {
726         fMinsValue -= 60.0;
727         fHoursValue += 1.0;
728     }
729 
730     if (fHoursValue < 10)
731         rBuffer.append( sal_Unicode('0'));
732     rBuffer.append( sal_Int32( fHoursValue));
733     rBuffer.append( sal_Unicode('H'));
734     if (fMinsValue < 10)
735         rBuffer.append( sal_Unicode('0'));
736     rBuffer.append( sal_Int32( fMinsValue));
737     rBuffer.append( sal_Unicode('M'));
738     if (fSecsValue < 10)
739         rBuffer.append( sal_Unicode('0'));
740     rBuffer.append( sal_Int32( fSecsValue));
741     if (f100SecsValue > 0.0)
742     {
743         ::rtl::OUString a100th( ::rtl::math::doubleToUString( fValue,
744                     rtl_math_StringFormat_F, XML_MAXDIGITSCOUNT_TIME - 5, '.',
745                     true));
746         if ( a100th.getLength() > 2 )
747         {
748             rBuffer.append( sal_Unicode('.'));
749             rBuffer.append( a100th.copy( 2 ) );     // strip 0.
750         }
751     }
752     rBuffer.append( sal_Unicode('S'));
753 }
754 
755 /** convert ISO "duration" string to double; negative durations allowed */
756 bool Converter::convertDuration(double& rfTime,
757                                 const ::rtl::OUString& rString)
758 {
759     rtl::OUString aTrimmed = rString.trim().toAsciiUpperCase();
760     const sal_Unicode* pStr = aTrimmed.getStr();
761 
762     // negative time duration?
763     bool bIsNegativeDuration = false;
764     if ( sal_Unicode('-') == (*pStr) )
765     {
766         bIsNegativeDuration = true;
767         pStr++;
768     }
769 
770     if ( *(pStr++) != sal_Unicode('P') )            // duration must start with "P"
771         return false;
772 
773     rtl::OUString sDoubleStr;
774     bool bSuccess = true;
775     bool bDone = false;
776     bool bTimePart = false;
777     bool bIsFraction = false;
778     sal_Int32 nDays  = 0;
779     sal_Int32 nHours = 0;
780     sal_Int32 nMins  = 0;
781     sal_Int32 nSecs  = 0;
782     sal_Int32 nTemp = 0;
783 
784     while ( bSuccess && !bDone )
785     {
786         sal_Unicode c = *(pStr++);
787         if ( !c )                               // end
788             bDone = true;
789         else if ( sal_Unicode('0') <= c && sal_Unicode('9') >= c )
790         {
791             if ( nTemp >= SAL_MAX_INT32 / 10 )
792                 bSuccess = false;
793             else
794             {
795                 if ( !bIsFraction )
796                 {
797                     nTemp *= 10;
798                     nTemp += (c - sal_Unicode('0'));
799                 }
800                 else
801                 {
802                     sDoubleStr += OUString::valueOf(c);
803                 }
804             }
805         }
806         else if ( bTimePart )
807         {
808             if ( c == sal_Unicode('H') )
809             {
810                 nHours = nTemp;
811                 nTemp = 0;
812             }
813             else if ( c == sal_Unicode('M') )
814             {
815                 nMins = nTemp;
816                 nTemp = 0;
817             }
818             else if ( (c == sal_Unicode(',')) || (c == sal_Unicode('.')) )
819             {
820                 nSecs = nTemp;
821                 nTemp = 0;
822                 bIsFraction = true;
823                 sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0."));
824             }
825             else if ( c == sal_Unicode('S') )
826             {
827                 if ( !bIsFraction )
828                 {
829                     nSecs = nTemp;
830                     nTemp = 0;
831                     sDoubleStr = OUString(RTL_CONSTASCII_USTRINGPARAM("0.0"));
832                 }
833             }
834             else
835                 bSuccess = false;               // invalid character
836         }
837         else
838         {
839             if ( c == sal_Unicode('T') )            // "T" starts time part
840                 bTimePart = true;
841             else if ( c == sal_Unicode('D') )
842             {
843                 nDays = nTemp;
844                 nTemp = 0;
845             }
846             else if ( c == sal_Unicode('Y') || c == sal_Unicode('M') )
847             {
848                 //! how many days is a year or month?
849 
850                 OSL_ENSURE( false, "years or months in duration: not implemented");
851                 bSuccess = false;
852             }
853             else
854                 bSuccess = false;               // invalid character
855         }
856     }
857 
858     if ( bSuccess )
859     {
860         if ( nDays )
861             nHours += nDays * 24;               // add the days to the hours part
862         double fTempTime = 0.0;
863         double fHour = nHours;
864         double fMin = nMins;
865         double fSec = nSecs;
866         double fSec100 = 0.0;
867         double fFraction = sDoubleStr.toDouble();
868         fTempTime = fHour / 24;
869         fTempTime += fMin / (24 * 60);
870         fTempTime += fSec / (24 * 60 * 60);
871         fTempTime += fSec100 / (24 * 60 * 60 * 60);
872         fTempTime += fFraction / (24 * 60 * 60);
873 
874         // negative duration?
875         if ( bIsNegativeDuration )
876         {
877             fTempTime = -fTempTime;
878         }
879 
880         rfTime = fTempTime;
881     }
882     return bSuccess;
883 }
884 
885 /** convert util::Duration to ISO "duration" string */
886 void Converter::convertDuration(::rtl::OUStringBuffer& rBuffer,
887         const ::util::Duration& rDuration)
888 {
889     if (rDuration.Negative)
890     {
891         rBuffer.append(sal_Unicode('-'));
892     }
893     rBuffer.append(sal_Unicode('P'));
894     const bool bHaveDate(static_cast<sal_Int32>(rDuration.Years)
895                         +static_cast<sal_Int32>(rDuration.Months)
896                         +static_cast<sal_Int32>(rDuration.Days));
897     if (rDuration.Years)
898     {
899         rBuffer.append(static_cast<sal_Int32>(rDuration.Years));
900         rBuffer.append(sal_Unicode('Y'));
901     }
902     if (rDuration.Months)
903     {
904         rBuffer.append(static_cast<sal_Int32>(rDuration.Months));
905         rBuffer.append(sal_Unicode('M'));
906     }
907     if (rDuration.Days)
908     {
909         rBuffer.append(static_cast<sal_Int32>(rDuration.Days));
910         rBuffer.append(sal_Unicode('D'));
911     }
912     const sal_Int32 nMSecs(static_cast<sal_Int32>(rDuration.Seconds)
913                          + static_cast<sal_Int32>(rDuration.MilliSeconds));
914     if (static_cast<sal_Int32>(rDuration.Hours) +
915         static_cast<sal_Int32>(rDuration.Minutes) + nMSecs)
916     {
917         rBuffer.append(sal_Unicode('T')); // time separator
918         if (rDuration.Hours)
919         {
920             rBuffer.append(static_cast<sal_Int32>(rDuration.Hours));
921             rBuffer.append(sal_Unicode('H'));
922         }
923         if (rDuration.Minutes)
924         {
925             rBuffer.append(static_cast<sal_Int32>(rDuration.Minutes));
926             rBuffer.append(sal_Unicode('M'));
927         }
928         if (nMSecs)
929         {
930             // seconds must not be omitted (i.e. ".42S" is not valid)
931             rBuffer.append(static_cast<sal_Int32>(rDuration.Seconds));
932             if (rDuration.MilliSeconds)
933             {
934                 rBuffer.append(sal_Unicode('.'));
935                 const sal_Int32 nMilliSeconds(rDuration.MilliSeconds % 1000);
936                 if (nMilliSeconds < 100)
937                 {
938                     rBuffer.append(sal_Unicode('0'));
939                 }
940                 if (nMilliSeconds < 10)
941                 {
942                     rBuffer.append(sal_Unicode('0'));
943                 }
944                 if (0 == (nMilliSeconds % 10))
945                 {
946                     if (0 == (nMilliSeconds % 100))
947                     {
948                         rBuffer.append(nMilliSeconds / 100);
949                     }
950                     else
951                     {
952                         rBuffer.append(nMilliSeconds / 10);
953                     }
954                 }
955                 else
956                 {
957                     rBuffer.append(nMilliSeconds);
958                 }
959             }
960             rBuffer.append(sal_Unicode('S'));
961         }
962     }
963     else if (!bHaveDate)
964     {
965         // zero duration: XMLSchema-2 says there must be at least one component
966         rBuffer.append(sal_Unicode('0'));
967         rBuffer.append(sal_Unicode('D'));
968     }
969 }
970 
971 enum Result { R_NOTHING, R_OVERFLOW, R_SUCCESS };
972 
973 static Result
974 readUnsignedNumber(const ::rtl::OUString & rString,
975     sal_Int32 & io_rnPos, sal_Int32 & o_rNumber)
976 {
977     bool bOverflow(false);
978     sal_Int32 nTemp(0);
979     sal_Int32 nPos(io_rnPos);
980 
981     while (nPos < rString.getLength())
982     {
983         const sal_Unicode c = rString[nPos];
984         if ((sal_Unicode('0') <= c) && (c <= sal_Unicode('9')))
985         {
986             nTemp *= 10;
987             nTemp += (c - sal_Unicode('0'));
988             if (nTemp >= SAL_MAX_INT16)
989             {
990                 bOverflow = true;
991             }
992         }
993         else
994         {
995             break;
996         }
997         ++nPos;
998     }
999 
1000     if (io_rnPos == nPos) // read something?
1001     {
1002         o_rNumber = -1;
1003         return R_NOTHING;
1004     }
1005 
1006     io_rnPos = nPos;
1007     o_rNumber = nTemp;
1008     return (bOverflow) ? R_OVERFLOW : R_SUCCESS;
1009 }
1010 
1011 static bool
1012 readDurationT(const ::rtl::OUString & rString, sal_Int32 & io_rnPos)
1013 {
1014     if ((io_rnPos < rString.getLength()) &&
1015         (rString[io_rnPos] == sal_Unicode('T')))
1016     {
1017         ++io_rnPos;
1018         return true;
1019     }
1020     return false;
1021 }
1022 
1023 static bool
1024 readDurationComponent(const ::rtl::OUString & rString,
1025     sal_Int32 & io_rnPos, sal_Int32 & io_rnTemp, bool & io_rbTimePart,
1026     sal_Int32 & o_rnTarget, const sal_Unicode c)
1027 {
1028     if ((io_rnPos < rString.getLength()))
1029     {
1030         if (c == rString[io_rnPos])
1031         {
1032             ++io_rnPos;
1033             if (-1 != io_rnTemp)
1034             {
1035                 o_rnTarget = io_rnTemp;
1036                 io_rnTemp = -1;
1037                 if (!io_rbTimePart)
1038                 {
1039                     io_rbTimePart = readDurationT(rString, io_rnPos);
1040                 }
1041                 return (R_OVERFLOW !=
1042                         readUnsignedNumber(rString, io_rnPos, io_rnTemp));
1043             }
1044             else
1045             {
1046                 return false;
1047             }
1048         }
1049     }
1050     return true;
1051 }
1052 
1053 /** convert ISO "duration" string to util::Duration */
1054 bool Converter::convertDuration(util::Duration& rDuration,
1055                                 const ::rtl::OUString& rString)
1056 {
1057     const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
1058     sal_Int32 nPos(0);
1059 
1060     bool bIsNegativeDuration(false);
1061     if (string.getLength() && (sal_Unicode('-') == string[0]))
1062     {
1063         bIsNegativeDuration = true;
1064         ++nPos;
1065     }
1066 
1067     if ((nPos < string.getLength())
1068         && (string[nPos] != sal_Unicode('P'))) // duration must start with "P"
1069     {
1070         return false;
1071     }
1072 
1073     ++nPos;
1074 
1075     /// last read number; -1 == no valid number! always reset after using!
1076     sal_Int32 nTemp(-1);
1077     bool bTimePart(false); // have we read 'T'?
1078     bool bSuccess(false);
1079     sal_Int32 nYears(0);
1080     sal_Int32 nMonths(0);
1081     sal_Int32 nDays(0);
1082     sal_Int32 nHours(0);
1083     sal_Int32 nMinutes(0);
1084     sal_Int32 nSeconds(0);
1085     sal_Int32 nMilliSeconds(0);
1086 
1087     bTimePart = readDurationT(string, nPos);
1088     bSuccess = (R_SUCCESS == readUnsignedNumber(string, nPos, nTemp));
1089 
1090     if (!bTimePart && bSuccess)
1091     {
1092         bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1093                      nYears, sal_Unicode('Y'));
1094     }
1095 
1096     if (!bTimePart && bSuccess)
1097     {
1098         bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1099                      nMonths, sal_Unicode('M'));
1100     }
1101 
1102     if (!bTimePart && bSuccess)
1103     {
1104         bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1105                      nDays, sal_Unicode('D'));
1106     }
1107 
1108     if (bTimePart)
1109     {
1110         if (-1 == nTemp) // a 'T' must be followed by a component
1111         {
1112             bSuccess = false;
1113         }
1114 
1115         if (bSuccess)
1116         {
1117             bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1118                          nHours, sal_Unicode('H'));
1119         }
1120 
1121         if (bSuccess)
1122         {
1123             bSuccess = readDurationComponent(string, nPos, nTemp, bTimePart,
1124                          nMinutes, sal_Unicode('M'));
1125         }
1126 
1127         // eeek! seconds are icky.
1128         if ((nPos < string.getLength()) && bSuccess)
1129         {
1130             if (sal_Unicode('.') == string[nPos])
1131             {
1132                 ++nPos;
1133                 if (-1 != nTemp)
1134                 {
1135                     nSeconds = nTemp;
1136                     nTemp = -1;
1137                     const sal_Int32 nStart(nPos);
1138                     bSuccess =
1139                         (R_NOTHING != readUnsignedNumber(string, nPos, nTemp));
1140                     if ((nPos < string.getLength()) && bSuccess)
1141                     {
1142                         if (-1 != nTemp)
1143                         {
1144                             nTemp = -1;
1145                             const sal_Int32 nDigits = nPos - nStart;
1146                             OSL_ENSURE(nDigits > 0, "bad code monkey");
1147                             const sal_Unicode cZero('0');
1148                             nMilliSeconds = 100 * (string[nStart] - cZero);
1149                             if (nDigits >= 2)
1150                             {
1151                                 nMilliSeconds += 10 *
1152                                     (string[nStart+1] - cZero);
1153                                 if (nDigits >= 3)
1154                                 {
1155                                     nMilliSeconds += (string[nStart+2] - cZero);
1156                                 }
1157                             }
1158 
1159                             if (sal_Unicode('S') == string[nPos])
1160                             {
1161                                 ++nPos;
1162                             }
1163                             else
1164                             {
1165                                 bSuccess = false;
1166                             }
1167                         }
1168                         else
1169                         {
1170                             bSuccess = false;
1171                         }
1172                     }
1173                 }
1174                 else
1175                 {
1176                     bSuccess = false;
1177                 }
1178             }
1179             else if (sal_Unicode('S') == string[nPos])
1180             {
1181                 ++nPos;
1182                 if (-1 != nTemp)
1183                 {
1184                     nSeconds = nTemp;
1185                     nTemp = -1;
1186                 }
1187                 else
1188                 {
1189                     bSuccess = false;
1190                 }
1191             }
1192         }
1193     }
1194 
1195     if (nPos != string.getLength()) // string not processed completely?
1196     {
1197         bSuccess = false;
1198     }
1199 
1200     if (nTemp != -1) // unprocessed number?
1201     {
1202         bSuccess = false;
1203     }
1204 
1205     if (bSuccess)
1206     {
1207         rDuration.Negative      = bIsNegativeDuration;
1208         rDuration.Years         = static_cast<sal_Int16>(nYears);
1209         rDuration.Months        = static_cast<sal_Int16>(nMonths);
1210         rDuration.Days          = static_cast<sal_Int16>(nDays);
1211         rDuration.Hours         = static_cast<sal_Int16>(nHours);
1212         rDuration.Minutes       = static_cast<sal_Int16>(nMinutes);
1213         rDuration.Seconds       = static_cast<sal_Int16>(nSeconds);
1214         rDuration.MilliSeconds  = static_cast<sal_Int16>(nMilliSeconds);
1215     }
1216 
1217     return bSuccess;
1218 }
1219 
1220 
1221 /** convert util::Date to ISO "date" string */
1222 void Converter::convertDate(
1223         ::rtl::OUStringBuffer& i_rBuffer,
1224         const util::Date& i_rDate)
1225 {
1226     const util::DateTime dt(
1227             0, 0, 0, 0, i_rDate.Day, i_rDate.Month, i_rDate.Year);
1228     convertDateTime(i_rBuffer, dt, false);
1229 }
1230 
1231 /** convert util::DateTime to ISO "date" or "dateTime" string */
1232 void Converter::convertDateTime(
1233         ::rtl::OUStringBuffer& i_rBuffer,
1234         const com::sun::star::util::DateTime& i_rDateTime,
1235         bool i_bAddTimeIf0AM )
1236 {
1237     const sal_Unicode dash('-');
1238     const sal_Unicode col (':');
1239     const sal_Unicode dot ('.');
1240     const sal_Unicode zero('0');
1241     const sal_Unicode tee ('T');
1242 
1243     if (i_rDateTime.Year < 1000) {
1244         i_rBuffer.append(zero);
1245     }
1246     if (i_rDateTime.Year < 100) {
1247         i_rBuffer.append(zero);
1248     }
1249     if (i_rDateTime.Year < 10) {
1250         i_rBuffer.append(zero);
1251     }
1252     i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Year)  ).append(dash);
1253     if( i_rDateTime.Month < 10 ) {
1254         i_rBuffer.append(zero);
1255     }
1256     i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Month) ).append(dash);
1257     if( i_rDateTime.Day   < 10 ) {
1258         i_rBuffer.append(zero);
1259     }
1260     i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Day)   );
1261 
1262     if( i_rDateTime.Seconds != 0 ||
1263         i_rDateTime.Minutes != 0 ||
1264         i_rDateTime.Hours   != 0 ||
1265         i_bAddTimeIf0AM )
1266     {
1267         i_rBuffer.append(tee);
1268         if( i_rDateTime.Hours   < 10 ) {
1269             i_rBuffer.append(zero);
1270         }
1271         i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Hours)   )
1272                  .append(col);
1273         if( i_rDateTime.Minutes < 10 ) {
1274             i_rBuffer.append(zero);
1275         }
1276         i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Minutes) )
1277                  .append(col);
1278         if( i_rDateTime.Seconds < 10 ) {
1279             i_rBuffer.append(zero);
1280         }
1281         i_rBuffer.append( static_cast<sal_Int32>(i_rDateTime.Seconds) );
1282         if( i_rDateTime.HundredthSeconds > 0 ) {
1283             i_rBuffer.append(dot);
1284             if( i_rDateTime.HundredthSeconds < 10 ) {
1285                 i_rBuffer.append(zero);
1286             }
1287             i_rBuffer.append(
1288                 static_cast<sal_Int32>(i_rDateTime.HundredthSeconds) );
1289         }
1290     }
1291 }
1292 
1293 /** convert ISO "date" or "dateTime" string to util::DateTime */
1294 bool Converter::convertDateTime( util::DateTime& rDateTime,
1295                                  const ::rtl::OUString& rString )
1296 {
1297     bool isDateTime;
1298     util::Date date;
1299     if (convertDateOrDateTime(date, rDateTime, isDateTime, rString))
1300     {
1301         if (!isDateTime)
1302         {
1303             rDateTime.Year = date.Year;
1304             rDateTime.Month = date.Month;
1305             rDateTime.Day = date.Day;
1306             rDateTime.Hours = 0;
1307             rDateTime.Minutes = 0;
1308             rDateTime.Seconds = 0;
1309             rDateTime.HundredthSeconds = 0;
1310         }
1311         return true;
1312     }
1313     else
1314     {
1315         return false;
1316     }
1317 }
1318 
1319 static bool
1320 readDateTimeComponent(const ::rtl::OUString & rString,
1321     sal_Int32 & io_rnPos, sal_Int32 & o_rnTarget,
1322     const sal_Int32 nMinLength, const bool bExactLength)
1323 {
1324     const sal_Int32 nOldPos(io_rnPos);
1325     sal_Int32 nTemp(0);
1326     if (R_SUCCESS != readUnsignedNumber(rString, io_rnPos, nTemp))
1327     {
1328         return false;
1329     }
1330     const sal_Int32 nTokenLength(io_rnPos - nOldPos);
1331     if ((nTokenLength < nMinLength) ||
1332         (bExactLength && (nTokenLength > nMinLength)))
1333     {
1334         return false; // bad length
1335     }
1336     o_rnTarget = nTemp;
1337     return true;
1338 }
1339 
1340 static bool lcl_isLeapYear(const sal_uInt32 nYear)
1341 {
1342     return ((nYear % 4) == 0)
1343         && !(((nYear % 100) == 0) || ((nYear % 400) == 0));
1344 }
1345 
1346 static sal_uInt16
1347 lcl_MaxDaysPerMonth(const sal_Int32 nMonth, const sal_Int32 nYear)
1348 {
1349     static sal_uInt16 s_MaxDaysPerMonth[12] =
1350         { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
1351     OSL_ASSERT(0 < nMonth && nMonth <= 12);
1352     if ((2 == nMonth) && lcl_isLeapYear(nYear))
1353     {
1354         return 29;
1355     }
1356     return s_MaxDaysPerMonth[nMonth - 1];
1357 }
1358 
1359 /** convert ISO "date" or "dateTime" string to util::DateTime or util::Date */
1360 bool Converter::convertDateOrDateTime(
1361                 util::Date & rDate, util::DateTime & rDateTime,
1362                 bool & rbDateTime, const ::rtl::OUString & rString )
1363 {
1364     bool bSuccess = true;
1365 
1366     const ::rtl::OUString string = rString.trim().toAsciiUpperCase();
1367     sal_Int32 nPos(0);
1368     bool bNegative(false);
1369     if ((string.getLength() > nPos) && (sal_Unicode('-') == string[nPos]))
1370     {
1371         ++nPos;
1372         bNegative = true;
1373     }
1374 
1375     sal_Int32 nYear(0);
1376     {
1377         bSuccess = readDateTimeComponent(string, nPos, nYear, 4, false);
1378         bSuccess &= (0 < nYear);
1379         bSuccess &= (nPos < string.getLength()); // not last token
1380     }
1381     if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
1382     {
1383         bSuccess = false;
1384     }
1385     if (bSuccess)
1386     {
1387         ++nPos;
1388     }
1389 
1390     sal_Int32 nMonth(0);
1391     if (bSuccess)
1392     {
1393         bSuccess = readDateTimeComponent(string, nPos, nMonth, 2, true);
1394         bSuccess &= (0 < nMonth) && (nMonth <= 12);
1395         bSuccess &= (nPos < string.getLength()); // not last token
1396     }
1397     if (bSuccess && (sal_Unicode('-') != string[nPos])) // separator
1398     {
1399         bSuccess = false;
1400     }
1401     if (bSuccess)
1402     {
1403         ++nPos;
1404     }
1405 
1406     sal_Int32 nDay(0);
1407     if (bSuccess)
1408     {
1409         bSuccess = readDateTimeComponent(string, nPos, nDay, 2, true);
1410         bSuccess &= (0 < nDay) && (nDay <= lcl_MaxDaysPerMonth(nMonth, nYear));
1411     }
1412 
1413     bool bHaveTime(false);
1414     if (bSuccess && (nPos < string.getLength()))
1415     {
1416         if (sal_Unicode('T') == string[nPos]) // time separator
1417         {
1418             bHaveTime = true;
1419             ++nPos;
1420         }
1421     }
1422 
1423     sal_Int32 nHours(0);
1424     sal_Int32 nMinutes(0);
1425     sal_Int32 nSeconds(0);
1426     sal_Int32 nMilliSeconds(0);
1427     if (bSuccess && bHaveTime)
1428     {
1429         {
1430             bSuccess = readDateTimeComponent(string, nPos, nHours, 2, true);
1431             bSuccess &= (0 <= nHours) && (nHours <= 24);
1432             bSuccess &= (nPos < string.getLength()); // not last token
1433         }
1434         if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
1435         {
1436             bSuccess = false;
1437         }
1438         if (bSuccess)
1439         {
1440             ++nPos;
1441         }
1442 
1443         if (bSuccess)
1444         {
1445             bSuccess = readDateTimeComponent(string, nPos, nMinutes, 2, true);
1446             bSuccess &= (0 <= nMinutes) && (nMinutes < 60);
1447             bSuccess &= (nPos < string.getLength()); // not last token
1448         }
1449         if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
1450         {
1451             bSuccess = false;
1452         }
1453         if (bSuccess)
1454         {
1455             ++nPos;
1456         }
1457 
1458         if (bSuccess)
1459         {
1460             bSuccess = readDateTimeComponent(string, nPos, nSeconds, 2, true);
1461             bSuccess &= (0 <= nSeconds) && (nSeconds < 60);
1462         }
1463         if (bSuccess && (nPos < string.getLength()) &&
1464             (sal_Unicode('.') == string[nPos])) // fraction separator
1465         {
1466             ++nPos;
1467             const sal_Int32 nStart(nPos);
1468             sal_Int32 nTemp(0);
1469             if (R_NOTHING == readUnsignedNumber(string, nPos, nTemp))
1470             {
1471                 bSuccess = false;
1472             }
1473             if (bSuccess)
1474             {
1475                 // cannot use nTemp because of possible leading zeros
1476                 // and possible overflow => read digits directly
1477                 const sal_Int32 nDigits(nPos - nStart);
1478                 OSL_ENSURE(nDigits > 0, "bad code monkey");
1479                 const sal_Unicode cZero('0');
1480                 nMilliSeconds = 100 * (string[nStart] - cZero);
1481                 if (nDigits >= 2)
1482                 {
1483                     nMilliSeconds += 10 * (string[nStart+1] - cZero);
1484                     if (nDigits >= 3)
1485                     {
1486                         nMilliSeconds += (string[nStart+2] - cZero);
1487                     }
1488                 }
1489             }
1490         }
1491 
1492         if (bSuccess && (nHours == 24))
1493         {
1494             if (!((0 == nMinutes) && (0 == nSeconds) && (0 == nMilliSeconds)))
1495             {
1496                 bSuccess = false; // only 24:00:00 is valid
1497             }
1498 #if 0
1499             else
1500             {
1501                 nHours = 0; // normalize 24:00:00 to 00:00:00 of next day
1502                 lcl_addDay(bNegative, nYear, nMonth, nDay, 1);
1503             }
1504 #endif
1505         }
1506     }
1507 
1508     bool bHaveTimezone(false);
1509     bool bHaveTimezonePlus(false);
1510     bool bHaveTimezoneMinus(false);
1511     if (bSuccess && (nPos < string.getLength()))
1512     {
1513         const sal_Unicode c(string[nPos]);
1514         if (sal_Unicode('+') == c)
1515         {
1516             bHaveTimezone = true;
1517             bHaveTimezonePlus = true;
1518             ++nPos;
1519         }
1520         else if (sal_Unicode('-') == c)
1521         {
1522             bHaveTimezone = true;
1523             bHaveTimezoneMinus = true;
1524             ++nPos;
1525         }
1526         else if (sal_Unicode('Z') == c)
1527         {
1528             bHaveTimezone = true;
1529             ++nPos;
1530         }
1531         else
1532         {
1533             bSuccess = false;
1534         }
1535     }
1536     sal_Int32 nTimezoneHours(0);
1537     sal_Int32 nTimezoneMinutes(0);
1538     if (bSuccess && (bHaveTimezonePlus || bHaveTimezoneMinus))
1539     {
1540         bSuccess = readDateTimeComponent(
1541                         string, nPos, nTimezoneHours, 2, true);
1542         bSuccess &= (0 <= nTimezoneHours) && (nTimezoneHours <= 14);
1543         bSuccess &= (nPos < string.getLength()); // not last token
1544         if (bSuccess && (sal_Unicode(':') != string[nPos])) // separator
1545         {
1546             bSuccess = false;
1547         }
1548         if (bSuccess)
1549         {
1550             ++nPos;
1551         }
1552         if (bSuccess)
1553         {
1554             bSuccess = readDateTimeComponent(
1555                         string, nPos, nTimezoneMinutes, 2, true);
1556             bSuccess &= (0 <= nTimezoneMinutes) && (nTimezoneMinutes < 60);
1557         }
1558         if (bSuccess && (nTimezoneHours == 14))
1559         {
1560             if (0 != nTimezoneMinutes)
1561             {
1562                 bSuccess = false; // only +-14:00 is valid
1563             }
1564         }
1565     }
1566 
1567     bSuccess &= (nPos == string.getLength()); // trailing junk?
1568 
1569     if (bSuccess && bHaveTimezone)
1570     {
1571         // util::DateTime does not support timezones!
1572 #if 0
1573         // do not add timezone, just strip it (as suggested by er)
1574         lcl_addTimezone(bNegative, nYear, nMonth, nDay, nHours, nMinutes,
1575                 !bHaveTimezoneMinus, nTimezoneHours, nTimezoneMinutes);
1576 #endif
1577     }
1578 
1579     if (bSuccess)
1580     {
1581         if (bHaveTime) // time is optional
1582         {
1583             // util::DateTime does not support negative years!
1584             rDateTime.Year = static_cast<sal_uInt16>(nYear);
1585             rDateTime.Month = static_cast<sal_uInt16>(nMonth);
1586             rDateTime.Day = static_cast<sal_uInt16>(nDay);
1587             rDateTime.Hours = static_cast<sal_uInt16>(nHours);
1588             rDateTime.Minutes = static_cast<sal_uInt16>(nMinutes);
1589             rDateTime.Seconds = static_cast<sal_uInt16>(nSeconds);
1590             // util::DateTime does not support 3 decimal digits of precision!
1591             rDateTime.HundredthSeconds =
1592                 static_cast<sal_uInt16>(nMilliSeconds / 10);
1593             rbDateTime = true;
1594         }
1595         else
1596         {
1597             rDate.Year = static_cast<sal_uInt16>(nYear);
1598             rDate.Month = static_cast<sal_uInt16>(nMonth);
1599             rDate.Day = static_cast<sal_uInt16>(nDay);
1600             rbDateTime = false;
1601         }
1602     }
1603     return bSuccess;
1604 }
1605 
1606 
1607 /** gets the position of the first comma after npos in the string
1608     rStr. Commas inside '"' pairs are not matched */
1609 sal_Int32 Converter::indexOfComma( const OUString& rStr,
1610                                             sal_Int32 nPos )
1611 {
1612     sal_Unicode cQuote = 0;
1613     sal_Int32 nLen = rStr.getLength();
1614     for( ; nPos < nLen; nPos++ )
1615     {
1616         sal_Unicode c = rStr[nPos];
1617         switch( c )
1618         {
1619         case sal_Unicode('\''):
1620             if( 0 == cQuote )
1621                 cQuote = c;
1622             else if( '\'' == cQuote )
1623                 cQuote = 0;
1624             break;
1625 
1626         case sal_Unicode('"'):
1627             if( 0 == cQuote )
1628                 cQuote = c;
1629             else if( '\"' == cQuote )
1630                 cQuote = 0;
1631             break;
1632 
1633         case sal_Unicode(','):
1634             if( 0 == cQuote )
1635                 return nPos;
1636             break;
1637         }
1638     }
1639 
1640     return -1;
1641 }
1642 
1643 const
1644   sal_Char aBase64EncodeTable[] =
1645     { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
1646       'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
1647       'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
1648       'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
1649       '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/' };
1650 
1651 const
1652   sal_uInt8 aBase64DecodeTable[]  =
1653     {											 62,255,255,255, 63, // 43-47
1654 //                                                +               /
1655 
1656      52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255, // 48-63
1657 //    0   1   2   3   4   5   6   7   8   9               =
1658 
1659     255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // 64-79
1660 //        A   B   C   D   E   F   G   H   I   J   K   L   M   N   O
1661 
1662      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255, // 80-95
1663 //    P   Q   R   S   T   U   V   W   X   Y   Z
1664 
1665       0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96-111
1666 //        a   b   c   d   e   f   g   h   i   j   k   l   m   n   o
1667 
1668      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 }; // 112-123
1669 //    p   q   r   s   t   u   v   w   x   y   z
1670 
1671 
1672 
1673 void ThreeByteToFourByte (const sal_Int8* pBuffer, const sal_Int32 nStart, const sal_Int32 nFullLen, rtl::OUStringBuffer& sBuffer)
1674 {
1675     sal_Int32 nLen(nFullLen - nStart);
1676     if (nLen > 3)
1677         nLen = 3;
1678     if (nLen == 0)
1679     {
1680         sBuffer.setLength(0);
1681         return;
1682     }
1683 
1684     sal_Int32 nBinaer;
1685     switch (nLen)
1686     {
1687         case 1:
1688         {
1689             nBinaer = ((sal_uInt8)pBuffer[nStart + 0]) << 16;
1690         }
1691         break;
1692         case 2:
1693         {
1694             nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
1695                     (((sal_uInt8)pBuffer[nStart + 1]) <<  8);
1696         }
1697         break;
1698         default:
1699         {
1700             nBinaer = (((sal_uInt8)pBuffer[nStart + 0]) << 16) +
1701                     (((sal_uInt8)pBuffer[nStart + 1]) <<  8) +
1702                     ((sal_uInt8)pBuffer[nStart + 2]);
1703         }
1704         break;
1705     }
1706 
1707     sBuffer.appendAscii("====");
1708 
1709     sal_uInt8 nIndex (static_cast<sal_uInt8>((nBinaer & 0xFC0000) >> 18));
1710     sBuffer.setCharAt(0, aBase64EncodeTable [nIndex]);
1711 
1712     nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F000) >> 12);
1713     sBuffer.setCharAt(1, aBase64EncodeTable [nIndex]);
1714     if (nLen == 1)
1715         return;
1716 
1717     nIndex = static_cast<sal_uInt8>((nBinaer & 0xFC0) >> 6);
1718     sBuffer.setCharAt(2, aBase64EncodeTable [nIndex]);
1719     if (nLen == 2)
1720         return;
1721 
1722     nIndex = static_cast<sal_uInt8>((nBinaer & 0x3F));
1723     sBuffer.setCharAt(3, aBase64EncodeTable [nIndex]);
1724 }
1725 
1726 void Converter::encodeBase64(rtl::OUStringBuffer& aStrBuffer, const uno::Sequence<sal_Int8>& aPass)
1727 {
1728 	sal_Int32 i(0);
1729 	sal_Int32 nBufferLength(aPass.getLength());
1730 	const sal_Int8* pBuffer = aPass.getConstArray();
1731 	while (i < nBufferLength)
1732 	{
1733 		rtl::OUStringBuffer sBuffer;
1734 		ThreeByteToFourByte (pBuffer, i, nBufferLength, sBuffer);
1735 		aStrBuffer.append(sBuffer);
1736 		i += 3;
1737 	}
1738 }
1739 
1740 void Converter::decodeBase64(uno::Sequence<sal_Int8>& aBuffer, const rtl::OUString& sBuffer)
1741 {
1742 #if OSL_DEBUG_LEVEL > 0
1743 	sal_Int32 nCharsDecoded =
1744 #endif
1745 	decodeBase64SomeChars( aBuffer, sBuffer );
1746 	OSL_ENSURE( nCharsDecoded == sBuffer.getLength(), "some bytes left in base64 decoding!" );
1747 }
1748 
1749 sal_Int32 Converter::decodeBase64SomeChars(
1750 		uno::Sequence<sal_Int8>& rOutBuffer,
1751 		const rtl::OUString& rInBuffer)
1752 {
1753 	sal_Int32 nInBufferLen = rInBuffer.getLength();
1754 	sal_Int32 nMinOutBufferLen = (nInBufferLen / 4) * 3;
1755 	if( rOutBuffer.getLength() < nMinOutBufferLen )
1756 		rOutBuffer.realloc( nMinOutBufferLen );
1757 
1758 	const sal_Unicode *pInBuffer = rInBuffer.getStr();
1759 	sal_Int8 *pOutBuffer = rOutBuffer.getArray();
1760 	sal_Int8 *pOutBufferStart = pOutBuffer;
1761 	sal_Int32 nCharsDecoded = 0;
1762 
1763 	sal_uInt8 aDecodeBuffer[4];
1764 	sal_Int32 nBytesToDecode = 0;
1765 	sal_Int32 nBytesGotFromDecoding = 3;
1766 	sal_Int32 nInBufferPos= 0;
1767 	while( nInBufferPos < nInBufferLen )
1768 	{
1769 		sal_Unicode cChar = *pInBuffer;
1770 		if( cChar >= '+' && cChar <= 'z' )
1771 		{
1772 			sal_uInt8 nByte = aBase64DecodeTable[cChar-'+'];
1773 			if( nByte != 255 )
1774 			{
1775 				// We have found a valid character!
1776 				aDecodeBuffer[nBytesToDecode++] = nByte;
1777 
1778 				// One '=' character at the end means 2 out bytes
1779 				// Two '=' characters at the end mean 1 out bytes
1780 				if( '=' == cChar && nBytesToDecode > 2 )
1781 					nBytesGotFromDecoding--;
1782 				if( 4 == nBytesToDecode )
1783 				{
1784 					// Four characters found, so we may convert now!
1785 					sal_uInt32 nOut = (aDecodeBuffer[0] << 18) +
1786 									  (aDecodeBuffer[1] << 12) +
1787 									  (aDecodeBuffer[2] << 6) +
1788 									   aDecodeBuffer[3];
1789 
1790 					*pOutBuffer++  = (sal_Int8)((nOut & 0xff0000) >> 16);
1791 					if( nBytesGotFromDecoding > 1 )
1792 						*pOutBuffer++  = (sal_Int8)((nOut & 0xff00) >> 8);
1793 					if( nBytesGotFromDecoding > 2 )
1794 						*pOutBuffer++  = (sal_Int8)(nOut & 0xff);
1795 					nCharsDecoded = nInBufferPos + 1;
1796 					nBytesToDecode = 0;
1797 					nBytesGotFromDecoding = 3;
1798 				}
1799 			}
1800 			else
1801 			{
1802 				nCharsDecoded++;
1803 			}
1804 		}
1805 		else
1806 		{
1807 			nCharsDecoded++;
1808 		}
1809 
1810 		nInBufferPos++;
1811 		pInBuffer++;
1812 	}
1813 	if( (pOutBuffer - pOutBufferStart) != rOutBuffer.getLength() )
1814 		rOutBuffer.realloc( pOutBuffer - pOutBufferStart );
1815 
1816 	return nCharsDecoded;
1817 }
1818 
1819 void Converter::clearUndefinedChars(rtl::OUString& rTarget, const rtl::OUString& rSource)
1820 {
1821 	sal_uInt32 nLength(rSource.getLength());
1822 	rtl::OUStringBuffer sBuffer(nLength);
1823 	for (sal_uInt32 i = 0; i < nLength; i++)
1824 	{
1825 		sal_Unicode cChar = rSource[i];
1826 		if (!(cChar < 0x0020) ||
1827 			(cChar == 0x0009) ||		// TAB
1828 			(cChar == 0x000A) ||		// LF
1829 			(cChar == 0x000D))			// legal character
1830 			sBuffer.append(cChar);
1831 	}
1832 	rTarget = sBuffer.makeStringAndClear();
1833 }
1834 
1835 double Converter::GetConversionFactor(::rtl::OUStringBuffer& rUnit, sal_Int16 nSourceUnit, sal_Int16 nTargetUnit)
1836 {
1837 	double fRetval(1.0);
1838 	rUnit.setLength(0L);
1839 
1840 	const sal_Char* psUnit = 0;
1841 
1842 	if(nSourceUnit != nTargetUnit)
1843 	{
1844 		switch(nSourceUnit)
1845 		{
1846 			case MeasureUnit::TWIP:
1847 			{
1848 				switch(nTargetUnit)
1849 				{
1850 					case MeasureUnit::MM_100TH:
1851 					case MeasureUnit::MM_10TH:
1852 					{
1853                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
1854 					}
1855 					case MeasureUnit::MM:
1856 					{
1857 						// 0.01mm = 0.57twip (exactly)
1858 						fRetval = ((25400.0 / 1440.0) / 1000.0);
1859 						psUnit = gpsMM;
1860 						break;
1861 					}
1862 					case MeasureUnit::CM:
1863 					{
1864 						// 0.001cm = 0.57twip (exactly)
1865 						fRetval = ((25400.0 / 1440.0) / 10000.0);
1866 						psUnit = gpsCM;
1867 						break;
1868 					}
1869 					case MeasureUnit::POINT:
1870 					{
1871 						// 0.01pt = 0.2twip (exactly)
1872 						fRetval = ((1000.0 / 20.0) / 1000.0);
1873 						psUnit = gpsPT;
1874 						break;
1875 					}
1876 					case MeasureUnit::INCH:
1877 					default:
1878 					{
1879                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for twip values");
1880 						// 0.0001in = 0.144twip (exactly)
1881 						fRetval = ((100000.0 / 1440.0) / 100000.0);
1882 						psUnit = gpsINCH;
1883 						break;
1884 					}
1885 				}
1886 				break;
1887 			}
1888 			case MeasureUnit::POINT:
1889 			{
1890                 switch(nTargetUnit)
1891                 {
1892                     case MeasureUnit::MM:
1893                         // 1mm = 72 / 25.4 pt (exactly)
1894                         fRetval = ( 25.4 / 72.0 );
1895                         psUnit = gpsMM;
1896                         break;
1897 
1898                     case MeasureUnit::CM:
1899                         // 1cm = 72 / 2.54 pt (exactly)
1900                         fRetval = ( 2.54 / 72.0 );
1901                         psUnit = gpsCM;
1902                         break;
1903 
1904                     case MeasureUnit::TWIP:
1905                         // 1twip = 72 / 1440 pt (exactly)
1906                         fRetval = 20.0;     // 1440.0 / 72.0
1907                         psUnit = gpsPC;
1908                         break;
1909 
1910                     case MeasureUnit::INCH:
1911                     default:
1912                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for pt values");
1913                         // 1in = 72 pt (exactly)
1914                         fRetval = ( 1.0 / 72.0 );
1915                         psUnit = gpsINCH;
1916                         break;
1917                 }
1918                 break;
1919 			}
1920             case MeasureUnit::MM_10TH:
1921 			{
1922 				switch(nTargetUnit)
1923 				{
1924 					case MeasureUnit::MM_100TH:
1925 					case MeasureUnit::MM_10TH:
1926 					{
1927                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
1928 					}
1929 					case MeasureUnit::MM:
1930 					{
1931 						// 0.01mm = 1 mm/100 (exactly)
1932 						fRetval = ((10.0 / 1.0) / 100.0);
1933 						psUnit = gpsMM;
1934 						break;
1935 					}
1936 					case MeasureUnit::CM:
1937 					{
1938 						// 0.001mm = 1 mm/100 (exactly)
1939 						fRetval = ((10.0 / 1.0) / 1000.0);
1940 						psUnit = gpsCM;
1941 						break;
1942 					}
1943 					case MeasureUnit::POINT:
1944 					{
1945 						// 0.01pt = 0.35 mm/100 (exactly)
1946 						fRetval = ((72000.0 / 2540.0) / 100.0);
1947 						psUnit = gpsPT;
1948 						break;
1949 					}
1950 					case MeasureUnit::INCH:
1951 					default:
1952 					{
1953                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
1954 						// 0.0001in = 0.254 mm/100 (exactly)
1955 						fRetval = ((100000.0 / 2540.0) / 10000.0);
1956 						psUnit = gpsINCH;
1957 						break;
1958 					}
1959 				}
1960 				break;
1961             }
1962 			case MeasureUnit::MM_100TH:
1963 			{
1964 				switch(nTargetUnit)
1965 				{
1966 					case MeasureUnit::MM_100TH:
1967 					case MeasureUnit::MM_10TH:
1968 					{
1969                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
1970 					}
1971 					case MeasureUnit::MM:
1972 					{
1973 						// 0.01mm = 1 mm/100 (exactly)
1974 						fRetval = ((10.0 / 1.0) / 1000.0);
1975 						psUnit = gpsMM;
1976 						break;
1977 					}
1978 					case MeasureUnit::CM:
1979 					{
1980 						// 0.001mm = 1 mm/100 (exactly)
1981 						fRetval = ((10.0 / 1.0) / 10000.0);
1982 						psUnit = gpsCM;
1983 						break;
1984 					}
1985 					case MeasureUnit::POINT:
1986 					{
1987 						// 0.01pt = 0.35 mm/100 (exactly)
1988 						fRetval = ((72000.0 / 2540.0) / 1000.0);
1989 						psUnit = gpsPT;
1990 						break;
1991 					}
1992 					case MeasureUnit::INCH:
1993 					default:
1994 					{
1995                         OSL_ENSURE( MeasureUnit::INCH == nTargetUnit, "output unit not supported for 1/100mm values");
1996 						// 0.0001in = 0.254 mm/100 (exactly)
1997 						fRetval = ((100000.0 / 2540.0) / 100000.0);
1998 						psUnit = gpsINCH;
1999 						break;
2000 					}
2001 				}
2002 				break;
2003 			}
2004 		}
2005 
2006 		if( psUnit )
2007 			rUnit.appendAscii( psUnit );
2008 	}
2009 
2010 	return fRetval;
2011 }
2012 
2013 sal_Int16 Converter::GetUnitFromString(const ::rtl::OUString& rString, sal_Int16 nDefaultUnit)
2014 {
2015 	sal_Int32 nPos = 0L;
2016 	sal_Int32 nLen = rString.getLength();
2017 	sal_Int16 nRetUnit = nDefaultUnit;
2018 
2019 	// skip white space
2020 	while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
2021 		nPos++;
2022 
2023 	// skip negative
2024 	if( nPos < nLen && sal_Unicode('-') == rString[nPos] )
2025 		nPos++;
2026 
2027 	// skip number
2028 	while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
2029 		nPos++;
2030 
2031 	if( nPos < nLen && sal_Unicode('.') == rString[nPos] )
2032 	{
2033 		nPos++;
2034 		while( nPos < nLen && sal_Unicode('0') <= rString[nPos] && sal_Unicode('9') >= rString[nPos] )
2035 			nPos++;
2036 	}
2037 
2038 	// skip white space
2039 	while( nPos < nLen && sal_Unicode(' ') == rString[nPos] )
2040 		nPos++;
2041 
2042 	if( nPos < nLen )
2043 	{
2044 		switch(rString[nPos])
2045 		{
2046 			case sal_Unicode('%') :
2047 			{
2048 				nRetUnit = MeasureUnit::PERCENT;
2049 				break;
2050 			}
2051 			case sal_Unicode('c'):
2052 			case sal_Unicode('C'):
2053 			{
2054 				if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
2055 					|| rString[nPos+1] == sal_Unicode('M')))
2056 					nRetUnit = MeasureUnit::CM;
2057 				break;
2058 			}
2059 			case sal_Unicode('e'):
2060 			case sal_Unicode('E'):
2061 			{
2062 				// CSS1_EMS or CSS1_EMX later
2063 				break;
2064 			}
2065 			case sal_Unicode('i'):
2066 			case sal_Unicode('I'):
2067 			{
2068 				if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('n')
2069 					|| rString[nPos+1] == sal_Unicode('n')))
2070 					nRetUnit = MeasureUnit::INCH;
2071 				break;
2072 			}
2073 			case sal_Unicode('m'):
2074 			case sal_Unicode('M'):
2075 			{
2076 				if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('m')
2077 					|| rString[nPos+1] == sal_Unicode('M')))
2078 					nRetUnit = MeasureUnit::MM;
2079 				break;
2080 			}
2081 			case sal_Unicode('p'):
2082 			case sal_Unicode('P'):
2083 			{
2084 				if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('t')
2085 					|| rString[nPos+1] == sal_Unicode('T')))
2086 					nRetUnit = MeasureUnit::POINT;
2087 				if(nPos+1 < nLen && (rString[nPos+1] == sal_Unicode('c')
2088 					|| rString[nPos+1] == sal_Unicode('C')))
2089 					nRetUnit = MeasureUnit::TWIP;
2090 				break;
2091 			}
2092 		}
2093 	}
2094 
2095 	return nRetUnit;
2096 }
2097 
2098 }
2099