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