xref: /trunk/main/sax/source/tools/converter.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
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